@lobehub/chat
Version:
Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.
96 lines (81 loc) • 3.02 kB
text/typescript
import { ChatStreamPayload, ModelProvider } from '../types';
import { processMultiProviderModelList } from '../utils/modelParse';
import { createOpenAICompatibleRuntime } from '../utils/openaiCompatibleFactory';
import { pruneReasoningPayload } from '../utils/openaiHelpers';
import { responsesAPIModels } from '@/const/models';
export interface OpenAIModelCard {
id: string;
}
const prunePrefixes = ['o1', 'o3', 'o4', 'codex', 'computer-use'];
const oaiSearchContextSize = process.env.OPENAI_SEARCH_CONTEXT_SIZE; // low, medium, high
export const LobeOpenAI = createOpenAICompatibleRuntime({
baseURL: 'https://api.openai.com/v1',
chatCompletion: {
handlePayload: (payload) => {
const { enabledSearch, model, ...rest } = payload;
if (responsesAPIModels.has(model) || enabledSearch) {
return { ...rest, apiMode: 'responses', enabledSearch, model } as ChatStreamPayload;
}
if (prunePrefixes.some((prefix) => model.startsWith(prefix))) {
return pruneReasoningPayload(payload) as any;
}
if (model.includes('-search-')) {
return {
...rest,
frequency_penalty: undefined,
model,
presence_penalty: undefined,
stream: payload.stream ?? true,
temperature: undefined,
top_p: undefined,
...(oaiSearchContextSize && {
web_search_options: {
search_context_size: oaiSearchContextSize,
},
}),
} as any;
}
return { ...rest, model, stream: payload.stream ?? true };
},
},
debug: {
chatCompletion: () => process.env.DEBUG_OPENAI_CHAT_COMPLETION === '1',
responses: () => process.env.DEBUG_OPENAI_RESPONSES === '1',
},
models: async ({ client }) => {
const modelsPage = (await client.models.list()) as any;
const modelList: OpenAIModelCard[] = modelsPage.data;
// 自动检测模型提供商并选择相应配置
return processMultiProviderModelList(modelList);
},
provider: ModelProvider.OpenAI,
responses: {
handlePayload: (payload) => {
const { enabledSearch, model, tools, ...rest } = payload;
const openaiTools = enabledSearch
? [
...(tools || []),
{
type: 'web_search_preview',
...(oaiSearchContextSize && {
search_context_size: oaiSearchContextSize,
}),
},
]
: tools;
if (prunePrefixes.some((prefix) => model.startsWith(prefix))) {
if (!payload.reasoning) {
payload.reasoning = { summary: 'auto' };
} else {
payload.reasoning.summary = 'auto';
}
// computer-use series must set truncation as auto
if (model.startsWith('computer-use')) {
payload.truncation = 'auto';
}
return pruneReasoningPayload(payload) as any;
}
return { ...rest, model, stream: payload.stream ?? true, tools: openaiTools } as any;
},
},
});