diff --git a/README.md b/README.md index 6a97826..bec1328 100644 --- a/README.md +++ b/README.md @@ -96,22 +96,6 @@ npm install npm run dev ``` -## 构建状态 - -用于开发者排查发布链路,普通用户可忽略: - -
- ## 致谢 - [密语 CipherTalk](https://github.com/ILoveBingLu/miyu) 为本项目提供了基础框架 diff --git a/electron/main.ts b/electron/main.ts index 48d18de..dca37dc 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -2363,6 +2363,21 @@ function registerIpcHandlers() { return chatService.searchMessages(keyword, sessionId, limit, offset, beginTimestamp, endTimestamp) }) + ipcMain.handle('chat:getMyFootprintStats', async (_, beginTimestamp: number, endTimestamp: number, options?: { + myWxid?: string + privateSessionIds?: string[] + groupSessionIds?: string[] + mentionLimit?: number + privateLimit?: number + mentionMode?: 'text_at_me' | string + }) => { + return chatService.getMyFootprintStats(beginTimestamp, endTimestamp, options) + }) + + ipcMain.handle('chat:exportMyFootprint', async (_, beginTimestamp: number, endTimestamp: number, format: 'csv' | 'json', filePath: string) => { + return chatService.exportMyFootprint(beginTimestamp, endTimestamp, format, filePath) + }) + ipcMain.handle('sns:getTimeline', async (_, limit: number, offset: number, usernames?: string[], keyword?: string, startTime?: number, endTime?: number) => { return snsService.getTimeline(limit, offset, usernames, keyword, startTime, endTime) }) diff --git a/electron/preload.ts b/electron/preload.ts index 48564f1..9e45516 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -258,6 +258,24 @@ contextBridge.exposeInMainWorld('electronAPI', { ipcRenderer.invoke('chat:getMessage', sessionId, localId), searchMessages: (keyword: string, sessionId?: string, limit?: number, offset?: number, beginTimestamp?: number, endTimestamp?: number) => ipcRenderer.invoke('chat:searchMessages', keyword, sessionId, limit, offset, beginTimestamp, endTimestamp), + getMyFootprintStats: ( + beginTimestamp: number, + endTimestamp: number, + options?: { + myWxid?: string + privateSessionIds?: string[] + groupSessionIds?: string[] + mentionLimit?: number + privateLimit?: number + mentionMode?: 'text_at_me' | string + } + ) => ipcRenderer.invoke('chat:getMyFootprintStats', beginTimestamp, endTimestamp, options), + exportMyFootprint: ( + beginTimestamp: number, + endTimestamp: number, + format: 'csv' | 'json', + filePath: string + ) => ipcRenderer.invoke('chat:exportMyFootprint', beginTimestamp, endTimestamp, format, filePath), onWcdbChange: (callback: (event: any, data: { type: string; json: string }) => void) => { ipcRenderer.on('wcdb-change', callback) return () => ipcRenderer.removeListener('wcdb-change', callback) diff --git a/electron/services/chatService.ts b/electron/services/chatService.ts index 24da2ca..90f2555 100644 --- a/electron/services/chatService.ts +++ b/electron/services/chatService.ts @@ -232,6 +232,99 @@ interface SessionDetailExtra { type SessionDetail = SessionDetailFast & SessionDetailExtra +interface MyFootprintSummary { + private_inbound_people: number + private_replied_people: number + private_outbound_people: number + private_reply_rate: number + mention_count: number + mention_group_count: number +} + +interface MyFootprintPrivateSession { + session_id: string + incoming_count: number + outgoing_count: number + replied: boolean + first_incoming_ts: number + first_reply_ts: number + latest_ts: number + anchor_local_id: number + anchor_create_time: number + displayName?: string + avatarUrl?: string +} + +interface MyFootprintPrivateSegment { + session_id: string + segment_index: number + start_ts: number + end_ts: number + duration_sec: number + incoming_count: number + outgoing_count: number + message_count: number + replied: boolean + first_incoming_ts: number + first_reply_ts: number + latest_ts: number + anchor_local_id: number + anchor_create_time: number + displayName?: string + avatarUrl?: string +} + +interface MyFootprintMentionItem { + session_id: string + local_id: number + create_time: number + sender_username: string + message_content: string + source: string + sessionDisplayName?: string + senderDisplayName?: string + senderAvatarUrl?: string +} + +interface MyFootprintMentionGroup { + session_id: string + count: number + latest_ts: number + displayName?: string + avatarUrl?: string +} + +interface MyFootprintDiagnostics { + truncated: boolean + scanned_dbs: number + elapsed_ms: number + mention_truncated?: boolean + private_truncated?: boolean + native_ms?: number + source_filter_ms?: number + fallback_ms?: number + enrich_ms?: number + pipeline_ms?: number + fallback_used?: boolean + private_limit_effective?: number + mention_candidate_limit?: number + native_mention_candidates?: number + source_filtered_mentions?: number + private_session_count?: number + group_session_count?: number + native_passes?: number + native_group_chunks?: number +} + +interface MyFootprintData { + summary: MyFootprintSummary + private_sessions: MyFootprintPrivateSession[] + private_segments: MyFootprintPrivateSegment[] + mentions: MyFootprintMentionItem[] + mention_groups: MyFootprintMentionGroup[] + diagnostics: MyFootprintDiagnostics +} + // 表情包缓存 const emojiCache: Map范围:{currentRange.label}
+{error}
+ +最上方是时间区间开始,最下方是时间区间终点,中间按时间展示群聊 @我 与私聊分段会话节点。
+{exportModalDescription}
+ {exportModalPath &&{exportModalPath}}
+ {exportModalStatus !== 'progress' && (
+