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"}