feat: 完善群聊日报语音转写缓存

支持空内容的微信语音消息并兼容历史缓存转写结果
将系统通知标记为微信系统消息,排除活跃成员与发言排行
This commit is contained in:
Wxw-Gu
2026-08-11 11:08:55 +08:00
parent 68f0c0b5a3
commit 6192e7cd35
16 changed files with 240 additions and 42 deletions
+74 -1
View File
@@ -1,6 +1,11 @@
import { describe, expect, it } from 'vitest'
import { parseGroupDailyReport } from '../../src/renderer/src/utils/group-report'
import {
buildGroupReportInput,
parseGroupDailyReport
} from '../../src/renderer/src/utils/group-report'
import { summaryContent } from '../../src/renderer/src/utils/group-report-facts'
import { summarySender } from '../../src/renderer/src/utils/group-report-facts'
import { selectHeroParticipantNames } from '../../src/shared/group-report'
import type { GroupReportMetadata } from '../../src/shared/group-report'
import type { Message } from '../../src/shared/types'
@@ -25,6 +30,12 @@ const media = {
}
describe('group report parsing', () => {
it('keeps only distinct real participants in the hero avatar list', () => {
expect(
selectHeroParticipantNames(['濑岛田井卫', '测试群昵称', '濑岛田井卫', '', ' '])
).toEqual(['濑岛田井卫', '测试群昵称'])
})
it('includes a cached voice transcript in the report input content', () => {
const message: Message = {
id: 'voice-1',
@@ -40,6 +51,68 @@ describe('group report parsing', () => {
expect(summaryContent(message)).toContain('今晚八点确认发布。')
})
it('includes a voice transcript when legacy cached messages have no contentData', () => {
const message: Message = {
id: 'voice-legacy',
from: 'member',
type: '语音',
datetime: '2026-08-11 10:00:00',
content: '[语音消息]',
isSender: false,
voiceTranscript: '能不能听见这个语音?'
}
expect(summaryContent(message)).toBe('[语音] 能不能听见这个语音?')
})
it('passes legacy voice transcripts into the daily-report model prompt', async () => {
const message: Message = {
id: 'voice-prompt',
from: 'member',
type: '语音',
datetime: '2026-08-11 10:00:00',
content: '[语音消息]',
isSender: false,
name: '测试成员',
voiceTranscript: '试一下好不好使?'
}
const input = await buildGroupReportInput([message], null, true, 'full')
expect(input.prompt).toContain('[语音] 试一下好不好使?')
})
it('labels system notices separately and excludes them from active members', async () => {
const systemMessage: Message = {
id: 'system-1',
from: 'system',
type: '系统消息',
datetime: '2026-08-11 09:59:00',
content: '由于账号安全原因,无法加入当前群聊。',
isSender: false,
contentData: {
type: 'system',
content: '由于账号安全原因,无法加入当前群聊。'
}
}
const memberMessage: Message = {
id: 'member-1',
from: 'member',
type: '普通文本',
datetime: '2026-08-11 10:00:00',
content: '收到',
name: '测试成员',
isSender: false
}
expect(summarySender(systemMessage, null, true)).toBe('微信系统消息')
const input = await buildGroupReportInput([systemMessage, memberMessage], null, true, 'full')
expect(input.metadata.activeUsers).toBe(1)
expect(input.topSpeakers).toEqual([{ name: '测试成员', count: 1 }])
expect(input.prompt).toContain('微信系统消息:由于账号安全原因,无法加入当前群聊。')
})
it('falls back to topic keywords when the model omits top-level keywords', () => {
const report = parseGroupDailyReport(
JSON.stringify({