File size: 2,058 Bytes
37438a4
e70a374
 
 
b538a81
e70a374
 
37438a4
ed4076c
b538a81
e70a374
b538a81
e70a374
 
ed4076c
 
 
 
e70a374
 
b538a81
ed4076c
e70a374
 
 
 
 
 
37438a4
ed4076c
 
 
 
 
 
37438a4
ed4076c
 
 
e70a374
b538a81
 
 
 
 
 
 
ed4076c
b538a81
ed4076c
b538a81
 
 
 
 
 
 
 
 
 
ed4076c
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, Header
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
from kokoro import KPipeline
import numpy as np
import io
import logging
import os

# --- Logging ---
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("tts_stream")

app = FastAPI()

# Charger les clés valides depuis l'environnement
VALID_HF_KEYS = os.environ.get('VALID_HF_KEYS', '').split(',')

# Initialiser le pipeline au démarrage
pipeline = KPipeline(lang_code='a', device='cpu')
logger.info("✅ KPipeline loaded successfully.")

class TTSRequest(BaseModel):
    text: str
    voice: str = 'af_heart'
    speed: float = 1.0

@app.post("/tts/stream")
async def stream_speech(request: TTSRequest, hf_key: str = Header(None)):
    logger.info(f"🚀 Request: text='{request.text[:30]}...', voice='{request.voice}'")
    logger.info(f"🔑 Received key: {hf_key[:10] + '...' if hf_key else 'NONE'}")
    
    # Vérifier le token
    if not hf_key or hf_key not in VALID_HF_KEYS:
        logger.error(f"❌ Unauthorized: key not in valid list")
        raise HTTPException(status_code=401, detail="Unauthorized: invalid or missing hf_key")
    
    logger.info(f"✅ Key validated, generating audio...")
    
    def generate():
        chunk_index = 0
        try:
            for result in pipeline(request.text, voice=request.voice, speed=request.speed):
                chunk_index += 1
                audio_bytes = result.audio.numpy().astype(np.float32).tobytes()
                logger.info(f"✅ Chunk {chunk_index} ready, size={len(audio_bytes)} bytes")
                yield audio_bytes
            logger.info(f"🏁 Streaming finished: {chunk_index} chunks")
        except Exception as e:
            logger.error(f"❌ Error at chunk {chunk_index}: {e}")
            raise

    return StreamingResponse(
        generate(),
        media_type="audio/pcm",
        headers={
            "X-Sample-Rate": "24000",
            "X-Channels": "1",
            "X-Bit-Depth": "32"
        }
    )