1- import type { DeepSeekLanguageModelOptions } from '@ai-sdk/deepseek'
2- import type { GoogleGenerativeAIProviderOptions } from '@ai-sdk/google'
31import type { LanguageModel , ModelMessage } from 'ai'
42import type { ThinkingLevel } from '~/lib/stores/appConfig'
53import type { EnrichedTweet , Entity } from '~/types'
6- import { createDeepSeek } from '@ai-sdk/deepseek'
7- import { createGoogleGenerativeAI } from '@ai-sdk/google'
84import { generateText , Output , zodSchema } from 'ai'
95import { z } from 'zod'
106import { models } from '~/lib/constants'
7+ import { getProviderStrategy , getThinkingConfig } from '~/lib/providers'
118import {
129 applyAITranslations ,
1310 restoreEntities ,
1411 serializeForAI ,
1512} from '~/lib/react-tweet'
1613
17- /**
18- * 将思考程度映射为 Gemini 2.0 的 thinkingBudget (token 数)
19- */
20- export function mapLevelToBudget ( level : ThinkingLevel ) : number {
21- switch ( level ) {
22- case 'minimal' : return 0
23- case 'low' : return 1024
24- case 'medium' : return 4096
25- case 'high' : return 16384
26- case 'max' : return 32768
27- default : return 0
28- }
29- }
30-
31- /**
32- * 获取对应模型的思考配置
33- */
34- export function getThinkingConfig ( modelName : string , level : ThinkingLevel = 'minimal' ) {
35- const modelConfig = models . find ( m => m . name === modelName )
36- const thinkingConfig : any = { includeThoughts : false }
37-
38- if ( ! modelConfig )
39- return thinkingConfig
40-
41- if ( modelConfig . provider === 'google' ) {
42- if ( modelConfig . thinkingType === 'level' ) {
43- thinkingConfig . thinkingLevel = level
44- }
45- else if ( modelConfig . thinkingType === 'budget' ) {
46- thinkingConfig . thinkingBudget = mapLevelToBudget ( level )
47- }
48- }
49- else if ( modelConfig . provider === 'deepseek' ) {
50- // DeepSeek 映射逻辑
51- if ( level === 'minimal' )
52- return 'disabled'
53- if ( level === 'max' )
54- return 'max'
55- return 'high'
56- }
57-
58- return thinkingConfig
59- }
60-
6114/**
6215 * 将实体 Map 转换为 AI 可读的参考文本
6316 * 目的:让 AI 知道占位符背后是什么,以便更好地理解上下文,但不需要 AI 翻译它们
@@ -278,13 +231,11 @@ ${maskedText}
278231`
279232
280233 const baseMessages : ModelMessage [ ] = [
281- { role : 'system' , content : systemPrompt } ,
282234 { role : 'user' , content : userContent } ,
283235 ]
284236
285237 const modelConfig = models . find ( m => m . name === modelName )
286- const isDeepSeek = modelConfig ?. provider === 'deepseek'
287- const isGoogle = modelConfig ?. provider === 'google'
238+ const strategy = modelConfig ? getProviderStrategy ( modelConfig . provider ) : null
288239
289240 const thinkingConfig = getThinkingConfig ( modelName , thinkingLevel )
290241 const expectedNewlineCount = countNewlines ( maskedText )
@@ -308,22 +259,13 @@ ${maskedText}
308259 for ( let attempt = 0 ; attempt < 2 ; attempt ++ ) {
309260 const response = await generateText ( {
310261 model,
262+ system : systemPrompt ,
311263 messages,
312264 output,
313265 temperature : 0.5 ,
314- providerOptions : {
315- ...( isGoogle ? {
316- google : {
317- thinkingConfig,
318- } satisfies GoogleGenerativeAIProviderOptions ,
319- } : { } ) ,
320- ...( isDeepSeek && modelConfig ?. thinkingType === 'level' ? {
321- deepseek : {
322- thinking : { type : thinkingConfig === 'disabled' ? 'disabled' : 'enabled' } ,
323- ...( thinkingConfig !== 'disabled' && typeof thinkingConfig === 'string' ? { reasoningEffort : thinkingConfig } : { } ) ,
324- } satisfies DeepSeekLanguageModelOptions ,
325- } : { } ) ,
326- } ,
266+ providerOptions : strategy && modelConfig
267+ ? strategy . buildProviderOptions ( thinkingConfig , modelConfig )
268+ : { } ,
327269 } )
328270
329271 const translated = normalizeNewlineEscapes ( response . output . translation , expectedNewlineCount ) . trim ( )
@@ -392,25 +334,16 @@ export async function autoTranslateTweet({
392334 }
393335 const entityContext = generateEntityContext ( entityMap )
394336
395- let aiProvider : any
396- if ( provider === 'google' ) {
397- aiProvider = createGoogleGenerativeAI ( {
398- apiKey,
399- } )
400- }
401- else {
402- aiProvider = createDeepSeek ( {
403- apiKey,
404- } )
405- }
337+ const strategy = getProviderStrategy ( provider )
338+ const sdkProvider = strategy . createSDKProvider ( apiKey )
406339
407340 const { translatedText, entityText } = await translateText ( {
408341 tweet,
409342 maskedText,
410343 entityContext,
411344 placeholders : Array . from ( entityMap . keys ( ) ) ,
412345 entityMap,
413- model : aiProvider ( model ) ,
346+ model : sdkProvider ( model ) ,
414347 modelName : model ,
415348 translationGlossary,
416349 thinkingLevel,
0 commit comments