Kazeia-engine/dist/jni/stt_engine.h

104 lines
4.5 KiB
C++

// Engine STT Whisper-Small Qualcomm AI Hub (HfWhisper KV-cache) in-process.
// Load une fois (encoder QAIRT context + decoder QAIRT context + mel_filters +
// vocab), transcribe N fois (PCM 16kHz mono -> texte FR/EN).
//
// Backend : ONNX Runtime + QNN ExecutionProvider (HTP V79 sur SM8750).
// Empreinte RAM : ~545 MB (encoder ctx 201 MB + decoder ctx 345 MB).
//
// Bench de référence prod (Whisper-Small, FR, audio 1.6s) :
// mel 189 ms (CPU C++) + encoder 125 ms (NPU) + decoder 510 ms (NPU, 22 tokens)
// total 825 ms, RTF 0.51, RAM peak 545 MB.
//
// Construit pour remplacer WhisperHybridEngine.kt + libmel_extractor.so + VadStage.kt
// derrière une API unifiée Kazeia-Engine. La sélection de backend (HTP vs CPU) est
// automatique via QNN EP : si le contexte QAIRT est trouvé, HTP ; sinon CPU fallback.
#pragma once
#include <cstdint>
#include <string>
#include <vector>
struct SttEngine; // opaque
struct SttEngineLoadCfg {
// Dir contenant : HfWhisperEncoder.onnx + HfWhisperEncoder_qairt_context.bin,
// HfWhisperDecoder.onnx + HfWhisperDecoder_qairt_context.bin,
// mel_filters.json (ou .bin), vocab.json (BPE byte-level).
const char * model_dir = nullptr;
// 1 = QNN HTP (NPU, défaut prod). 0 = CPU fallback (ONNX Runtime CPU EP).
// QNN EP requiert que libQnnHtp.so + libQnnHtpV79Skel.so + libcdsprpc.so soient
// dans LD_LIBRARY_PATH (côté tablette : push depuis dist/lib/).
bool use_htp = true;
int n_threads = 6;
int max_decode_steps = 200; // borne hard du loop decoder autorégressif
};
struct SttTranscribeCfg {
// PCM mono 16-bit signed, n'importe quelle longueur (le mel pad fait à 30s).
// Si vous avez du PCM 24kHz, resamplez externe avant (ou utilisez SttTranscribeWaveform).
const int16_t * pcm16 = nullptr;
int n_samples = 0;
int sample_rate = 16000;
// "fr", "en", "auto", etc. Whisper-Small supporte 99 langues. "auto" = détection
// via la langue token de Whisper.
const char * language = "fr";
// 1 = force le mode "transcribe" (FR -> texte FR). 0 = laisse Whisper choisir
// entre transcribe et translate (translate force la sortie en EN, pas voulu pour
// Kazeia FR). Défaut : 1 (cf override prod KazeiaService).
bool force_transcribe = true;
// Inclure les timestamps (segments + offsets) dans la sortie.
bool with_timestamps = false;
};
struct SttSegment {
int t0_ms; // début segment (ms relatif au début audio)
int t1_ms; // fin segment
std::string text;
};
struct SttTranscribeResult {
int err = 0; // 0 = ok, <0 = err
std::string text; // texte concaténé (sans timestamps)
std::vector<SttSegment> segments; // vide si !with_timestamps
std::string detected_language; // "fr", "en", ...
// Métriques perf (ms)
int mel_ms = 0;
int encoder_ms = 0;
int decoder_ms = 0;
int total_ms = 0;
float rtf = 0.0f; // total_ms / (audio_duration_ms)
int n_tokens = 0;
};
// Charge encoder + decoder + mel basis + vocab. Retourne nullptr si échec.
// Idempotent vis-à-vis de llama_backend_init() (cohabite avec tts_engine).
SttEngine * stt_engine_load(const SttEngineLoadCfg & cfg);
// Transcrit une fenêtre audio. Stateful pour le warm path NPU (sessions ORT
// gardées en RAM entre appels).
SttTranscribeResult stt_engine_transcribe(SttEngine * eng, const SttTranscribeCfg & cfg);
// Libère tout (encoder ctx, decoder ctx, sessions ORT, vocab).
void stt_engine_free(SttEngine * eng);
// Helper VAD RMS énergie : renvoie true si le buffer PCM contient de la parole
// (énergie > seuil). Compatible drop-in avec VadStage.kt prod (frame=1600 @ 16kHz,
// seuil 150 PCM, ≥3 frames consécutives parole, ≥8 frames silence).
// Tu peux passer le PCM en streaming par chunks de 100ms et lire is_speech / is_end_of_speech.
struct SttVadState;
SttVadState * stt_vad_new(int sample_rate = 16000,
int frame_size = 1600,
int rms_threshold = 150,
int min_speech_frames = 3,
int silence_end_frames = 8);
bool stt_vad_push(SttVadState * s, const int16_t * pcm, int n_samples);
bool stt_vad_is_speech(const SttVadState * s);
bool stt_vad_is_end_of_speech(const SttVadState * s);
void stt_vad_reset(SttVadState * s);
void stt_vad_free(SttVadState * s);