mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-05-26 00:20:26 +08:00
482 lines
13 KiB
TypeScript
482 lines
13 KiB
TypeScript
/**
|
|
* 聊天记录 API - 导入、分析、管理聊天记录
|
|
*/
|
|
import { ipcRenderer } from 'electron'
|
|
import type { AnalysisSession, MessageType, ImportProgress } from '../../../src/types/base'
|
|
import type {
|
|
MemberActivity,
|
|
MemberNameHistory,
|
|
HourlyActivity,
|
|
DailyActivity,
|
|
WeekdayActivity,
|
|
MonthlyActivity,
|
|
RepeatAnalysis,
|
|
CatchphraseAnalysis,
|
|
NightOwlAnalysis,
|
|
DragonKingAnalysis,
|
|
DivingAnalysis,
|
|
MentionAnalysis,
|
|
LaughAnalysis,
|
|
CheckInAnalysis,
|
|
MemeBattleAnalysis,
|
|
MemberWithStats,
|
|
} from '../../../src/types/analysis'
|
|
import type { FileParseInfo, ConflictCheckResult, MergeParams, MergeResult } from '../../../src/types/format'
|
|
|
|
// Chat Analysis API
|
|
export const chatApi = {
|
|
// ==================== 数据库迁移 ====================
|
|
|
|
/**
|
|
* 检查是否需要数据库迁移
|
|
*/
|
|
checkMigration: (): Promise<{
|
|
needsMigration: boolean
|
|
count: number
|
|
currentVersion: number
|
|
pendingMigrations: Array<{ version: number; userMessage: string }>
|
|
}> => {
|
|
return ipcRenderer.invoke('chat:checkMigration')
|
|
},
|
|
|
|
/**
|
|
* 执行数据库迁移
|
|
*/
|
|
runMigration: (): Promise<{ success: boolean; migratedCount: number; error?: string }> => {
|
|
return ipcRenderer.invoke('chat:runMigration')
|
|
},
|
|
|
|
// ==================== 聊天记录导入与分析 ====================
|
|
|
|
/**
|
|
* 选择聊天记录文件
|
|
*/
|
|
selectFile: (): Promise<{ filePath?: string; format?: string; error?: string } | null> => {
|
|
return ipcRenderer.invoke('chat:selectFile')
|
|
},
|
|
|
|
/**
|
|
* 导入聊天记录
|
|
*/
|
|
import: (filePath: string): Promise<{ success: boolean; sessionId?: string; error?: string }> => {
|
|
return ipcRenderer.invoke('chat:import', filePath)
|
|
},
|
|
|
|
/**
|
|
* 获取所有分析会话列表
|
|
*/
|
|
getSessions: (): Promise<AnalysisSession[]> => {
|
|
return ipcRenderer.invoke('chat:getSessions')
|
|
},
|
|
|
|
/**
|
|
* 获取单个会话信息
|
|
*/
|
|
getSession: (sessionId: string): Promise<AnalysisSession | null> => {
|
|
return ipcRenderer.invoke('chat:getSession', sessionId)
|
|
},
|
|
|
|
/**
|
|
* 删除会话
|
|
*/
|
|
deleteSession: (sessionId: string): Promise<boolean> => {
|
|
return ipcRenderer.invoke('chat:deleteSession', sessionId)
|
|
},
|
|
|
|
/**
|
|
* 重命名会话
|
|
*/
|
|
renameSession: (sessionId: string, newName: string): Promise<boolean> => {
|
|
return ipcRenderer.invoke('chat:renameSession', sessionId, newName)
|
|
},
|
|
|
|
/**
|
|
* 获取可用年份列表
|
|
*/
|
|
getAvailableYears: (sessionId: string): Promise<number[]> => {
|
|
return ipcRenderer.invoke('chat:getAvailableYears', sessionId)
|
|
},
|
|
|
|
/**
|
|
* 获取成员活跃度排行
|
|
*/
|
|
getMemberActivity: (sessionId: string, filter?: { startTs?: number; endTs?: number }): Promise<MemberActivity[]> => {
|
|
return ipcRenderer.invoke('chat:getMemberActivity', sessionId, filter)
|
|
},
|
|
|
|
/**
|
|
* 获取成员历史昵称
|
|
*/
|
|
getMemberNameHistory: (sessionId: string, memberId: number): Promise<MemberNameHistory[]> => {
|
|
return ipcRenderer.invoke('chat:getMemberNameHistory', sessionId, memberId)
|
|
},
|
|
|
|
/**
|
|
* 获取每小时活跃度分布
|
|
*/
|
|
getHourlyActivity: (sessionId: string, filter?: { startTs?: number; endTs?: number }): Promise<HourlyActivity[]> => {
|
|
return ipcRenderer.invoke('chat:getHourlyActivity', sessionId, filter)
|
|
},
|
|
|
|
/**
|
|
* 获取每日活跃度趋势
|
|
*/
|
|
getDailyActivity: (sessionId: string, filter?: { startTs?: number; endTs?: number }): Promise<DailyActivity[]> => {
|
|
return ipcRenderer.invoke('chat:getDailyActivity', sessionId, filter)
|
|
},
|
|
|
|
/**
|
|
* 获取星期活跃度分布
|
|
*/
|
|
getWeekdayActivity: (
|
|
sessionId: string,
|
|
filter?: { startTs?: number; endTs?: number }
|
|
): Promise<WeekdayActivity[]> => {
|
|
return ipcRenderer.invoke('chat:getWeekdayActivity', sessionId, filter)
|
|
},
|
|
|
|
/**
|
|
* 获取月份活跃度分布
|
|
*/
|
|
getMonthlyActivity: (
|
|
sessionId: string,
|
|
filter?: { startTs?: number; endTs?: number }
|
|
): Promise<MonthlyActivity[]> => {
|
|
return ipcRenderer.invoke('chat:getMonthlyActivity', sessionId, filter)
|
|
},
|
|
|
|
/**
|
|
* 获取年份活跃度分布
|
|
*/
|
|
getYearlyActivity: (
|
|
sessionId: string,
|
|
filter?: { startTs?: number; endTs?: number }
|
|
): Promise<Array<{ year: number; messageCount: number }>> => {
|
|
return ipcRenderer.invoke('chat:getYearlyActivity', sessionId, filter)
|
|
},
|
|
|
|
/**
|
|
* 获取消息长度分布
|
|
*/
|
|
getMessageLengthDistribution: (
|
|
sessionId: string,
|
|
filter?: { startTs?: number; endTs?: number }
|
|
): Promise<{
|
|
detail: Array<{ len: number; count: number }>
|
|
grouped: Array<{ range: string; count: number }>
|
|
}> => {
|
|
return ipcRenderer.invoke('chat:getMessageLengthDistribution', sessionId, filter)
|
|
},
|
|
|
|
/**
|
|
* 获取消息类型分布
|
|
*/
|
|
getMessageTypeDistribution: (
|
|
sessionId: string,
|
|
filter?: { startTs?: number; endTs?: number }
|
|
): Promise<Array<{ type: MessageType; count: number }>> => {
|
|
return ipcRenderer.invoke('chat:getMessageTypeDistribution', sessionId, filter)
|
|
},
|
|
|
|
/**
|
|
* 获取时间范围
|
|
*/
|
|
getTimeRange: (sessionId: string): Promise<{ start: number; end: number } | null> => {
|
|
return ipcRenderer.invoke('chat:getTimeRange', sessionId)
|
|
},
|
|
|
|
/**
|
|
* 获取数据库存储目录
|
|
*/
|
|
getDbDirectory: (): Promise<string | null> => {
|
|
return ipcRenderer.invoke('chat:getDbDirectory')
|
|
},
|
|
|
|
/**
|
|
* 获取支持的格式列表
|
|
*/
|
|
getSupportedFormats: (): Promise<Array<{ name: string; platform: string }>> => {
|
|
return ipcRenderer.invoke('chat:getSupportedFormats')
|
|
},
|
|
|
|
/**
|
|
* 监听导入进度
|
|
*/
|
|
onImportProgress: (callback: (progress: ImportProgress) => void) => {
|
|
const handler = (_event: Electron.IpcRendererEvent, progress: ImportProgress) => {
|
|
callback(progress)
|
|
}
|
|
ipcRenderer.on('chat:importProgress', handler)
|
|
return () => {
|
|
ipcRenderer.removeListener('chat:importProgress', handler)
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 获取复读分析数据
|
|
*/
|
|
getRepeatAnalysis: (sessionId: string, filter?: { startTs?: number; endTs?: number }): Promise<RepeatAnalysis> => {
|
|
return ipcRenderer.invoke('chat:getRepeatAnalysis', sessionId, filter)
|
|
},
|
|
|
|
/**
|
|
* 获取口头禅分析数据
|
|
*/
|
|
getCatchphraseAnalysis: (
|
|
sessionId: string,
|
|
filter?: { startTs?: number; endTs?: number }
|
|
): Promise<CatchphraseAnalysis> => {
|
|
return ipcRenderer.invoke('chat:getCatchphraseAnalysis', sessionId, filter)
|
|
},
|
|
|
|
/**
|
|
* 获取夜猫分析数据
|
|
*/
|
|
getNightOwlAnalysis: (
|
|
sessionId: string,
|
|
filter?: { startTs?: number; endTs?: number }
|
|
): Promise<NightOwlAnalysis> => {
|
|
return ipcRenderer.invoke('chat:getNightOwlAnalysis', sessionId, filter)
|
|
},
|
|
|
|
/**
|
|
* 获取龙王分析数据
|
|
*/
|
|
getDragonKingAnalysis: (
|
|
sessionId: string,
|
|
filter?: { startTs?: number; endTs?: number }
|
|
): Promise<DragonKingAnalysis> => {
|
|
return ipcRenderer.invoke('chat:getDragonKingAnalysis', sessionId, filter)
|
|
},
|
|
|
|
/**
|
|
* 获取潜水分析数据
|
|
*/
|
|
getDivingAnalysis: (sessionId: string, filter?: { startTs?: number; endTs?: number }): Promise<DivingAnalysis> => {
|
|
return ipcRenderer.invoke('chat:getDivingAnalysis', sessionId, filter)
|
|
},
|
|
|
|
/**
|
|
* 获取 @ 互动分析数据
|
|
*/
|
|
getMentionAnalysis: (sessionId: string, filter?: { startTs?: number; endTs?: number }): Promise<MentionAnalysis> => {
|
|
return ipcRenderer.invoke('chat:getMentionAnalysis', sessionId, filter)
|
|
},
|
|
|
|
/**
|
|
* 获取 @ 互动关系图数据
|
|
*/
|
|
getMentionGraph: (
|
|
sessionId: string,
|
|
filter?: { startTs?: number; endTs?: number }
|
|
): Promise<{
|
|
nodes: Array<{ id: number; name: string; value: number; symbolSize: number }>
|
|
links: Array<{ source: string; target: string; value: number }>
|
|
maxLinkValue: number
|
|
}> => {
|
|
return ipcRenderer.invoke('chat:getMentionGraph', sessionId, filter)
|
|
},
|
|
|
|
/**
|
|
* 获取含笑量分析数据
|
|
*/
|
|
getLaughAnalysis: (
|
|
sessionId: string,
|
|
filter?: { startTs?: number; endTs?: number },
|
|
keywords?: string[]
|
|
): Promise<LaughAnalysis> => {
|
|
return ipcRenderer.invoke('chat:getLaughAnalysis', sessionId, filter, keywords)
|
|
},
|
|
|
|
/**
|
|
* 获取斗图分析数据
|
|
*/
|
|
getMemeBattleAnalysis: (
|
|
sessionId: string,
|
|
filter?: { startTs?: number; endTs?: number }
|
|
): Promise<MemeBattleAnalysis> => {
|
|
return ipcRenderer.invoke('chat:getMemeBattleAnalysis', sessionId, filter)
|
|
},
|
|
|
|
/**
|
|
* 获取打卡分析数据(火花榜 + 忠臣榜)
|
|
*/
|
|
getCheckInAnalysis: (sessionId: string, filter?: { startTs?: number; endTs?: number }): Promise<CheckInAnalysis> => {
|
|
return ipcRenderer.invoke('chat:getCheckInAnalysis', sessionId, filter)
|
|
},
|
|
|
|
// ==================== 成员管理 ====================
|
|
|
|
/**
|
|
* 获取所有成员列表(含消息数和别名)
|
|
*/
|
|
getMembers: (sessionId: string): Promise<MemberWithStats[]> => {
|
|
return ipcRenderer.invoke('chat:getMembers', sessionId)
|
|
},
|
|
|
|
/**
|
|
* 获取成员列表(分页版本)
|
|
*/
|
|
getMembersPaginated: (
|
|
sessionId: string,
|
|
params: { page: number; pageSize: number; search?: string; sortOrder?: 'asc' | 'desc' }
|
|
): Promise<{
|
|
members: MemberWithStats[]
|
|
total: number
|
|
page: number
|
|
pageSize: number
|
|
totalPages: number
|
|
}> => {
|
|
return ipcRenderer.invoke('chat:getMembersPaginated', sessionId, params)
|
|
},
|
|
|
|
/**
|
|
* 更新成员别名
|
|
*/
|
|
updateMemberAliases: (sessionId: string, memberId: number, aliases: string[]): Promise<boolean> => {
|
|
return ipcRenderer.invoke('chat:updateMemberAliases', sessionId, memberId, aliases)
|
|
},
|
|
|
|
/**
|
|
* 删除成员及其所有消息
|
|
*/
|
|
deleteMember: (sessionId: string, memberId: number): Promise<boolean> => {
|
|
return ipcRenderer.invoke('chat:deleteMember', sessionId, memberId)
|
|
},
|
|
|
|
/**
|
|
* 更新会话的所有者(ownerId)
|
|
* @param ownerId 成员的 platformId,设置为 null 则清除
|
|
*/
|
|
updateSessionOwnerId: (sessionId: string, ownerId: string | null): Promise<boolean> => {
|
|
return ipcRenderer.invoke('chat:updateSessionOwnerId', sessionId, ownerId)
|
|
},
|
|
|
|
// ==================== SQL 实验室 ====================
|
|
|
|
/**
|
|
* 执行用户 SQL 查询
|
|
*/
|
|
executeSQL: (
|
|
sessionId: string,
|
|
sql: string
|
|
): Promise<{
|
|
columns: string[]
|
|
rows: any[][]
|
|
rowCount: number
|
|
duration: number
|
|
limited: boolean
|
|
}> => {
|
|
return ipcRenderer.invoke('chat:executeSQL', sessionId, sql)
|
|
},
|
|
|
|
/**
|
|
* 获取数据库 Schema
|
|
*/
|
|
getSchema: (
|
|
sessionId: string
|
|
): Promise<
|
|
Array<{
|
|
name: string
|
|
columns: Array<{
|
|
name: string
|
|
type: string
|
|
notnull: boolean
|
|
pk: boolean
|
|
}>
|
|
}>
|
|
> => {
|
|
return ipcRenderer.invoke('chat:getSchema', sessionId)
|
|
},
|
|
|
|
// ==================== 增量导入 ====================
|
|
|
|
/**
|
|
* 分析增量导入(检测去重后能新增多少消息)
|
|
*/
|
|
analyzeIncrementalImport: (
|
|
sessionId: string,
|
|
filePath: string
|
|
): Promise<{
|
|
newMessageCount: number
|
|
duplicateCount: number
|
|
totalInFile: number
|
|
error?: string
|
|
diagnosis?: { suggestion?: string }
|
|
}> => {
|
|
return ipcRenderer.invoke('chat:analyzeIncrementalImport', sessionId, filePath)
|
|
},
|
|
|
|
/**
|
|
* 执行增量导入
|
|
*/
|
|
incrementalImport: (
|
|
sessionId: string,
|
|
filePath: string
|
|
): Promise<{
|
|
success: boolean
|
|
newMessageCount: number
|
|
error?: string
|
|
}> => {
|
|
return ipcRenderer.invoke('chat:incrementalImport', sessionId, filePath)
|
|
},
|
|
|
|
/**
|
|
* 导出多个会话为临时文件(用于批量管理中的合并)
|
|
*/
|
|
exportSessionsToTempFiles: (
|
|
sessionIds: string[]
|
|
): Promise<{
|
|
success: boolean
|
|
tempFiles: string[]
|
|
error?: string
|
|
}> => {
|
|
return ipcRenderer.invoke('chat:exportSessionsToTempFiles', sessionIds)
|
|
},
|
|
|
|
/**
|
|
* 清理临时导出文件
|
|
*/
|
|
cleanupTempExportFiles: (
|
|
filePaths: string[]
|
|
): Promise<{
|
|
success: boolean
|
|
error?: string
|
|
}> => {
|
|
return ipcRenderer.invoke('chat:cleanupTempExportFiles', filePaths)
|
|
},
|
|
}
|
|
|
|
// Merge API - 合并功能
|
|
export const mergeApi = {
|
|
/**
|
|
* 解析文件获取基本信息(用于合并预览)
|
|
* 解析后结果会被缓存,后续合并时无需再次读取原始文件
|
|
*/
|
|
parseFileInfo: (filePath: string): Promise<FileParseInfo> => {
|
|
return ipcRenderer.invoke('merge:parseFileInfo', filePath)
|
|
},
|
|
|
|
/**
|
|
* 检测合并冲突
|
|
*/
|
|
checkConflicts: (filePaths: string[]): Promise<ConflictCheckResult> => {
|
|
return ipcRenderer.invoke('merge:checkConflicts', filePaths)
|
|
},
|
|
|
|
/**
|
|
* 执行合并
|
|
*/
|
|
mergeFiles: (params: MergeParams): Promise<MergeResult> => {
|
|
return ipcRenderer.invoke('merge:mergeFiles', params)
|
|
},
|
|
|
|
/**
|
|
* 清理解析缓存
|
|
* @param filePath 可选,指定文件路径则清理该文件的缓存,否则清理所有缓存
|
|
*/
|
|
clearCache: (filePath?: string): Promise<boolean> => {
|
|
return ipcRenderer.invoke('merge:clearCache', filePath)
|
|
},
|
|
}
|