From 3ddd49384744c89825ed83a8cc7278aaf8c5bf38 Mon Sep 17 00:00:00 2001 From: thzxx Date: Sun, 28 Jun 2026 19:52:53 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E7=89=88=E6=9C=AC=E5=8F=B7=200.14.2?= =?UTF-8?q?=20=E2=86=92=200.14.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: AI 回复消息卡片重复渲染 — onDone 去掉 updateLastAssistantMessage 避免双重 DOM fix: 用户消息卡片只显示用户文字,代码生成的附件标记不显示 fix: onDone assistantMsg 补充 model 字段 --- README.md | 6 ++--- package-lock.json | 4 +-- package.json | 2 +- src/main/menu.ts | 2 +- src/renderer/components/input-area.ts | 35 ++++++++------------------- src/renderer/index.html | 2 +- src/renderer/types.d.ts | 2 ++ 7 files changed, 20 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index ab11877..527690b 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@

- version + version electron typescript license @@ -253,7 +253,7 @@ npm start ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ npm run dist ``` -产出:`release/Metona Ollama Setup v0.14.2.exe` +产出:`release/Metona Ollama Setup v0.14.3.exe` ## 🛠️ 常用命令 @@ -501,7 +501,7 @@ npm start ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ npm run dist ``` -Output: `release/Metona Ollama Setup v0.14.2.exe` +Output: `release/Metona Ollama Setup v0.14.3.exe` ## 🛠️ Common Commands diff --git a/package-lock.json b/package-lock.json index b8fca5d..b27a86f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "metona-ollama-desktop", - "version": "0.14.2", + "version": "0.14.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "metona-ollama-desktop", - "version": "0.14.2", + "version": "0.14.3", "license": "MIT", "dependencies": { "ffmpeg-static": "^5.2.0", diff --git a/package.json b/package.json index 3995f0b..cd02b83 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metona-ollama-desktop", - "version": "0.14.2", + "version": "0.14.3", "description": "Metona Ollama - TypeScript + Electron 桌面 AI 聊天客户端", "main": "dist/main/main.js", "author": "thzxx", diff --git a/src/main/menu.ts b/src/main/menu.ts index a3849c0..20f0a80 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -101,7 +101,7 @@ export function createMenu(): void { dialog.showMessageBox(mainWindow!, { type: 'info', title: '关于 Metona Ollama', - message: 'Metona Ollama Desktop v0.14.2', + message: 'Metona Ollama Desktop v0.14.3', detail: 'TypeScript + Electron Ollama AI 聊天客户端\n\nhttps://gitee.com/thzxx/metona-ollama', icon: getIconPath() }); diff --git a/src/renderer/components/input-area.ts b/src/renderer/components/input-area.ts index 7d3ba54..c3b6133 100644 --- a/src/renderer/components/input-area.ts +++ b/src/renderer/components/input-area.ts @@ -588,7 +588,7 @@ async function handleRetry(): Promise { if (retryIterations > 0) { if (finalContent) { const lastMsg: ChatMessage = { - role: 'assistant', content: finalContent, timestamp: Date.now(), + role: 'assistant', content: finalContent, model: getSelectedModel(), timestamp: Date.now(), ...(retryThinkContent && { think: retryThinkContent }), ...(toolRecords?.length && { toolCalls: toolRecords }), ...(loopStats?.eval_count && { eval_count: loopStats.eval_count }), @@ -599,10 +599,9 @@ async function handleRetry(): Promise { ...s, messages: [...s.messages, lastMsg], updatedAt: Date.now() })); } - updateLastAssistantMessage(finalContent, retryThinkContent || null, loopStats || null, getSelectedModel(), Date.now(), toolRecords?.length ? toolRecords : undefined); } else { const assistantMsg: ChatMessage = { - role: 'assistant', content: finalContent || '', timestamp: Date.now(), + role: 'assistant', content: finalContent || '', model: getSelectedModel(), timestamp: Date.now(), ...(retryThinkContent && { think: retryThinkContent }), ...(toolRecords?.length && { toolCalls: toolRecords }), ...(loopStats?.eval_count && { eval_count: loopStats.eval_count }), @@ -612,8 +611,9 @@ async function handleRetry(): Promise { state.update(KEYS.CURRENT_SESSION, (s: any) => ({ ...s, messages: [...s.messages, assistantMsg], updatedAt: Date.now() })); - updateLastAssistantMessage(finalContent, retryThinkContent || null, loopStats || null, getSelectedModel(), Date.now(), toolRecords?.length ? toolRecords : undefined); } + // renderMessages 统一渲染 session 数据,先清掉流式 placeholder 避免 DOM 重复 + clearMessagesDOM(); renderMessages(); // ── 保存 Plan Mode 最终进度到会话(供下一轮 Loop 注入)── const lastPlanStatus = state.get('_lastPlanStatus', ''); @@ -1135,26 +1135,10 @@ async function sendMessageWithAgentLoop(text: string, currentSession: ChatSessio const hasAttachments = pendingImages.length > 0 || hasVideos || userFiles.length > 0; if (hasAttachments) { - // 聊天卡片显示用的简短描述 - const displayParts: string[] = []; - if (text) displayParts.push(text); - if (pendingVideoMeta && pendingVideoFrames.length > 0) { - displayParts.push(`[视频: ${pendingVideoMeta.fileName}, ${pendingVideoFrames.length}帧, 1fps]`); - } - for (const v of completedVideos) { - displayParts.push(`[视频: ${v.fileName}, ${v.frames.length}帧, 1fps]`); - } - if (pendingImages.length === 1) { - displayParts.push(`[图片: ${pendingImages[0].name}]`); - } else if (pendingImages.length > 1) { - displayParts.push(`[${pendingImages.length} 张图片]`); - } - for (const f of userFiles) { - displayParts.push(`[文件: ${f.name}]`); - } - const displayContent = displayParts.join('\n'); + // ── 聊天卡片:只显示用户自己的文字 + 附件视觉预览(缩略图/文件卡片/视频帧),不含代码生成的文本标记 ── + const displayContent = text || ''; - // Ollama API 用的完整描述(文字 + 文件 + 视频帧序列 + 图片提示) + // ── Ollama API 用:完整描述(文字 + 文件内容 + 视频帧序列 + 图片提示)── const apiParts: string[] = []; if (text) apiParts.push(text); if (userFiles.length > 0) { @@ -1164,9 +1148,9 @@ async function sendMessageWithAgentLoop(text: string, currentSession: ChatSessio logInfo('📄 文件内容已注入', `${fileParts.length} 段, 共 ${fileContents.reduce((s, f) => s + f.content.length, 0)} 字符`); } if (pendingImages.length === 1) { - apiParts.push(`[已上传图片: ${pendingImages[0].name} — 此图片已随消息提供,你可以直接分析,无需去磁盘查找]`); + apiParts.push(`[已上传图片: ${pendingImages[0].name}]`); } else if (pendingImages.length > 1) { - apiParts.push(`[已上传 ${pendingImages.length} 张图片: ${pendingImages.map(img => img.name).join(', ')} — 这些图片已随消息提供,你可以直接分析,无需去磁盘查找]`); + apiParts.push(`[已上传 ${pendingImages.length} 张图片: ${pendingImages.map(img => img.name).join(', ')}]`); } let allVids: Array<{ name: string; count: number; dur: number; frames: Array<{ timestampSeconds: number; name: string; base64: string }> }> = []; if (hasVideos) { @@ -1190,6 +1174,7 @@ async function sendMessageWithAgentLoop(text: string, currentSession: ChatSessio role: 'user', content: displayContent, images: [...pendingImages.map(img => img.base64)], + _apiContent: apiContentForModel, // 给模型的完整内容,不显示给用户 timestamp: now }; if (allVids.length > 0) { diff --git a/src/renderer/index.html b/src/renderer/index.html index 2701985..3698022 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -28,7 +28,7 @@

Metona Ollama - v0.14.2 + v0.14.3