mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-22 06:28:11 +02:00
Modèles : un .gguf gardé se réutilise et s'efface
Un modèle téléchargé depuis l'éditeur d'un preset survit à la suppression de ce preset (c'est voulu : on le réutilise ailleurs). Il devenait pourtant inatteignable — impossible de refaire un preset dessus, impossible de l'effacer. Trois causes, trois correctifs. 1. « Le modèle existe déjà » n'est plus une erreur. La recherche Hugging Face proposait le quant, le clic lançait la sonde, et le téléchargement répondait en rouge « le modèle existe déjà » — fin du parcours. La sonde constate maintenant la présence du fichier (sans même sortir sur le réseau) et renvoie la valeur à écrire dans MODEL= : l'interface le SÉLECTIONNE, et la file continue (le projecteur vision, par exemple). Les quants déjà présents portent une pastille « déjà installé » dans la liste du dépôt, avant le clic. 2. Le sélecteur de modèle reconnaissait mal ce qu'il avait sous les yeux. /api/models comparait le dossier de chaque .gguf à LokiHome() alors que les téléchargements atterrissent dans $LOKI_HOME/models : la comparaison ne pouvait jamais être vraie. Conséquences : l'étiquette « dossier loki » ne s'affichait nulle part, et un preset écrit MODEL=modele.gguf s'affichait « introuvable ; ajoute son dossier ci-dessous » — le fichier étant juste à côté. Un nom simple est désormais résolu comme le fait le moteur : dossier de loki d'abord, puis les autres. 3. Une liste « Modèles installés », dans le groupe Modèle de l'éditeur. La route /api/models/delete existait depuis longtemps ; aucun bouton ne l'appelait. Le seul moment où un .gguf pouvait disparaître, c'était en cochant « supprimer aussi le fichier » à la suppression de son preset. La liste montre taille, dossier, tranches manquantes, et qui s'en sert : le modèle en service ne s'efface pas (le moteur l'a ouvert, la place ne serait même pas rendue), celui que des presets nomment prévient en les nommant puis obéit. La suppression dit ce qu'elle a libéré. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0129sffVC43rezAXUMQuzUog
This commit is contained in:
9 files changed
+1061
-71
No files matched your search
@@ -299,14 +299,30 @@ func handleLlamacppUninstallCustom(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// handleModels lists *.gguf files (size in bytes) for the preset editor's model
|
||||
// picker, dans LOKI_HOME ET dans les dossiers supplémentaires déclarés (disque
|
||||
// externe…). "value" est ce qu'il faut écrire dans MODEL= : un simple nom de
|
||||
// fichier pour LOKI_HOME (compatibilité avec l'existant), le chemin complet
|
||||
// pour un dossier externe.
|
||||
// picker, dans le dossier de modèles de Loki ET dans les dossiers
|
||||
// supplémentaires déclarés (disque externe…). "value" est ce qu'il faut écrire
|
||||
// dans MODEL= : un simple nom de fichier pour le dossier de Loki
|
||||
// (compatibilité avec l'existant, et preset portable d'une machine à l'autre),
|
||||
// le chemin complet pour un dossier externe.
|
||||
//
|
||||
// ⚠️ Le dossier « maison » est modelsDir() — $LOKI_HOME/models — et non
|
||||
// LokiHome() : c'est là que les téléchargements atterrissent (downloadDestPath)
|
||||
// et c'est lui que resolveModelPath essaie en premier pour un nom simple. Le
|
||||
// comparer à LokiHome() ne pouvait JAMAIS être vrai : chaque modèle sortait en
|
||||
// chemin absolu, l'étiquette « dossier loki » ne s'affichait nulle part, et un
|
||||
// preset écrit à la main avec MODEL=modele.gguf ne correspondait à aucune
|
||||
// option du sélecteur — il s'affichait « introuvable » alors que le fichier
|
||||
// était bien là.
|
||||
//
|
||||
// Chaque entrée porte aussi QUI la référence (« used » : noms de presets,
|
||||
// « active » : la configuration en service). C'est ce qui permet à l'interface
|
||||
// de proposer la suppression d'un .gguf sans faire disparaître le modèle sous
|
||||
// le moteur qui tourne.
|
||||
func handleModels(w http.ResponseWriter, r *http.Request) {
|
||||
out := []map[string]any{}
|
||||
seen := map[string]bool{}
|
||||
home := LokiHome()
|
||||
home := modelsDir()
|
||||
refs := buildModelRefIndex()
|
||||
for _, dir := range modelDirs() {
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
@@ -341,6 +357,12 @@ func handleModels(w http.ResponseWriter, r *http.Request) {
|
||||
"name": e.Name(), "size": size, "value": value,
|
||||
"path": full, "dir": dir, "home": isHome,
|
||||
}
|
||||
if users, active := refs.lookup(full); len(users) > 0 || active {
|
||||
if len(users) > 0 {
|
||||
m["used"] = users
|
||||
}
|
||||
m["active"] = active
|
||||
}
|
||||
// Taille annoncée = la famille entière, et on signale les tranches
|
||||
// manquantes : un modèle incomplet démarre puis meurt sur un tenseur
|
||||
// introuvable, autant le voir avant de le sélectionner.
|
||||
@@ -462,14 +484,24 @@ func handlePresetDelete(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
modelDeleted, modelErr := "", ""
|
||||
freed := int64(0)
|
||||
if req.DeleteModel && model != "" {
|
||||
if err := deleteModelFile(model); err != nil {
|
||||
// Le preset vient de disparaître : les « utilisé par » comptés ici sont
|
||||
// donc les AUTRES presets, et le refus « en service » vise bien le modèle
|
||||
// que le moteur a ouvert. On ne bloque pas sur un autre preset — c'est un
|
||||
// geste explicite, coché dans la confirmation — mais on le DIT.
|
||||
others, _ := modelUsers(model)
|
||||
if n, err := deleteModelFile(model); err != nil {
|
||||
modelErr = err.Error()
|
||||
} else {
|
||||
modelDeleted = model
|
||||
modelDeleted, freed = model, n
|
||||
if len(others) > 0 {
|
||||
modelErr = "supprimé, mais il était aussi référencé par : " + strings.Join(others, ", ")
|
||||
}
|
||||
}
|
||||
}
|
||||
sendJSON(w, 200, map[string]any{"ok": true, "modelDeleted": modelDeleted, "modelError": modelErr})
|
||||
sendJSON(w, 200, map[string]any{"ok": true, "modelDeleted": modelDeleted,
|
||||
"modelError": modelErr, "freed": freed})
|
||||
}
|
||||
|
||||
// handleAgent renvoie l'état du mode agent ET la liste des pages mémoire (que
|
||||
|
||||
Reference in new issue
Block a user