UNPKG

@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.

129 lines (114 loc) 4.29 kB
import { ModelProvider } from 'model-bank'; import { responsesAPIModels } from '../../const/models'; import { pruneReasoningPayload } from '../../core/contextBuilders/openai'; import { OpenAICompatibleFactoryOptions, createOpenAICompatibleRuntime, } from '../../core/openaiCompatibleFactory'; import { ChatStreamPayload } from '../../types'; import { processMultiProviderModelList } from '../../utils/modelParse'; export interface OpenAIModelCard { id: string; } const prunePrefixes = ['o1', 'o3', 'o4', 'codex', 'computer-use', 'gpt-5']; const oaiSearchContextSize = process.env.OPENAI_SEARCH_CONTEXT_SIZE; // low, medium, high const enableServiceTierFlex = process.env.OPENAI_SERVICE_TIER_FLEX === '1'; const flexSupportedModels = ['gpt-5', 'o3', 'o4-mini']; // Flex 处理仅适用于这些模型 const supportsFlexTier = (model: string) => { // 排除 o3-mini,其不支持 Flex 处理 if (model.startsWith('o3-mini')) { return false; } return flexSupportedModels.some((supportedModel) => model.startsWith(supportedModel)); }; export const params = { 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, ...(enableServiceTierFlex && supportsFlexTier(model) && { service_tier: 'flex' }), ...(oaiSearchContextSize && { web_search_options: { search_context_size: oaiSearchContextSize, }, }), } as any; } return { ...rest, model, ...(enableServiceTierFlex && supportsFlexTier(model) && { service_tier: 'flex' }), 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, 'openai'); }, provider: ModelProvider.OpenAI, responses: { handlePayload: (payload) => { const { enabledSearch, model, tools, verbosity, ...rest } = payload; const openaiTools = enabledSearch ? [ ...(tools || []), { type: 'web_search', ...(oaiSearchContextSize && { search_context_size: oaiSearchContextSize, }), }, ] : tools; if (prunePrefixes.some((prefix) => model.startsWith(prefix))) { const reasoning = payload.reasoning ? { ...payload.reasoning, summary: 'auto' } : { summary: 'auto' }; if (model.startsWith('gpt-5-pro')) { reasoning.effort = 'high'; } return pruneReasoningPayload({ ...rest, model, reasoning, ...(enableServiceTierFlex && supportsFlexTier(model) && { service_tier: 'flex' }), stream: payload.stream ?? true, tools: openaiTools as any, // computer-use series must set truncation as auto ...(model.startsWith('computer-use') && { truncation: 'auto' }), text: verbosity ? { verbosity } : undefined, }) as any; } return { ...rest, model, ...(enableServiceTierFlex && supportsFlexTier(model) && { service_tier: 'flex' }), stream: payload.stream ?? true, tools: openaiTools, } as any; }, }, } satisfies OpenAICompatibleFactoryOptions; export const LobeOpenAI = createOpenAICompatibleRuntime(params);