// CLI dev autour de tts_engine. La logique est maintenant dans tts_engine.{h,cpp} // (réutilisée par le JNI). Ce binaire reste pour les bench A/B et la régression. // // Usage: // tts_pipeline [cpu|htp] [max_steps] // // Variables d'environnement : // KZTTS_TEXT, KZTTS_VOCAB_GGUF : texte arbitraire au lieu de input_ids_full.bin (fixture) // (le mode fixture est conservé pour bench/régression) // KZTTS_CP_CACHE : 1 (défaut) = cp_predict_cached, 0 = cp_predict oracle // KZTTS_SEED : seed sampling (défaut 42) // KZTTS_THREADS : threads CPU (défaut 6) // KZTTS_TEMP / TOPK / TOPP / REPP : sampling Talker // KZTTS_CP_TEMP / CP_TOPK / CP_TOPP / CP_REPP : sampling CP #include "tts_engine.h" #include "kazeia_text_tokenizer.h" #include "llama.h" #include #include #include #include #include #include static float env_f(const char* k, float dflt) { const char* v = getenv(k); return v ? (float)atof(v) : dflt; } static int env_i(const char* k, int dflt) { const char* v = getenv(k); return v ? atoi(v) : dflt; } int main(int argc, char** argv) { if (argc < 4) { printf("usage: %s [cpu|htp] [max_steps]\n", argv[0]); printf(" Texte arbitraire :\n"); printf(" KZTTS_VOCAB_GGUF=/path/qwen3.gguf KZTTS_TEXT=\"phrase libre\" %s ...\n", argv[0]); printf(" Mode fixture (input_ids_full.bin) : aucune variable d'env requise.\n"); return 1; } const char* talker_gguf = argv[1]; std::string D = argv[2]; if (D.back() != '/') D += '/'; const char* out_wav = argv[3]; const bool use_htp = (argc >= 5 && !strcmp(argv[4], "htp")); const int max_steps = (argc >= 6) ? atoi(argv[5]) : 256; const char* kz_text = getenv("KZTTS_TEXT"); const char* kz_vocab_gguf = getenv("KZTTS_VOCAB_GGUF"); if (!kz_text || !kz_vocab_gguf) { fprintf(stderr, "tts_pipeline: mode fixture (input_ids_full.bin) demandé mais non implémenté\n"); fprintf(stderr, " -> poser KZTTS_TEXT et KZTTS_VOCAB_GGUF pour utiliser le pipeline live.\n"); fprintf(stderr, " (Le mode fixture a été déporté en branche fixture pour test_engine séparé.)\n"); return 2; } TtsEngineLoadCfg lc; lc.talker_gguf = talker_gguf; lc.vocab_gguf = kz_vocab_gguf; lc.dump_dir = D.c_str(); lc.use_htp = use_htp; lc.n_threads = env_i("KZTTS_THREADS", 6); lc.cp_use_cache = env_i("KZTTS_CP_CACHE", 1) != 0; auto * eng = tts_engine_load(lc); if (!eng) { fprintf(stderr, "tts_engine_load FAIL\n"); return 3; } TtsSynthesizeCfg sc; sc.text = kz_text; sc.out_wav_path = out_wav; sc.max_steps = max_steps; sc.seed = env_i("KZTTS_SEED", 42); sc.cp_temp = env_f("KZTTS_CP_TEMP", 0.9f); sc.cp_top_k = env_i("KZTTS_CP_TOPK", 50); sc.cp_top_p = env_f("KZTTS_CP_TOPP", 1.0f); sc.cp_rep_penalty = env_f("KZTTS_CP_REPP", 1.05f); sc.talker_temp = env_f("KZTTS_TEMP", 0.9f); sc.talker_top_k = env_i("KZTTS_TOPK", 50); sc.talker_top_p = env_f("KZTTS_TOPP", 1.0f); sc.talker_rep_penalty = env_f("KZTTS_REPP", 1.05f); auto R = tts_engine_synthesize(eng, sc); if (R.err) { fprintf(stderr, "tts_engine_synthesize FAIL err=%d\n", R.err); tts_engine_free(eng); return 4; } printf("=== TTS : N=%d frames (audio %.2fs) en %.3fs (RTF %.2f) ===\n", R.frames, R.audio_s, R.total_s, R.total_s / R.audio_s); printf(" prefill %.3fs | talker_loop %.3fs | cp_loop %.3fs | decoder %.3fs\n", R.prefill_s, R.talker_loop_s, R.cp_loop_s, R.decoder_s); printf(" per-frame talker=%.1fms cp=%.1fms\n", R.talker_loop_s * 1000.0 / R.frames, R.cp_loop_s * 1000.0 / R.frames); printf("WAV -> %s\n", out_wav); tts_engine_free(eng); return 0; }