Skip to content

Commit 3a63726

Browse files
feat: implement conversation review feature with IPC integration
- Added ReviewService to handle conversation reviews, including generation and retrieval of review data. - Enhanced IPC handlers to support new review-related commands for generating and fetching reviews. - Updated LLMSuggestionService to save action suggestions to the database, linking them to conversations for review purposes. - Introduced new UI components for displaying and generating conversation reviews, improving user interaction and experience. - Created database schema for storing conversation reviews and added seed data for testing. - Implemented hooks and pages in the renderer for managing and displaying review data effectively.
1 parent 0d1ecf7 commit 3a63726

17 files changed

Lines changed: 1136 additions & 41 deletions

desktop/src/core/modules/ipc-handlers.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import DatabaseManager from '../../db/database.js';
33
import ASRManager from '../../asr/asr-manager.js';
44
import ASRModelManager from '../../asr/model-manager.js';
55
import LLMSuggestionService from './llm-suggestion-service.js';
6+
import ReviewService from './review-service.js';
67
import MemoryService from './memory-service.js';
78
import { registerWindowHandlers } from './ipc-handlers/window-handlers.js';
89
import { registerDatabaseHandlers } from './ipc-handlers/database-handlers.js';
910
import { registerLLMHandlers } from './ipc-handlers/llm-handlers.js';
1011
import { registerSuggestionHandlers } from './ipc-handlers/suggestion-handlers.js';
12+
import { registerReviewHandlers } from './ipc-handlers/review-handlers.js';
1113
import { registerMemoryHandlers } from './ipc-handlers/memory-handlers.js';
1214
import { registerASRModelHandlers } from './ipc-handlers/asr-model-handlers.js';
1315
import { registerASRAudioHandlers } from './ipc-handlers/asr-audio-handlers.js';
@@ -23,6 +25,7 @@ export class IPCManager {
2325
this.modelManager = null;
2426
this.asrManager = null;
2527
this.llmSuggestionService = null;
28+
this.reviewService = null;
2629
this.memoryService = null;
2730
this.asrModelPreloading = false;
2831
this.asrModelPreloaded = false;
@@ -78,6 +81,14 @@ export class IPCManager {
7881
this.memoryService = new MemoryService();
7982
}
8083
}
84+
/**
85+
* 初始化 Review Service
86+
*/
87+
initReviewService() {
88+
if (!this.reviewService) {
89+
this.reviewService = new ReviewService(() => this.db);
90+
}
91+
}
8192

8293
/**
8394
* 注册所有 IPC 处理器
@@ -88,11 +99,13 @@ export class IPCManager {
8899
this.initDatabase();
89100
this.initModelManager();
90101
this.initLLMSuggestionService();
102+
this.initReviewService();
91103
this.initMemoryService();
92104
this.setupWindowHandlers();
93105
this.setupDatabaseHandlers();
94106
this.setupLLMHandlers();
95107
this.setupSuggestionHandlers();
108+
this.setupReviewHandlers();
96109
this.setupMemoryHandlers();
97110
this.setupASRModelHandlers();
98111
this.setupASRAudioHandlers();
@@ -101,6 +114,15 @@ export class IPCManager {
101114
console.log('[IPCHandlers] All IPC handlers registered successfully');
102115
}
103116

117+
/**
118+
* 设置复盘相关 IPC 处理器
119+
*/
120+
setupReviewHandlers() {
121+
registerReviewHandlers({
122+
reviewService: this.reviewService
123+
});
124+
}
125+
104126
/**
105127
* 设置窗口相关 IPC 处理器
106128
*/

desktop/src/core/modules/ipc-handlers/database-handlers.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,15 @@ export function registerDatabaseHandlers({ db }) {
127127
}
128128
});
129129

130+
ipcMain.handle('db-get-conversation-by-id', (event, conversationId) => {
131+
try {
132+
return db.getConversationById(conversationId);
133+
} catch (error) {
134+
console.error('Error getting conversation by id:', error);
135+
return null;
136+
}
137+
});
138+
130139
ipcMain.handle('db-update-message', (event, messageId, updates) => {
131140
try {
132141
return db.updateMessage(messageId, updates);
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
2+
import { ipcMain } from 'electron';
3+
4+
export function registerReviewHandlers({ reviewService }) {
5+
if (!reviewService) {
6+
console.error('[IPC] ReviewService is required for review handlers');
7+
return;
8+
}
9+
10+
// 生成复盘
11+
ipcMain.handle('review:generate', async (event, payload) => {
12+
try {
13+
const { conversationId, force = false } =
14+
typeof payload === 'object' && payload !== null
15+
? payload
16+
: { conversationId: payload, force: false };
17+
18+
if (!conversationId) {
19+
throw new Error('conversationId is required');
20+
}
21+
22+
console.log(`[IPC] Handling review:generate for conversation ${conversationId}, force=${force}`);
23+
const review = await reviewService.generateReview(conversationId, { force });
24+
return { success: true, data: review };
25+
} catch (error) {
26+
console.error(`[IPC] review:generate failed:`, error);
27+
return { success: false, error: error.message };
28+
}
29+
});
30+
31+
// 获取复盘
32+
ipcMain.handle('review:get', async (event, conversationId) => {
33+
try {
34+
console.log(`[IPC] Handling review:get for conversation ${conversationId}`);
35+
const review = reviewService.getExistingReview(conversationId);
36+
return { success: true, data: review };
37+
} catch (error) {
38+
console.error(`[IPC] review:get failed:`, error);
39+
return { success: false, error: error.message };
40+
}
41+
});
42+
}

desktop/src/core/modules/llm-suggestion-service.js

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,14 @@ export default class LLMSuggestionService {
159159
let totalContentLength = 0;
160160
let rawStreamContent = '';
161161

162+
// 记录批次时间戳,同一批次的所有建议使用相同的时间戳
163+
const batchTimestamp = Date.now();
164+
165+
// 获取最新的消息ID(用于关联suggestion)
166+
const latestMessageId = context.history && context.history.length > 0
167+
? context.history[context.history.length - 1]?.id || null
168+
: null;
169+
162170
console.log('[LLMSuggestionService] Creating TOON parser');
163171
const parser = createToonSuggestionStreamParser({
164172
onHeader: (header) => {
@@ -174,10 +182,22 @@ export default class LLMSuggestionService {
174182
onSuggestion: (item) => {
175183
console.log(`[LLMSuggestionService] Parser received suggestion #${emittedCount + 1}:`, item);
176184
const suggestionIndex = emittedCount;
177-
const suggestion = this.decorateSuggestion(item, emittedCount, { trigger, reason });
185+
const suggestion = this.decorateSuggestion(item, emittedCount, { trigger, reason }, batchTimestamp);
178186
suggestion.index = suggestionIndex;
179187
console.log(`[LLMSuggestionService] Decorated suggestion:`, suggestion);
180188
emittedCount += 1;
189+
190+
// 保存suggestion到数据库
191+
if (conversationId && this.db.saveActionSuggestion) {
192+
try {
193+
this.db.saveActionSuggestion(suggestion, conversationId, latestMessageId);
194+
console.log(`[LLMSuggestionService] Saved suggestion to database: ${suggestion.id}`);
195+
} catch (error) {
196+
console.error('[LLMSuggestionService] Failed to save suggestion to database:', error);
197+
// 不阻断流程,继续执行
198+
}
199+
}
200+
181201
handlers.onSuggestion?.(suggestion);
182202
},
183203
onError: (error) => {
@@ -406,8 +426,11 @@ export default class LLMSuggestionService {
406426
}
407427
}
408428

409-
decorateSuggestion(item, index, { trigger, reason }) {
410-
const suggestionId = `llm-suggestion-${Date.now()}-${index}`;
429+
decorateSuggestion(item, index, { trigger, reason }, batchTimestamp = null) {
430+
// 使用批次时间戳,确保同一批次的所有建议使用相同的时间戳
431+
// 如果没有提供批次时间戳,则使用当前时间(向后兼容)
432+
const timestamp = batchTimestamp || Date.now();
433+
const suggestionId = `llm-suggestion-${timestamp}-${index}`;
411434
const tags = Array.isArray(item.tags)
412435
? item.tags.slice(0, 3)
413436
: typeof item.tags === 'string'
@@ -421,7 +444,8 @@ export default class LLMSuggestionService {
421444
tags,
422445
// affinity_hint: item.affinity_hint || null,
423446
trigger,
424-
reason
447+
reason,
448+
created_at: timestamp // 使用批次时间戳,确保同一批次的所有建议使用相同的时间戳
425449
};
426450
}
427451

0 commit comments

Comments
 (0)