mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-17 02:05:22 -04:00
Cookbook/Dependencies recipes: install into configured venv, drop 'uv venv'
Recipes now hold ONLY the install command(s). The rendered <pre> prepends a 'source <envPath>/bin/activate' line so the user sees a paste-ready sequence; Run uses env_prefix (same path the Install button uses) to activate the configured venv before the install command, so the install lands in the existing environment rather than a fresh .venv in whatever CWD the tmux task happens to start in. - cookbook-deps-recipes.js: trim each recipe to its single pip command - cookbook.js: _recipeDisplayText() prepends the activate context for display; pre's data-dep-recipe-install holds the raw install-only command list so Run knows what to send; Run builds env_prefix the same way _installDep does.
This commit is contained in:
@@ -5,6 +5,11 @@
|
|||||||
// Entries are matched first-hit; put the more specific patterns ABOVE the
|
// Entries are matched first-hit; put the more specific patterns ABOVE the
|
||||||
// generic fallback for that backend.
|
// generic fallback for that backend.
|
||||||
|
|
||||||
|
// Recipes hold ONLY the install command(s). The renderer prepends a
|
||||||
|
// `source <venv>/bin/activate` line for context using the active server's
|
||||||
|
// configured envPath; the Run button reuses env_prefix to activate that
|
||||||
|
// same venv before executing, so the install lands in your existing
|
||||||
|
// environment rather than a fresh `.venv` in some random CWD.
|
||||||
const _RECIPES = [
|
const _RECIPES = [
|
||||||
// ── vllm ──────────────────────────────────────────────────────────────
|
// ── vllm ──────────────────────────────────────────────────────────────
|
||||||
// MiniMax M2/M2.7 — same generic vllm install for now; kept as its own
|
// MiniMax M2/M2.7 — same generic vllm install for now; kept as its own
|
||||||
@@ -15,8 +20,6 @@ const _RECIPES = [
|
|||||||
label: 'MiniMax M2 / M2.7',
|
label: 'MiniMax M2 / M2.7',
|
||||||
match: (m) => /minimax[-_]?m\s?2(\.7)?/i.test(m || ''),
|
match: (m) => /minimax[-_]?m\s?2(\.7)?/i.test(m || ''),
|
||||||
commands: [
|
commands: [
|
||||||
'uv venv',
|
|
||||||
'source .venv/bin/activate',
|
|
||||||
'uv pip install -U vllm --torch-backend auto',
|
'uv pip install -U vllm --torch-backend auto',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -27,8 +30,6 @@ const _RECIPES = [
|
|||||||
label: 'Any vLLM model',
|
label: 'Any vLLM model',
|
||||||
match: () => true,
|
match: () => true,
|
||||||
commands: [
|
commands: [
|
||||||
'uv venv',
|
|
||||||
'source .venv/bin/activate',
|
|
||||||
'uv pip install -U vllm --torch-backend auto',
|
'uv pip install -U vllm --torch-backend auto',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -39,8 +40,6 @@ const _RECIPES = [
|
|||||||
label: 'Any SGLang model',
|
label: 'Any SGLang model',
|
||||||
match: () => true,
|
match: () => true,
|
||||||
commands: [
|
commands: [
|
||||||
'uv venv',
|
|
||||||
'source .venv/bin/activate',
|
|
||||||
'uv pip install -U "sglang[all]" --torch-backend auto',
|
'uv pip install -U "sglang[all]" --torch-backend auto',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -53,8 +52,6 @@ const _RECIPES = [
|
|||||||
label: 'Any GGUF model',
|
label: 'Any GGUF model',
|
||||||
match: () => true,
|
match: () => true,
|
||||||
commands: [
|
commands: [
|
||||||
'uv venv',
|
|
||||||
'source .venv/bin/activate',
|
|
||||||
'CMAKE_ARGS="-DGGML_CUDA=on" uv pip install -U "llama-cpp-python[server]"',
|
'CMAKE_ARGS="-DGGML_CUDA=on" uv pip install -U "llama-cpp-python[server]"',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
+36
-5
@@ -834,6 +834,17 @@ async function _fetchDependencies() {
|
|||||||
+ recipePanel;
|
+ recipePanel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Prepend the configured venv's activate line (when one is set) so the
|
||||||
|
// user sees the full sequence they'd need to paste, while Run keeps
|
||||||
|
// using env_prefix to activate the same venv before the pip command.
|
||||||
|
function _recipeDisplayText(commands) {
|
||||||
|
const envPath = (_envState.envPath || '').replace(/\/+$/, '');
|
||||||
|
const activate = envPath
|
||||||
|
? `source ${envPath}${envPath.endsWith('/bin/activate') ? '' : '/bin/activate'}`
|
||||||
|
: '# (activate your venv first)';
|
||||||
|
return [activate, ...commands].join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
// Per-backend recipe panel (model picker + commands + Copy/Run).
|
// Per-backend recipe panel (model picker + commands + Copy/Run).
|
||||||
// Lives directly below the row it expands and starts collapsed.
|
// Lives directly below the row it expands and starts collapsed.
|
||||||
// The model picker lists every downloaded model from _cachedModelIds
|
// The model picker lists every downloaded model from _cachedModelIds
|
||||||
@@ -858,7 +869,7 @@ async function _fetchDependencies() {
|
|||||||
<span style="font-size:11px;opacity:0.75;flex-shrink:0;">Serving which model?</span>
|
<span style="font-size:11px;opacity:0.75;flex-shrink:0;">Serving which model?</span>
|
||||||
<select class="settings-select cookbook-dep-recipe-pick" data-dep-recipe-pick="${esc(backend)}" style="flex:1;font-size:11px;padding:3px 6px;">${opts}</select>
|
<select class="settings-select cookbook-dep-recipe-pick" data-dep-recipe-pick="${esc(backend)}" style="flex:1;font-size:11px;padding:3px 6px;">${opts}</select>
|
||||||
</div>
|
</div>
|
||||||
<pre class="cookbook-dep-recipe-cmds" data-dep-recipe-cmds="${esc(backend)}" style="margin:0;padding:8px 10px;background:rgba(0,0,0,0.08);border-radius:4px;font-size:11px;line-height:1.5;overflow-x:auto;white-space:pre;">${esc(initial.commands.join('\n'))}</pre>
|
<pre class="cookbook-dep-recipe-cmds" data-dep-recipe-cmds="${esc(backend)}" data-dep-recipe-install="${esc(initial.commands.join('\n'))}" style="margin:0;padding:8px 10px;background:rgba(0,0,0,0.08);border-radius:4px;font-size:11px;line-height:1.5;overflow-x:auto;white-space:pre;">${esc(_recipeDisplayText(initial.commands))}</pre>
|
||||||
<div style="display:flex;gap:6px;justify-content:flex-end;margin-top:6px;">
|
<div style="display:flex;gap:6px;justify-content:flex-end;margin-top:6px;">
|
||||||
<button type="button" class="cookbook-dep-tag cookbook-dep-recipe-copy" data-dep-recipe-copy="${esc(backend)}" style="display:inline-flex;align-items:center;gap:4px;cursor:pointer;"><svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>Copy</button>
|
<button type="button" class="cookbook-dep-tag cookbook-dep-recipe-copy" data-dep-recipe-copy="${esc(backend)}" style="display:inline-flex;align-items:center;gap:4px;cursor:pointer;"><svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>Copy</button>
|
||||||
<button type="button" class="cookbook-dep-tag cookbook-dep-install cookbook-dep-recipe-run" data-dep-recipe-run="${esc(backend)}" style="display:inline-flex;align-items:center;gap:4px;cursor:pointer;"><svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg>Run</button>
|
<button type="button" class="cookbook-dep-tag cookbook-dep-install cookbook-dep-recipe-run" data-dep-recipe-run="${esc(backend)}" style="display:inline-flex;align-items:center;gap:4px;cursor:pointer;"><svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg>Run</button>
|
||||||
@@ -988,13 +999,18 @@ async function _fetchDependencies() {
|
|||||||
});
|
});
|
||||||
// Model select: pickRecipe matches the model id against the catalog
|
// Model select: pickRecipe matches the model id against the catalog
|
||||||
// (e.g. minimax-m2.7 → MiniMax recipe; anything else → generic).
|
// (e.g. minimax-m2.7 → MiniMax recipe; anything else → generic).
|
||||||
|
// Visible text gets the activate-line prefix; the actual install
|
||||||
|
// command stays on data-dep-recipe-install so Run knows what to send.
|
||||||
list.querySelectorAll('[data-dep-recipe-pick]').forEach(sel => {
|
list.querySelectorAll('[data-dep-recipe-pick]').forEach(sel => {
|
||||||
sel.addEventListener('change', () => {
|
sel.addEventListener('change', () => {
|
||||||
const backend = sel.dataset.depRecipePick;
|
const backend = sel.dataset.depRecipePick;
|
||||||
const recipe = pickRecipe(backend, sel.value || '');
|
const recipe = pickRecipe(backend, sel.value || '');
|
||||||
if (!recipe) return;
|
if (!recipe) return;
|
||||||
const pre = list.querySelector(`[data-dep-recipe-cmds="${CSS.escape(backend)}"]`);
|
const pre = list.querySelector(`[data-dep-recipe-cmds="${CSS.escape(backend)}"]`);
|
||||||
if (pre) pre.textContent = recipe.commands.join('\n');
|
if (pre) {
|
||||||
|
pre.textContent = _recipeDisplayText(recipe.commands);
|
||||||
|
pre.dataset.depRecipeInstall = recipe.commands.join('\n');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// Copy: drop the visible command block on the clipboard.
|
// Copy: drop the visible command block on the clipboard.
|
||||||
@@ -1015,23 +1031,38 @@ async function _fetchDependencies() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// Run: launch the joined `cmd1 && cmd2 && …` as a tmux task on the
|
// Run: launch the install command(s) as a tmux task on the currently-
|
||||||
// currently-selected deps server, same plumbing as Install.
|
// selected deps server. Activation comes from env_prefix (same plumbing
|
||||||
|
// the Install button uses) so the install lands in the configured venv
|
||||||
|
// instead of a fresh .venv in some random CWD.
|
||||||
list.querySelectorAll('[data-dep-recipe-run]').forEach(btn => {
|
list.querySelectorAll('[data-dep-recipe-run]').forEach(btn => {
|
||||||
btn.addEventListener('click', async (e) => {
|
btn.addEventListener('click', async (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const backend = btn.dataset.depRecipeRun;
|
const backend = btn.dataset.depRecipeRun;
|
||||||
const pre = list.querySelector(`[data-dep-recipe-cmds="${CSS.escape(backend)}"]`);
|
const pre = list.querySelector(`[data-dep-recipe-cmds="${CSS.escape(backend)}"]`);
|
||||||
if (!pre) return;
|
if (!pre) return;
|
||||||
const cmd = pre.textContent.split('\n').map(s => s.trim()).filter(Boolean).join(' && ');
|
// Use the install-only command list (no activate line) — the
|
||||||
|
// displayed source line is for the user's reading; env_prefix
|
||||||
|
// handles it for the actual run.
|
||||||
|
const installRaw = pre.dataset.depRecipeInstall || pre.textContent;
|
||||||
|
const cmd = installRaw.split('\n').map(s => s.trim()).filter(Boolean).join(' && ');
|
||||||
const depsSel = document.getElementById('hwfit-deps-server');
|
const depsSel = document.getElementById('hwfit-deps-server');
|
||||||
if (depsSel) _applyServerSelection(depsSel.value);
|
if (depsSel) _applyServerSelection(depsSel.value);
|
||||||
const targetHost = _envState.remoteHost || 'local';
|
const targetHost = _envState.remoteHost || 'local';
|
||||||
|
// Build env_prefix from the configured envPath (matches _installDep).
|
||||||
|
let envPrefix = '';
|
||||||
|
if (_envState.env === 'venv' && _envState.envPath) {
|
||||||
|
const p = _envState.envPath;
|
||||||
|
envPrefix = 'source ' + _shellQuote(p.endsWith('/bin/activate') ? p : p + '/bin/activate');
|
||||||
|
} else if (_envState.env === 'conda' && _envState.envPath) {
|
||||||
|
envPrefix = 'eval "$(conda shell.bash hook)" && conda activate ' + _shellQuote(_envState.envPath);
|
||||||
|
}
|
||||||
const reqBody = {
|
const reqBody = {
|
||||||
repo_id: `${backend} setup`,
|
repo_id: `${backend} setup`,
|
||||||
cmd: cmd,
|
cmd: cmd,
|
||||||
remote_host: _envState.remoteHost || undefined,
|
remote_host: _envState.remoteHost || undefined,
|
||||||
ssh_port: _getPort(_envState.remoteHost) || undefined,
|
ssh_port: _getPort(_envState.remoteHost) || undefined,
|
||||||
|
env_prefix: envPrefix || undefined,
|
||||||
platform: _envState.platform || undefined,
|
platform: _envState.platform || undefined,
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user