ST-STTAPI / app.py
bafifi4972's picture
Update app.py
c43dd80 verified
Raw
History Blame
3.16 kB
import os
import io
import traceback
import numpy as np
import scipy.io.wavfile as wavfile # Используем scipy вместо soundfile
from fastapi import FastAPI, HTTPException
from fastapi.responses import Response
from pydantic import BaseModel
from supertonic import TTS
import uvicorn
app = FastAPI(title="Supertonic TTS API")
class TTSRequest(BaseModel):
text: str
lang: str = "ru"
voice: str = "M2"
print("Загрузка модели Supertonic TTS...")
tts = TTS(auto_download=True)
default_style = tts.get_voice_style(voice_name="M2")
print("Модель успешно загружена и готова к работе!")
@app.get("/")
async def root():
return {
"status": "ok",
"message": "Supertonic TTS API is running",
"docs": "/docs",
"usage": "POST /api/tts с JSON: {'text': 'ваш текст', 'lang': 'ru', 'voice': 'M2'}"
}
@app.post("/api/tts")
async def synthesize(request: TTSRequest):
try:
# 1. Получаем стиль голоса
if request.voice == "M2":
style = default_style
else:
style = tts.get_voice_style(voice_name=request.voice)
# 2. Синтез
wav, duration = tts.synthesize(request.text, voice_style=style, lang=request.lang)
# 3. Конвертация в numpy (если модель вернула тензор PyTorch)
if hasattr(wav, 'cpu'):
wav = wav.cpu().numpy()
elif hasattr(wav, 'numpy'):
wav = wav.numpy()
wav = np.asarray(wav)
# 4. Убираем лишние измерения (например, если форма (1, 48000) -> (48000,))
wav = wav.squeeze()
# 5. Нормализация и конвертация в int16 (стандарт для WAV)
# Сначала приводим к float32 для безопасной нормализации
wav = wav.astype(np.float32)
max_val = np.max(np.abs(wav))
if max_val > 1.0:
wav = wav / max_val
# Конвертируем в int16 (от -32768 до 32767)
wav_int16 = (wav * 32767).astype(np.int16)
# 6. Получаем sample rate
sample_rate = getattr(tts, 'sample_rate', 24000)
# 7. Записываем в память через scipy (работает безотказно)
out = io.BytesIO()
wavfile.write(out, sample_rate, wav_int16)
audio_bytes = out.getvalue()
# 8. Возвращаем аудио
return Response(
content=audio_bytes,
media_type='audio/wav',
headers={
"Content-Disposition": "attachment; filename=speech.wav",
"X-Audio-Duration": str(round(duration, 2))
}
)
except Exception as e:
traceback.print_exc()
raise HTTPException(status_code=500, detail=f"Ошибка генерации: {str(e)}")
if __name__ == '__main__':
port = int(os.environ.get('PORT', 7860))
uvicorn.run(app, host='0.0.0.0', port=port)