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.

111 lines (98 loc) 3.5 kB
import { ModelProvider } from 'model-bank'; import { type OpenAICompatibleFactoryOptions, createOpenAICompatibleRuntime, } from '../../core/openaiCompatibleFactory'; import { processMultiProviderModelList } from '../../utils/modelParse'; export interface VercelAIGatewayModelCard { context_window?: number; created?: number | string; description?: string; id: string; max_tokens?: number; name?: string; pricing?: { input?: string | number; input_cache_read?: string | number; input_cache_write?: string | number; output?: string | number; }; tags?: string[]; type?: string; } export const formatPrice = (price?: string | number) => { if (price === undefined || price === null) return undefined; const n = typeof price === 'number' ? price : Number(price); if (Number.isNaN(n)) return undefined; // Convert per-token price (USD) to per million tokens return Number((n * 1e6).toPrecision(5)); }; export const params = { baseURL: 'https://ai-gateway.vercel.sh/v1', chatCompletion: { handlePayload: (payload) => { const { model, reasoning_effort, verbosity, ...rest } = payload; const providerOptions: any = {}; if (reasoning_effort || verbosity) { providerOptions.openai = {}; if (reasoning_effort) { providerOptions.openai.reasoningEffort = reasoning_effort; providerOptions.openai.reasoningSummary = 'auto'; } if (verbosity) { providerOptions.openai.textVerbosity = verbosity; } } return { ...rest, model, providerOptions, } as any; }, }, constructorOptions: { defaultHeaders: { 'http-referer': 'https://lobehub.com', 'x-title': 'LobeHub', }, }, debug: { chatCompletion: () => process.env.DEBUG_VERCELAIGATEWAY_CHAT_COMPLETION === '1', }, models: async ({ client }) => { const modelsPage = (await client.models.list()) as any; const modelList: VercelAIGatewayModelCard[] = modelsPage.data; const formattedModels = (modelList || []).map((m) => { const tags = Array.isArray(m.tags) ? m.tags : []; const inputPrice = formatPrice(m.pricing?.input); const outputPrice = formatPrice(m.pricing?.output); const cachedInputPrice = formatPrice(m.pricing?.input_cache_read); const writeCacheInputPrice = formatPrice(m.pricing?.input_cache_write); let displayName = m.name ?? m.id; if (inputPrice === 0 && outputPrice === 0) { displayName += ' (free)'; } return { contextWindowTokens: m.context_window ?? undefined, created: m.created, description: m.description ?? '', displayName, functionCall: tags.includes('tool-use') || false, id: m.id, maxOutput: typeof m.max_tokens === 'number' ? m.max_tokens : undefined, pricing: { cachedInput: cachedInputPrice, input: inputPrice, output: outputPrice, writeCacheInput: writeCacheInputPrice, }, reasoning: tags.includes('reasoning') || false, type: m.type === 'embedding' ? 'embedding' : 'chat', vision: tags.includes('vision') || false, } as any; }); return await processMultiProviderModelList(formattedModels, 'vercelaigateway'); }, provider: ModelProvider.VercelAIGateway, } satisfies OpenAICompatibleFactoryOptions; export const LobeVercelAIGatewayAI = createOpenAICompatibleRuntime(params);