mirror of
https://github.com/mudler/LocalAI.git
synced 2026-11-07 13:03:20 -05:00
qwentts.cpp batches concurrent qt_synthesize calls on one context when it is initialized with max_batch > 1 (its compute worker coalesces them into batched decode steps; qt_synthesize stays blocking and thread safe). The LocalAI wrapper never set max_batch and serialized every request with base.SingleThread, so concurrent /v1/audio/speech requests always ran one after another. - new model option `max_batch:N` (alias `parallel:N`, default 1 = current behavior), passed to qt_init_params.max_batch via qt3_load - Locking() keeps LocalAI's per-backend request lock only for max_batch 1; with batching TTS/TTSStream reach the native worker concurrently - TTSStream routes chunks per request: a fresh id travels as the C callback's user_data (one shared purego callback, as before), each request has its own queue drained into its channel, so the native worker never blocks on a slow consumer and concurrent streams cannot mix - TTSLive rejects max_batch > 1 (qwentts incremental mode requires a max_batch=1 context, docs/INCREMENTAL.md) - README: option, measurements, TTSLive limit, ROCm/gfx1201 hipBLASLt note - unit tests: option parsing, Locking, concurrent stream routing (fails if requests were serialized), TTSLive rejection Measured with qwentts' own tts-server and the 1.7B Base Q4_K_M talker, four concurrent streaming requests, time to first PCM: RTX 5060 Ti (CUDA) 0.02/0.36/0.70/1.04 s at max_batch 1 vs 0.06 s for all four at 4; Radeon AI PRO R9700 (ROCm, with ROCBLAS_USE_HIPBLASLT=0) 0.03/0.71/1.36/ 2.02 s vs <= 0.11 s. Signed-off-by: nexxtmobile.de <git@nexxtmobile.de> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
58 lines
2.8 KiB
C
58 lines
2.8 KiB
C
#pragma once
|
|
#include <stddef.h>
|
|
|
|
extern "C" {
|
|
|
|
// Streaming PCM chunk callback. samples is mono float PCM at 24 kHz, valid
|
|
// only for the duration of the call. Return non-zero to continue, 0 to abort.
|
|
typedef int (*qt3_chunk_cb)(const float *samples, int n_samples,
|
|
void *user_data);
|
|
|
|
// Load the talker + codec/tokenizer GGUFs. use_fa / clamp_fp16 / max_batch
|
|
// map to qt_init_params (the qt ABI exposes no thread count; ggml uses its
|
|
// own default). max_batch > 1 lets concurrent qt3_tts / qt3_tts_stream calls
|
|
// share batched decode steps; 0 or 1 keeps single-sequence synthesis.
|
|
// Returns 0 on success, non-zero on failure.
|
|
int qt3_load(const char *talker_path, const char *codec_path, int use_fa,
|
|
int clamp_fp16, int max_batch);
|
|
|
|
// Synthesize to a malloc'd float PCM buffer (caller frees via qt3_pcm_free).
|
|
// The synthesis mode (base / custom_voice / voice_design) is auto-detected by
|
|
// qt from the talker GGUF; speaker is honoured only for custom_voice, instruct
|
|
// for voice_design / custom_voice, and ref_samples (+ optional ref_text) drive
|
|
// base-mode cloning. qt enforces the rules and we surface qt_last_error() on
|
|
// QT_STATUS_MODE_INVALID. Writes the sample count to *out_n. Returns NULL on
|
|
// failure (out_n set to 0).
|
|
float *qt3_tts(const char *text, const char *lang, const char *instruct,
|
|
const char *speaker, const float *ref_samples, int ref_n,
|
|
const char *ref_text, long long seed, float temperature,
|
|
int top_k, float top_p, float repetition_penalty,
|
|
int max_new_tokens, int *out_n);
|
|
|
|
// Streaming synthesis: cb is invoked per PCM chunk as audio is produced. Same
|
|
// param semantics as qt3_tts. Returns 0 on success.
|
|
int qt3_tts_stream(const char *text, const char *lang, const char *instruct,
|
|
const char *speaker, const float *ref_samples, int ref_n,
|
|
const char *ref_text, long long seed, float temperature,
|
|
int top_k, float top_p, float repetition_penalty,
|
|
int max_new_tokens, qt3_chunk_cb cb, void *user_data);
|
|
|
|
typedef int (*qt3_text_cb)(void *user_data, const char **text, size_t *n_bytes);
|
|
int qt3_tts_live(const char *lang, const char *instruct, const char *speaker,
|
|
const float *ref_samples, int ref_n, const char *ref_text,
|
|
long long seed, float temperature, int top_k, float top_p,
|
|
float repetition_penalty, int max_new_tokens,
|
|
qt3_text_cb next_text, qt3_chunk_cb cb, void *user_data);
|
|
|
|
// Free a buffer returned by qt3_tts.
|
|
void qt3_pcm_free(float *p);
|
|
|
|
// Release the qt context.
|
|
void qt3_unload(void);
|
|
|
|
// Named-speaker introspection (custom_voice models). Returns 0 / NULL when no
|
|
// model is loaded or the index is out of range.
|
|
int qt3_n_speakers(void);
|
|
const char *qt3_speaker_name(int i);
|
|
}
|