// Code Predictor (Qwen3-TTS) inference, extrait de
// /opt/Kazeia/kazeia-tts-decoder-ggml/src/cp_runner.cpp et exposé en API
// utilisable depuis tts_orchestrate. Architecture : transformer qwen3 5 couches,
// hidden 1024, GQA 16/8, head_dim 128, RMS eps 1e-6, RoPE NEOX theta=1e6.
// q_norm/k_norm AVANT RoPE (gotcha critique).
//
// Forward autoregressif RVQ : 15 passes pour produire CB1..CB15 depuis
// (hidden_Talker[1024], cb0_emb[1024]). Approche "recompute" (T<=16 -> coût
// quadratique négligeable, pas de KV cache manuel).
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include <unordered_map>

struct ggml_context;
struct ggml_tensor;

struct CPState {
    ggml_context * weights_ctx = nullptr;
    std::unordered_map<std::string, ggml_tensor*> tensors;  // weights par nom
    std::vector<float> heads;        // [15, 2048, 1024] f32
    std::vector<float> codec_embs;   // [15, 2048, 1024] f32
    int n_threads = 4;
};

// Charge cp_f16.gguf + cp_heads.bin + cp_codec_embs.bin. Retourne false en cas d'échec.
bool cp_load(CPState& s, const char* gguf_path, const char* heads_path, const char* embs_path);

// Libère les ressources.
void cp_free(CPState& s);

// Prédit CB1..CB15 (15 codes int32) depuis le hidden state du Talker et l'embed de CB0.
//   hidden : float[1024]
//   cb0_emb: float[1024]
//   out_codes : int32_t[15] (CB1..CB15)
void cp_predict(CPState& s, const float* hidden, const float* cb0_emb, int32_t* out_codes);
