ui: improve manual model load and cancel (#847)
- When a model is manually loaded show a cancel buttton and a queued status - Implement cancellation in scheduler.Scheduler interface and FIFO scheduler - Add cache bust query parameter to bypass browser cache Fixes #844
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
|
||||
let isUnloading = $state(false);
|
||||
let menuOpen = $state(false);
|
||||
let pendingLoads = $state<Record<string, boolean>>({});
|
||||
const loadControllers = new Map<string, AbortController>();
|
||||
|
||||
const showUnlistedStore = persistentStore<boolean>("showUnlisted", true);
|
||||
const showIdorNameStore = persistentStore<"id" | "name">("showIdorName", "id");
|
||||
@@ -42,6 +44,25 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function handleLoadModel(modelId: string): Promise<void> {
|
||||
if (pendingLoads[modelId]) return;
|
||||
const controller = new AbortController();
|
||||
loadControllers.set(modelId, controller);
|
||||
pendingLoads[modelId] = true;
|
||||
try {
|
||||
await loadModel(modelId, controller.signal);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
loadControllers.delete(modelId);
|
||||
delete pendingLoads[modelId];
|
||||
}
|
||||
}
|
||||
|
||||
function cancelLoad(modelId: string): void {
|
||||
loadControllers.get(modelId)?.abort();
|
||||
}
|
||||
|
||||
function toggleIdorName(): void {
|
||||
showIdorNameStore.update((prev) => (prev === "name" ? "id" : "name"));
|
||||
}
|
||||
@@ -170,14 +191,20 @@
|
||||
{/if}
|
||||
</td>
|
||||
<td class="w-12">
|
||||
{#if model.state === "stopped"}
|
||||
<button class="btn btn--sm" onclick={() => loadModel(model.id)}>Load</button>
|
||||
{#if model.state === "stopped" && pendingLoads[model.id]}
|
||||
<button class="btn btn--sm" onclick={() => cancelLoad(model.id)}>Cancel</button>
|
||||
{:else if model.state === "stopped"}
|
||||
<button class="btn btn--sm" onclick={() => handleLoadModel(model.id)}>Load</button>
|
||||
{:else}
|
||||
<button class="btn btn--sm" onclick={() => unloadSingleModel(model.id)} disabled={model.state !== "ready"}>Unload</button>
|
||||
{/if}
|
||||
</td>
|
||||
<td class="w-20">
|
||||
<span class="w-16 text-center status status--{model.state}">{model.state}</span>
|
||||
{#if model.state === "stopped" && pendingLoads[model.id]}
|
||||
<span class="w-16 text-center status status--queued">queued</span>
|
||||
{:else}
|
||||
<span class="w-16 text-center status status--{model.state}">{model.state}</span>
|
||||
{/if}
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
|
||||
@@ -139,7 +139,8 @@
|
||||
}
|
||||
|
||||
.status--starting,
|
||||
.status--stopping {
|
||||
.status--stopping,
|
||||
.status--queued {
|
||||
@apply bg-warning/10 text-warning;
|
||||
}
|
||||
|
||||
|
||||
@@ -176,15 +176,19 @@ export async function unloadSingleModel(model: string): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadModel(model: string): Promise<void> {
|
||||
export async function loadModel(model: string, signal?: AbortSignal): Promise<void> {
|
||||
try {
|
||||
const response = await fetch(`/upstream/${model}/`, {
|
||||
const response = await fetch(`/upstream/${model}/?_=${Date.now()}`, {
|
||||
method: "GET",
|
||||
signal,
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load model: ${response.status}`);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof DOMException && error.name === "AbortError") {
|
||||
return;
|
||||
}
|
||||
console.error("Failed to load model:", error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user