OpenAPI-AI/ST-STTAPI
0
1import os2import io3import traceback4import numpy as np5import scipy.io.wavfile as wavfile6from fastapi import FastAPI, HTTPException7from fastapi.responses import Response8from pydantic import BaseModel9from supertonic import TTS10import uvicorn11 12app = FastAPI(title="Supertonic TTS API")13 14class TTSRequest(BaseModel):15 text: str16 lang: str = "ru"17 voice: str = "M2"18 19print("Загрузка модели Supertonic TTS...")20tts = TTS(auto_download=True)21default_style = tts.get_voice_style(voice_name="M2")22print("Модель успешно загружена и готова к работе!")23 24@app.get("/")25async def root():26 return {27 "status": "ok",28 "message": "Supertonic TTS API is running",29 "docs": "/docs",30 "usage": "POST /api/tts с JSON: {'text': 'ваш текст', 'lang': 'ru', 'voice': 'M2'}"31 }32 33@app.post("/api/tts")34async def synthesize(request: TTSRequest):35 try:36 # 1. Получаем стиль голоса37 if request.voice == "M2":38 style = default_style39 else:40 style = tts.get_voice_style(voice_name=request.voice)41 42 # 2. Синтез43 wav, duration = tts.synthesize(request.text, voice_style=style, lang=request.lang)44 45 # 3. Конвертация аудио в numpy (если модель вернула тензор PyTorch)46 if hasattr(wav, 'cpu'):47 wav = wav.cpu().numpy()48 elif hasattr(wav, 'numpy'):49 wav = wav.numpy()50 51 wav = np.asarray(wav)52 53 # 4. Убираем лишние измерения (например, если форма (1, 48000) -> (48000,))54 wav = wav.squeeze()55 56 # 5. Нормализация и конвертация в int16 (стандарт для WAV)57 wav = wav.astype(np.float32)58 max_val = np.max(np.abs(wav))59 if max_val > 1.0:60 wav = wav / max_val61 62 # Конвертируем в int16 (от -32768 до 32767)63 wav_int16 = (wav * 32767).astype(np.int16)64 65 # 6. Получаем sample rate66 sample_rate = getattr(tts, 'sample_rate', 24000)67 68 # 7. Записываем в память через scipy69 out = io.BytesIO()70 wavfile.write(out, sample_rate, wav_int16)71 audio_bytes = out.getvalue()72 73 # 8. ИСПРАВЛЕНИЕ: Превращаем duration из numpy массива в обычный float74 # .item() безопасно извлекает скалярное значение из numpy array75 duration_float = float(np.asarray(duration).item())76 77 # 9. Возвращаем аудио78 return Response(79 content=audio_bytes,80 media_type='audio/wav',81 headers={82 "Content-Disposition": "attachment; filename=speech.wav",83 "X-Audio-Duration": str(round(duration_float, 2))84 }85 )86 87 except Exception as e:88 traceback.print_exc()89 raise HTTPException(status_code=500, detail=f"Ошибка генерации: {str(e)}")90 91if __name__ == '__main__':92 port = int(os.environ.get('PORT', 7860))93 uvicorn.run(app, host='0.0.0.0', port=port)