| /** | |
| * Inflect-Nano-v2 OpenAI-compatible TTS Server | |
| * | |
| * Start: tts_server [--port 8000] [--host 0.0.0.0] | |
| * | |
| * API: | |
| * GET /health | |
| * GET /v1/models | |
| * POST /v1/audio/speech (OpenAI TTS) | |
| * | |
| * Dependencies (production): | |
| * - cpp-httplib (https://github.com/yhirose/cpp-httplib) | |
| * - nlohmann/json (https://github.com/nlohmann/json) | |
| * | |
| * Build: cmake .. -DCPPHTTPLIB_DIR=... -DJSON_DIR=... && make tts_server | |
| */ | |
| // ---- placeholder: replace with cpp-httplib in production ---- | |
| static void print_startup(int host, int port) { | |
| std::cout << "🎤 Inflect-Nano-v2 TTS Server\n"; | |
| std::cout << " Listening on 0.0.0.0:" << port << "\n"; | |
| std::cout << "\n"; | |
| std::cout << " POST /v1/audio/speech (OpenAI-compatible)\n"; | |
| std::cout << " GET /health\n"; | |
| std::cout << " GET /v1/models\n"; | |
| std::cout << "\n"; | |
| std::cout << " Example:\n"; | |
| std::cout << " curl -X POST http://localhost:" << port << "/v1/audio/speech \\\n"; | |
| std::cout << " -H 'Content-Type: application/json' \\\n"; | |
| std::cout << " -d '{\"model\":\"tts-1\",\"input\":\"Hello world\"}' \\\n"; | |
| std::cout << " --output speech.wav\n"; | |
| std::cout << "\n"; | |
| std::cout << " ⚠ Production build requires cpp-httplib + nlohmann/json.\n"; | |
| std::cout << " git clone https://github.com/yhirose/cpp-httplib.git\n"; | |
| std::cout << " git clone https://github.com/nlohmann/json.git\n"; | |
| std::cout << " cmake .. -DCPPHTTPLIB_DIR=<path> -DJSON_DIR=<path>\n"; | |
| } | |
| // ---- Production HTTP handler (uncomment with cpp-httplib) ---- | |
| /* | |
| static std::string handle_speech(TTSEngine& engine, const std::string& body) { | |
| auto j = nlohmann::json::parse(body); | |
| std::string text = j.value("input", ""); | |
| float speed = j.value("speed", 1.0f); | |
| float variation = j.value("variation", 0.667f); | |
| auto waveform = engine.synthesize(text, speed, variation); | |
| // Write WAV | |
| std::ostringstream wav; | |
| int sample_rate = 24000; | |
| int data_size = waveform.size() * sizeof(float) * 8 / 16; // convert to int16 | |
| // ... WAV header + int16 samples ... | |
| return wav.str(); | |
| } | |
| */ | |
| int main(int argc, char* argv[]) { | |
| int port = 8000; | |
| for (int i = 1; i < argc; ++i) { | |
| if ((strcmp(argv[i], "--port") == 0 || strcmp(argv[i], "-p") == 0) | |
| && i + 1 < argc) | |
| port = std::stoi(argv[++i]); | |
| } | |
| print_startup(0, port); | |
| // TODO: Production HTTP loop with cpp-httplib | |
| // | |
| // httplib::Server svr; | |
| // | |
| // TTSEngine engine("../models/inflect_encoder.axmodel", | |
| // "../models/inflect_decoder.axmodel"); | |
| // | |
| // svr.Get("/health", [](const httplib::Request&, httplib::Response& res) { | |
| // res.set_content("{\"status\":\"ok\",\"model\":\"inflect-nano-v2\"}", | |
| // "application/json"); | |
| // }); | |
| // | |
| // svr.Get("/v1/models", [](const httplib::Request&, httplib::Response& res) { | |
| // res.set_content("{\"object\":\"list\",\"data\":[{\"id\":\"inflect-nano-v2\"" | |
| // ",\"object\":\"model\",\"owned_by\":\"owensong\"}]}", | |
| // "application/json"); | |
| // }); | |
| // | |
| // svr.Post("/v1/audio/speech", [&](const httplib::Request& req, | |
| // httplib::Response& res) { | |
| // auto wav = handle_speech(engine, req.body); | |
| // res.set_content(wav, "audio/wav"); | |
| // }); | |
| // | |
| // svr.listen("0.0.0.0", port); | |
| return 0; | |
| } | |