feat(cmf): per-model generation defaults; safer delete-file default
Docker / publish (push) Canceled after 0s
Release / crates-io (push) Canceled after 0s
Release / release (macos-14, aarch64-apple-darwin) (push) Canceled after 0s
Release / release (ubuntu-latest, x86_64-unknown-linux-gnu) (push) Canceled after 0s
Release / release (windows-latest, x86_64-pc-windows-msvc) (push) Canceled after 0s

- Each Local-models row gains default generation params — temperature, top-p,
  max tokens — applied by the gateway when the incoming request doesn't set
  them (an explicit request value always wins). Works for both the plain and
  streaming paths; top_p is now forwarded to OpenAI-compatible providers.
- The "also delete the model file from disk" checkbox in the delete dialog now
  defaults to UNCHECKED — deleting a pool entry no longer silently costs a
  multi-GB re-download/conversion.
This commit is contained in:
infosave2007
2026-07-14 15:22:26 +03:00
parent 46c11b9b88
commit 3c4be5e966
9 changed files with 66 additions and 9 deletions
+12 -2
View File
@@ -240,6 +240,10 @@ export async function renderSettings() {
...o1Opts.map((v) => h("option", { value: v, selected: (sv.o1 || "") === v ? true : null },
v === "" ? t("settings.cmf.o1Auto") : v)));
if (sv.o1 && !o1Opts.includes(sv.o1)) o1In.appendChild(h("option", { value: sv.o1, selected: true }, sv.o1));
// per-model generation defaults (applied when the request doesn't set them)
const tempIn = h("input", { type: "number", step: "0.1", min: 0, max: 2, value: sv.temperature ?? "", placeholder: "T° 0.7", style: "width:74px", title: t("settings.cmf.tempHelp") });
const topPIn = h("input", { type: "number", step: "0.05", min: 0, max: 1, value: sv.top_p ?? "", placeholder: "top-p", style: "width:70px", title: t("settings.cmf.topPHelp") });
const maxTokIn = h("input", { type: "number", min: 1, value: sv.max_tokens ?? "", placeholder: "max tok", style: "width:82px", title: t("settings.cmf.maxTokHelp") });
const checkBtn = h("button", { class: "btn small", type: "button" }, t("settings.cmf.checkPort"));
const removeBtn = h("button", { class: "btn small danger", type: "button", title: t("common.delete") }, "✕");
const st = h("span", { class: "small" });
@@ -264,8 +268,14 @@ export async function renderSettings() {
checkBtn.disabled = false;
});
const row = h("div", { class: "flex wrap", style: "gap:6px;align-items:center;margin:6px 0" },
idIn, modelSel, portIn, checkBtn, threadsIn, h("label", { class: "flex", style: "gap:4px" }, gpuIn, "GPU"), o1In, removeBtn, st);
const entry = { node: row, read: () => ({ id: idIn.value.trim() || autoId(modelSel.value), model: modelSel.value.trim(), port: parseInt(portIn.value) || 8090, threads: parseInt(threadsIn.value) || 0, gpu: gpuIn.checked, o1: o1In.value }) };
idIn, modelSel, portIn, checkBtn, threadsIn, h("label", { class: "flex", style: "gap:4px" }, gpuIn, "GPU"), o1In, tempIn, topPIn, maxTokIn, removeBtn, st);
const entry = { node: row, read: () => {
const v = { id: idIn.value.trim() || autoId(modelSel.value), model: modelSel.value.trim(), port: parseInt(portIn.value) || 8090, threads: parseInt(threadsIn.value) || 0, gpu: gpuIn.checked, o1: o1In.value };
if (tempIn.value !== "") v.temperature = parseFloat(tempIn.value);
if (topPIn.value !== "") v.top_p = parseFloat(topPIn.value);
if (maxTokIn.value !== "") v.max_tokens = parseInt(maxTokIn.value);
return v;
} };
removeBtn.addEventListener("click", () => { const i = serverRows.indexOf(entry); if (i >= 0) serverRows.splice(i, 1); row.remove(); });
serverRows.push(entry);
serversWrap.appendChild(row);