mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-24 07:28:13 +02:00
v0.6.8 : les modeles peuvent vivre ailleurs que dans le dossier jean
Un .gguf pose sur un disque externe etait invisible dans l'UI : la liste des modeles ne scannait que JEAN_HOME et un preset pointant ailleurs affichait « introuvable ». On peut desormais declarer des dossiers de modeles supplementaires (replies derriere une ligne dans l'editeur de preset, persistes dans model_dirs.json, ou via JEAN_MODEL_DIRS). Acces distant : la pastille affiche « non connecte » au lieu de rester vide quand le serveur n'est lie a aucun compte.
This commit is contained in:
1 parent
acf094f961
commit
73a772520c
15 files changed
+584
-59
No files matched your search
@@ -83,25 +83,25 @@ func detectQuant(content string) string {
|
||||
}
|
||||
}
|
||||
}
|
||||
return quantFromName(modelFromPresetContent(content))
|
||||
return quantFromName(baseName(modelFromPresetContent(content)))
|
||||
}
|
||||
|
||||
// modelFilePath resolves a model file name to a path inside JEAN_HOME, refusing
|
||||
// anything that would escape it (path traversal). config.env conventionally
|
||||
// stores only the basename, so we deliberately strip any directory component.
|
||||
func modelFilePath(name string) (string, error) {
|
||||
// downloadDestPath resolves the destination of a downloaded model: always
|
||||
// JEAN_HOME (les dossiers externes sont en lecture, on n'y écrit pas), en
|
||||
// refusant tout ce qui en sortirait (path traversal).
|
||||
func downloadDestPath(name string) (string, error) {
|
||||
base := filepath.Base(strings.TrimSpace(name))
|
||||
if base == "" || base == "." || base == string(filepath.Separator) {
|
||||
return "", fmt.Errorf("nom de modèle invalide")
|
||||
}
|
||||
if !strings.HasSuffix(strings.ToLower(base), ".gguf") {
|
||||
return "", fmt.Errorf("seuls les fichiers .gguf peuvent être supprimés")
|
||||
return "", fmt.Errorf("seuls les fichiers .gguf sont acceptés")
|
||||
}
|
||||
return filepath.Join(JeanHome(), base), nil
|
||||
}
|
||||
|
||||
// modelFromPresetContent extracts the MODEL= value (basename) from a preset's
|
||||
// config.env body, or "" if absent.
|
||||
// modelFromPresetContent extracts the MODEL= value from a preset's config.env
|
||||
// body (nom de fichier ou chemin absolu, tel quel), or "" if absent.
|
||||
func modelFromPresetContent(content string) string {
|
||||
for _, line := range strings.Split(content, "\n") {
|
||||
s := strings.TrimSpace(line)
|
||||
@@ -113,16 +113,16 @@ func modelFromPresetContent(content string) string {
|
||||
continue
|
||||
}
|
||||
if strings.TrimSpace(s[:i]) == "MODEL" {
|
||||
v := strings.Trim(strings.TrimSpace(s[i+1:]), "\"")
|
||||
return filepath.Base(v)
|
||||
return strings.Trim(strings.TrimSpace(s[i+1:]), "\"")
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// deleteModelFile removes a .gguf file from JEAN_HOME after validating the name.
|
||||
// deleteModelFile removes a .gguf file from one of the declared model folders
|
||||
// after validating the name.
|
||||
func deleteModelFile(name string) error {
|
||||
p, err := modelFilePath(name)
|
||||
p, err := resolveModelPath(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -257,7 +257,7 @@ func handleModelDownload(w http.ResponseWriter, r *http.Request) {
|
||||
sendJSON(w, 400, map[string]any{"ok": false, "error": err.Error()})
|
||||
return
|
||||
}
|
||||
dest, err := modelFilePath(name)
|
||||
dest, err := downloadDestPath(name)
|
||||
if err != nil {
|
||||
sendJSON(w, 400, map[string]any{"ok": false, "error": err.Error()})
|
||||
return
|
||||
|
||||
Reference in new issue
Block a user