From fd83422e975e04573b53b83106f3fa2b402d217d Mon Sep 17 00:00:00 2001 From: foxhui Date: Thu, 19 Mar 2026 17:01:10 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E8=B1=86=E5=8C=85=20?= =?UTF-8?q?Pro=20=E6=A8=A1=E5=9E=8B=E5=B9=B6=E4=BF=AE=E5=A4=8D=E8=B1=86?= =?UTF-8?q?=E5=8C=85=E5=9B=9E=E5=A4=8D=E6=88=AA=E6=96=AD=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98=20(closes=20#23,=20closes=20#24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 9 ++++ src/backend/adapter/doubao_text.js | 77 +++++++++++++++++++----------- 2 files changed, 59 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10105e9..b99dd12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.5.5] - 2026-03-05 +### ✨ Added +- **豆包** + - 增加豆包 Pro 模型的支持 + +### 🐛 Fixed +- **适配器** + - 修复豆包文本被截断的问题 + ## [3.5.5] - 2026-03-05 ### ✨ Added diff --git a/src/backend/adapter/doubao_text.js b/src/backend/adapter/doubao_text.js index 4a9eb36..527497a 100644 --- a/src/backend/adapter/doubao_text.js +++ b/src/backend/adapter/doubao_text.js @@ -31,7 +31,14 @@ async function generate(context, prompt, imgPaths, modelId, meta = {}) { const { page } = context; // 是否使用深度思考模式 - const useThinking = modelId === 'seed-thinking'; + const useThinking = modelId === 'seed-thinking' || modelId === 'seed-pro'; + + // 模型 ID 到菜单项无障碍名称的映射 + const MODEL_MENU_MAP = { + 'seed': 'Fast Solves most questions', + 'seed-thinking': 'Think Solves more complex problems', + 'seed-pro': 'Pro Advanced Pro model' + }; try { logger.info('适配器', '开启新会话...', meta); @@ -63,7 +70,7 @@ async function generate(context, prompt, imgPaths, modelId, meta = {}) { try { // 点击上传菜单按钮 - const uploadMenuBtn = page.locator('main button[aria-haspopup="menu"]').first(); + const uploadMenuBtn = page.locator('main button[aria-haspopup="menu"]:not(:has(div[data-testid="deep-thinking-action-button"]))').first(); await safeClick(page, uploadMenuBtn, { bias: 'button' }); await sleep(300, 500); @@ -86,20 +93,21 @@ async function generate(context, prompt, imgPaths, modelId, meta = {}) { logger.info('适配器', '图片上传完成', meta); } - // 3. 切换深度思考模式 (如需) - const deepThinkBtn = page.locator('div[data-testid="use-deep-thinking-switch-btn"] button'); - const btnExists = await deepThinkBtn.count() > 0; + // 3. 选择模型 + const modelMenuName = MODEL_MENU_MAP[modelId] || MODEL_MENU_MAP['seed']; + logger.debug('适配器', `选择模型: ${modelId} -> ${modelMenuName}`, meta); - if (btnExists) { - const isChecked = await deepThinkBtn.getAttribute('data-checked') === 'true'; + const modelSelectorBtn = page.locator('div[data-testid="deep-thinking-action-button"]'); + const selectorExists = await modelSelectorBtn.count() > 0; - if (useThinking && !isChecked) { - logger.debug('适配器', '启用深度思考模式...', meta); - await safeClick(page, deepThinkBtn, { bias: 'button' }); - } else if (!useThinking && isChecked) { - logger.debug('适配器', '关闭深度思考模式...', meta); - await safeClick(page, deepThinkBtn, { bias: 'button' }); - } + if (selectorExists) { + await safeClick(page, modelSelectorBtn, { bias: 'button' }); + await sleep(300, 500); + + const menuItem = page.getByRole('menuitem', { name: modelMenuName }); + await menuItem.waitFor({ state: 'visible', timeout: 5000 }); + await safeClick(page, menuItem, { bias: 'button' }); + await sleep(200, 400); } // 4. 填写提示词 @@ -212,13 +220,16 @@ function parseSSEResponse(body, useThinking) { try { const data = JSON.parse(dataLine); - // SSE_REPLY_END with end_type: 1 包含完整回复 + // SSE_REPLY_END with end_type: 1 的 brief 仅作兜底 if (eventType === 'SSE_REPLY_END' && data.end_type === 1) { - resultText = data.msg_finish_attr?.brief || ''; + const brief = data.msg_finish_attr?.brief || ''; + if (!resultText && brief) { + resultText = brief; + } } // STREAM_MSG_NOTIFY 检测深度思考块 - if (eventType === 'STREAM_MSG_NOTIFY' && useThinking) { + if (eventType === 'STREAM_MSG_NOTIFY') { const blocks = data.content?.content_block || []; for (const block of blocks) { if (block.block_type === 10040 && block.content?.thinking_block) { @@ -229,28 +240,39 @@ function parseSSEResponse(body, useThinking) { } // STREAM_CHUNK 处理内容块 - if (eventType === 'STREAM_CHUNK' && useThinking && data.patch_op) { + if (eventType === 'STREAM_CHUNK' && data.patch_op) { for (const op of data.patch_op) { if (op.patch_object === 1 && op.patch_value?.content_block) { for (const block of op.patch_value.content_block) { - // 如果有 parent_id 指向 thinking_block,则是思考内容 - if (block.parent_id === thinkingBlockId) { - const text = block.content?.text_block?.text || ''; - if (text) reasoningText += text; - } // 思考块结束标记 if (block.block_type === 10040 && block.is_finish) { inThinkingBlock = false; } + // 思考内容 (parent_id 指向 thinking_block) + if (useThinking && block.parent_id === thinkingBlockId) { + const text = block.content?.text_block?.text || ''; + if (text) reasoningText += text; + } + // 正文内容 (block_type 10000,非思考子块) + else if (block.block_type === 10000 && block.parent_id !== thinkingBlockId) { + const text = block.content?.text_block?.text || ''; + if (text) resultText += text; + } } } } } - // CHUNK_DELTA 增量文本 (思考过程中的增量) - if (eventType === 'CHUNK_DELTA' && useThinking && inThinkingBlock) { + // CHUNK_DELTA 增量文本 + if (eventType === 'CHUNK_DELTA') { const text = data.text || ''; - if (text) reasoningText += text; + if (text) { + if (useThinking && inThinkingBlock) { + reasoningText += text; + } else { + resultText += text; + } + } } } catch (e) { @@ -277,7 +299,8 @@ export const manifest = { models: [ { id: 'seed', imagePolicy: 'optional', type: 'text' }, - { id: 'seed-thinking', imagePolicy: 'optional', type: 'text' } + { id: 'seed-thinking', imagePolicy: 'optional', type: 'text' }, + { id: 'seed-pro', imagePolicy: 'optional', type: 'text' } ], navigationHandlers: [],