refactor: format with eslint & prettier

This commit is contained in:
digua
2026-02-11 20:24:46 +08:00
committed by digua
parent 5068df81c3
commit f3ba043140
79 changed files with 883 additions and 525 deletions
+6 -2
View File
@@ -20,11 +20,15 @@ const SALT = 'chatlab-api-key-encryption-v1'
function deriveKey(): Buffer {
try {
const machineId = machineIdSync()
return createHash('sha256').update(machineId + SALT).digest()
return createHash('sha256')
.update(machineId + SALT)
.digest()
} catch (error) {
// 如果无法获取机器 ID,使用固定的回退值(安全性降低)
console.warn('无法获取机器 ID,使用回退密钥:', error)
return createHash('sha256').update('chatlab-fallback-key' + SALT).digest()
return createHash('sha256')
.update('chatlab-fallback-key' + SALT)
.digest()
}
}
+1 -1
View File
@@ -40,7 +40,7 @@ export const GEMINI_INFO: ProviderInfo = {
* 统一处理 Gemini 的 baseUrl,确保包含 /v1beta
*/
function normalizeBaseUrl(baseUrl?: string): string {
let normalized = (baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, '')
const normalized = (baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, '')
if (normalized.endsWith(DEFAULT_API_VERSION)) {
return normalized
@@ -19,7 +19,6 @@ import type {
import { aiLogger } from '../logger'
import { buildModelMessages, buildToolSet, mapFinishReason, mapToolCalls, mapUsage } from './sdkUtils'
/**
* 从 AI SDK 错误中提取详细信息
* 特别是从 responseBody 中获取模型/服务端返回的错误消息
+1 -3
View File
@@ -414,9 +414,7 @@ export function checkMigrationNeeded(): {
// 仅迁移聊天会话数据库:这里最小依赖是 meta + message
// 这样可跳过非聊天库,同时避免把 member 缺失的异常库直接误归为“非聊天库”
const requiredTableCount = db
.prepare(
"SELECT COUNT(*) as cnt FROM sqlite_master WHERE type='table' AND name IN ('meta', 'message')"
)
.prepare("SELECT COUNT(*) as cnt FROM sqlite_master WHERE type='table' AND name IN ('meta', 'message')")
.get() as { cnt: number }
const isChatSessionDb = requiredTableCount.cnt === 2
if (!isChatSessionDb) {
+1 -1
View File
@@ -171,7 +171,7 @@ async function* parseChatLab(options: ParseOptions): AsyncGenerator<ParseEvent,
// 收集成员和消息
const memberMapFromMessages = new Map<string, ParsedMember>()
let messageBatch: ParsedMessage[] = []
const messageBatch: ParsedMessage[] = []
// 流式解析
await new Promise<void>((resolve, reject) => {
+50 -55
View File
@@ -160,48 +160,48 @@ const SYSTEM_MSG_PATTERN = /^((?:上午|下午|午前|午後)?\d{1,2}:\d{2}(?:[A
*/
const SPECIAL_MESSAGE_TYPES: Record<string, MessageType> = {
// 图片 / Photo
'[Photo]': MessageType.IMAGE, // EN
'[照片]': MessageType.IMAGE, // ZH-CN / ZH-TW
'[写真]': MessageType.IMAGE, // JA
Photos: MessageType.IMAGE, // EN (fallback)
'[Photo]': MessageType.IMAGE, // EN
'[照片]': MessageType.IMAGE, // ZH-CN / ZH-TW
'[写真]': MessageType.IMAGE, // JA
Photos: MessageType.IMAGE, // EN (fallback)
// 语音 / Voice
'[Voice message]': MessageType.VOICE, // EN
'[语音信息]': MessageType.VOICE, // ZH-CN
'[語音訊息]': MessageType.VOICE, // ZH-TW
'[Voice message]': MessageType.VOICE, // EN
'[语音信息]': MessageType.VOICE, // ZH-CN
'[語音訊息]': MessageType.VOICE, // ZH-TW
'[ボイスメッセージ]': MessageType.VOICE, // JA
Audio: MessageType.VOICE, // EN (fallback)
Audio: MessageType.VOICE, // EN (fallback)
// 视频 / Video
'[Video]': MessageType.VIDEO, // EN
'[视频]': MessageType.VIDEO, // ZH-CN
'[影片]': MessageType.VIDEO, // ZH-TW
'[動画]': MessageType.VIDEO, // JA
Videos: MessageType.VIDEO, // EN (fallback)
'[Video]': MessageType.VIDEO, // EN
'[视频]': MessageType.VIDEO, // ZH-CN
'[影片]': MessageType.VIDEO, // ZH-TW
'[動画]': MessageType.VIDEO, // JA
Videos: MessageType.VIDEO, // EN (fallback)
// 文件 / File
'[File]': MessageType.FILE, // EN
'[文件]': MessageType.FILE, // ZH-CN
'[檔案]': MessageType.FILE, // ZH-TW
'[ファイル]': MessageType.FILE, // JA
'[File]': MessageType.FILE, // EN
'[文件]': MessageType.FILE, // ZH-CN
'[檔案]': MessageType.FILE, // ZH-TW
'[ファイル]': MessageType.FILE, // JA
// 贴纸 / Sticker
'[Sticker]': MessageType.EMOJI, // EN
'[贴图]': MessageType.EMOJI, // ZH-CN
'[貼圖]': MessageType.EMOJI, // ZH-TW
'[スタンプ]': MessageType.EMOJI, // JA
Stickers: MessageType.EMOJI, // EN (fallback)
'[Sticker]': MessageType.EMOJI, // EN
'[贴图]': MessageType.EMOJI, // ZH-CN
'[貼圖]': MessageType.EMOJI, // ZH-TW
'[スタンプ]': MessageType.EMOJI, // JA
Stickers: MessageType.EMOJI, // EN (fallback)
// 位置 / Location
'[Location]': MessageType.LOCATION, // EN
'[位置]': MessageType.LOCATION, // ZH-CN / ZH-TW
'[位置]': MessageType.LOCATION, // ZH-CN / ZH-TW
'[位置情報]': MessageType.LOCATION, // JA
// 记事本 / Notes
'[Notes]': MessageType.TEXT, // EN
'[记事本]': MessageType.TEXT, // ZH-CN
'[記事本]': MessageType.TEXT, // ZH-TW
'[ノート]': MessageType.TEXT, // JA
'[Notes]': MessageType.TEXT, // EN
'[记事本]': MessageType.TEXT, // ZH-CN
'[記事本]': MessageType.TEXT, // ZH-TW
'[ノート]': MessageType.TEXT, // JA
}
/**
@@ -223,42 +223,37 @@ function detectMessageType(content: string): MessageType {
// 检查系统消息(多语言:EN / ZH-CN / ZH-TW / JA
if (
// --- 加入群组 / Join group ---
content.includes(' joined the group') || // EN
content.includes('已加入该群') || // ZH-CN
content.includes('已加入群組') || // ZH-TW
content.includes(' joined the group') || // EN
content.includes('已加入该群') || // ZH-CN
content.includes('已加入群組') || // ZH-TW
content.includes('がグループに参加しました') || // JA
// --- 拉人进群 / Added to group ---
content.includes(' added ') || // EN
content.includes(' to the group') || // EN
content.includes('已将') || // ZH-CN
content.includes('添加至群') || // ZH-CN
content.includes('添加到群') || // ZH-CN (另一格式)
content.includes('已新增') || // ZH-TW
content.includes('至群組') || // ZH-TW
content.includes(' added ') || // EN
content.includes(' to the group') || // EN
content.includes('已将') || // ZH-CN
content.includes('添加至群') || // ZH-CN
content.includes('添加到群') || // ZH-CN (另一格式)
content.includes('已新增') || // ZH-TW
content.includes('至群組') || // ZH-TW
content.includes('をグループに追加しました') || // JA
// --- 退出群组 / Left group ---
content.includes(' left the group') || // EN
content.includes('已退群') || // ZH-CN
content.includes('已離開群組') || // ZH-TW
content.includes(' left the group') || // EN
content.includes('已退群') || // ZH-CN
content.includes('已離開群組') || // ZH-TW
content.includes('がグループを退会しました') || // JA
// --- 设定公告 / Announcement ---
content.includes('made an announcement') || // EN
content.includes('发布了通告') || // ZH-CN
content.includes('已設定公告') || // ZH-TW
content.includes('がアナウンスしました') || // JA
content.includes('made an announcement') || // EN
content.includes('发布了通告') || // ZH-CN
content.includes('已設定公告') || // ZH-TW
content.includes('がアナウンスしました') || // JA
// --- 收回讯息 / Unsent message ---
content.includes('unsent a message') || // EN
content === 'Message unsent.' || // EN
content.includes('撤回了一条消息') || // ZH-CN
content.includes('已收回訊息') || // ZH-TW
content.includes('送信を取り消しました') || // JA
content.includes('unsent a message') || // EN
content === 'Message unsent.' || // EN
content.includes('撤回了一条消息') || // ZH-CN
content.includes('已收回訊息') || // ZH-TW
content.includes('送信を取り消しました') || // JA
// --- 其他 / Others ---
content.startsWith('Auto-reply') // EN 自动回复
content.startsWith('Auto-reply') // EN 自动回复
) {
return MessageType.SYSTEM
}
@@ -225,7 +225,7 @@ async function* parseTxt(options: ParseOptions): AsyncGenerator<ParseEvent, void
const rawNickname = headerMatch[2].trim()
let nickname = cleanNickname(rawNickname) // 清理前缀污染
// platformId: (id) 或 <email>,如果没有则使用昵称(讨论组格式)
let platformId = headerMatch[3] || headerMatch[4] || nickname
const platformId = headerMatch[3] || headerMatch[4] || nickname
// 如果昵称和 ID 相同,可能是系统故障,使用之前记录的昵称
if (nickname === platformId && headerMatch[3]) {
@@ -309,7 +309,7 @@ async function* parseDiscordExporter(options: ParseOptions): AsyncGenerator<Pars
// 收集成员和消息
const memberMap = new Map<string, ParsedMember>()
let messageBatch: ParsedMessage[] = []
const messageBatch: ParsedMessage[] = []
// 流式解析消息
await new Promise<void>((resolve, reject) => {
+1 -6
View File
@@ -283,12 +283,7 @@ export class FormatSniffer {
/**
* 检查特征是否匹配
*/
private matchFeature(
feature: FormatFeature,
ext: string,
headContent: string,
filePath?: string
): boolean {
private matchFeature(feature: FormatFeature, ext: string, headContent: string, filePath?: string): boolean {
// 1. 检查扩展名
if (!feature.extensions.includes(ext)) {
return false
+3 -3
View File
@@ -153,9 +153,9 @@ export function setCustomDataDir(
const newDir = getDefaultAppDataDir()
// 防止目标目录是当前目录的子目录,避免递归复制
if (migrate && oldDir !== newDir && isSubPath(oldDir, newDir)) {
return { success: false, error: '目标目录不能是当前数据目录的子目录' }
}
if (migrate && oldDir !== newDir && isSubPath(oldDir, newDir)) {
return { success: false, error: '目标目录不能是当前数据目录的子目录' }
}
// 先清除自定义配置,切回默认目录
writeStorageConfig({})
+1 -5
View File
@@ -181,11 +181,7 @@ export function copyDirMerge(
/**
* 写入迁移日志到 app.log
*/
export function writeMigrationLog(
logDir: string,
message: string,
ensureDir: (dirPath: string) => void
): void {
export function writeMigrationLog(logDir: string, message: string, ensureDir: (dirPath: string) => void): void {
try {
ensureDir(logDir)
const logPath = path.join(logDir, 'app.log')
+1 -2
View File
@@ -156,8 +156,7 @@ const syncHandlers: Record<string, (payload: any) => any> = {
// 自定义筛选(支持分页)
filterMessagesWithContext: (p) =>
filterMessagesWithContext(p.sessionId, p.keywords, p.timeFilter, p.senderIds, p.contextSize, p.page, p.pageSize),
getMultipleSessionsMessages: (p) =>
getMultipleSessionsMessages(p.sessionId, p.chatSessionIds, p.page, p.pageSize),
getMultipleSessionsMessages: (p) => getMultipleSessionsMessages(p.sessionId, p.chatSessionIds, p.page, p.pageSize),
// NLP 查询
getWordFrequency: (p) => getWordFrequency(p),
+1 -1
View File
@@ -293,7 +293,7 @@ export async function streamImport(filePath: string, requestId: string): Promise
let importError: string | null = null
// 统计回调调用次数(用于诊断)
let callbackStats = {
const callbackStats = {
onProgressCalls: 0,
onLogCalls: 0,
onMetaCalls: 0,
@@ -818,7 +818,10 @@ export function getClusterGraph(
.all(...params) as Array<{ senderId: number; ts: number }>
if (messages.length < 2) {
return { ...emptyResult, stats: { ...emptyResult.stats, totalMembers: members.length, totalMessages: messages.length } }
return {
...emptyResult,
stats: { ...emptyResult.stats, totalMembers: members.length, totalMessages: messages.length },
}
}
// 3. 统计每个成员的消息数(用于归一化)
+1 -5
View File
@@ -4,11 +4,7 @@
*/
import { openReadonlyDatabase } from './core'
import type {
FilterMessage,
ContextBlock,
FilterResultWithPagination,
} from './types'
import type { FilterMessage, ContextBlock, FilterResultWithPagination } from './types'
/**
* 按条件筛选消息并扩充上下文(支持分页)
@@ -164,7 +164,7 @@ export function generateSessions(
*/
export function generateIncrementalSessions(
sessionId: string,
gapThreshold: number = DEFAULT_SESSION_GAP_THRESHOLD,
gapThreshold: number = DEFAULT_SESSION_GAP_THRESHOLD
): number {
// 先关闭缓存的只读连接
closeDatabase(sessionId)
@@ -177,7 +177,9 @@ export function generateIncrementalSessions(
try {
// 1. 获取已索引消息的 ID 集合(通过 message_context 表)
const indexedIds = new Set<number>()
const existingContextRows = db.prepare('SELECT message_id FROM message_context').all() as Array<{ message_id: number }>
const existingContextRows = db.prepare('SELECT message_id FROM message_context').all() as Array<{
message_id: number
}>
for (const row of existingContextRows) {
indexedIds.add(row.message_id)
}
@@ -195,9 +197,9 @@ export function generateIncrementalSessions(
}
// 3. 获取最后一个已有会话的信息
const lastSession = db.prepare(
'SELECT id, end_ts FROM chat_session ORDER BY end_ts DESC LIMIT 1'
).get() as { id: number; end_ts: number } | undefined
const lastSession = db.prepare('SELECT id, end_ts FROM chat_session ORDER BY end_ts DESC LIMIT 1').get() as
| { id: number; end_ts: number }
| undefined
// 4. 按时间排序新消息,然后用 gap-based 算法切分
newMessages.sort((a, b) => a.ts - b.ts || a.id - b.id)
@@ -231,7 +233,7 @@ export function generateIncrementalSessions(
if (isFirst) {
// 第一条新消息:检查是否能并入最后一个已有会话
if (lastSession && (msg.ts - lastSession.end_ts) <= gapThreshold * 1000) {
if (lastSession && msg.ts - lastSession.end_ts <= gapThreshold * 1000) {
// 并入已有会话
currentSessionId = lastSession.id
currentEndTs = lastSession.end_ts
@@ -242,7 +244,7 @@ export function generateIncrementalSessions(
} else {
// 后续消息:检查与上一条的时间差
const prevMsg = newMessages[i - 1]
if ((msg.ts - prevMsg.ts) > gapThreshold * 1000) {
if (msg.ts - prevMsg.ts > gapThreshold * 1000) {
// 如果之前在追加已有会话,先更新它
if (currentSessionId && appendCount > 0) {
updateSessionEndAndCount.run(currentEndTs, appendCount, currentSessionId)