Di7x commited on
Commit
95588ae
·
verified ·
1 Parent(s): 4dca30d

Upload 5 files

Browse files
Files changed (5) hide show
  1. Dockerfile +12 -0
  2. README.md +7 -7
  3. app.py +172 -0
  4. gitattributes +35 -0
  5. requirements.txt +4 -0
Dockerfile ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /app
4
+
5
+ COPY requirements.txt /app/requirements.txt
6
+ RUN pip install --no-cache-dir -r /app/requirements.txt
7
+
8
+ COPY app.py /app/app.py
9
+
10
+ EXPOSE 7860
11
+
12
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
README.md CHANGED
@@ -1,11 +1,11 @@
1
  ---
2
- title: Ets2
3
- emoji: 🏃
4
- colorFrom: green
5
- colorTo: blue
6
  sdk: docker
 
7
  pinned: false
8
  license: apache-2.0
9
- ---
10
-
11
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: Edge Tts Api 1
3
+ emoji: 😻
4
+ colorFrom: red
5
+ colorTo: pink
6
  sdk: docker
7
+ app_port: 7860
8
  pinned: false
9
  license: apache-2.0
10
+ short_description: edge-tts-api-1
11
+ ---
 
app.py ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ import uuid
3
+ from pathlib import Path
4
+
5
+ import edge_tts
6
+ from fastapi import FastAPI, HTTPException, Query
7
+ from fastapi.middleware.cors import CORSMiddleware
8
+ from fastapi.responses import FileResponse, JSONResponse
9
+ from pydantic import BaseModel
10
+ from starlette.background import BackgroundTask
11
+
12
+ app = FastAPI(title="Edge TTS API")
13
+
14
+ app.add_middleware(
15
+ CORSMiddleware,
16
+ allow_origins=["*"],
17
+ allow_credentials=False,
18
+ allow_methods=["*"],
19
+ allow_headers=["*"],
20
+ )
21
+
22
+ TMP_DIR = Path("/tmp/edge_tts_api")
23
+ TMP_DIR.mkdir(parents=True, exist_ok=True)
24
+
25
+
26
+ class TTSRequest(BaseModel):
27
+ text: str
28
+ voice: str = "bg-BG-BorislavNeural"
29
+ rate: str = "+0%"
30
+ volume: str = "+0%"
31
+ pitch: str = "+0Hz"
32
+
33
+
34
+ def simplify_voice(v: dict) -> dict:
35
+ short_name = v.get("ShortName", "")
36
+ locale = v.get("Locale", "")
37
+ return {
38
+ "Name": v.get("Name", ""),
39
+ "ShortName": short_name,
40
+ "FriendlyName": v.get("FriendlyName", ""),
41
+ "Locale": locale,
42
+ "Gender": v.get("Gender", ""),
43
+ "SuggestedCodec": v.get("SuggestedCodec", ""),
44
+ "Status": v.get("Status", ""),
45
+ "IsMultilingual": "Multilingual" in short_name,
46
+ "IsBulgarian": locale == "bg-BG",
47
+ }
48
+
49
+
50
+ def cleanup_old_files(folder: Path, max_age_seconds: int = 3600):
51
+ now = time.time()
52
+ for file in folder.glob("*.mp3"):
53
+ try:
54
+ age = now - file.stat().st_mtime
55
+ if age > max_age_seconds:
56
+ file.unlink(missing_ok=True)
57
+ except Exception:
58
+ pass
59
+
60
+
61
+ def delete_file(path: Path):
62
+ try:
63
+ path.unlink(missing_ok=True)
64
+ except Exception:
65
+ pass
66
+
67
+
68
+ @app.get("/")
69
+ async def root():
70
+ return {
71
+ "ok": True,
72
+ "service": "Edge TTS API",
73
+ "routes": {
74
+ "health": "/health",
75
+ "voices": "/voices",
76
+ "tts": "/tts",
77
+ },
78
+ }
79
+
80
+
81
+ @app.get("/health")
82
+ async def health():
83
+ return {"status": "ok"}
84
+
85
+
86
+ @app.get("/voices")
87
+ async def voices(
88
+ locale: str | None = Query(default=None),
89
+ multilingual_only: bool = Query(default=False),
90
+ bulgarian_only: bool = Query(default=False),
91
+ ):
92
+ try:
93
+ voices_data = await edge_tts.list_voices()
94
+ simplified = [simplify_voice(v) for v in voices_data]
95
+ simplified.sort(key=lambda v: (v["Locale"], v["ShortName"]))
96
+
97
+ if locale:
98
+ simplified = [v for v in simplified if v["Locale"].lower() == locale.lower()]
99
+
100
+ if multilingual_only:
101
+ simplified = [v for v in simplified if v["IsMultilingual"]]
102
+
103
+ if bulgarian_only:
104
+ simplified = [v for v in simplified if v["IsBulgarian"]]
105
+
106
+ return JSONResponse(
107
+ content={
108
+ "count": len(simplified),
109
+ "voices": simplified,
110
+ }
111
+ )
112
+ except Exception as e:
113
+ raise HTTPException(status_code=500, detail=f"Failed to fetch voices: {str(e)}")
114
+
115
+
116
+ @app.get("/voices/bulgarian")
117
+ async def voices_bulgarian():
118
+ try:
119
+ voices_data = await edge_tts.list_voices()
120
+ simplified = [simplify_voice(v) for v in voices_data]
121
+ simplified = [v for v in simplified if v["IsBulgarian"]]
122
+ simplified.sort(key=lambda v: v["ShortName"])
123
+ return {"count": len(simplified), "voices": simplified}
124
+ except Exception as e:
125
+ raise HTTPException(status_code=500, detail=f"Failed to fetch Bulgarian voices: {str(e)}")
126
+
127
+
128
+ @app.get("/voices/multilingual")
129
+ async def voices_multilingual():
130
+ try:
131
+ voices_data = await edge_tts.list_voices()
132
+ simplified = [simplify_voice(v) for v in voices_data]
133
+ simplified = [v for v in simplified if v["IsMultilingual"]]
134
+ simplified.sort(key=lambda v: (v["Locale"], v["ShortName"]))
135
+ return {"count": len(simplified), "voices": simplified}
136
+ except Exception as e:
137
+ raise HTTPException(status_code=500, detail=f"Failed to fetch multilingual voices: {str(e)}")
138
+
139
+
140
+ @app.post("/tts")
141
+ async def tts(req: TTSRequest):
142
+ text = req.text.strip()
143
+
144
+ if not text:
145
+ raise HTTPException(status_code=400, detail="Text is empty")
146
+
147
+ cleanup_old_files(TMP_DIR, max_age_seconds=3600)
148
+
149
+ output_file = TMP_DIR / f"{uuid.uuid4().hex}.mp3"
150
+
151
+ try:
152
+ communicate = edge_tts.Communicate(
153
+ text=text,
154
+ voice=req.voice,
155
+ rate=req.rate,
156
+ volume=req.volume,
157
+ pitch=req.pitch,
158
+ )
159
+ await communicate.save(str(output_file))
160
+
161
+ if not output_file.exists():
162
+ raise HTTPException(status_code=500, detail="Audio file was not created")
163
+
164
+ return FileResponse(
165
+ path=str(output_file),
166
+ media_type="audio/mpeg",
167
+ filename="speech.mp3",
168
+ background=BackgroundTask(delete_file, output_file),
169
+ )
170
+ except Exception as e:
171
+ delete_file(output_file)
172
+ raise HTTPException(status_code=500, detail=f"TTS generation failed: {str(e)}")
gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ fastapi
2
+ uvicorn[standard]
3
+ edge-tts
4
+ pydantic