diff --git a/README.md b/README.md index 83a07f1..1be0a4c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ macOS / Windows 微信聊天记录查看,AI 一键生成群聊总结。 在微信 4.0 数据库解析、解密思路上,项目参考了 [WeFlow](https://github.com/hicccc77/WeFlow) 等开源项目的实现方式;此项目围绕我自己的使用场景做的定制化工具,重点放在本地聊天记录查看、群聊总结和个人工作流集成上。 -> 当前版本:`v2.1.0`。macOS 支持相对稳定;Windows 已初步支持微信 4.0 数据库连接、自动获取密钥和聊天记录查看,仍在持续兼容不同微信版本与本地目录结构。 +> 当前版本:`v2.1.2`。macOS 支持相对稳定;Windows 已初步支持微信 4.0 数据库连接、自动获取密钥和聊天记录查看,仍在持续兼容不同微信版本与本地目录结构。 ## ✨ 功能特性 diff --git a/src/main/index.ts b/src/main/index.ts index c6f65e8..04fc512 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -556,9 +556,9 @@ app.whenReady().then(async () => { if (!provider || !model) { return { success: false, error: '当前 AI 模型不存在' } } - if (!model.capabilities.vision) { - return { success: false, error: '当前模型不支持图片理解' } - } + // Capability metadata is stored per machine. A model verified on macOS + // may still be unmarked on Windows, so do not reject before making the + // real multimodal request. The provider response remains authoritative. // request 来自 renderer,imageHash 是 md5(优先)或 sha256(...),dataUrl 在内部算出 // 这里直接调 service,dataUrl 由 renderer 通过 window.api.getImage 拿到再传进来 return imageInsightService.analyze(request) diff --git a/src/main/services/ai-provider-service.ts b/src/main/services/ai-provider-service.ts index 14a5c10..5accd30 100644 --- a/src/main/services/ai-provider-service.ts +++ b/src/main/services/ai-provider-service.ts @@ -195,6 +195,9 @@ export class AIProviderService { const imageError = validateVisionImage(imagePart.dataUrl) if (imageError) throw new Error(imageError) const result = await this.request(messages as AIMessage[], options) + if (options?.providerId && options.modelId) { + this.markCapabilities(options.providerId, options.modelId, { vision: true, ocr: true }) + } return { success: true, ...result } } catch (error) { return { success: false, error: safeAIError(error) } diff --git a/src/renderer/src/hooks/useGroupReportGeneration.ts b/src/renderer/src/hooks/useGroupReportGeneration.ts index 23afc9f..bef992c 100644 --- a/src/renderer/src/hooks/useGroupReportGeneration.ts +++ b/src/renderer/src/hooks/useGroupReportGeneration.ts @@ -175,13 +175,18 @@ const applyGroupMemberNames = async ( const member = memberMap.get(senderId) if (!member) return message const preferredNames: Record = { - groupNickname: [member.groupNickname, member.wechatNickname, member.remark, member.nickname], - wechatNickname: [member.wechatNickname, member.groupNickname, member.remark, member.nickname], + // Keep the three modes semantically distinct. `member.nickname` may + // already be a contact remark, so it must not leak into the first two. + groupNickname: [member.groupNickname, member.wechatNickname], + wechatNickname: [member.wechatNickname, member.groupNickname], remark: [member.remark, member.groupNickname, member.wechatNickname, member.nickname] } const name = preferredNames[preference].find((value) => value && !isInternalName(value)) - if (!name) return message - return { ...message, name, img: message.img || member.avatar } + return { + ...message, + name: name || (preference === 'remark' ? message.name : ''), + img: message.img || member.avatar + } }) } @@ -222,11 +227,12 @@ export function useGroupReportGeneration({ const [generatedImage, setGeneratedImage] = useState(null) const [reportPaths, setReportPaths] = useState(null) const [templateId, setTemplateId] = useState('v1') - const [memberNamePreference, setMemberNamePreferenceState] = - useState(() => { + const [memberNamePreference, setMemberNamePreferenceState] = useState( + () => { const saved = localStorage.getItem('group_report_member_name_preference') return saved === 'wechatNickname' || saved === 'remark' ? saved : 'groupNickname' - }) + } + ) const [reportTimeoutSeconds, setReportTimeoutSecondsState] = useState(() => { const saved = Number(localStorage.getItem('group_report_timeout_seconds')) return Number.isFinite(saved) && saved >= 30 ? saved : 300