mirror of
https://wget.la/https://github.com/Wxw-Gu/WechatExplorer
synced 2026-08-21 21:47:00 +08:00
fix(ai): 让严格执行max_tokens的API恢复工作,如DeepSeek (#19)
* fix(ai): 让严格执行`max_tokens`的API恢复工作,如DeepSeek - AI 请求优先使用当前模型配置的`Max Tokens`,并依次回退到供应商高级设置的`Max Tokens`和默认值 4096 - 透传`OpenAI-compatible`与`Anthropic`的结束原因,补充`preload`类型声明 - 群日报生成和修复遇到模型异常结束生成时终止处理,并针对token上限给出配置提示 - 优化 AI 未返回有效内容时的错误信息 - 统一行尾配置 Signed-off-by: longhuan1999 <2114467924@qq.com> * Update .gitignore --------- Signed-off-by: longhuan1999 <2114467924@qq.com> Co-authored-by: qingmao <84499436+Wxw-Gu@users.noreply.github.com>
This commit is contained in:
@@ -2,3 +2,4 @@ singleQuote: true
|
||||
semi: false
|
||||
printWidth: 100
|
||||
trailingComma: none
|
||||
endOfLine: auto
|
||||
|
||||
Vendored
+1
-1
@@ -8,7 +8,7 @@
|
||||
"cwd": "${workspaceRoot}",
|
||||
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite",
|
||||
"windows": {
|
||||
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite.cmd"
|
||||
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite.CMD"
|
||||
},
|
||||
"runtimeArgs": ["--sourcemap"],
|
||||
"env": {
|
||||
|
||||
Vendored
+2
-1
@@ -7,5 +7,6 @@
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "vscode.json-language-features"
|
||||
}
|
||||
},
|
||||
"files.eol": "\n"
|
||||
}
|
||||
@@ -24,6 +24,12 @@ export default defineConfig(
|
||||
'react-refresh': eslintPluginReactRefresh
|
||||
},
|
||||
rules: {
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
endOfLine: 'auto'
|
||||
}
|
||||
],
|
||||
...eslintPluginReactHooks.configs.recommended.rules,
|
||||
...eslintPluginReactRefresh.configs.vite.rules
|
||||
}
|
||||
|
||||
@@ -26,16 +26,18 @@ type AIMessagePart = { type: 'text'; text: string } | { type: 'image'; dataUrl:
|
||||
type AIMessage = { role: string; content: string | AIMessagePart[] }
|
||||
type AIRequestResult = {
|
||||
data: string
|
||||
finishReason?: string
|
||||
usage?: { input?: number; output?: number; total?: number; estimated?: boolean }
|
||||
}
|
||||
interface OpenAIResponsePayload {
|
||||
error?: { message?: string }
|
||||
choices?: Array<{ message?: { content?: string } }>
|
||||
choices?: Array<{ message?: { content?: string }; finish_reason?: string }>
|
||||
usage?: { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number }
|
||||
}
|
||||
interface AnthropicResponsePayload {
|
||||
error?: { message?: string }
|
||||
content?: Array<{ type?: string; text?: string }>
|
||||
stop_reason?: string
|
||||
usage?: { input_tokens?: number; output_tokens?: number }
|
||||
}
|
||||
|
||||
@@ -612,6 +614,12 @@ async function requestOpenAICompatible(
|
||||
const endpoint = provider.baseUrl.endsWith('/chat/completions')
|
||||
? provider.baseUrl
|
||||
: `${provider.baseUrl.replace(/\/+$/, '')}/chat/completions`
|
||||
let modelMaxTokens = 0
|
||||
for (const m of provider.models) {
|
||||
if (m.id === model && m.maxTokens) {
|
||||
modelMaxTokens = m.maxTokens
|
||||
}
|
||||
}
|
||||
const response = await fetchWithTimeout(
|
||||
endpoint,
|
||||
{
|
||||
@@ -621,7 +629,11 @@ async function requestOpenAICompatible(
|
||||
model,
|
||||
messages: toOpenAIMessages(messages),
|
||||
temperature: provider.advanced.temperature,
|
||||
max_tokens: testing ? 8 : provider.advanced.maxTokens
|
||||
max_tokens: testing
|
||||
? 8
|
||||
: modelMaxTokens > 0
|
||||
? modelMaxTokens
|
||||
: provider.advanced.maxTokens || 4096
|
||||
})
|
||||
},
|
||||
provider.advanced.timeoutMs,
|
||||
@@ -631,6 +643,7 @@ async function requestOpenAICompatible(
|
||||
if (!response.ok) throw new Error(payload.error?.message || `AI 请求失败 (${response.status})`)
|
||||
return {
|
||||
data: String(payload.choices?.[0]?.message?.content || ''),
|
||||
finishReason: String(payload.choices?.[0]?.finish_reason || 'unknown'),
|
||||
usage: payload.usage
|
||||
? {
|
||||
input: payload.usage.prompt_tokens,
|
||||
@@ -667,6 +680,12 @@ async function requestAnthropic(
|
||||
const endpoint = provider.baseUrl.endsWith('/messages')
|
||||
? provider.baseUrl
|
||||
: `${provider.baseUrl.replace(/\/+$/, '')}/messages`
|
||||
let modelMaxTokens = 0
|
||||
for (const m of provider.models) {
|
||||
if (m.id === model && m.maxTokens) {
|
||||
modelMaxTokens = m.maxTokens
|
||||
}
|
||||
}
|
||||
const response = await fetchWithTimeout(
|
||||
endpoint,
|
||||
{
|
||||
@@ -677,7 +696,11 @@ async function requestAnthropic(
|
||||
system: system || undefined,
|
||||
messages: anthropicMessages,
|
||||
temperature: provider.advanced.temperature,
|
||||
max_tokens: testing ? 8 : provider.advanced.maxTokens || 4096
|
||||
max_tokens: testing
|
||||
? 8
|
||||
: modelMaxTokens > 0
|
||||
? modelMaxTokens
|
||||
: provider.advanced.maxTokens || 4096
|
||||
})
|
||||
},
|
||||
provider.advanced.timeoutMs,
|
||||
@@ -693,6 +716,7 @@ async function requestAnthropic(
|
||||
.map((item) => item.text || '')
|
||||
.join('\n')
|
||||
: '',
|
||||
finishReason: String(payload.stop_reason || 'unknown'),
|
||||
usage: payload.usage
|
||||
? {
|
||||
input: payload.usage.input_tokens,
|
||||
|
||||
Vendored
+1
@@ -229,6 +229,7 @@ declare global {
|
||||
) => Promise<{
|
||||
success: boolean
|
||||
data?: string
|
||||
finishReason?: string
|
||||
usage?: {
|
||||
input?: number
|
||||
output?: number
|
||||
|
||||
@@ -511,7 +511,19 @@ export function useGroupReportGeneration({
|
||||
reportTimeoutSeconds * 1000 + REPORT_MODEL_TIMEOUT_BUFFER_MS
|
||||
)
|
||||
)
|
||||
if (!result.success || !result.data) throw new Error(result.error || 'AI 请求失败')
|
||||
if (
|
||||
result.finishReason &&
|
||||
result.finishReason !== 'stop' &&
|
||||
result.finishReason !== 'end_turn'
|
||||
) {
|
||||
let errMsg = `当前模型\`异常结束生成\`,原因:${result.finishReason}`
|
||||
if (result.finishReason === 'length' || result.finishReason === 'max_tokens') {
|
||||
errMsg += ',请尝试在`设置-AI 模型-新增/编辑供应商-模型配置/高级设置`中调高`Max Tokens`'
|
||||
}
|
||||
throw new Error(errMsg)
|
||||
}
|
||||
if (!result.success || !result.data)
|
||||
throw new Error(result.error || 'AI 请求失败,未返回有效内容')
|
||||
writeReportLog('info', '模型响应完成', {
|
||||
outputLength: result.data.length,
|
||||
usage: result.usage
|
||||
@@ -552,8 +564,23 @@ export function useGroupReportGeneration({
|
||||
reportTimeoutSeconds * 1000 + REPORT_MODEL_TIMEOUT_BUFFER_MS
|
||||
)
|
||||
)
|
||||
if (
|
||||
repairResult.finishReason &&
|
||||
repairResult.finishReason !== 'stop' &&
|
||||
repairResult.finishReason !== 'end_turn'
|
||||
) {
|
||||
let errMsg = `当前模型\`异常结束生成\`,原因:${repairResult.finishReason}`
|
||||
if (
|
||||
repairResult.finishReason === 'length' ||
|
||||
repairResult.finishReason === 'max_tokens'
|
||||
) {
|
||||
errMsg +=
|
||||
',请尝试在`设置-AI 模型-新增/编辑供应商-模型配置/高级设置`中调高`Max Tokens`'
|
||||
}
|
||||
throw new Error(errMsg)
|
||||
}
|
||||
if (!repairResult.success || !repairResult.data) {
|
||||
throw new Error(repairResult.error || 'AI 修复日报 JSON 失败', {
|
||||
throw new Error(repairResult.error || 'AI 修复日报 JSON 失败,未返回有效内容', {
|
||||
cause: parseError
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user