feat: 移除一些废弃逻辑

This commit is contained in:
digua
2025-12-06 13:14:20 +08:00
parent cd2dc0b8db
commit 2048d5d70d
7 changed files with 57 additions and 554 deletions
-50
View File
@@ -305,56 +305,6 @@ export function hasActiveConfig(): boolean {
return config !== null
}
// ==================== 兼容旧 APIdeprecated====================
/**
* @deprecated 使用 loadConfigStore 代替
*/
export function loadLLMConfig(): LegacyStoredConfig | null {
const activeConfig = getActiveConfig()
if (!activeConfig) return null
return {
provider: activeConfig.provider,
apiKey: activeConfig.apiKey,
model: activeConfig.model,
maxTokens: activeConfig.maxTokens,
}
}
/**
* @deprecated 使用 addConfig 或 updateConfig 代替
*/
export function saveLLMConfig(config: LegacyStoredConfig): void {
const store = loadConfigStore()
// 如果有激活配置,更新它;否则创建新的
if (store.activeConfigId) {
updateConfig(store.activeConfigId, config)
} else {
addConfig({
name: getProviderInfo(config.provider)?.name || config.provider,
...config,
})
}
}
/**
* @deprecated 使用 deleteConfig 代替
*/
export function deleteLLMConfig(): void {
const store = loadConfigStore()
if (store.activeConfigId) {
deleteConfig(store.activeConfigId)
}
}
/**
* @deprecated 使用 hasActiveConfig 代替
*/
export function hasLLMConfig(): boolean {
return hasActiveConfig()
}
/**
* 扩展的 LLM 配置(包含本地服务特有选项)
*/
+54 -110
View File
@@ -236,7 +236,7 @@ export function registerAIHandlers({ win }: IpcContext): void {
*/
ipcMain.handle('llm:deleteConfig', async (_, id?: string) => {
try {
// 兼容旧 API如果没有传 id,删除当前激活的配置
// 如果没有传 id,删除当前激活的配置
if (!id) {
const activeConfig = llm.getActiveConfig()
if (activeConfig) {
@@ -289,63 +289,6 @@ export function registerAIHandlers({ win }: IpcContext): void {
return llm.hasActiveConfig()
})
// ==================== 兼容旧 APIdeprecated====================
/**
* @deprecated 使用 llm:getAllConfigs 代替
* 获取当前 LLM 配置
*/
ipcMain.handle('llm:getConfig', async () => {
const config = llm.getActiveConfig()
if (!config) return null
return {
provider: config.provider,
apiKey: config.apiKey ? `${config.apiKey.slice(0, 8)}...${config.apiKey.slice(-4)}` : '',
apiKeySet: !!config.apiKey,
model: config.model,
baseUrl: config.baseUrl,
maxTokens: config.maxTokens,
}
})
/**
* @deprecated 使用 llm:addConfig 或 llm:updateConfig 代替
* 保存 LLM 配置
*/
ipcMain.handle(
'llm:saveConfig',
async (
_,
config: { provider: llm.LLMProvider; apiKey: string; model?: string; baseUrl?: string; maxTokens?: number }
) => {
try {
const activeConfig = llm.getActiveConfig()
if (activeConfig) {
// 更新现有配置
const updates: Record<string, unknown> = { ...config }
if (!config.apiKey || config.apiKey.trim() === '') {
delete updates.apiKey
}
return llm.updateConfig(activeConfig.id, updates)
} else {
// 创建新配置
if (!config.apiKey || config.apiKey.trim() === '') {
return { success: false, error: '请输入 API Key' }
}
const providerInfo = llm.getProviderInfo(config.provider)
return llm.addConfig({
name: providerInfo?.name || config.provider,
...config,
})
}
} catch (error) {
console.error('保存 LLM 配置失败:', error)
return { success: false, error: String(error) }
}
}
)
/**
* 发送 LLM 聊天请求(非流式)
*/
@@ -468,68 +411,69 @@ export function registerAIHandlers({ win }: IpcContext): void {
promptConfig
)
// 异步执行,通过事件发送流式数据
;(async () => {
try {
const result = await agent.executeStream(userMessage, (chunk: AgentStreamChunk) => {
// 如果已中止,不再发送
// 异步执行,通过事件发送流式数据
;(async () => {
try {
const result = await agent.executeStream(userMessage, (chunk: AgentStreamChunk) => {
// 如果已中止,不再发送
if (abortController.signal.aborted) {
return
}
// 减少日志噪音:只在工具调用时记录
if (chunk.type === 'tool_start' || chunk.type === 'tool_result') {
aiLogger.debug('IPC', `Agent chunk: ${requestId}`, {
type: chunk.type,
toolName: chunk.toolName,
})
}
win.webContents.send('agent:streamChunk', { requestId, chunk })
})
// 如果已中止,不发送完成信息
if (abortController.signal.aborted) {
aiLogger.info('IPC', `Agent 已中止,跳过完成信息: ${requestId}`)
return
}
// 减少日志噪音:只在工具调用时记录
if (chunk.type === 'tool_start' || chunk.type === 'tool_result') {
aiLogger.debug('IPC', `Agent chunk: ${requestId}`, {
type: chunk.type,
toolName: chunk.toolName,
})
}
win.webContents.send('agent:streamChunk', { requestId, chunk })
})
// 如果已中止,不发送完成信息
if (abortController.signal.aborted) {
aiLogger.info('IPC', `Agent 已中止,跳过完成信息: ${requestId}`)
return
}
// 发送完成信息
win.webContents.send('agent:complete', {
requestId,
result: {
content: result.content,
toolsUsed: result.toolsUsed,
toolRounds: result.toolRounds,
},
})
// 发送完成信息
win.webContents.send('agent:complete', {
requestId,
result: {
content: result.content,
aiLogger.info('IPC', `Agent 执行完成: ${requestId}`, {
toolsUsed: result.toolsUsed,
toolRounds: result.toolRounds,
},
})
aiLogger.info('IPC', `Agent 执行完成: ${requestId}`, {
toolsUsed: result.toolsUsed,
toolRounds: result.toolRounds,
contentLength: result.content.length,
})
} catch (error) {
// 如果是中止错误,不报告为错误
if (error instanceof Error && error.name === 'AbortError') {
aiLogger.info('IPC', `Agent 请求已中止: ${requestId}`)
return
contentLength: result.content.length,
})
} catch (error) {
// 如果是中止错误,不报告为错误
if (error instanceof Error && error.name === 'AbortError') {
aiLogger.info('IPC', `Agent 请求已中止: ${requestId}`)
return
}
aiLogger.error('IPC', `Agent 执行出错: ${requestId}`, { error: String(error) })
win.webContents.send('agent:streamChunk', {
requestId,
chunk: { type: 'error', error: String(error), isFinished: true },
})
} finally {
// 清理请求追踪
activeAgentRequests.delete(requestId)
}
aiLogger.error('IPC', `Agent 执行出错: ${requestId}`, { error: String(error) })
win.webContents.send('agent:streamChunk', {
requestId,
chunk: { type: 'error', error: String(error), isFinished: true },
})
} finally {
// 清理请求追踪
activeAgentRequests.delete(requestId)
}
})()
})()
return { success: true }
} catch (error) {
aiLogger.error('IPC', `创建 Agent 请求失败: ${requestId}`, { error: String(error) })
return { success: false, error: String(error) }
return { success: true }
} catch (error) {
aiLogger.error('IPC', `创建 Agent 请求失败: ${requestId}`, { error: String(error) })
return { success: false, error: String(error) }
}
}
})
)
/**
* 中止 Agent 请求
+3 -306
View File
@@ -86,115 +86,6 @@ function getMessageKey(msg: ParsedMessage): string {
return `${msg.timestamp}_${msg.senderPlatformId}_${(msg.content || '').length}`
}
/**
* 检测合并冲突(使用缓存的解析结果)
* 规则:时间戳 + 用户名 + 字符长度,当两项相同但另一项不同时报告冲突
*/
export async function checkConflictsWithCache(
filePaths: string[],
cache: Map<string, ParseResult>
): Promise<ConflictCheckResult> {
const allMessages: Array<{ msg: ParsedMessage; source: string }> = []
const conflicts: MergeConflict[] = []
console.log('[Merger] checkConflictsWithCache: 开始检测冲突')
console.log(
'[Merger] 文件列表:',
filePaths.map((p) => path.basename(p))
)
console.log(
'[Merger] 缓存状态:',
filePaths.map((p) => `${path.basename(p)}: ${cache.has(p) ? '已缓存' : '未缓存'}`)
)
// 解析所有文件(优先使用缓存)
const parseResults: Array<{ result: ParseResult; source: string }> = []
for (const filePath of filePaths) {
let result: ParseResult
if (cache.has(filePath)) {
result = cache.get(filePath)!
console.log(`[Merger] 使用缓存: ${path.basename(filePath)}`)
} else {
// 回退到文件解析(兼容性)
console.log(`[Merger] 缓存未命中,重新解析: ${path.basename(filePath)}`)
result = await parseFileSync(filePath)
}
parseResults.push({ result, source: path.basename(filePath) })
}
// 检查格式一致性
const formats = parseResults.map((p) => p.result.meta.platform)
const uniqueFormats = [...new Set(formats)]
if (uniqueFormats.length > 1) {
throw new Error(
`不支持合并不同格式的聊天记录。\n检测到的格式:${uniqueFormats.join('、')}\n请确保所有文件使用相同的导出工具和格式。`
)
}
console.log('[Merger] 格式检查通过:', uniqueFormats[0])
// 收集所有消息
for (const { result, source } of parseResults) {
console.log(`[Merger] 处理 ${source}: ${result.messages.length} 条消息`)
for (const msg of result.messages) {
allMessages.push({ msg, source })
}
}
console.log(`[Merger] 总消息数: ${allMessages.length}`)
return detectConflictsInMessages(allMessages, conflicts)
}
/**
* 检测合并冲突(原版,直接读取文件)
* @deprecated 使用 checkConflictsWithCache 替代
*/
export async function checkConflicts(filePaths: string[]): Promise<ConflictCheckResult> {
const allMessages: Array<{ msg: ParsedMessage; source: string }> = []
const conflicts: MergeConflict[] = []
console.log('[Merger] checkConflicts: 开始检测冲突')
console.log(
'[Merger] 文件列表:',
filePaths.map((p) => path.basename(p))
)
// 先检查格式一致性
const formats: string[] = []
for (const filePath of filePaths) {
const format = detectFormat(filePath)
if (format) {
formats.push(format.name)
} else {
throw new Error(`无法识别文件格式: ${path.basename(filePath)}`)
}
}
// 检查是否所有文件格式一致
const uniqueFormats = [...new Set(formats)]
if (uniqueFormats.length > 1) {
throw new Error(
`不支持合并不同格式的聊天记录。\n检测到的格式:${uniqueFormats.join('、')}\n请确保所有文件使用相同的导出工具和格式。`
)
}
console.log('[Merger] 格式检查通过:', uniqueFormats[0])
// 解析所有文件
for (const filePath of filePaths) {
const result = await parseFileSync(filePath)
const sourceName = path.basename(filePath)
console.log(`[Merger] 解析 ${sourceName}: ${result.messages.length} 条消息`)
for (const msg of result.messages) {
allMessages.push({ msg, source: sourceName })
}
}
console.log(`[Merger] 总消息数: ${allMessages.length}`)
return detectConflictsInMessages(allMessages, conflicts)
}
/**
* 内部函数:检测消息中的冲突
*/
/**
* 检查消息是否是纯图片消息
* 纯图片消息格式如:[图片: xxx.jpg]、[图片: {xxx}.jpg] 等
@@ -377,201 +268,7 @@ export async function mergeFilesWithCache(params: MergeParams, cache: Map<string
}
}
/**
* 合并多个聊天记录文件(原版,直接读取文件)
* @deprecated 使用 mergeFilesWithCache 替代
*/
export async function mergeFiles(params: MergeParams): Promise<MergeResult> {
try {
const { filePaths, outputName, outputDir, conflictResolutions, andAnalyze } = params
// 解析所有文件
const parseResults: Array<{ result: ParseResult; source: string }> = []
for (const filePath of filePaths) {
const result = await parseFileSync(filePath)
parseResults.push({ result, source: path.basename(filePath) })
}
return executeMerge(parseResults, outputName, outputDir, conflictResolutions, andAnalyze)
} catch (err) {
return {
success: false,
error: err instanceof Error ? err.message : '合并失败',
}
}
}
/**
* 内部函数:执行合并逻辑
*/
function executeMerge(
parseResults: Array<{ result: ParseResult; source: string }>,
outputName: string,
outputDir: string | undefined,
conflictResolutions: ConflictResolution[],
andAnalyze: boolean
): MergeResult {
try {
// 合并成员
const memberMap = new Map<string, ChatLabMember>()
for (const { result } of parseResults) {
for (const member of result.members) {
const existing = memberMap.get(member.platformId)
if (existing) {
// 更新为最新的名字
if (member.accountName) {
existing.accountName = member.accountName
}
if (member.groupNickname) {
existing.groupNickname = member.groupNickname
}
} else {
memberMap.set(member.platformId, {
platformId: member.platformId,
accountName: member.accountName,
groupNickname: member.groupNickname,
})
}
}
}
// 合并消息(带冲突解决和去重)
const resolutionMap = new Map(conflictResolutions.map((r) => [r.id, r.resolution]))
const allMessages: Array<{ msg: ParsedMessage; source: string }> = []
for (const { result, source } of parseResults) {
for (const msg of result.messages) {
allMessages.push({ msg, source })
}
}
// 去重逻辑
const messageMap = new Map<string, ChatLabMessage[]>()
const processedConflicts = new Set<string>()
for (const { msg } of allMessages) {
const key = getMessageKey(msg)
// 检查是否是冲突消息
const conflictId = conflictResolutions.find((c) => {
return c.id.includes(`${msg.timestamp}_${msg.senderPlatformId}`)
})?.id
if (conflictId && !processedConflicts.has(conflictId)) {
processedConflicts.add(conflictId)
const resolution = resolutionMap.get(conflictId)
// 根据解决方案处理
if (resolution === 'keepBoth') {
// 保留两者:不去重
} else if (resolution === 'keep1' || resolution === 'keep2') {
// 保留其中一个:跳过另一个(简化处理,保留第一个遇到的)
}
}
// 添加消息
if (!messageMap.has(key)) {
messageMap.set(key, [])
}
const chatLabMsg: ChatLabMessage = {
sender: msg.senderPlatformId,
accountName: msg.senderAccountName,
groupNickname: msg.senderGroupNickname,
timestamp: msg.timestamp,
type: msg.type,
content: msg.content,
}
// 只添加一次(去重)
const existing = messageMap.get(key)!
if (existing.length === 0) {
existing.push(chatLabMsg)
}
}
// 扁平化并排序
const mergedMessages = Array.from(messageMap.values())
.flat()
.sort((a, b) => a.timestamp - b.timestamp)
// 确定平台
const platforms = new Set(parseResults.map((r) => r.result.meta.platform))
const platform = platforms.size === 1 ? parseResults[0].result.meta.platform : 'mixed'
// 构建来源信息
const sources: MergeSource[] = parseResults.map(({ result, source }) => ({
filename: source,
platform: result.meta.platform,
messageCount: result.messages.length,
}))
// 构建 ChatLab 格式
const chatLabData: ChatLabFormat = {
chatlab: {
version: '1.0.0',
exportedAt: Math.floor(Date.now() / 1000),
generator: 'ChatLab Merge Tool',
},
meta: {
name: outputName,
platform: platform as ChatPlatform,
type: parseResults[0].result.meta.type as ChatType,
sources,
},
members: Array.from(memberMap.values()),
messages: mergedMessages,
}
// 写入文件
const targetDir = outputDir || getDefaultOutputDir()
ensureOutputDir(targetDir)
const filename = generateOutputFilename(outputName)
const outputPath = path.join(targetDir, filename)
fs.writeFileSync(outputPath, JSON.stringify(chatLabData, null, 2), 'utf-8')
// 如果需要分析,导入数据库
let sessionId: string | undefined
if (andAnalyze) {
// 将 ChatLab 格式转换为 ParseResult
const parseResult: ParseResult = {
meta: {
name: chatLabData.meta.name,
platform: chatLabData.meta.platform,
type: chatLabData.meta.type,
},
members: chatLabData.members.map((m) => ({
platformId: m.platformId,
accountName: m.accountName,
groupNickname: m.groupNickname,
})),
messages: chatLabData.messages.map((msg) => ({
senderPlatformId: msg.sender,
senderAccountName: msg.accountName,
senderGroupNickname: msg.groupNickname,
timestamp: msg.timestamp,
type: msg.type,
content: msg.content,
})),
}
sessionId = importData(parseResult)
}
return {
success: true,
outputPath,
sessionId,
}
} catch (err) {
return {
success: false,
error: err instanceof Error ? err.message : '合并失败',
}
}
}
// ==================== 临时数据库版本(方案3:内存优化) ====================
// ==================== 临时数据库版本(内存优化) ====================
/**
* 检测合并冲突(使用临时数据库,内存友好)
@@ -780,14 +477,14 @@ export async function mergeFilesWithTempDb(
messages: mergedMessages,
}
// 写入文件(格式化 JSON 以提高性能
// 写入文件(格式化 JSON,便于阅读
const targetDir = outputDir || getDefaultOutputDir()
ensureOutputDir(targetDir)
const filename = generateOutputFilename(outputName)
const outputPath = path.join(targetDir, filename)
const writeStartTime = Date.now()
fs.writeFileSync(outputPath, JSON.stringify(chatLabData), 'utf-8')
fs.writeFileSync(outputPath, JSON.stringify(chatLabData, null, 2), 'utf-8')
console.log(`[Merger] 写入文件耗时: ${Date.now() - writeStartTime}ms`)
console.log(`[Merger] 总合并耗时: ${Date.now() - startTime}ms`)
-26
View File
@@ -42,30 +42,7 @@ import {
updateMemberAliases,
deleteMember,
} from './query'
import { parseFile, detectFormat } from '../parser'
import { streamImport, streamParseFileInfo } from './import'
import type { FileParseInfo } from '../../../src/types/chat'
/**
* 解析文件获取基本信息(在 Worker 线程中执行,不阻塞主进程)
* @deprecated 使用 streamParseFileInfo 替代
*/
function parseFileInfo(filePath: string): FileParseInfo {
const format = detectFormat(filePath)
if (!format) {
throw new Error('无法识别文件格式')
}
const result = parseFile(filePath)
return {
name: result.meta.name,
format,
platform: result.meta.platform,
messageCount: result.messages.length,
memberCount: result.members.length,
}
}
// 初始化数据库目录
initDbDir(workerData.dbDir)
@@ -80,9 +57,6 @@ interface WorkerMessage {
// 同步消息处理器
const syncHandlers: Record<string, (payload: any) => any> = {
// 文件解析(合并功能使用,已废弃)
parseFileInfo: (p) => parseFileInfo(p.filePath),
// 基础查询
getAvailableYears: (p) => getAvailableYears(p.sessionId),
getMemberActivity: (p) => getMemberActivity(p.sessionId, p.filter),
-8
View File
@@ -337,14 +337,6 @@ export async function deleteMember(sessionId: string, memberId: number): Promise
return sendToWorker('deleteMember', { sessionId, memberId })
}
/**
* 解析文件获取基本信息(在 Worker 线程中执行)
* @deprecated 使用 streamParseFileInfo 替代
*/
export async function parseFileInfo(filePath: string): Promise<any> {
return sendToWorker('parseFileInfo', { filePath })
}
/**
* 流式解析文件,写入临时数据库(用于合并功能)
* 返回基本信息和临时数据库路径
-22
View File
@@ -177,16 +177,6 @@ interface AIServiceConfigDisplay {
updatedAt: number
}
// 兼容旧 API 的配置类型
interface LLMConfig {
provider: string
apiKey: string
apiKeySet: boolean
model?: string
baseUrl?: string
maxTokens?: number
}
interface LLMChatMessage {
role: 'system' | 'user' | 'assistant'
content: string
@@ -238,18 +228,6 @@ interface LlmApi {
validateApiKey: (provider: string, apiKey: string, baseUrl?: string, model?: string) => Promise<boolean>
hasConfig: () => Promise<boolean>
// 兼容旧 APIdeprecated
/** @deprecated 使用 getAllConfigs 代替 */
getConfig: () => Promise<LLMConfig | null>
/** @deprecated 使用 addConfig 或 updateConfig 代替 */
saveConfig: (config: {
provider: string
apiKey: string
model?: string
baseUrl?: string
maxTokens?: number
}) => Promise<{ success: boolean; error?: string }>
// 聊天功能
chat: (
messages: LLMChatMessage[],
-32
View File
@@ -507,14 +507,6 @@ interface LLMProvider {
models: Array<{ id: string; name: string; description?: string }>
}
interface LLMConfig {
provider: string
apiKey: string
apiKeySet: boolean
model?: string
maxTokens?: number
}
interface ChatMessage {
role: 'system' | 'user' | 'assistant'
content: string
@@ -650,30 +642,6 @@ const llmApi = {
return ipcRenderer.invoke('llm:hasConfig')
},
// ==================== 兼容旧 APIdeprecated====================
/**
* @deprecated 使用 getAllConfigs 代替
* 获取当前 LLM 配置
*/
getConfig: (): Promise<LLMConfig | null> => {
return ipcRenderer.invoke('llm:getConfig')
},
/**
* @deprecated 使用 addConfig 或 updateConfig 代替
* 保存 LLM 配置
*/
saveConfig: (config: {
provider: string
apiKey: string
model?: string
baseUrl?: string
maxTokens?: number
}): Promise<{ success: boolean; error?: string }> => {
return ipcRenderer.invoke('llm:saveConfig', config)
},
/**
* 发送 LLM 聊天请求(非流式)
*/