mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
Chaque dictée relançait whisper-cli, qui relisait le modèle depuis le disque avant de transcrire. Ce chargement dominait le temps de réponse — 3,2 s de calcul pour 3,4 s d'audio — et aucun réglage ne pouvait le rattraper. whisper-server garde le modèle en mémoire entre deux phrases. Loki le supervise : démarrage au premier clic sur le micro, extinction après dix minutes sans dictée. Une dictée n'est pas un service permanent, et garder un modèle chargé toute la journée priverait le moteur de chat de sa VRAM. - Réglages serveur (modèle, langue, matériel, réactivité) dans bkState, avec leurs routes. La langue par défaut passe de « auto » à « fr » : sur quelques secondes d'audio la détection se trompe, et une langue mal détectée produit du charabia — des suites de caractères géorgiens ont été observées. - Catalogue de quatre modèles, de small à large-v3 ; large-v3-turbo par défaut. Téléchargement par identifiant, dans un .part renommé à la fin : un transfert interrompu ne laisse plus un .bin tronqué qu'on croirait bon. - Le GPU se choisit par CUDA_VISIBLE_DEVICES, posé en REMPLAÇANT toute valeur héritée. Dupliquée, la variable laisse le gagnant dépendre de la libc. - Les marqueurs de whisper ([BLANK_AUDIO], (silence)) ne sont plus collés dans le champ de saisie comme s'ils étaient du texte dicté. L'image construit DEUX binaires whisper-server, CPU et CUDA. LLAMACPP_IMAGE accepte la variante CPU de l'image amont ; sur cette base les .so CUDA sont absentes et un binaire lié à CUDA n'a même pas de quoi démarrer, donc aucun repli n'est possible depuis le programme. Le garde-fou du Dockerfile vérifie maintenant les deux étapes : les drapeaux de portabilité de la PR #18 doivent survivre à l'arrivée de CUDA. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W3ewMAsXhkw9RY11kb9Dc9
76 lines
2.3 KiB
Go
76 lines
2.3 KiB
Go
package loki
|
|
|
|
import (
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestCatalogueContientLeDefautEtLAncien(t *testing.T) {
|
|
// Le défaut doit exister, sinon dictateCfgSave refuse sa propre valeur par
|
|
// défaut et plus aucun réglage n'est enregistrable.
|
|
if _, ok := whisperCatalogue["large-v3-turbo-q5_0"]; !ok {
|
|
t.Error("le modèle par défaut large-v3-turbo-q5_0 est absent du catalogue")
|
|
}
|
|
// small-q5_1 est le modèle déjà téléchargé sur les installations
|
|
// existantes : le retirer le rendrait insélectionnable alors que son
|
|
// fichier est là.
|
|
if _, ok := whisperCatalogue["small-q5_1"]; !ok {
|
|
t.Error("small-q5_1 est absent : les installations existantes l'ont déjà sur disque")
|
|
}
|
|
}
|
|
|
|
func TestModelPathEtURL(t *testing.T) {
|
|
testHome(t)
|
|
p := whisperModelPathFor("small-q5_1")
|
|
if filepath.Base(p) != "ggml-small-q5_1.bin" {
|
|
t.Errorf("chemin = %q, le fichier doit s'appeler ggml-small-q5_1.bin", p)
|
|
}
|
|
// Le chemin DOIT rester celui d'avant, sinon les installations existantes
|
|
// re-téléchargent 190 Mo pour rien.
|
|
if filepath.Base(filepath.Dir(p)) != "whisper" {
|
|
t.Errorf("chemin = %q, le dossier doit rester <LOKI_HOME>/whisper", p)
|
|
}
|
|
u := whisperModelURLFor("small-q5_1")
|
|
if !strings.HasSuffix(u, "/ggml-small-q5_1.bin") {
|
|
t.Errorf("URL = %q, doit finir par /ggml-small-q5_1.bin", u)
|
|
}
|
|
if !strings.HasPrefix(u, "https://") {
|
|
t.Errorf("URL = %q, doit être en HTTPS", u)
|
|
}
|
|
}
|
|
|
|
func TestModelPathInconnuVide(t *testing.T) {
|
|
testHome(t)
|
|
if p := whisperModelPathFor("nawak"); p != "" {
|
|
t.Errorf("un modèle hors catalogue doit donner un chemin vide, pas %q", p)
|
|
}
|
|
if u := whisperModelURLFor("nawak"); u != "" {
|
|
t.Errorf("URL d'un modèle inconnu = %q, attendu vide", u)
|
|
}
|
|
if whisperModelPresent("nawak") {
|
|
t.Error("un modèle inconnu ne peut pas être présent")
|
|
}
|
|
}
|
|
|
|
func TestCatalogueTrieParTaille(t *testing.T) {
|
|
testHome(t)
|
|
l := whisperCatalogueTrie()
|
|
if len(l) < 4 {
|
|
t.Fatalf("catalogue de %d entrées, au moins 4 attendues", len(l))
|
|
}
|
|
var prec int64
|
|
for i, m := range l {
|
|
o, _ := m["octets"].(int64)
|
|
if i > 0 && o < prec {
|
|
t.Errorf("entrée %d : catalogue non trié par taille croissante", i)
|
|
}
|
|
prec = o
|
|
for _, clef := range []string{"id", "nom", "octets", "vram_mo", "present"} {
|
|
if _, ok := m[clef]; !ok {
|
|
t.Errorf("entrée %d : clé %q manquante — l'UI en a besoin", i, clef)
|
|
}
|
|
}
|
|
}
|
|
}
|