mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-08-05 02:45:28 +00:00
Merge 2376bb7ce2 into 20e7fc0164
This commit is contained in:
commit
14cb453697
3 changed files with 121 additions and 7 deletions
|
|
@ -1067,6 +1067,36 @@ export function _persistEnvState() {
|
|||
// ── Dependencies ──
|
||||
|
||||
// Category colors removed — using theme CSS classes instead
|
||||
const _pendingDepInstalls = new Set();
|
||||
const _ACTIVE_DEP_STATUSES = new Set(['queued', 'running']);
|
||||
|
||||
function _depHostKey(host) {
|
||||
const h = String(host || '').trim();
|
||||
return (!h || h === 'local' || h === 'localhost' || h === '127.0.0.1') ? 'local' : h;
|
||||
}
|
||||
|
||||
function _depInstallKey(pipName, host = '', port = '', envPath = '') {
|
||||
return [
|
||||
String(pipName || '').trim(),
|
||||
_depHostKey(host),
|
||||
String(port || '').trim(),
|
||||
String(envPath || '').trim(),
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function _taskDepInstallKey(task) {
|
||||
if (!task?.payload?._dep || !task.payload.repo_id) return '';
|
||||
return _depInstallKey(
|
||||
task.payload.repo_id,
|
||||
task.remoteHost || task.payload.remote_host || '',
|
||||
task.sshPort || task.payload.ssh_port || '',
|
||||
task.payload.env_path || task.payload._envPath || ''
|
||||
);
|
||||
}
|
||||
|
||||
function _isActiveDepTask(task) {
|
||||
return !!task?.payload?._dep && _ACTIVE_DEP_STATUSES.has(task.status || '');
|
||||
}
|
||||
|
||||
async function _fetchDependencies() {
|
||||
const list = document.getElementById('cookbook-deps-list');
|
||||
|
|
@ -1128,9 +1158,31 @@ async function _fetchDependencies() {
|
|||
if (!pkgs.length) { list.innerHTML = '<div class="hwfit-loading">No packages found</div>'; return; }
|
||||
const _winUnsupported = new Set(['hf_transfer', 'vllm', 'rembg', 'gfpgan']);
|
||||
const _systemInstallable = new Set(['tmux']);
|
||||
const _activeDepTasks = new Map();
|
||||
_loadTasks().forEach(task => {
|
||||
if (!_isActiveDepTask(task)) return;
|
||||
const key = _taskDepInstallKey(task);
|
||||
if (key && !_activeDepTasks.has(key)) _activeDepTasks.set(key, task);
|
||||
});
|
||||
_pendingDepInstalls.forEach(key => {
|
||||
if (key && !_activeDepTasks.has(key)) _activeDepTasks.set(key, { _pending: true });
|
||||
});
|
||||
|
||||
const _statusTag = (pkg, isLocal, isSystemDep, winBlocked) => {
|
||||
const _depTarget = (isLocal) => isLocal
|
||||
? { host: '', port: '', envPath: '' }
|
||||
: { host: _depHost, port: _depPort, envPath: _depVenv };
|
||||
const _activeDepFor = (pkg, isLocal) => {
|
||||
if (!pkg?.pip) return null;
|
||||
const target = _depTarget(isLocal);
|
||||
return _activeDepTasks.get(_depInstallKey(pkg.pip, target.host, target.port, target.envPath)) || null;
|
||||
};
|
||||
|
||||
const _statusTag = (pkg, isLocal, isSystemDep, winBlocked, activeDep) => {
|
||||
if (winBlocked) return `<span class="cookbook-dep-tag cookbook-dep-na">N/A</span>`;
|
||||
if (activeDep) {
|
||||
const session = activeDep.sessionId ? ` (${activeDep.sessionId})` : '';
|
||||
return `<span class="cookbook-dep-tag cookbook-dep-downloading" title="Dependency install is already running${esc(session)}">downloading</span>`;
|
||||
}
|
||||
if (pkg.installed && isSystemDep) return `<span class="cookbook-dep-tag cookbook-dep-installed" title="Found on selected server">Installed</span>`;
|
||||
if (pkg.installed && pkg.pip_update_available === false && pkg.name !== 'llama_cpp') {
|
||||
const tip = esc(pkg.update_note || pkg.status_note || 'Found externally; update outside Odysseus.');
|
||||
|
|
@ -1174,6 +1226,7 @@ async function _fetchDependencies() {
|
|||
const isLocal = pkg.target === 'local';
|
||||
const isSystemDep = pkg.kind === 'system';
|
||||
const winBlocked = !isLocal && _isWindows() && _winUnsupported.has(pkg.name);
|
||||
const activeDep = _activeDepFor(pkg, isLocal);
|
||||
const note = pkg.status_note ? `<div class="memory-item-meta" style="font-size:10px;opacity:0.65;margin-top:3px;">${esc(pkg.status_note)}</div>` : '';
|
||||
const updateNote = pkg.installed && pkg.pip_update_available === false && pkg.update_note ? `<div class="memory-item-meta" style="font-size:10px;opacity:0.55;margin-top:3px;">${esc(pkg.update_note)}</div>` : '';
|
||||
// Inline rebuild/reinstall tag. Styled as a .cookbook-dep-tag so it
|
||||
|
|
@ -1183,7 +1236,11 @@ async function _fetchDependencies() {
|
|||
// diagnosis-style `_launchServeTask` with `pip install --force-reinstall`
|
||||
// so the user can watch the pip install in the Running tab.
|
||||
let _rebuildBtn = '';
|
||||
if (pkg.name === 'vllm' && pkg.installed) {
|
||||
if (activeDep) {
|
||||
_rebuildBtn = '';
|
||||
} else if (pkg.name === 'llama_cpp') {
|
||||
_rebuildBtn = `<button type="button" class="cookbook-dep-tag cookbook-dep-rebuild" id="cookbook-rebuild-engine" title="Clear the cached llama.cpp build so the next serve recompiles from source (use after installing a CUDA/ROCm toolkit to turn a CPU-only build into a GPU build).">Rebuild</button>`;
|
||||
} else if (pkg.name === 'vllm' && pkg.installed) {
|
||||
_rebuildBtn = `<button type="button" class="cookbook-dep-tag cookbook-dep-rebuild cookbook-dep-reinstall" data-reinstall-pkg="vllm" title="Force-reinstall vLLM (pulls a matching torch). Runs as a tmux task in the Running tab.">Reinstall</button>`;
|
||||
} else if (pkg.name === 'sglang' && pkg.installed) {
|
||||
_rebuildBtn = `<button type="button" class="cookbook-dep-tag cookbook-dep-rebuild cookbook-dep-reinstall" data-reinstall-pkg="sglang" title="Force-reinstall SGLang (pulls a matching torch). Runs as a tmux task in the Running tab.">Reinstall</button>`;
|
||||
|
|
@ -1229,7 +1286,7 @@ async function _fetchDependencies() {
|
|||
+ _rebuildBtn
|
||||
+ _buildDepsBtn
|
||||
+ `<span class="cookbook-dep-tag cookbook-dep-cat">${esc(pkg.category)}</span>`
|
||||
+ _statusTag(pkg, isLocal, isSystemDep, winBlocked)
|
||||
+ _statusTag(pkg, isLocal, isSystemDep, winBlocked, activeDep)
|
||||
+ recipeCaret
|
||||
+ `</div>`
|
||||
+ recipePanel;
|
||||
|
|
@ -1417,6 +1474,28 @@ async function _fetchDependencies() {
|
|||
}
|
||||
const targetPlatform = isLocalOnly ? (_envState.hostPlatform || _envState.platform || '') : (targetServer?.platform || _envState.platform || '');
|
||||
const targetRemoteHost = isLocalOnly ? '' : (targetServer?.host || _envState.remoteHost || '');
|
||||
const activeKey = _depInstallKey(
|
||||
pipName,
|
||||
targetRemoteHost || '',
|
||||
isLocalOnly ? '' : (_getPort(targetRemoteHost) || ''),
|
||||
targetEnvPath || ''
|
||||
);
|
||||
if (_pendingDepInstalls.has(activeKey) || _loadTasks().some(task => _isActiveDepTask(task) && _taskDepInstallKey(task) === activeKey)) {
|
||||
uiModule.showToast(`${pkgName} is already downloading on ${targetHost}.`);
|
||||
if (statusEl) {
|
||||
statusEl.textContent = 'downloading';
|
||||
statusEl.disabled = true;
|
||||
statusEl.classList.add('cookbook-dep-downloading');
|
||||
}
|
||||
return;
|
||||
}
|
||||
_pendingDepInstalls.add(activeKey);
|
||||
if (statusEl) {
|
||||
statusEl.textContent = 'downloading';
|
||||
statusEl.disabled = true;
|
||||
statusEl.classList.add('cookbook-dep-downloading');
|
||||
statusEl.title = `${pkgName} is already downloading`;
|
||||
}
|
||||
// Always go through `python -m pip` so the leading token is `python`
|
||||
// — matches the /api/model/serve allow-list (bare `pip` is blocked).
|
||||
// Inside a venv/conda env, `--user` is invalid (pip refuses), so we
|
||||
|
|
@ -1488,13 +1567,20 @@ async function _fetchDependencies() {
|
|||
action: 'OK',
|
||||
onAction: () => {},
|
||||
});
|
||||
_pendingDepInstalls.delete(activeKey);
|
||||
if (statusEl) {
|
||||
statusEl.textContent = upgrade ? 'Update' : 'Install';
|
||||
statusEl.disabled = false;
|
||||
statusEl.classList.remove('cookbook-dep-downloading');
|
||||
statusEl.title = '';
|
||||
}
|
||||
return;
|
||||
}
|
||||
// _dep flags this as a pip dependency/driver install (not a servable
|
||||
// model) so the running-task card doesn't offer a "Serve →" button.
|
||||
const payload = { repo_id: depTaskId, _cmd: cmd, remote_host: targetRemoteHost || '', _dep: true, env_path: targetEnvPath || '', platform: targetPlatform || '' };
|
||||
const payload = { repo_id: depTaskId, _cmd: cmd, remote_host: targetRemoteHost || '', ssh_port: isLocalOnly ? '' : (_getPort(targetRemoteHost) || ''), _dep: true, _dep_action: upgrade ? 'update' : 'install', env_path: targetEnvPath || '', platform: targetPlatform || '' };
|
||||
_addTask(data.session_id, 'pip ' + pkgName, 'download', payload);
|
||||
if (statusEl) { statusEl.textContent = upgrade ? 'Updating...' : 'Installing...'; statusEl.disabled = true; }
|
||||
_pendingDepInstalls.delete(activeKey);
|
||||
uiModule.showToast(`${upgrade ? 'Updating' : 'Installing'} ${pkgName} on ${targetHost}...`);
|
||||
} catch (err) {
|
||||
uiModule.showToast('Install failed: ' + err.message, {
|
||||
|
|
@ -1502,6 +1588,13 @@ async function _fetchDependencies() {
|
|||
action: 'OK',
|
||||
onAction: () => {},
|
||||
});
|
||||
_pendingDepInstalls.delete(activeKey);
|
||||
if (statusEl) {
|
||||
statusEl.textContent = upgrade ? 'Update' : 'Install';
|
||||
statusEl.disabled = false;
|
||||
statusEl.classList.remove('cookbook-dep-downloading');
|
||||
statusEl.title = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -969,6 +969,9 @@ function _updateTask(sessionId, updates) {
|
|||
if (uptime) uptime.style.display = 'none';
|
||||
}
|
||||
}
|
||||
if (task?.type === 'download' && task.payload?._dep && updates.status && !['queued', 'running'].includes(task.status || '')) {
|
||||
_refreshDepsAfterInstall(task);
|
||||
}
|
||||
}
|
||||
|
||||
function _refreshDepsAfterInstall(task) {
|
||||
|
|
@ -980,8 +983,10 @@ function _refreshDepsAfterInstall(task) {
|
|||
|
||||
export function _removeTask(sessionId) {
|
||||
_tombstoneTask(sessionId); // so sync/poll can't resurrect it
|
||||
const tasks = _loadTasks().filter(t => t.sessionId !== sessionId);
|
||||
_saveTasks(tasks);
|
||||
const tasks = _loadTasks();
|
||||
const task = tasks.find(t => t.sessionId === sessionId);
|
||||
_saveTasks(tasks.filter(t => t.sessionId !== sessionId));
|
||||
_refreshDepsAfterInstall(task);
|
||||
_renderRunningTab();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20632,6 +20632,14 @@ body.gallery-selecting .gallery-dl-btn,
|
|||
padding: 0 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.cookbook-dep-downloading {
|
||||
background: color-mix(in srgb, var(--orange, #ffb86c) 18%, transparent);
|
||||
color: var(--orange, #ffb86c);
|
||||
border: 1px solid color-mix(in srgb, var(--orange, #ffb86c) 35%, transparent);
|
||||
min-width: 75.85px;
|
||||
padding: 0 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.cookbook-dep-na {
|
||||
background: color-mix(in srgb, var(--fg) 8%, transparent);
|
||||
color: color-mix(in srgb, var(--fg) 60%, transparent);
|
||||
|
|
@ -20660,6 +20668,13 @@ body.gallery-selecting .gallery-dl-btn,
|
|||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
}
|
||||
.cookbook-dep-install.cookbook-dep-downloading {
|
||||
background: color-mix(in srgb, var(--orange, #ffb86c) 18%, transparent);
|
||||
color: var(--orange, #ffb86c);
|
||||
border: 1px solid color-mix(in srgb, var(--orange, #ffb86c) 35%, transparent);
|
||||
cursor: default;
|
||||
opacity: 1;
|
||||
}
|
||||
/* Conditional line under the Download h2: only when the section is folded
|
||||
(collapsed). When expanded, the body content provides separation; the
|
||||
underline reads as clutter. */
|
||||
|
|
@ -20693,6 +20708,7 @@ body.gallery-selecting .gallery-dl-btn,
|
|||
padding-left: 0.5px;
|
||||
}
|
||||
.cookbook-dep-install:hover { opacity: 0.85; }
|
||||
.cookbook-dep-install.cookbook-dep-downloading:hover { opacity: 1; }
|
||||
/* Installed split button: "Installed" label + separator + ▾ caret; clicking it
|
||||
opens the actions menu (Update). Replaces the old ⋮ button. */
|
||||
.cookbook-dep-installed-btn {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue