mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-17 12:16:21 +02:00
Strata : seconde carte en partage des couches au choix, l'aide aux experts reste le défaut
Repris d'AJEAN 38919238 (#121 amont) et de la partie moteur de 6db3f3d0 : STRATA_SPLIT=layers dans le preset fait lister les deux cartes dans la clé « gpu » de la config (principale d'abord, numéros nvidia-smi) ; le serveur de Strata en déduit --layer-split. Rien du mode d'aide ne subsiste alors : ni --expert-cache-device1 / --remote-expert-opt, ni source d'aide à la lecture des prompts, ni encodeur d'images déplacé ; la réserve de VRAM de l'installeur reste. Sans la clé, ou la seconde carte coupée, rien ne change. Propre à Loki : le placement des experts selon la RAM disponible ne choisit jamais le mode hors RAM en partage des couches (la seconde carte n'y garde pas d'experts, la marge calculée pour elle serait fausse). Réglages : « split » (helper ou layers ; absent = inchangé pour un ancien client), détail split_layers. Fenêtre Strata : la case « Carte d'appoint » devient un choix « Seconde carte » (non utilisée, aide aux experts, partage des couches) ; la carte de configuration du moteur actif l'affiche. Façade Rust alignée (strata/mod.rs, strata/api.rs, tests portés) ; journal de parité régénéré sous Linux avec les réglages et l'affichage du partage. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9792953d62
commit
615e58dd2f
13 files changed
+823
-120
No files matched your search
@@ -220,7 +220,9 @@ func strataPackHasExpertsBin(args []string) bool {
|
||||
// Pure : la décision se teste en table.
|
||||
func strataResolveExperts(cfg map[string]string, args []string, availGB, helperGB float64) string {
|
||||
binReady := strataPackHasExpertsBin(args) && strataEngineInstalled() == strataEngineAsset
|
||||
dropReady := binReady && strataHelperOn(cfg) && cfg["STRATA_DROP"] != "0"
|
||||
// (experts de la carte d'aide hors RAM : propre au mode d'aide, jamais en
|
||||
// partage des couches, où la seconde carte ne garde pas d'experts)
|
||||
dropReady := binReady && strataHelperOn(cfg) && !strataLayerSplit(cfg) && cfg["STRATA_DROP"] != "0"
|
||||
arena := strataArenaGB(cfg)
|
||||
switch strings.ToLower(strings.TrimSpace(cfg["STRATA_EXPERTS"])) {
|
||||
case strataExpertsDisk:
|
||||
@@ -504,6 +506,7 @@ type strataDetails struct {
|
||||
// pour les réglages : ce que la machine permet et l'état actuel
|
||||
HasHelper bool `json:"has_helper"` // une carte d'aide est disponible
|
||||
HelperOn bool `json:"helper_on"`
|
||||
Split bool `json:"split_layers"` // les deux cartes se partagent les couches
|
||||
Vision bool `json:"vision"`
|
||||
}
|
||||
|
||||
@@ -565,6 +568,7 @@ func strataDetailsFor(presetID string, env strataEnv) *strataDetails {
|
||||
if strataHelperOn(pc) {
|
||||
d.HelperOn = true
|
||||
d.HelperGPU = gpuName(h)
|
||||
d.Split = strataLayerSplit(pc)
|
||||
}
|
||||
}
|
||||
d.Vision = pc["STRATA_VISION"] != "0"
|
||||
@@ -968,6 +972,16 @@ func strataBuildConfig(base map[string]any, cfg map[string]string, apiKey, mode
|
||||
}
|
||||
helper := strings.TrimSpace(cfg["STRATA_HELPER_GPU"])
|
||||
hasHelper := strataHelperOn(cfg)
|
||||
if strataLayerSplit(cfg) {
|
||||
// Partage des couches : le serveur de Strata le fait de lui-même quand sa
|
||||
// clé « gpu » liste plusieurs cartes (--layer-split auto, réparti selon la
|
||||
// VRAM libre), numérotées comme nvidia-smi. Pas de chemin « aide » : la
|
||||
// réserve de VRAM de l'installeur et l'encodeur d'images restent en place.
|
||||
main, _ := strconv.Atoi(strings.TrimSpace(cfg["STRATA_MAIN_GPU"]))
|
||||
second, _ := strconv.Atoi(helper)
|
||||
out["gpu"] = []any{main, second}
|
||||
hasHelper = false
|
||||
}
|
||||
// Deuxième carte en aide : elle garde et CALCULE sa part des experts (le
|
||||
// chemin « helper » du moteur), la carte principale reste CUDA0. Les cartes
|
||||
// sont posées par CUDA_VISIBLE_DEVICES (serveStrata), PAS par la clé « gpu » :
|
||||
@@ -1191,6 +1205,16 @@ func strataHelperOn(cfg map[string]string) bool {
|
||||
return h != "" && h != "-1" && cfg["STRATA_HELPER"] != "0"
|
||||
}
|
||||
|
||||
// strataLayerSplit : les deux cartes se partagent les COUCHES du modèle (clé de
|
||||
// preset STRATA_SPLIT=layers) au lieu que la seconde n'aide que pour une part
|
||||
// des experts. Mesuré par un utilisateur d'AJEAN sur deux RTX 3060 identiques
|
||||
// (#121 amont) : la carte d'aide ne travaillait qu'à ~15 %, le partage des
|
||||
// couches donnait +50 % en génération. Sur deux cartes très différentes, le
|
||||
// mode d'aide reste le défaut mesuré : le partage est un choix, jamais imposé.
|
||||
func strataLayerSplit(cfg map[string]string) bool {
|
||||
return strataHelperOn(cfg) && cfg["STRATA_SPLIT"] == "layers"
|
||||
}
|
||||
|
||||
// strataCudaDevices : ordre des cartes vu par le moteur, la principale en CUDA0.
|
||||
func strataCudaDevices(cfg map[string]string) string {
|
||||
main := strings.TrimSpace(cfg["STRATA_MAIN_GPU"])
|
||||
@@ -1437,6 +1461,9 @@ type strataSettingsReq struct {
|
||||
Vision bool `json:"vision"`
|
||||
Helper bool `json:"helper"`
|
||||
Experts string `json:"experts"` // auto, ram ou disk ; vide = inchangé
|
||||
// Split : rôle de la seconde carte, « helper » (aide aux experts) ou
|
||||
// « layers » (partage des couches). Vide = inchangé (anciens clients).
|
||||
Split string `json:"split"`
|
||||
}
|
||||
|
||||
// strataApplySettings réécrit les clés du preset (pure, testable).
|
||||
@@ -1451,6 +1478,8 @@ func strataApplySettings(content string, r strataSettingsReq) (string, error) {
|
||||
return "", fmt.Errorf("MTP hors limites : %d", r.Spec)
|
||||
case r.Experts != "" && r.Experts != strataExpertsAuto && r.Experts != strataExpertsRAM && r.Experts != strataExpertsDisk:
|
||||
return "", fmt.Errorf("placement des experts inconnu : %s", r.Experts)
|
||||
case r.Split != "" && r.Split != "helper" && r.Split != "layers":
|
||||
return "", fmt.Errorf("répartition inconnue : %s", r.Split)
|
||||
}
|
||||
set := map[string]string{
|
||||
"CTX": strconv.Itoa(r.Ctx), "STRATA_KV": r.KV, "STRATA_SPEC": strconv.Itoa(r.Spec),
|
||||
@@ -1461,6 +1490,14 @@ func strataApplySettings(content string, r strataSettingsReq) (string, error) {
|
||||
set["STRATA_EXPERTS"] = r.Experts
|
||||
keys = append(keys, "STRATA_EXPERTS")
|
||||
}
|
||||
if r.Split != "" {
|
||||
// « helper » est le défaut : la clé disparaît plutôt que d'être écrite
|
||||
set["STRATA_SPLIT"] = ""
|
||||
if r.Split == "layers" {
|
||||
set["STRATA_SPLIT"] = "layers"
|
||||
}
|
||||
keys = append(keys, "STRATA_SPLIT")
|
||||
}
|
||||
var lines []string
|
||||
for _, l := range strings.Split(strings.TrimRight(content, "\n"), "\n") {
|
||||
k, _, _ := strings.Cut(strings.TrimSpace(l), "=")
|
||||
@@ -1470,6 +1507,9 @@ func strataApplySettings(content string, r strataSettingsReq) (string, error) {
|
||||
lines = append(lines, l)
|
||||
}
|
||||
for _, k := range keys {
|
||||
if set[k] == "" && k == "STRATA_SPLIT" {
|
||||
continue
|
||||
}
|
||||
lines = append(lines, k+"="+set[k])
|
||||
}
|
||||
return strings.Join(lines, "\n") + "\n", nil
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
package loki
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Partage des couches (#121 amont) : la clé « gpu » liste les deux cartes (le
|
||||
// serveur de Strata en déduit --layer-split), et rien du mode d'aide ne subsiste.
|
||||
func TestStrataBuildConfigLayerSplit(t *testing.T) {
|
||||
base := map[string]any{
|
||||
"args": []any{"--pack", "/p", "--vram-reserve-mib", "900"},
|
||||
"vision": map[string]any{"exe": "/v"},
|
||||
}
|
||||
cfg := map[string]string{"STRATA_MAIN_GPU": "1", "STRATA_HELPER_GPU": "0", "STRATA_SPLIT": "layers"}
|
||||
out, err := strataBuildConfig(base, cfg, "", "drop")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
g, ok := out["gpu"].([]any)
|
||||
if !ok || len(g) != 2 || g[0] != 1 || g[1] != 0 {
|
||||
t.Fatalf("gpu = %v, attendu [1 0] (principale d'abord, numéros nvidia-smi)", out["gpu"])
|
||||
}
|
||||
a := strataArgs(t, out)
|
||||
if strataHasArg(a, "--remote-expert-opt") || strataHasArg(a, "--expert-cache-device1") {
|
||||
t.Errorf("options du mode d'aide en partage des couches : %v", a)
|
||||
}
|
||||
if argAfter(a, "--vram-reserve-mib") != "900" {
|
||||
t.Errorf("la réserve de VRAM de l'installeur doit rester : %v", a)
|
||||
}
|
||||
if argAfter(a, "--short-read") != "150" {
|
||||
t.Errorf("lecture des prompts par la carte d'aide en partage des couches : %v", a)
|
||||
}
|
||||
env := out["env"].(map[string]any)
|
||||
if env["STRATA_REMOTE_DROP"] != nil || env["STRATA_PREFILL_HELPER_SOURCE"] != nil {
|
||||
t.Errorf("experts hors RAM ou source d'aide (mode d'aide) en partage des couches : %v", env)
|
||||
}
|
||||
if _, has := out["vision"].(map[string]any)["cuda_device"]; has {
|
||||
t.Errorf("encodeur d'images déplacé sur la seconde carte en partage des couches")
|
||||
}
|
||||
|
||||
// Sans la clé, rien ne change : le mode d'aide reste le défaut.
|
||||
delete(cfg, "STRATA_SPLIT")
|
||||
out, _ = strataBuildConfig(base, cfg, "", "drop")
|
||||
if _, has := out["gpu"]; has {
|
||||
t.Errorf("clé gpu posée en mode d'aide : %v", out["gpu"])
|
||||
}
|
||||
if !strataHasArg(strataArgs(t, out), "--remote-expert-opt") {
|
||||
t.Errorf("mode d'aide perdu sans STRATA_SPLIT")
|
||||
}
|
||||
// Seconde carte coupée : pas de partage même si la clé traîne.
|
||||
cfg["STRATA_SPLIT"], cfg["STRATA_HELPER"] = "layers", "0"
|
||||
if strataLayerSplit(cfg) {
|
||||
t.Errorf("partage des couches avec la seconde carte coupée")
|
||||
}
|
||||
}
|
||||
|
||||
// En partage des couches, la seconde carte ne garde pas d'experts : le mode
|
||||
// hors RAM (qui compte sur elle pour en loger une part) n'est jamais choisi.
|
||||
func TestStrataResolveExpertsLayerSplit(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("LOKI_HOME", home)
|
||||
pack := filepath.Join(home, "pack")
|
||||
_ = os.MkdirAll(pack, 0o755)
|
||||
_ = os.WriteFile(filepath.Join(pack, "experts.bin"), []byte("x"), 0o644)
|
||||
_ = os.MkdirAll(filepath.Join(strataSrcDir(), "engine-cuda12"), 0o755)
|
||||
_ = os.WriteFile(strataEngineMarker(), []byte(strataEngineAsset+"\n"), 0o644)
|
||||
args := []string{"--pack", pack}
|
||||
cfg := map[string]string{"STRATA_CONFIG": "/x/strata-swift-iq3_xxs.json", "STRATA_HELPER_GPU": "1", "STRATA_DROP": "1"}
|
||||
if got := strataResolveExperts(cfg, args, 44, 12); got != "drop" {
|
||||
t.Fatalf("mode d'aide : %s, attendu drop", got)
|
||||
}
|
||||
cfg["STRATA_SPLIT"] = "layers"
|
||||
if got := strataResolveExperts(cfg, args, 44, 12); got != "arena" {
|
||||
t.Errorf("partage des couches : %s, attendu arena", got)
|
||||
}
|
||||
cfg["STRATA_EXPERTS"] = "ram"
|
||||
if got := strataResolveExperts(cfg, args, 44, 12); got != "ram" {
|
||||
t.Errorf("partage des couches, experts en RAM : %s, attendu ram", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStrataApplySettingsSplit(t *testing.T) {
|
||||
in := "ENGINE=strata\nSTRATA_HELPER_GPU=0\n"
|
||||
req := strataSettingsReq{Ctx: 131072, KV: "fp16", Spec: 3, Vision: true, Helper: true, Split: "layers"}
|
||||
out, err := strataApplySettings(in, req)
|
||||
if err != nil || !strings.Contains(out, "STRATA_SPLIT=layers\n") {
|
||||
t.Fatalf("STRATA_SPLIT=layers attendu : %q (%v)", out, err)
|
||||
}
|
||||
req.Split = "helper"
|
||||
if out, _ = strataApplySettings(out, req); strings.Contains(out, "STRATA_SPLIT") {
|
||||
t.Errorf("retour au mode d'aide : la clé doit disparaître : %q", out)
|
||||
}
|
||||
// un ancien client n'envoie pas « split » : la clé est conservée
|
||||
req.Split = ""
|
||||
out, _ = strataApplySettings("STRATA_SPLIT=layers\n", req)
|
||||
if !strings.Contains(out, "STRATA_SPLIT=layers") {
|
||||
t.Errorf("clé effacée par un client qui ne la connaît pas : %q", out)
|
||||
}
|
||||
req.Split = "nimporte"
|
||||
if _, err := strataApplySettings(in, req); err == nil {
|
||||
t.Errorf("répartition inconnue acceptée")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStrataDetailsForLayerSplit(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("LOKI_HOME", home)
|
||||
base := filepath.Join(home, "base.json")
|
||||
_ = os.WriteFile(base, []byte(`{"args":["--pack","/p"],"vision":{"exe":"v"}}`), 0o644)
|
||||
_ = os.MkdirAll(presetsDir(), 0o755)
|
||||
preset := "ENGINE=strata\nSTRATA_CONFIG=" + base + "\nSTRATA_MAIN_GPU=1\nSTRATA_HELPER_GPU=0\nSTRATA_SPLIT=layers\n"
|
||||
_ = os.WriteFile(filepath.Join(presetsDir(), "X.env"), []byte(preset), 0o644)
|
||||
env := strataEnv{GPUs: []strataGPU{{Index: 0, Name: "NVIDIA GeForce RTX 3060", VRAMGB: 12}, {Index: 1, Name: "NVIDIA GeForce RTX 3060", VRAMGB: 12}}}
|
||||
d := strataDetailsFor("X", env)
|
||||
if d == nil {
|
||||
t.Fatal("pas de détails")
|
||||
}
|
||||
if !d.Split || !d.HelperOn || d.HelperGPU == "" || d.VisionGPU != d.MainGPU || d.ShortRead != "150" {
|
||||
t.Errorf("%+v", *d)
|
||||
}
|
||||
}
|
||||
@@ -333,7 +333,7 @@ func TestPariteStrata(t *testing.T) {
|
||||
mu.Unlock()
|
||||
st.After = map[string]string{}
|
||||
cfg := ReadConfig()
|
||||
for _, k := range []string{"ENGINE", "STRATA_CONFIG", "CTX", "STRATA_KV", "STRATA_HELPER"} {
|
||||
for _, k := range []string{"ENGINE", "STRATA_CONFIG", "CTX", "STRATA_KV", "STRATA_HELPER", "STRATA_SPLIT"} {
|
||||
if v := cfg[k]; v != "" {
|
||||
st.After["config/"+k] = mask(v)
|
||||
}
|
||||
@@ -382,6 +382,10 @@ func TestPariteStrata(t *testing.T) {
|
||||
Method: "POST", Path: "/api/strata/settings", Body: settings("S", 98304, "")},
|
||||
{Name: "réglages du preset actif pendant une optimisation", Tune: true,
|
||||
Method: "POST", Path: "/api/strata/settings", Body: settings("S", 98304, "")},
|
||||
{Name: "réglages, répartition inconnue", Method: "POST", Path: "/api/strata/settings", Body: settings("S", 98304, `,"split":"nimporte"`)},
|
||||
{Name: "réglages, partage des couches", Method: "POST", Path: "/api/strata/settings", Body: settings("S", 98304, `,"split":"layers"`)},
|
||||
{Name: "réglages d'un ancien client, partage gardé", Method: "POST", Path: "/api/strata/settings", Body: settings("S", 98304, "")},
|
||||
{Name: "réglages, retour à l'aide aux experts", Method: "POST", Path: "/api/strata/settings", Body: settings("S", 98304, `,"split":"helper"`)},
|
||||
|
||||
// Installation.
|
||||
{Name: "installation en GET", Method: "GET", Path: "/api/strata/install"},
|
||||
@@ -417,6 +421,11 @@ func TestPariteStrata(t *testing.T) {
|
||||
"STRATA_CONFIG={{HOME}}/strata/" + srcDir + "/strata-swift-iq3_xxs.json\nSTRATA_MAIN_GPU=1\nSTRATA_HELPER_GPU=0\n" +
|
||||
"STRATA_VISION=1\nSTRATA_EXPERTS=auto\nSTRATA_DROP=1\nSTRATA_KV=fp16\nSTRATA_KV_RESIDENT=32768\nSTRATA_SPEC=3\nCTX=196608\nREASONING=off\n",
|
||||
}, Method: "GET", Path: "/api/strata"},
|
||||
{Name: "seconde carte en partage des couches", Files: map[string]string{
|
||||
"presets/STRATA FLASH NEXT SWIFT 1.5 IQ3_XXS.env": "# NAME=Qwen3.8 Flash Next Swift 1.5 IQ3_XXS (Strata)\nENGINE=strata\n" +
|
||||
"STRATA_CONFIG={{HOME}}/strata/" + srcDir + "/strata-swift-iq3_xxs.json\nSTRATA_MAIN_GPU=1\nSTRATA_HELPER_GPU=0\n" +
|
||||
"STRATA_VISION=1\nSTRATA_EXPERTS=auto\nSTRATA_DROP=1\nSTRATA_KV=fp16\nSTRATA_KV_RESIDENT=32768\nSTRATA_SPEC=3\nCTX=196608\nREASONING=off\nSTRATA_SPLIT=layers\n",
|
||||
}, Method: "GET", Path: "/api/strata"},
|
||||
{Name: "mode hors RAM coupé dans le preset", Files: map[string]string{
|
||||
"presets/STRATA FLASH NEXT SWIFT 1.5 IQ3_XXS.env": "# NAME=Qwen3.8 Flash Next Swift 1.5 IQ3_XXS (Strata)\nENGINE=strata\n" +
|
||||
"STRATA_CONFIG={{HOME}}/strata/" + srcDir + "/strata-swift-iq3_xxs.json\nSTRATA_MAIN_GPU=1\nSTRATA_HELPER_GPU=0\n" +
|
||||
|
||||
@@ -4521,6 +4521,7 @@ async function loadCfg(){
|
||||
rows.push(row('CTX', d.ctx));
|
||||
rows.push(row('KV', d.kv+(d.kv_resident ? ' · '+k(d.kv_resident)+' VRAM' : '')));
|
||||
rows.push(row('MTP', d.spec));
|
||||
if(d.helper_gpu) rows.push(row('GPU 2', d.split_layers ? 'couches' : 'aide', d.helper_gpu));
|
||||
rows.push(row('EXPERTS', ({drop:'mlock (hors appoint)', ram:'RAM', arena:'experts.bin', disk:'mmap (disque)'})[d.mode] || (d.mmap ? 'mmap' : 'RAM'), d.mode_label||''));
|
||||
if(d.vision_gpu) rows.push(row('VISION', 'on', d.vision_gpu));
|
||||
}else if(c.CTX) rows.push(row('CTX', c.CTX));
|
||||
@@ -9281,7 +9282,11 @@ function strataRenderSettings(fit){
|
||||
['Experts', sel('strata-s-experts', [['auto','auto (selon la RAM libre)'],['ram','en RAM (le plus rapide)'],['disk','depuis le disque (mmap, économe)']], d.experts||'auto')],
|
||||
['Lire les images', sw('strata-s-vision', d.vision)],
|
||||
];
|
||||
if(d.has_helper) rows.push(["Carte d'appoint", sw('strata-s-helper', d.helper_on)]);
|
||||
// Seconde carte : aide aux experts (défaut mesuré) ou partage des couches,
|
||||
// souvent plus rapide avec deux cartes identiques (#121 d'AJEAN).
|
||||
if(d.has_helper) rows.push(['Seconde carte', sel('strata-s-helper',
|
||||
[['off', 'non utilisée'], ['helper', 'aide aux experts'], ['layers', 'partage des couches']],
|
||||
!d.helper_on ? 'off' : d.split_layers ? 'layers' : 'helper')]);
|
||||
document.getElementById('strata-settings').innerHTML = rows.map(([a,b])=>
|
||||
'<div class="moe-kv"><span>'+escHtml(a)+'</span><span>'+b+'</span></div>').join('');
|
||||
strataCtxLbl();
|
||||
@@ -9301,8 +9306,11 @@ async function strataSaveSettings(){
|
||||
if(!fit || !fit.preset) return;
|
||||
const v = id => document.getElementById(id);
|
||||
const body = {preset: fit.preset, ctx: +v('strata-s-ctx').value, kv: v('strata-s-kv').value, spec: +v('strata-s-spec').value,
|
||||
vision: v('strata-s-vision').checked, helper: v('strata-s-helper') ? v('strata-s-helper').checked : false,
|
||||
vision: v('strata-s-vision').checked,
|
||||
experts: v('strata-s-experts') ? v('strata-s-experts').value : ''};
|
||||
const second = v('strata-s-helper') ? v('strata-s-helper').value : 'off';
|
||||
body.helper = second !== 'off';
|
||||
if(body.helper) body.split = second;
|
||||
if(fit.active && !await askConfirm('Le modèle va redémarrer avec ces réglages (quelques minutes).', {title:'Strata — Qwen3.8 Flash Next', okText:'Enregistrer'})) return;
|
||||
const r = await jpost('/api/strata/settings', body);
|
||||
if(!r.ok){ toast('Erreur : '+(r.error||'')); return; }
|
||||
@@ -9321,7 +9329,7 @@ function strataRenderDetails(fit){
|
||||
const k = n => (+n >= 1024 ? Math.round(+n/1024)+'K' : n);
|
||||
const rows = [
|
||||
['Carte principale', d.main_gpu],
|
||||
["Carte d'appoint", d.helper_gpu || 'aucune'],
|
||||
['Seconde carte', d.helper_gpu ? d.helper_gpu + (d.split_layers ? ' · partage des couches' : ' · aide aux experts') : 'aucune'],
|
||||
['Lecture des images', d.vision_gpu || 'aucune'],
|
||||
['Contexte', (+d.ctx).toLocaleString('fr-FR')+' jetons'],
|
||||
['Cache KV', d.kv + (d.kv_resident ? ' · '+k(d.kv_resident)+' en VRAM, le reste en RAM' : '')],
|
||||
|
||||
@@ -330,6 +330,7 @@ async function loadCfg(){
|
||||
rows.push(row('CTX', d.ctx));
|
||||
rows.push(row('KV', d.kv+(d.kv_resident ? ' · '+k(d.kv_resident)+' VRAM' : '')));
|
||||
rows.push(row('MTP', d.spec));
|
||||
if(d.helper_gpu) rows.push(row('GPU 2', d.split_layers ? 'couches' : 'aide', d.helper_gpu));
|
||||
rows.push(row('EXPERTS', ({drop:'mlock (hors appoint)', ram:'RAM', arena:'experts.bin', disk:'mmap (disque)'})[d.mode] || (d.mmap ? 'mmap' : 'RAM'), d.mode_label||''));
|
||||
if(d.vision_gpu) rows.push(row('VISION', 'on', d.vision_gpu));
|
||||
}else if(c.CTX) rows.push(row('CTX', c.CTX));
|
||||
|
||||
@@ -128,7 +128,11 @@ function strataRenderSettings(fit){
|
||||
['Experts', sel('strata-s-experts', [['auto','auto (selon la RAM libre)'],['ram','en RAM (le plus rapide)'],['disk','depuis le disque (mmap, économe)']], d.experts||'auto')],
|
||||
['Lire les images', sw('strata-s-vision', d.vision)],
|
||||
];
|
||||
if(d.has_helper) rows.push(["Carte d'appoint", sw('strata-s-helper', d.helper_on)]);
|
||||
// Seconde carte : aide aux experts (défaut mesuré) ou partage des couches,
|
||||
// souvent plus rapide avec deux cartes identiques (#121 d'AJEAN).
|
||||
if(d.has_helper) rows.push(['Seconde carte', sel('strata-s-helper',
|
||||
[['off', 'non utilisée'], ['helper', 'aide aux experts'], ['layers', 'partage des couches']],
|
||||
!d.helper_on ? 'off' : d.split_layers ? 'layers' : 'helper')]);
|
||||
document.getElementById('strata-settings').innerHTML = rows.map(([a,b])=>
|
||||
'<div class="moe-kv"><span>'+escHtml(a)+'</span><span>'+b+'</span></div>').join('');
|
||||
strataCtxLbl();
|
||||
@@ -148,8 +152,11 @@ async function strataSaveSettings(){
|
||||
if(!fit || !fit.preset) return;
|
||||
const v = id => document.getElementById(id);
|
||||
const body = {preset: fit.preset, ctx: +v('strata-s-ctx').value, kv: v('strata-s-kv').value, spec: +v('strata-s-spec').value,
|
||||
vision: v('strata-s-vision').checked, helper: v('strata-s-helper') ? v('strata-s-helper').checked : false,
|
||||
vision: v('strata-s-vision').checked,
|
||||
experts: v('strata-s-experts') ? v('strata-s-experts').value : ''};
|
||||
const second = v('strata-s-helper') ? v('strata-s-helper').value : 'off';
|
||||
body.helper = second !== 'off';
|
||||
if(body.helper) body.split = second;
|
||||
if(fit.active && !await askConfirm('Le modèle va redémarrer avec ces réglages (quelques minutes).', {title:'Strata — Qwen3.8 Flash Next', okText:'Enregistrer'})) return;
|
||||
const r = await jpost('/api/strata/settings', body);
|
||||
if(!r.ok){ toast('Erreur : '+(r.error||'')); return; }
|
||||
@@ -168,7 +175,7 @@ function strataRenderDetails(fit){
|
||||
const k = n => (+n >= 1024 ? Math.round(+n/1024)+'K' : n);
|
||||
const rows = [
|
||||
['Carte principale', d.main_gpu],
|
||||
["Carte d'appoint", d.helper_gpu || 'aucune'],
|
||||
['Seconde carte', d.helper_gpu ? d.helper_gpu + (d.split_layers ? ' · partage des couches' : ' · aide aux experts') : 'aucune'],
|
||||
['Lecture des images', d.vision_gpu || 'aucune'],
|
||||
['Contexte', (+d.ctx).toLocaleString('fr-FR')+' jetons'],
|
||||
['Cache KV', d.kv + (d.kv_resident ? ' · '+k(d.kv_resident)+' en VRAM, le reste en RAM' : '')],
|
||||
|
||||
Reference in new issue
Block a user