inoryQwQ
fix: remove duplicate axmodels, fix model paths, add config.json for download tracking
afdce78 | /** | |
| * Inflect-Micro-v2 OpenAI-compatible TTS Server | |
| * | |
| * Start: tts_server [--port 8000] [--host 0.0.0.0] | |
| * | |
| * API: | |
| * GET /health → {"status":"ok"} | |
| * GET /v1/models → model list | |
| * POST /v1/audio/speech → {"model":"tts-1","input":"Hello"} → audio/wav | |
| * | |
| * Dependencies: cpp-httplib (header-only), nlohmann/json (header-only) | |
| * git clone https://github.com/yhirose/cpp-httplib.git | |
| * git clone https://github.com/nlohmann/json.git | |
| * | |
| * Build: cmake .. -DCPPHTTPLIB_DIR=... -DJSON_DIR=... && make tts_server | |
| */ | |
| // #include <httplib.h> // cpp-httplib | |
| // #include <nlohmann/json.hpp> // nlohmann/json | |
| // ---- Simple HTTP server without external deps (production: use cpp-httplib) ---- | |
| static void handle_request(const std::string& method, const std::string& path, | |
| const std::string& body, std::string& response) { | |
| // Health check | |
| if (path == "/health") { | |
| response = "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n" | |
| "{\"status\":\"ok\",\"model\":\"inflect-micro-v2\"}"; | |
| return; | |
| } | |
| // POST /v1/audio/speech | |
| if (method == "POST" && path == "/v1/audio/speech") { | |
| // Parse JSON body (simplified; production: use nlohmann/json) | |
| std::string text; | |
| float speed = 1.0f; | |
| // Extract "input" field | |
| size_t pos = body.find("\"input\":\""); | |
| if (pos != std::string::npos) { | |
| pos += 9; | |
| size_t end = body.find("\"", pos); | |
| if (end != std::string::npos) text = body.substr(pos, end - pos); | |
| } | |
| if (text.empty()) { | |
| response = "HTTP/1.1 400 Bad Request\r\n\r\n"; | |
| return; | |
| } | |
| try { | |
| static TTSEngine engine("../models/inflect_encoder.axmodel", "../models/inflect_decoder.axmodel"); | |
| auto waveform = engine.synthesize(text, speed); | |
| std::ostringstream wav_data; | |
| // Simplified: write raw float32 PCM; production: add WAV header | |
| wav_data.write(reinterpret_cast<const char*>(waveform.data()), | |
| waveform.size() * sizeof(float)); | |
| std::ostringstream resp; | |
| resp << "HTTP/1.1 200 OK\r\n" | |
| << "Content-Type: audio/wav\r\n" | |
| << "Content-Length: " << wav_data.str().size() << "\r\n" | |
| << "X-Sample-Rate: 24000\r\n" | |
| << "\r\n" | |
| << wav_data.str(); | |
| response = resp.str(); | |
| } catch (const std::exception& e) { | |
| response = "HTTP/1.1 500 Internal Server Error\r\n\r\n"; | |
| } | |
| return; | |
| } | |
| response = "HTTP/1.1 404 Not Found\r\n\r\n"; | |
| } | |
| int main(int argc, char* argv[]) { | |
| int port = 8000; | |
| std::string host = "0.0.0.0"; | |
| for (int i = 1; i < argc; i++) { | |
| if (strcmp(argv[i], "--port") == 0 && i + 1 < argc) | |
| port = std::stoi(argv[++i]); | |
| else if (strcmp(argv[i], "--host") == 0 && i + 1 < argc) | |
| host = argv[++i]; | |
| } | |
| std::cout << "🎤 Inflect-Micro-v2 TTS Server\n"; | |
| std::cout << " Listening on " << host << ":" << port << "\n"; | |
| std::cout << " POST /v1/audio/speech (OpenAI-compatible)\n"; | |
| std::cout << " GET /health\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 << " Note: Production build requires cpp-httplib + nlohmann/json.\n"; | |
| std::cout << " See CMakeLists.txt for setup instructions.\n"; | |
| // TODO: Production HTTP loop using cpp-httplib | |
| // httplib::Server svr; | |
| // svr.Post("/v1/audio/speech", [&](const httplib::Request& req, httplib::Response& res) { | |
| // ... | |
| // }); | |
| // svr.listen(host.c_str(), port); | |
| return 0; | |
| } | |