diff --git a/app/api/ai/claude/route.js b/app/api/ai/claude/route.js index 0482676..d337f19 100644 --- a/app/api/ai/claude/route.js +++ b/app/api/ai/claude/route.js @@ -5,7 +5,7 @@ export const runtime = 'edge'; export async function POST(request) { try { - const { systemPrompt, userPrompt, apiConfig, maxTokens } = await request.json(); + const { systemPrompt, userPrompt, apiConfig, maxTokens, temperature, topP } = await request.json(); const apiKey = apiConfig?.apiKey; const baseUrl = (apiConfig?.baseUrl || 'https://api.anthropic.com').replace(/\/$/, ''); @@ -23,12 +23,14 @@ export async function POST(request) { // 构造 Messages API 请求体 const requestBody = { model, - max_tokens: maxTokens || 2000, + max_tokens: maxTokens || 4096, system: systemPrompt, messages: [ { role: 'user', content: userPrompt } ], stream: true, + ...(temperature != null ? { temperature } : {}), + ...(topP != null ? { top_p: topP } : {}), }; // 如果模型支持 extended thinking (claude-3-7-sonnet),可以启用 diff --git a/app/api/ai/gemini/route.js b/app/api/ai/gemini/route.js index a4b079b..7d9e07b 100644 --- a/app/api/ai/gemini/route.js +++ b/app/api/ai/gemini/route.js @@ -5,7 +5,7 @@ export const runtime = 'edge'; export async function POST(request) { try { - const { systemPrompt, userPrompt, apiConfig, maxTokens } = await request.json(); + const { systemPrompt, userPrompt, apiConfig, maxTokens, temperature, topP } = await request.json(); const apiKey = apiConfig?.apiKey || process.env.GEMINI_API_KEY; let rawBaseUrl = apiConfig?.baseUrl; @@ -36,8 +36,8 @@ export async function POST(request) { } ], generationConfig: { - temperature: 0.8, - topP: 0.9, + temperature: temperature ?? 0.8, + topP: topP ?? 0.9, ...(maxTokens ? { maxOutputTokens: maxTokens } : {}), }, }; diff --git a/app/api/ai/responses/route.js b/app/api/ai/responses/route.js index bcc06cf..416b865 100644 --- a/app/api/ai/responses/route.js +++ b/app/api/ai/responses/route.js @@ -5,7 +5,7 @@ export const runtime = 'edge'; export async function POST(request) { try { - const { systemPrompt, userPrompt, apiConfig, maxTokens } = await request.json(); + const { systemPrompt, userPrompt, apiConfig, maxTokens, temperature, topP } = await request.json(); const apiKey = apiConfig?.apiKey; const baseUrl = (apiConfig?.baseUrl || 'https://api.openai.com/v1').replace(/\/$/, ''); @@ -28,6 +28,8 @@ export async function POST(request) { { role: 'user', content: userPrompt }, ], stream: true, + ...(temperature != null ? { temperature } : {}), + ...(topP != null ? { top_p: topP } : {}), }; // 添加思考等级(默认 medium) diff --git a/app/api/ai/route.js b/app/api/ai/route.js index ce38690..411c80d 100644 --- a/app/api/ai/route.js +++ b/app/api/ai/route.js @@ -5,7 +5,7 @@ export const runtime = 'edge'; export async function POST(request) { try { - const { systemPrompt, userPrompt, apiConfig, maxTokens } = await request.json(); + const { systemPrompt, userPrompt, apiConfig, maxTokens, temperature, topP } = await request.json(); const apiKey = apiConfig?.apiKey || process.env.ZHIPU_API_KEY; const baseUrl = apiConfig?.baseUrl || 'https://open.bigmodel.cn/api/paas/v4'; @@ -33,7 +33,8 @@ export async function POST(request) { { role: 'system', content: systemPrompt }, { role: 'user', content: userPrompt } ], - temperature: 0.8, + temperature: temperature ?? 0.8, + ...(topP != null ? { top_p: topP } : {}), ...(maxTokens ? { max_tokens: maxTokens } : {}), stream: true, }), diff --git a/app/components/AiSidebar.js b/app/components/AiSidebar.js index cf654ea..a9492bc 100644 --- a/app/components/AiSidebar.js +++ b/app/components/AiSidebar.js @@ -208,7 +208,14 @@ export default function AiSidebar({ onInsertText }) { const res = await fetch(apiEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ systemPrompt, userPrompt, apiConfig, maxTokens: 2000 }), + body: JSON.stringify({ + systemPrompt, userPrompt, apiConfig, + ...(apiConfig?.useAdvancedParams ? { + maxTokens: apiConfig.maxOutputTokens || 65536, + temperature: apiConfig.temperature ?? 1, + topP: apiConfig.topP ?? 0.95, + } : { maxTokens: 4096 }), + }), }); const contentType = res.headers.get('content-type') || ''; diff --git a/app/components/SettingsConflictModal.js b/app/components/SettingsConflictModal.js index 1dc1d61..fb6ed47 100644 --- a/app/components/SettingsConflictModal.js +++ b/app/components/SettingsConflictModal.js @@ -133,7 +133,14 @@ ${importedFields} const res = await fetch(apiEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ systemPrompt, userPrompt, apiConfig, maxTokens: 2000 }), + body: JSON.stringify({ + systemPrompt, userPrompt, apiConfig, + ...(apiConfig?.useAdvancedParams ? { + maxTokens: apiConfig.maxOutputTokens || 65536, + temperature: apiConfig.temperature ?? 1, + topP: apiConfig.topP ?? 0.95, + } : { maxTokens: 4096 }), + }), }); if (!res.ok) { diff --git a/app/components/SettingsPanel.js b/app/components/SettingsPanel.js index 897c22a..8439df1 100644 --- a/app/components/SettingsPanel.js +++ b/app/components/SettingsPanel.js @@ -799,6 +799,7 @@ const PROVIDERS = [ { key: 'gemini-native', label: 'Gemini(原生格式)', baseUrl: 'https://generativelanguage.googleapis.com/v1beta', models: ['gemini-2.0-flash', 'gemini-2.0-flash-lite', 'gemini-1.5-flash', 'gemini-1.5-pro'] }, { key: 'openai-responses', label: 'OpenAI Responses', baseUrl: 'https://api.openai.com/v1', models: [] }, { key: 'siliconflow', label: 'SiliconFlow (硅基流动)', baseUrl: 'https://api.siliconflow.cn/v1', models: ['deepseek-ai/DeepSeek-V3', 'Qwen/Qwen2.5-72B-Instruct', 'THUDM/glm-4-9b-chat'] }, + { key: 'volcengine', label: '火山引擎 (豆包)', baseUrl: 'https://ark.cn-beijing.volces.com/api/v3', models: [] }, { key: 'moonshot', label: 'Moonshot (Kimi)', baseUrl: 'https://api.moonshot.cn/v1', models: ['moonshot-v1-8k', 'moonshot-v1-32k', 'moonshot-v1-128k'] }, { key: 'custom', label: '自定义 (OpenAI兼容)', baseUrl: '', models: [] }, ]; @@ -1055,6 +1056,102 @@ function ApiConfigForm({ data, onChange }) { )} + {/* 高级模型参数 */} +
+ +
+ {t('apiConfig.advancedParamsDesc')} +
+
+ + {data.useAdvancedParams && ( +
+ {/* Temperature */} +
+ +
+ update('temperature', parseFloat(e.target.value))} + style={{ flex: 1, accentColor: 'var(--accent)' }} + /> + update('temperature', parseFloat(e.target.value) || 0)} + /> +
+
{t('apiConfig.temperatureDesc')}
+
+ + {/* Top P */} +
+ +
+ update('topP', parseFloat(e.target.value))} + style={{ flex: 1, accentColor: 'var(--accent)' }} + /> + update('topP', parseFloat(e.target.value) || 0)} + /> +
+
{t('apiConfig.topPDesc')}
+
+ + {/* 最大上下文长度 */} +
+ + update('maxContextLength', parseInt(e.target.value) || 4096)} + /> +
{t('apiConfig.maxContextLengthDesc')}
+
+ + {/* 最大输出 Token */} +
+ + update('maxOutputTokens', parseInt(e.target.value) || 4096)} + /> +
{t('apiConfig.maxOutputTokensDesc')}
+
+
+ )} + {/* 独立 Embedding 配置 */}