You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

98 lines
2.8 KiB

import { requireUser } from "#server/utils/context";
import { getProviderById, getModelById } from "#server/service/llm";
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { streamText, type LanguageModelV1 } from "ai";
import log4js from "logger";
const logger = log4js.getLogger("APP");
function resolveModel(
provider: {
name: string;
apiKey: string | null;
baseUrl: string | null;
parseMode: string;
},
modelId: string,
): LanguageModelV1 {
const baseUrl = provider.baseUrl?.replace(/\/+$/, "") || undefined;
if (provider.parseMode === "anthropic") {
throw createError({
statusCode: 400,
statusMessage: "Anthropic 解析模式暂不支持流式对话,请使用 OpenAI 兼容模式",
});
}
const openaiCompatible = createOpenAICompatible({
name: provider.name,
apiKey: provider.apiKey || undefined,
baseURL: baseUrl || "https://api.openai.com/v1",
});
return openaiCompatible(modelId) as LanguageModelV1;
}
export default defineEventHandler(async (event) => {
const user = await requireUser(event);
if (!user) {
throw createError({ statusCode: 401, statusMessage: "未登录" });
}
const body = await readBody(event);
const { modelId: llmModelId, messages, enableThinking } = body as {
modelId: number;
messages: { role: "user" | "assistant" | "system"; content: string }[];
enableThinking?: boolean;
};
if (!llmModelId || !messages || !Array.isArray(messages) || messages.length === 0) {
throw createError({ statusCode: 400, statusMessage: "参数无效" });
}
const model = await getModelById(llmModelId, user.id);
if (!model) {
throw createError({ statusCode: 404, statusMessage: "模型不存在" });
}
const provider = await getProviderById(model.providerId, user.id);
if (!provider) {
throw createError({ statusCode: 404, statusMessage: "供应商不存在" });
}
if (provider.status !== "active") {
throw createError({ statusCode: 400, statusMessage: "供应商已禁用" });
}
if (!provider.apiKey) {
throw createError({ statusCode: 400, statusMessage: "供应商未配置 API Key" });
}
logger.info(
"[%s] [LLM-CHAT] userId=%d modelId=%d provider=%s parseMode=%s messages=%d thinking=%s",
event.context.requestId ?? "-",
user.id,
llmModelId,
provider.name,
provider.parseMode,
messages.length,
enableThinking ? "on" : "off",
);
const languageModel = resolveModel(provider, model.modelId);
const result = streamText({
model: languageModel,
messages,
maxTokens: model.maxTokens || undefined,
...(enableThinking
? {
providerOptions: {
openaiCompatible: { reasoningEffort: "high" },
},
}
: {}),
});
return result.toDataStreamResponse({ sendReasoning: true });
});