| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include <cstdio> |
| #include <cstdlib> |
| #include <cstring> |
| #include <iostream> |
| #include <sstream> |
| #include <string> |
| #include <unistd.h> |
|
|
| #include "zipvoice_resident_server.hpp" |
|
|
| |
| |
| |
| |
|
|
| static std::string JsonGetString(const std::string& json, const std::string& key, |
| const std::string& default_val = "") { |
| std::string pattern = "\"" + key + "\":"; |
| auto pos = json.find(pattern); |
| if (pos == std::string::npos) return default_val; |
| pos += pattern.size(); |
| while (pos < json.size() && (json[pos] == ' ' || json[pos] == '\t')) ++pos; |
| if (pos >= json.size() || json[pos] != '"') return default_val; |
| ++pos; |
| std::string val; |
| while (pos < json.size() && json[pos] != '"') { |
| if (json[pos] == '\\' && pos + 1 < json.size()) { ++pos; } |
| val += json[pos]; ++pos; |
| } |
| return val; |
| } |
|
|
| static float JsonGetFloat(const std::string& json, const std::string& key, float default_val = 1.0f) { |
| auto s = JsonGetString(json, key); |
| if (s.empty()) { |
| |
| std::string pattern = "\"" + key + "\":"; |
| auto pos = json.find(pattern); |
| if (pos == std::string::npos) return default_val; |
| pos += pattern.size(); |
| while (pos < json.size() && (json[pos] == ' ' || json[pos] == '\t')) ++pos; |
| return (float)std::atof(json.c_str() + pos); |
| } |
| return (float)std::atof(s.c_str()); |
| } |
|
|
| static std::string JsonEscape(const std::string& s) { |
| std::string out; |
| out.reserve(s.size() + 8); |
| for (char c : s) { |
| switch (c) { |
| case '\\': out += "\\\\"; break; |
| case '"': out += "\\\""; break; |
| case '\n': out += "\\n"; break; |
| case '\r': out += "\\r"; break; |
| case '\t': out += "\\t"; break; |
| default: out += c; break; |
| } |
| } |
| return out; |
| } |
|
|
| |
| |
| |
|
|
| int main(int argc, char** argv) { |
| |
| setbuf(stdout, NULL); |
|
|
| |
| |
| int stdout_backup = dup(STDOUT_FILENO); |
| dup2(STDERR_FILENO, STDOUT_FILENO); |
|
|
| |
| std::string root = "/data/shared/huyuan/voice_agent/001_Voice_Assistant.AXERA/models/zipvoice"; |
| std::string model_dir = root + "/zipvoice_distill_ax650"; |
| std::string token_file = root + "/resources/zipvoice_hf/zipvoice/tokens.txt"; |
| std::string vocoder_model = root + "/cpp/vocoder/vocos_full.axmodel"; |
| int max_tokens = 384, max_feat_len = 1024, num_step = 4; |
| float default_speed = 1.0f; |
| int seed = 42; |
|
|
| |
| for (int i = 1; i < argc; ++i) { |
| std::string arg = argv[i]; |
| if (arg == "--root" && i + 1 < argc) root = argv[++i]; |
| else if (arg == "--model-dir" && i + 1 < argc) model_dir = argv[++i]; |
| else if (arg == "--token-file" && i + 1 < argc) token_file = argv[++i]; |
| else if (arg == "--vocoder-model" && i + 1 < argc) vocoder_model = argv[++i]; |
| else if (arg == "--max-tokens" && i + 1 < argc) max_tokens = std::atoi(argv[++i]); |
| else if (arg == "--max-feat-len" && i + 1 < argc) max_feat_len = std::atoi(argv[++i]); |
| else if (arg == "--num-step" && i + 1 < argc) num_step = std::atoi(argv[++i]); |
| else if (arg == "--speed" && i + 1 < argc) default_speed = (float)std::atof(argv[++i]); |
| else if (arg == "--seed" && i + 1 < argc) seed = std::atoi(argv[++i]); |
| } |
|
|
| ZipVoiceResidentServer server; |
| bool ok = server.Init(root, model_dir, token_file, vocoder_model, |
| max_tokens, max_feat_len, num_step, default_speed, seed); |
|
|
| |
| dup2(stdout_backup, STDOUT_FILENO); |
| close(stdout_backup); |
| setbuf(stdout, NULL); |
|
|
| if (!ok) { |
| std::cout << "{\"ready\":false,\"error\":\"init failed\"}" << std::endl; |
| return 1; |
| } |
|
|
| std::cout << "{\"ready\":true}" << std::endl; |
| std::cout.flush(); |
|
|
| std::string line; |
| while (std::getline(std::cin, line)) { |
| if (line.empty()) continue; |
| if (line == "quit" || line == "exit") break; |
|
|
| |
| std::string cmd_type = JsonGetString(line, "cmd"); |
| if (cmd_type == "cache_prompt") { |
| std::string key = JsonGetString(line, "key", "custom"); |
| std::string wav = JsonGetString(line, "wav"); |
| std::string txt = JsonGetString(line, "text"); |
| bool ok = server.CachePrompt(key, wav, txt); |
| std::cout << "{\"id\":\"" << JsonGetString(line, "id", "0") |
| << "\",\"cmd\":\"cache_prompt\",\"ok\":" << (ok ? "true" : "false") |
| << ",\"key\":\"" << key << "\"}" << std::endl; |
| continue; |
| } |
| if (cmd_type == "prompts") { |
| std::cout << "{\"id\":\"" << JsonGetString(line, "id", "0") |
| << "\",\"cmd\":\"prompts\",\"ok\":true,\"prompts\":[\"zh\",\"en\",\"custom\"]}" << std::endl; |
| std::cout.flush(); |
| continue; |
| } |
|
|
| |
| ZipVoiceRequest req; |
| req.id = JsonGetString(line, "id", "0"); |
| req.text = JsonGetString(line, "text"); |
| req.prompt = JsonGetString(line, "prompt", "zh"); |
| req.speed = JsonGetFloat(line, "speed", default_speed); |
| req.output_wav = JsonGetString(line, "output_wav", "/tmp/zipvoice_daemon.wav"); |
|
|
| if (req.text.empty()) { |
| std::cout << "{\"id\":\"" << req.id << "\",\"ok\":false,\"error\":\"empty text\"}" << std::endl; |
| std::cout.flush(); |
| continue; |
| } |
|
|
| |
| |
| int saved_stdout = dup(STDOUT_FILENO); |
| dup2(STDERR_FILENO, STDOUT_FILENO); |
| auto resp = server.Infer(req); |
| dup2(saved_stdout, STDOUT_FILENO); |
| close(saved_stdout); |
|
|
| |
| char buf[1024]; |
| snprintf(buf, sizeof(buf), |
| "{\"id\":\"%s\",\"ok\":%s,\"path\":\"%s\",\"wall_sec\":%.3f,\"model_sec\":%.3f,\"rtf\":%.3f%s%s}", |
| resp.id.c_str(), |
| resp.ok ? "true" : "false", |
| JsonEscape(resp.ok ? resp.path : "").c_str(), |
| resp.wall_sec, resp.model_sec, resp.rtf, |
| resp.ok ? "" : ",\"error\":\"", |
| resp.ok ? "" : JsonEscape(resp.error).c_str()); |
| std::cout << buf; |
| if (!resp.ok) std::cout << "\""; |
| std::cout << std::endl; |
| std::cout.flush(); |
| } |
|
|
| return 0; |
| } |
|
|