feat(import): update demo data sources to 4 files

Switch from 2 demo files (group + private) to 4 files:
- demo-group.json
- demo-private-A-cuilan.json
- demo-private-B-wukong.json
- demo-private-C-spider.json

Update DemoImportResult.privateSessionId to privateSessionIds array
to support multiple private chat demos.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
diguaandCursor committed 2026-05-30 14:19:42 +08:00
1 parent b3c2b20a9f
commit fdb6d8f648
6 files changed
+65 -50

No files matched your search

+31 -23
View File
@@ -307,9 +307,17 @@ export function registerImportRoutes(server: FastifyInstance, dbManager: Databas
// ==================== Demo Import ====================
const DEMO_FILES = [
'demo-group.json',
'demo-private-A-cuilan.json',
'demo-private-B-wukong.json',
'demo-private-C-spider.json',
]
server.post<{ Body: { locale?: string } }>('/_web/demo/import', async (request, reply) => {
const locale = (request.body as any)?.locale || 'en'
const nativeBinding = resolveNativeBinding()
const total = DEMO_FILES.length
reply.raw.writeHead(200, {
'Content-Type': 'text/event-stream',
@@ -322,41 +330,41 @@ export function registerImportRoutes(server: FastifyInstance, dbManager: Databas
}
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'chatlab-demo-'))
const groupPath = path.join(tmpDir, 'demo-group.json')
const privatePath = path.join(tmpDir, 'demo-private.json')
try {
sendEvent('progress', { stage: 'downloading', current: 1, total: 2 })
const groupResp = await fetch(`${DEMO_BASE_URL}/${locale}/demo-group.json`, {
signal: AbortSignal.timeout(60_000),
})
if (!groupResp.ok) throw new Error(`Download group demo failed: ${groupResp.status}`)
fs.writeFileSync(groupPath, Buffer.from(await groupResp.arrayBuffer()))
const localPaths: string[] = []
for (let i = 0; i < total; i++) {
sendEvent('progress', { stage: 'downloading', current: i + 1, total })
const localPath = path.join(tmpDir, DEMO_FILES[i])
const resp = await fetch(`${DEMO_BASE_URL}/${locale}/${DEMO_FILES[i]}`, {
signal: AbortSignal.timeout(60_000),
})
if (!resp.ok) throw new Error(`Download demo failed (${DEMO_FILES[i]}): ${resp.status}`)
fs.writeFileSync(localPath, Buffer.from(await resp.arrayBuffer()))
localPaths.push(localPath)
}
sendEvent('progress', { stage: 'downloading', current: 2, total: 2 })
const privateResp = await fetch(`${DEMO_BASE_URL}/${locale}/demo-private.json`, {
signal: AbortSignal.timeout(60_000),
})
if (!privateResp.ok) throw new Error(`Download private demo failed: ${privateResp.status}`)
fs.writeFileSync(privatePath, Buffer.from(await privateResp.arrayBuffer()))
sendEvent('progress', { stage: 'importing', current: 1, total: 2 })
const groupResult = await streamImport(dbManager, groupPath, { nativeBinding })
sendEvent('progress', { stage: 'importing', current: 1, total })
const groupResult = await streamImport(dbManager, localPaths[0], { nativeBinding })
if (!groupResult.success) throw new Error(groupResult.error || 'Failed to import group demo')
sendEvent('progress', { stage: 'importing', current: 2, total: 2 })
const privateResult = await streamImport(dbManager, privatePath, { nativeBinding })
if (!privateResult.success) throw new Error(privateResult.error || 'Failed to import private demo')
const privateSessionIds: string[] = []
for (let i = 1; i < localPaths.length; i++) {
sendEvent('progress', { stage: 'importing', current: i + 1, total })
const result = await streamImport(dbManager, localPaths[i], { nativeBinding })
if (!result.success) throw new Error(result.error || `Failed to import private demo: ${DEMO_FILES[i]}`)
if (result.sessionId) privateSessionIds.push(result.sessionId)
}
sendEvent('progress', { stage: 'done', current: 2, total: 2 })
sendEvent('progress', { stage: 'done', current: total, total })
sendEvent('result', {
success: true,
groupSessionId: groupResult.sessionId,
privateSessionId: privateResult.sessionId,
privateSessionIds,
})
} catch (err) {
const message = err instanceof Error ? err.message : String(err)
sendEvent('progress', { stage: 'error', current: 0, total: 2, message })
sendEvent('progress', { stage: 'error', current: 0, total, message })
sendEvent('result', { success: false, error: message })
} finally {
reply.raw.end()
+29 -22
View File
@@ -60,6 +60,13 @@ export function registerDemoHandlers(ctx: IpcContext): void {
* 下载并导入 Demo 示例数据
* 返回群聊和私聊的 sessionId
*/
const DEMO_FILES = [
'demo-group.json',
'demo-private-A-cuilan.json',
'demo-private-B-wukong.json',
'demo-private-C-spider.json',
]
ipcMain.handle(
'demo:downloadAndImport',
async (
@@ -68,52 +75,52 @@ export function registerDemoHandlers(ctx: IpcContext): void {
): Promise<{
success: boolean
groupSessionId?: string
privateSessionId?: string
privateSessionIds?: string[]
error?: string
}> => {
const tempDir = getDemoTempDir()
const groupPath = path.join(tempDir, 'demo-group.json')
const privatePath = path.join(tempDir, 'demo-private.json')
const total = DEMO_FILES.length
const sendProgress = (progress: DemoProgress) => {
win.webContents.send('demo:progress', progress)
}
try {
// Phase 1: Download
sendProgress({ stage: 'downloading', current: 1, total: 2 })
await downloadFile(`${DEMO_BASE_URL}/${locale}/demo-group.json`, groupPath)
sendProgress({ stage: 'downloading', current: 2, total: 2 })
await downloadFile(`${DEMO_BASE_URL}/${locale}/demo-private.json`, privatePath)
// Phase 2: Import group chat
sendProgress({ stage: 'importing', current: 1, total: 2 })
const groupResult = await worker.streamImport(groupPath)
const localPaths: string[] = []
for (let i = 0; i < total; i++) {
sendProgress({ stage: 'downloading', current: i + 1, total })
const localPath = path.join(tempDir, DEMO_FILES[i])
await downloadFile(`${DEMO_BASE_URL}/${locale}/${DEMO_FILES[i]}`, localPath)
localPaths.push(localPath)
}
sendProgress({ stage: 'importing', current: 1, total })
const groupResult = await worker.streamImport(localPaths[0])
if (!groupResult.success || !groupResult.sessionId) {
throw new Error(groupResult.error || 'Failed to import group demo')
}
// Phase 3: Import private chat
sendProgress({ stage: 'importing', current: 2, total: 2 })
const privateResult = await worker.streamImport(privatePath)
if (!privateResult.success || !privateResult.sessionId) {
throw new Error(privateResult.error || 'Failed to import private demo')
const privateSessionIds: string[] = []
for (let i = 1; i < localPaths.length; i++) {
sendProgress({ stage: 'importing', current: i + 1, total })
const result = await worker.streamImport(localPaths[i])
if (!result.success || !result.sessionId) {
throw new Error(result.error || `Failed to import private demo: ${DEMO_FILES[i]}`)
}
privateSessionIds.push(result.sessionId)
}
sendProgress({ stage: 'done', current: 2, total: 2 })
sendProgress({ stage: 'done', current: total, total })
return {
success: true,
groupSessionId: groupResult.sessionId,
privateSessionId: privateResult.sessionId,
privateSessionIds,
}
} catch (error) {
const message = error instanceof Error ? error.message : String(error)
console.error('[Demo] Download and import failed:', message)
sendProgress({ stage: 'error', current: 0, total: 2, message })
sendProgress({ stage: 'error', current: 0, total, message })
return { success: false, error: message }
} finally {
cleanupDemoTemp(tempDir)
+1 -1
View File
@@ -501,7 +501,7 @@ export const chatApi = {
): Promise<{
success: boolean
groupSessionId?: string
privateSessionId?: string
privateSessionIds?: string[]
error?: string
}> => {
return ipcRenderer.invoke('demo:downloadAndImport', locale)
+1 -1
View File
@@ -198,7 +198,7 @@ interface ChatApi {
importDemo: (locale: string) => Promise<{
success: boolean
groupSessionId?: string
privateSessionId?: string
privateSessionIds?: string[]
error?: string
}>