add vision analysis service with prompt versioning, response schema, and structured JSON output
This commit is contained in:
@@ -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, onRawReply = null) => {
|
||||
if (!response.body) {
|
||||
throw new ModelServiceError("MODEL_BAD_RESPONSE", "Model backend returned no body.", 502);
|
||||
}
|
||||
@@ -161,6 +161,7 @@ export function createModelService(config, overrides = {}) {
|
||||
consume(buffer.trim());
|
||||
}
|
||||
if (!completed) throw new ModelServiceError("MODEL_INTERRUPTED", "Model response was interrupted.", 502);
|
||||
onRawReply?.(fullReply);
|
||||
return fullReply.trim();
|
||||
} finally {
|
||||
signal?.removeEventListener("abort", cancel);
|
||||
@@ -187,6 +188,18 @@ export function createModelService(config, overrides = {}) {
|
||||
};
|
||||
|
||||
return {
|
||||
getRequestMetadata(model, generation = {}, reasoning = false) {
|
||||
const body = buildRequestBody(model, [], generation, reasoning);
|
||||
return {
|
||||
model: body.model,
|
||||
think: body.think,
|
||||
stream: body.stream,
|
||||
temperature: body.options?.temperature ?? null,
|
||||
numCtx: body.options?.num_ctx ?? null,
|
||||
numPredict: body.options?.num_predict ?? null,
|
||||
keepAlive: body.keep_alive
|
||||
};
|
||||
},
|
||||
async generateReply(model, messagesPayload, options = {}) {
|
||||
const state = ensureModelState(model);
|
||||
state.activeRequests += 1;
|
||||
@@ -206,7 +219,8 @@ export function createModelService(config, overrides = {}) {
|
||||
}
|
||||
|
||||
touch();
|
||||
return readStreamingReply(response, null, options.reasoning === true && supportsReasoning(model) ? options.onThinking : null, touch, signal);
|
||||
return readStreamingReply(response, null, options.reasoning === true && supportsReasoning(model) ? options.onThinking : null,
|
||||
touch, signal, options.onRawReply);
|
||||
}, options.signal);
|
||||
lastHealth = { ok: true, checkedAt: new Date().toISOString(), error: null, latencyMs: Date.now() - startedAt };
|
||||
return fullReply;
|
||||
|
||||
Reference in New Issue
Block a user