| """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)), |
| ) |
|
|
| |
| 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) |
|
|