Spaces:
Sleeping
Sleeping
Update api.py
Browse files
api.py
CHANGED
|
@@ -2,7 +2,7 @@ import os
|
|
| 2 |
import uuid
|
| 3 |
import unicodedata
|
| 4 |
import re
|
| 5 |
-
from fastapi import FastAPI, HTTPException,
|
| 6 |
from fastapi.responses import FileResponse
|
| 7 |
from pydantic import BaseModel
|
| 8 |
import edge_tts
|
|
@@ -28,11 +28,8 @@ VOICES = {
|
|
| 28 |
SUPPORTED_LANGUAGES = list(VOICES.keys())
|
| 29 |
|
| 30 |
def clean_text(text: str) -> str:
|
| 31 |
-
# Normalize unicode (handles tashkeel and special chars)
|
| 32 |
text = unicodedata.normalize("NFC", text)
|
| 33 |
-
# Remove control characters except newlines and tabs
|
| 34 |
text = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '', text)
|
| 35 |
-
# Replace multiple newlines/spaces with single space
|
| 36 |
text = re.sub(r'\s+', ' ', text)
|
| 37 |
return text.strip()
|
| 38 |
|
|
@@ -46,10 +43,10 @@ class TTSRequest(BaseModel):
|
|
| 46 |
def root():
|
| 47 |
return {"message": "Edge TTS API is running ✅"}
|
| 48 |
|
|
|
|
| 49 |
@app.post("/tts")
|
| 50 |
async def synthesize(req: TTSRequest):
|
| 51 |
text = clean_text(req.text)
|
| 52 |
-
|
| 53 |
if not text:
|
| 54 |
raise HTTPException(status_code=400, detail="Text cannot be empty.")
|
| 55 |
if req.language not in VOICES:
|
|
@@ -60,7 +57,6 @@ async def synthesize(req: TTSRequest):
|
|
| 60 |
lang_voices = VOICES[req.language]
|
| 61 |
gender = req.gender if req.gender in lang_voices else list(lang_voices.keys())[0]
|
| 62 |
voice = lang_voices[gender]
|
| 63 |
-
|
| 64 |
output_path = os.path.join("tts_outputs", f"{uuid.uuid4()}.mp3")
|
| 65 |
|
| 66 |
try:
|
|
@@ -69,12 +65,38 @@ async def synthesize(req: TTSRequest):
|
|
| 69 |
except Exception as e:
|
| 70 |
raise HTTPException(status_code=500, detail=str(e))
|
| 71 |
|
| 72 |
-
return FileResponse(
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
|
| 79 |
@app.get("/voices")
|
| 80 |
def get_voices():
|
|
|
|
| 2 |
import uuid
|
| 3 |
import unicodedata
|
| 4 |
import re
|
| 5 |
+
from fastapi import FastAPI, HTTPException, Query
|
| 6 |
from fastapi.responses import FileResponse
|
| 7 |
from pydantic import BaseModel
|
| 8 |
import edge_tts
|
|
|
|
| 28 |
SUPPORTED_LANGUAGES = list(VOICES.keys())
|
| 29 |
|
| 30 |
def clean_text(text: str) -> str:
|
|
|
|
| 31 |
text = unicodedata.normalize("NFC", text)
|
|
|
|
| 32 |
text = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '', text)
|
|
|
|
| 33 |
text = re.sub(r'\s+', ' ', text)
|
| 34 |
return text.strip()
|
| 35 |
|
|
|
|
| 43 |
def root():
|
| 44 |
return {"message": "Edge TTS API is running ✅"}
|
| 45 |
|
| 46 |
+
# JSON endpoint (original)
|
| 47 |
@app.post("/tts")
|
| 48 |
async def synthesize(req: TTSRequest):
|
| 49 |
text = clean_text(req.text)
|
|
|
|
| 50 |
if not text:
|
| 51 |
raise HTTPException(status_code=400, detail="Text cannot be empty.")
|
| 52 |
if req.language not in VOICES:
|
|
|
|
| 57 |
lang_voices = VOICES[req.language]
|
| 58 |
gender = req.gender if req.gender in lang_voices else list(lang_voices.keys())[0]
|
| 59 |
voice = lang_voices[gender]
|
|
|
|
| 60 |
output_path = os.path.join("tts_outputs", f"{uuid.uuid4()}.mp3")
|
| 61 |
|
| 62 |
try:
|
|
|
|
| 65 |
except Exception as e:
|
| 66 |
raise HTTPException(status_code=500, detail=str(e))
|
| 67 |
|
| 68 |
+
return FileResponse(path=output_path, media_type="audio/mpeg", filename="output.mp3", headers={"X-Voice": voice})
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
# Plain text endpoint (easier for Swagger)
|
| 72 |
+
@app.post("/tts-text")
|
| 73 |
+
async def synthesize_text(
|
| 74 |
+
text: str = Query(..., description="النص المراد تحويله"),
|
| 75 |
+
language: str = Query("en", description="ar, en, fr, es, de, it, tr, ru, hi"),
|
| 76 |
+
gender: str = Query("female", description="male or female"),
|
| 77 |
+
rate: str = Query("+0%", description="السرعة: -50%, -25%, +0%, +25%, +50%")
|
| 78 |
+
):
|
| 79 |
+
text = clean_text(text)
|
| 80 |
+
if not text:
|
| 81 |
+
raise HTTPException(status_code=400, detail="Text cannot be empty.")
|
| 82 |
+
if language not in VOICES:
|
| 83 |
+
raise HTTPException(status_code=400, detail=f"Unsupported language. Choose from: {SUPPORTED_LANGUAGES}")
|
| 84 |
+
if gender not in ["male", "female"]:
|
| 85 |
+
raise HTTPException(status_code=400, detail="Gender must be 'male' or 'female'.")
|
| 86 |
+
|
| 87 |
+
lang_voices = VOICES[language]
|
| 88 |
+
gender = gender if gender in lang_voices else list(lang_voices.keys())[0]
|
| 89 |
+
voice = lang_voices[gender]
|
| 90 |
+
output_path = os.path.join("tts_outputs", f"{uuid.uuid4()}.mp3")
|
| 91 |
+
|
| 92 |
+
try:
|
| 93 |
+
communicate = edge_tts.Communicate(text, voice, rate=rate)
|
| 94 |
+
await communicate.save(output_path)
|
| 95 |
+
except Exception as e:
|
| 96 |
+
raise HTTPException(status_code=500, detail=str(e))
|
| 97 |
+
|
| 98 |
+
return FileResponse(path=output_path, media_type="audio/mpeg", filename="output.mp3", headers={"X-Voice": voice})
|
| 99 |
+
|
| 100 |
|
| 101 |
@app.get("/voices")
|
| 102 |
def get_voices():
|