"""OpenAI-compatible TTS Server for AX650 NPU3. Start: python -m inflect_tts_sdk.server --port 8000 API: POST /v1/audio/speech (OpenAI TTS API) GET /health GET /v1/models """ from __future__ import annotations import io, sys, argparse, json, struct, wave from pathlib import Path try: from fastapi import FastAPI, Request from fastapi.responses import Response, JSONResponse import uvicorn except ImportError: sys.exit("pip install fastapi uvicorn") def create_app(model_dir: str | None = None): app = FastAPI(title="Inflect-Nano-v2 TTS", version="1.0.0") engine = None def get_engine(): nonlocal engine if engine is None: sys.path.insert(0, str(Path(__file__).resolve().parent)) from tts_engine import InflectTTSEngine engine = InflectTTSEngine(model_dir=model_dir) return engine @app.get("/health") async def health(): return {"status": "ok", "model": "inflect-nano-v2", "hw": "AX650-NPU3"} @app.get("/v1/models") async def models(): return {"object": "list", "data": [ {"id": "inflect-nano-v2", "object": "model", "owned_by": "owensong", "created": 1753500000} ]} @app.post("/v1/audio/speech") async def speech(request: Request): try: body = await request.json() except Exception: return Response(content=b'{"error":"Invalid JSON"}', status_code=400, media_type="application/json") text = body.get("input", "") if not text: return Response(content=b'{"error":"input is required"}', status_code=400, media_type="application/json") eng = get_engine() sr, wav = eng.synthesize( text, speed=float(body.get("speed", 1.0)), variation=float(body.get("variation", 0.667)), seed=int(body.get("seed", 0)), ) # Write WAV to buffer buf = io.BytesIO() import soundfile as sf sf.write(buf, wav, sr, format="WAV") buf.seek(0) return Response( content=buf.read(), media_type="audio/wav", headers={"X-Sample-Rate": str(sr), "X-Audio-Duration": str(len(wav) / sr)} ) return app if __name__ == "__main__": ap = argparse.ArgumentParser(description="Inflect-Nano-v2 OpenAI TTS Server") ap.add_argument("--host", default="0.0.0.0") ap.add_argument("--port", type=int, default=8000) ap.add_argument("--model-dir", default=None) args = ap.parse_args() app = create_app(args.model_dir) print(f"🎤 Inflect-Nano-v2 TTS Server → http://{args.host}:{args.port}") print(f" POST /v1/audio/speech (OpenAI-compatible)") print(f" GET /health") print(f" GET /v1/models") print(f"") print(f" Example:") print(f" curl -X POST http://localhost:{args.port}/v1/audio/speech \\") print(f" -H 'Content-Type: application/json' \\") print(f" -d '{{\"model\":\"tts-1\",\"input\":\"Hello world\"}}' \\") print(f" --output speech.wav") uvicorn.run(app, host=args.host, port=args.port)