from pathlib import Path from threading import Lock from fastapi import FastAPI from pydantic import BaseModel, Field app = FastAPI(title="Emotion Museum TTS") _model = None _speaker_ids = None _model_lock = Lock() class SynthesizeRequest(BaseModel): text: str = Field(min_length=1, max_length=5000) voice: str = "default_zh_female" outputPath: str def get_model(): global _model, _speaker_ids with _model_lock: if _model is None: from melo.api import TTS _model = TTS(language="ZH", device="cpu") _speaker_ids = _model.hps.data.spk2id return _model, _speaker_ids @app.get("/health") def health(): return {"status": "ok"} @app.post("/synthesize") def synthesize(request: SynthesizeRequest): output = Path(request.outputPath) output.parent.mkdir(parents=True, exist_ok=True) try: model, speaker_ids = get_model() speaker_id = speaker_ids.get("ZH") model.tts_to_file(request.text, speaker_id, str(output), speed=1.0) except Exception as exc: return { "success": False, "audioPath": None, "durationMs": None, "engine": "melotts", "errorMessage": str(exc), } return { "success": True, "audioPath": str(output), "durationMs": None, "engine": "melotts", }