mirror of
https://github.com/ggml-org/llama.cpp.git
synced 2026-09-17 20:31:47 +02:00
ui : list models from a backend
Assisted-by: pi:llama.cpp/DeepSeek-V4.1-Flash
This commit is contained in:
@@ -1,15 +1,24 @@
|
||||
/**
|
||||
* BackendsService - Stateless backend connectivity checks
|
||||
* BackendsService - Stateless backend connectivity checks and model listing
|
||||
*
|
||||
* Probes a backend's models endpoint to validate its URL and credentials.
|
||||
* No reactive state; consumed by the backends settings UI.
|
||||
* Probes a backend's models endpoint to validate its URL and credentials, and
|
||||
* normalizes the response into the UI model shape. No reactive state;
|
||||
* consumed by the backends settings UI and the per-backend model cache.
|
||||
*/
|
||||
|
||||
import type { Backend } from '$lib/types';
|
||||
import type { Backend, ModelOption } from '$lib/types';
|
||||
import { isAbortError } from '$lib/utils/abort';
|
||||
import { getAuthHeadersForBackend } from '$lib/utils/api-headers';
|
||||
import { backendModelsUrl } from '$lib/utils/backend';
|
||||
|
||||
/** Models returned by a backend, plus the failure detail when the call fails. */
|
||||
export interface BackendModelsResult {
|
||||
error?: string;
|
||||
models: ModelOption[];
|
||||
ok: boolean;
|
||||
status: number | null;
|
||||
}
|
||||
|
||||
/** Outcome of a backend connectivity check. */
|
||||
export interface BackendTestResult {
|
||||
error?: string;
|
||||
@@ -20,14 +29,14 @@ export interface BackendTestResult {
|
||||
|
||||
export class BackendsService {
|
||||
/**
|
||||
* Check that a backend answers on its models endpoint.
|
||||
* List the models a backend exposes on its models endpoint.
|
||||
*
|
||||
* @param backend - Backend to probe. Does not need to be registered yet.
|
||||
* @param signal - Optional abort signal for a cancelled test.
|
||||
* @param backend - Backend to query. Does not need to be registered yet.
|
||||
* @param signal - Optional abort signal for a cancelled request.
|
||||
*/
|
||||
static async test(backend: Backend, signal?: AbortSignal): Promise<BackendTestResult> {
|
||||
static async listModels(backend: Backend, signal?: AbortSignal): Promise<BackendModelsResult> {
|
||||
if (!backend.baseUrl.trim()) {
|
||||
return { error: 'Backend URL is required', ok: false, status: null };
|
||||
return { error: 'Backend URL is required', models: [], ok: false, status: null };
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -37,25 +46,49 @@ export class BackendsService {
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
return { error: await describeFailure(response), ok: false, status: response.status };
|
||||
return {
|
||||
error: await describeFailure(response),
|
||||
models: [],
|
||||
ok: false,
|
||||
status: response.status
|
||||
};
|
||||
}
|
||||
|
||||
const body = (await response.json()) as { data?: unknown };
|
||||
const modelCount = Array.isArray(body?.data) ? body.data.length : 0;
|
||||
const entries = Array.isArray(body?.data) ? body.data : [];
|
||||
const models = entries.flatMap((entry) => normalizeBackendModel(entry));
|
||||
|
||||
return { modelCount, ok: true, status: response.status };
|
||||
return { models, ok: true, status: response.status };
|
||||
} catch (error) {
|
||||
if (isAbortError(error)) {
|
||||
return { ok: false, status: null };
|
||||
return { models: [], ok: false, status: null };
|
||||
}
|
||||
|
||||
return {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
models: [],
|
||||
ok: false,
|
||||
status: null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that a backend answers on its models endpoint.
|
||||
*
|
||||
* @param backend - Backend to probe. Does not need to be registered yet.
|
||||
* @param signal - Optional abort signal for a cancelled test.
|
||||
*/
|
||||
static async test(backend: Backend, signal?: AbortSignal): Promise<BackendTestResult> {
|
||||
const result = await BackendsService.listModels(backend, signal);
|
||||
|
||||
return {
|
||||
error: result.error,
|
||||
modelCount: result.models.length,
|
||||
ok: result.ok,
|
||||
status: result.status
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/** Build a human-readable message from a non-OK response. */
|
||||
@@ -73,3 +106,18 @@ async function describeFailure(response: Response): Promise<string> {
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize one entry of an OpenAI-compatible `/v1/models` response. External
|
||||
* backends only guarantee an id, so that doubles as the display name.
|
||||
*/
|
||||
function normalizeBackendModel(entry: unknown): ModelOption[] {
|
||||
if (!entry || typeof entry !== 'object') return [];
|
||||
|
||||
const raw = entry as Record<string, unknown>;
|
||||
const id = typeof raw.id === 'string' ? raw.id.trim() : '';
|
||||
|
||||
if (!id) return [];
|
||||
|
||||
return [{ capabilities: [], id, model: id, name: id }];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user