moved js files in public into js and css into css folder

This commit is contained in:
2026-09-22 21:55:02 +02:00
parent 99a3277e64
commit 08f5f3f8d9
40 changed files with 1772 additions and 1555 deletions
+29 -29
View File
@@ -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" } };
}
};
}