|
import gradio as gr |
|
import edge_tts |
|
import asyncio |
|
import tempfile |
|
import os |
|
from fastapi import FastAPI, Request, HTTPException |
|
from fastapi.responses import FileResponse, JSONResponse |
|
from fastapi.middleware.cors import CORSMiddleware |
|
import uvicorn |
|
|
|
|
|
app = FastAPI() |
|
|
|
|
|
app.add_middleware( |
|
CORSMiddleware, |
|
allow_origins=["*"], |
|
allow_methods=["POST", "GET"], |
|
allow_headers=["*"], |
|
) |
|
|
|
@app.post("/api/tts") |
|
async def api_tts(request: Request): |
|
try: |
|
data = await request.json() |
|
text = data.get("text", "").strip() |
|
voice = data.get("voice", "en-US-GuyNeural") |
|
rate = data.get("rate", 0) |
|
pitch = data.get("pitch", 0) |
|
|
|
if not text: |
|
raise HTTPException(status_code=400, detail="Text is required") |
|
|
|
rate_str = f"{rate:+d}%" |
|
pitch_str = f"{pitch:+d}Hz" |
|
|
|
communicate = edge_tts.Communicate(text, voice, rate=rate_str, pitch=pitch_str) |
|
output_file = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3").name |
|
await communicate.save(output_file) |
|
|
|
return FileResponse(output_file, media_type="audio/mpeg") |
|
|
|
except Exception as e: |
|
raise HTTPException(status_code=500, detail=str(e)) |
|
|
|
|
|
async def get_voices(): |
|
voices = await edge_tts.list_voices() |
|
return {f"{v['ShortName']} - {v['Locale']} ({v['Gender']})": v['ShortName'] for v in voices} |
|
|
|
async def text_to_speech(text, voice, rate, pitch): |
|
if not text.strip(): |
|
return None, "Please enter text to convert." |
|
if not voice: |
|
return None, "Please select a voice." |
|
|
|
voice_short_name = voice.split(" - ")[0] |
|
rate_str = f"{rate:+d}%" |
|
pitch_str = f"{pitch:+d}Hz" |
|
communicate = edge_tts.Communicate(text, voice_short_name, rate=rate_str, pitch=pitch_str) |
|
|
|
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp_file: |
|
tmp_path = tmp_file.name |
|
await communicate.save(tmp_path) |
|
|
|
return tmp_path, None |
|
|
|
async def create_demo(): |
|
voices = await get_voices() |
|
|
|
with gr.Blocks(analytics_enabled=False) as demo: |
|
|
|
|
|
|
|
return demo |
|
|
|
|
|
gradio_app = gr.mount_gradio_app(app, await create_demo(), path="/") |
|
|
|
@gradio_app.get("/") |
|
async def root(): |
|
return {"message": "Edge TTS API is running. Use /api/tts for API or / for Gradio UI."} |
|
|
|
if __name__ == "__main__": |
|
uvicorn.run(gradio_app, host="0.0.0.0", port=7860) |