moved js files in public into js and css into css folder
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import {supportsReasoning} from "../../public/app/modelCapabilities.js";
|
||||
import {AttachmentError} from "./attachmentService.js";
|
||||
import { supportsReasoning } from "../../public/js/modelCapabilities.js";
|
||||
import { AttachmentError } from "./attachmentService.js";
|
||||
|
||||
class ModelServiceError extends Error {
|
||||
constructor(code, message, status = 500) {
|
||||
@@ -25,14 +25,14 @@ export function createModelService(config, overrides = {}) {
|
||||
const modelState = new Map();
|
||||
let modelsCache = null;
|
||||
let modelsCacheAt = 0;
|
||||
let lastHealth = {ok: true, checkedAt: null, error: null, latencyMs: null};
|
||||
let lastHealth = { ok: true, checkedAt: null, error: null, latencyMs: null };
|
||||
let lastFailure = null;
|
||||
let lastListLatencyMs = null;
|
||||
const fetchImpl = overrides.fetch || global.fetch;
|
||||
|
||||
const ensureModelState = (model) => {
|
||||
if (!modelState.has(model)) {
|
||||
modelState.set(model, {activeRequests: 0, timer: null});
|
||||
modelState.set(model, { activeRequests: 0, timer: null });
|
||||
}
|
||||
return modelState.get(model);
|
||||
};
|
||||
@@ -53,7 +53,7 @@ export function createModelService(config, overrides = {}) {
|
||||
let timedOut = false;
|
||||
const abortFromCaller = () => controller.abort(externalSignal?.reason);
|
||||
if (externalSignal?.aborted) abortFromCaller();
|
||||
else externalSignal?.addEventListener("abort", abortFromCaller, {once: true});
|
||||
else externalSignal?.addEventListener("abort", abortFromCaller, { once: true });
|
||||
const timer = setTimeout(() => {
|
||||
timedOut = true;
|
||||
controller.abort();
|
||||
@@ -85,7 +85,7 @@ export function createModelService(config, overrides = {}) {
|
||||
};
|
||||
const abort = () => controller.abort();
|
||||
if (externalSignal?.aborted) abort();
|
||||
else externalSignal?.addEventListener("abort", abort, {once: true});
|
||||
else externalSignal?.addEventListener("abort", abort, { once: true });
|
||||
touch(config.modelConnectTimeoutMs ?? 30000);
|
||||
const maxTimer = setTimeout(expire, config.modelMaxGenerationMs ?? 600000);
|
||||
try {
|
||||
@@ -104,7 +104,7 @@ export function createModelService(config, overrides = {}) {
|
||||
}
|
||||
};
|
||||
|
||||
const readStreamingReply = async (response, onChunk = null, onThinking = null, touch = () => {}, signal = null) => {
|
||||
const readStreamingReply = async (response, onChunk = null, onThinking = null, touch = () => { }, signal = null) => {
|
||||
if (!response.body) {
|
||||
throw new ModelServiceError("MODEL_BAD_RESPONSE", "Model backend returned no body.", 502);
|
||||
}
|
||||
@@ -136,16 +136,16 @@ export function createModelService(config, overrides = {}) {
|
||||
if (data.done === true) completed = true;
|
||||
};
|
||||
|
||||
const cancel = () => { void reader.cancel().catch(() => {}); };
|
||||
signal?.addEventListener("abort", cancel, {once: true});
|
||||
const cancel = () => { void reader.cancel().catch(() => { }); };
|
||||
signal?.addEventListener("abort", cancel, { once: true });
|
||||
try {
|
||||
while (!completed) {
|
||||
signal?.throwIfAborted();
|
||||
const {value, done} = await reader.read();
|
||||
const { value, done } = await reader.read();
|
||||
signal?.throwIfAborted();
|
||||
if (done) break;
|
||||
touch();
|
||||
buffer += decoder.decode(value, {stream: true});
|
||||
buffer += decoder.decode(value, { stream: true });
|
||||
const lines = buffer.split("\n");
|
||||
buffer = lines.pop() || "";
|
||||
for (const line of lines) {
|
||||
@@ -164,7 +164,7 @@ export function createModelService(config, overrides = {}) {
|
||||
return fullReply.trim();
|
||||
} finally {
|
||||
signal?.removeEventListener("abort", cancel);
|
||||
await reader.cancel().catch(() => {});
|
||||
await reader.cancel().catch(() => { });
|
||||
reader.releaseLock();
|
||||
}
|
||||
};
|
||||
@@ -182,7 +182,7 @@ export function createModelService(config, overrides = {}) {
|
||||
stream: true,
|
||||
think: reasoning === true && supportsReasoning(model),
|
||||
keep_alive: config.ollamaKeepAlive ?? "30m",
|
||||
...(Object.keys(options).length ? {options} : {})
|
||||
...(Object.keys(options).length ? { options } : {})
|
||||
};
|
||||
};
|
||||
|
||||
@@ -196,8 +196,8 @@ export function createModelService(config, overrides = {}) {
|
||||
const fullReply = await withGenerationTimeout(async (signal, touch) => {
|
||||
const response = await fetchImpl(`${config.modelApiBaseUrl}/chat`, {
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/json"},
|
||||
body: JSON.stringify({...buildRequestBody(model, messagesPayload, options.generation, options.reasoning), ...(options.format ? {format: options.format} : {})}),
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ ...buildRequestBody(model, messagesPayload, options.generation, options.reasoning), ...(options.format ? { format: options.format } : {}) }),
|
||||
signal
|
||||
});
|
||||
|
||||
@@ -208,7 +208,7 @@ export function createModelService(config, overrides = {}) {
|
||||
touch();
|
||||
return readStreamingReply(response, null, options.reasoning === true && supportsReasoning(model) ? options.onThinking : null, touch, signal);
|
||||
}, options.signal);
|
||||
lastHealth = {ok: true, checkedAt: new Date().toISOString(), error: null, latencyMs: Date.now() - startedAt};
|
||||
lastHealth = { ok: true, checkedAt: new Date().toISOString(), error: null, latencyMs: Date.now() - startedAt };
|
||||
return fullReply;
|
||||
} catch (error) {
|
||||
const failure = error instanceof ModelServiceError ? error.message : "Model backend unavailable.";
|
||||
@@ -218,7 +218,7 @@ export function createModelService(config, overrides = {}) {
|
||||
error: failure,
|
||||
latencyMs: null
|
||||
};
|
||||
lastFailure = {at: lastHealth.checkedAt, error: failure};
|
||||
lastFailure = { at: lastHealth.checkedAt, error: failure };
|
||||
if (error instanceof ModelServiceError) throw error;
|
||||
throw new ModelServiceError("MODEL_UNAVAILABLE", "Model backend unavailable.", 502);
|
||||
} finally {
|
||||
@@ -235,7 +235,7 @@ export function createModelService(config, overrides = {}) {
|
||||
const fullReply = await withGenerationTimeout(async (signal, touch) => {
|
||||
const response = await fetchImpl(`${config.modelApiBaseUrl}/chat`, {
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/json"},
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(buildRequestBody(model, messagesPayload, options.generation, options.reasoning)),
|
||||
signal
|
||||
});
|
||||
@@ -247,7 +247,7 @@ export function createModelService(config, overrides = {}) {
|
||||
touch();
|
||||
return readStreamingReply(response, onChunk, options.reasoning === true && supportsReasoning(model) ? options.onThinking : null, touch, signal);
|
||||
}, options.signal);
|
||||
lastHealth = {ok: true, checkedAt: new Date().toISOString(), error: null, latencyMs: Date.now() - startedAt};
|
||||
lastHealth = { ok: true, checkedAt: new Date().toISOString(), error: null, latencyMs: Date.now() - startedAt };
|
||||
return fullReply;
|
||||
} catch (error) {
|
||||
const failure = error instanceof ModelServiceError ? error.message : "Model backend unavailable.";
|
||||
@@ -257,7 +257,7 @@ export function createModelService(config, overrides = {}) {
|
||||
error: failure,
|
||||
latencyMs: null
|
||||
};
|
||||
lastFailure = {at: lastHealth.checkedAt, error: failure};
|
||||
lastFailure = { at: lastHealth.checkedAt, error: failure };
|
||||
if (error instanceof ModelServiceError) throw error;
|
||||
throw new ModelServiceError("MODEL_UNAVAILABLE", "Model backend unavailable.", 502);
|
||||
} finally {
|
||||
@@ -273,7 +273,7 @@ export function createModelService(config, overrides = {}) {
|
||||
try {
|
||||
const startedAt = Date.now();
|
||||
modelsCache = await withTimeout(config.modelListTimeoutMs, async (signal) => {
|
||||
const response = await fetchImpl(`${config.modelApiBaseUrl}/tags`, {signal});
|
||||
const response = await fetchImpl(`${config.modelApiBaseUrl}/tags`, { signal });
|
||||
if (!response.ok) {
|
||||
throw new ModelServiceError("MODEL_LIST_FAILED", "Failed to load models.", 502);
|
||||
}
|
||||
@@ -281,7 +281,7 @@ export function createModelService(config, overrides = {}) {
|
||||
});
|
||||
lastListLatencyMs = Date.now() - startedAt;
|
||||
modelsCacheAt = Date.now();
|
||||
lastHealth = {ok: true, checkedAt: new Date().toISOString(), error: null, latencyMs: lastListLatencyMs};
|
||||
lastHealth = { ok: true, checkedAt: new Date().toISOString(), error: null, latencyMs: lastListLatencyMs };
|
||||
return modelsCache;
|
||||
} catch (error) {
|
||||
const failure = error instanceof ModelServiceError ? error.message : "Failed to load models.";
|
||||
@@ -291,7 +291,7 @@ export function createModelService(config, overrides = {}) {
|
||||
error: failure,
|
||||
latencyMs: null
|
||||
};
|
||||
lastFailure = {at: lastHealth.checkedAt, error: failure};
|
||||
lastFailure = { at: lastHealth.checkedAt, error: failure };
|
||||
if (error instanceof ModelServiceError) throw error;
|
||||
throw new ModelServiceError("MODEL_UNAVAILABLE", "Failed to load models.", 502);
|
||||
}
|
||||
@@ -300,13 +300,13 @@ export function createModelService(config, overrides = {}) {
|
||||
const startedAt = Date.now();
|
||||
try {
|
||||
await this.listModels();
|
||||
const health = {ok: true, checkedAt: new Date().toISOString(), error: null, latencyMs: Date.now() - startedAt};
|
||||
const health = { ok: true, checkedAt: new Date().toISOString(), error: null, latencyMs: Date.now() - startedAt };
|
||||
lastHealth = health;
|
||||
return health;
|
||||
} catch (error) {
|
||||
const health = {ok: false, checkedAt: new Date().toISOString(), error: error.message, latencyMs: null};
|
||||
const health = { ok: false, checkedAt: new Date().toISOString(), error: error.message, latencyMs: null };
|
||||
lastHealth = health;
|
||||
lastFailure = {at: health.checkedAt, error: error.message};
|
||||
lastFailure = { at: health.checkedAt, error: error.message };
|
||||
return health;
|
||||
}
|
||||
},
|
||||
@@ -333,11 +333,11 @@ export function createModelService(config, overrides = {}) {
|
||||
};
|
||||
},
|
||||
mapError(error) {
|
||||
if (error instanceof AttachmentError) return {status: error.status, body: {error: error.message}};
|
||||
if (error instanceof AttachmentError) return { status: error.status, body: { error: error.message } };
|
||||
if (error instanceof ModelServiceError) {
|
||||
return {status: error.status, body: {error: error.message, code: error.code}};
|
||||
return { status: error.status, body: { error: error.message, code: error.code } };
|
||||
}
|
||||
return {status: 500, body: {error: "Model request failed", code: "MODEL_UNKNOWN"}};
|
||||
return { status: 500, body: { error: "Model request failed", code: "MODEL_UNKNOWN" } };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user