Spaces:
Runtime error
Runtime error
| import io | |
| from fastapi import FastAPI, HTTPException, Query | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.responses import StreamingResponse | |
| from kokoro_onnx import Kokoro | |
| import soundfile as sf | |
| MODEL_PATH = "kokoro-v1.0.onnx" | |
| VOICES_PATH = "voices-v1.0.bin" | |
| VOICES = { | |
| "en": ["af_heart", "am_puck"], | |
| "fr": ["ff_siwis"], | |
| } | |
| LANG_CODES = {"en": "en-us", "fr": "fr-fr"} | |
| app = FastAPI(title="Speakeo TTS", description="API Kokoro TTS (EN/FR)") | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], # à restreindre au domaine de Speakeo plus tard | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| _kokoro: Kokoro | None = None | |
| def get_kokoro() -> Kokoro: | |
| global _kokoro | |
| if _kokoro is None: | |
| _kokoro = Kokoro(MODEL_PATH, VOICES_PATH) | |
| return _kokoro | |
| def root(): | |
| return {"status": "ok", "service": "speakeo-tts", "languages": list(VOICES)} | |
| def voices(): | |
| return VOICES | |
| def tts( | |
| text: str = Query(..., min_length=1, max_length=2000), | |
| lang: str = Query("en", pattern="^(en|fr)$"), | |
| voice: str | None = None, | |
| speed: float = Query(1.0, ge=0.5, le=2.0), | |
| ): | |
| if voice is None: | |
| voice = VOICES[lang][0] | |
| elif voice not in VOICES[lang]: | |
| raise HTTPException(400, f"Voix invalide pour '{lang}'. Options : {VOICES[lang]}") | |
| samples, sample_rate = get_kokoro().create( | |
| text, voice=voice, speed=speed, lang=LANG_CODES[lang] | |
| ) | |
| buf = io.BytesIO() | |
| sf.write(buf, samples, sample_rate, format="WAV") | |
| buf.seek(0) | |
| return StreamingResponse(buf, media_type="audio/wav") |