File size: 1,991 Bytes
c620425 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
from fastapi import FastAPI, HTTPException, Response
from pydantic import BaseModel
import requests
import base64
import os
app = FastAPI(title="OpenAI‑Compatible TTS Adapter")
class OpenAITTSRequest(BaseModel):
model: str # e.g. "tts-1"
input: str # the text prompt
voice: str = "tara" # optional voice parameter
format: str = "wav" # "wav" or "mp3"
@app.post(
"/v1/audio/speech",
summary="Generate speech",
response_class=Response, # raw bytes
)
def tts_speech(req: OpenAITTSRequest):
# Load your Chutes token
chutes_token = os.getenv("CHUTES_API_TOKEN")
if not chutes_token:
raise HTTPException(status_code=500, detail="Chutes API token not configured")
# Call Chutes TTS
resp = requests.post(
"https://chutes-orpheus-tts.chutes.ai/speak",
headers={
"Authorization": f"Bearer {chutes_token}",
"Content-Type": "application/json"
},
json={"voice": req.voice, "prompt": req.input},
timeout=30
)
if resp.status_code != 200:
raise HTTPException(
status_code=502,
detail=f"Chutes TTS error: {resp.status_code} {resp.text}"
)
# If Chutes returns JSON-wrapped base64, extract and decode
content_type = f"audio/{req.format}"
try:
segments = resp.json()
for seg in segments:
if seg.get("type") == "audio" and seg.get("data"):
# data:audio/wav;base64,AAAA...
prefix, b64 = seg["data"].split(",", 1)
audio_bytes = base64.b64decode(b64)
return Response(content=audio_bytes, media_type=content_type)
except ValueError:
# Not JSON — assume raw bytes
return Response(content=resp.content, media_type=content_type)
raise HTTPException(status_code=502, detail="No audio in Chutes response")
@app.get("/healthz")
def health_check():
return {"status": "ok"} |