Skip to content

Commit 8a7d484

Browse files
committed
refactor: clean code
1 parent deeb994 commit 8a7d484

79 files changed

Lines changed: 2668 additions & 2244 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/main/aiHandler.ts

Lines changed: 61 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ export interface FileAttachment {
2626

2727
export interface ChatMessage {
2828
role: 'user' | 'assistant' | 'system'
29-
content: string | Array<{ type: 'text' | 'image_url'; text?: string; image_url?: { url: string } }>
29+
content:
30+
| string
31+
| Array<{ type: 'text' | 'image_url'; text?: string; image_url?: { url: string } }>
3032
attachments?: FileAttachment[]
3133
}
3234

@@ -52,55 +54,64 @@ class AIHandler {
5254
/**
5355
* 准备 API 消息数组,处理 systemPrompt 和文件附件
5456
*/
55-
private async prepareApiMessages(messages: ChatMessage[], modelConfig: ModelConfig): Promise<ChatMessage[]> {
57+
private async prepareApiMessages(
58+
messages: ChatMessage[],
59+
modelConfig: ModelConfig
60+
): Promise<ChatMessage[]> {
5661
const attachmentsDir = path.join(app.getPath('userData'), 'attachments')
5762

58-
const apiMessages = await Promise.all(messages.map(async (msg) => {
59-
// 如果消息有附件,需要转换为多模态格式
60-
if (msg.attachments && msg.attachments.length > 0) {
61-
const contentParts: Array<{ type: 'text' | 'image_url'; text?: string; image_url?: { url: string } }> = []
62-
63-
// 添加文本内容
64-
if (typeof msg.content === 'string' && msg.content.trim()) {
65-
contentParts.push({
66-
type: 'text',
67-
text: msg.content
68-
})
69-
}
63+
const apiMessages = await Promise.all(
64+
messages.map(async (msg) => {
65+
// 如果消息有附件,需要转换为多模态格式
66+
if (msg.attachments && msg.attachments.length > 0) {
67+
const contentParts: Array<{
68+
type: 'text' | 'image_url'
69+
text?: string
70+
image_url?: { url: string }
71+
}> = []
72+
73+
// 添加文本内容
74+
if (typeof msg.content === 'string' && msg.content.trim()) {
75+
contentParts.push({
76+
type: 'text',
77+
text: msg.content
78+
})
79+
}
7080

71-
// 添加图片附件 - 从文件系统读取
72-
for (const attachment of msg.attachments) {
73-
if (attachment.type.startsWith('image/')) {
74-
try {
75-
const fullPath = path.join(attachmentsDir, attachment.localPath)
76-
const buffer = await readFile(fullPath)
77-
const base64Content = buffer.toString('base64')
78-
79-
contentParts.push({
80-
type: 'image_url',
81-
image_url: {
82-
url: `data:${attachment.type};base64,${base64Content}`
83-
}
84-
})
85-
} catch (error) {
86-
console.error('Failed to read attachment file:', attachment.localPath, error)
87-
// 跳过无法读取的附件
81+
// 添加图片附件 - 从文件系统读取
82+
for (const attachment of msg.attachments) {
83+
if (attachment.type.startsWith('image/')) {
84+
try {
85+
const fullPath = path.join(attachmentsDir, attachment.localPath)
86+
const buffer = await readFile(fullPath)
87+
const base64Content = buffer.toString('base64')
88+
89+
contentParts.push({
90+
type: 'image_url',
91+
image_url: {
92+
url: `data:${attachment.type};base64,${base64Content}`
93+
}
94+
})
95+
} catch (error) {
96+
console.error('Failed to read attachment file:', attachment.localPath, error)
97+
// 跳过无法读取的附件
98+
}
8899
}
89100
}
101+
102+
return {
103+
role: msg.role,
104+
content: contentParts
105+
}
90106
}
91107

108+
// 普通文本消息
92109
return {
93110
role: msg.role,
94-
content: contentParts
111+
content: msg.content
95112
}
96-
}
97-
98-
// 普通文本消息
99-
return {
100-
role: msg.role,
101-
content: msg.content
102-
}
103-
}))
113+
})
114+
)
104115

105116
// 如果有systemPrompt且第一条消息不是system消息,则插入system消息
106117
if (
@@ -298,12 +309,7 @@ class AIHandler {
298309
const fullResponse = { value: '' }
299310
const fullReasoning = { value: '' }
300311

301-
const parser = this.createStreamParser(
302-
event,
303-
eventChannel,
304-
fullResponse,
305-
fullReasoning
306-
)
312+
const parser = this.createStreamParser(event, eventChannel, fullResponse, fullReasoning)
307313

308314
await this.processStreamResponse(
309315
reader,
@@ -368,7 +374,9 @@ class AIHandler {
368374
}
369375
}
370376

371-
public async getModels(config: LLMConfig): Promise<{ success: boolean; models?: string[]; error?: string }> {
377+
public async getModels(
378+
config: LLMConfig
379+
): Promise<{ success: boolean; models?: string[]; error?: string }> {
372380
try {
373381
const response = await fetch(`${config.apiHost.replace(/\/$/, '')}/models`, {
374382
method: 'GET',
@@ -402,7 +410,11 @@ export function setupAIHandlers() {
402410
ipcMain.handle('ai:send-message-streaming', (event, request: AIRequest, eventChannel: string) =>
403411
aiHandler.sendMessageStreaming(event, request, eventChannel)
404412
)
405-
ipcMain.handle('ai:stop-streaming', (_event, requestId: string) => aiHandler.stopStreaming(requestId))
406-
ipcMain.handle('ai:test-connection', (_event, config: LLMConfig) => aiHandler.testConnection(config))
413+
ipcMain.handle('ai:stop-streaming', (_event, requestId: string) =>
414+
aiHandler.stopStreaming(requestId)
415+
)
416+
ipcMain.handle('ai:test-connection', (_event, config: LLMConfig) =>
417+
aiHandler.testConnection(config)
418+
)
407419
ipcMain.handle('ai:get-models', (_event, config: LLMConfig) => aiHandler.getModels(config))
408420
}

src/main/attachmentHandler.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,7 @@ class AttachmentHandler {
8888
* 删除附件
8989
* @param localPath 相对路径
9090
*/
91-
async deleteAttachment(
92-
localPath: string
93-
): Promise<{ success: boolean; error?: string }> {
91+
async deleteAttachment(localPath: string): Promise<{ success: boolean; error?: string }> {
9492
try {
9593
const fullPath = path.join(this.attachmentsDir, localPath)
9694
await unlink(fullPath)
@@ -167,9 +165,7 @@ class AttachmentHandler {
167165
* 清理指定页面的所有附件
168166
* @param pageId 页面ID
169167
*/
170-
async cleanupPageAttachments(
171-
pageId: string
172-
): Promise<{ success: boolean; error?: string }> {
168+
async cleanupPageAttachments(pageId: string): Promise<{ success: boolean; error?: string }> {
173169
try {
174170
const targetDir = path.join(this.attachmentsDir, pageId)
175171
await rm(targetDir, { recursive: true, force: true })

src/main/ipcHandlers.ts

Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -124,50 +124,53 @@ export function setupIpcHandlers(): void {
124124
})
125125

126126
// Handle select files (file picker dialog)
127-
ipcMain.handle('select-files', async (event, options?: {
128-
multiple?: boolean
129-
filters?: Array<{ name: string; extensions: string[] }>
130-
}) => {
131-
try {
132-
const result = await dialog.showOpenDialog({
133-
properties: [
134-
'openFile',
135-
...(options?.multiple ? ['multiSelections' as const] : [])
136-
],
137-
filters: options?.filters || [
138-
{ name: 'Images', extensions: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'] },
139-
{ name: 'Documents', extensions: ['pdf', 'doc', 'docx', 'txt'] },
140-
{ name: 'All Files', extensions: ['*'] }
141-
]
142-
})
143-
144-
if (result.canceled) {
145-
return { success: false, cancelled: true }
127+
ipcMain.handle(
128+
'select-files',
129+
async (
130+
event,
131+
options?: {
132+
multiple?: boolean
133+
filters?: Array<{ name: string; extensions: string[] }>
146134
}
147-
148-
// Read all selected files and convert to base64
149-
const files = await Promise.all(
150-
result.filePaths.map(async (filePath) => {
151-
const buffer = await readFile(filePath)
152-
const base64 = buffer.toString('base64')
153-
const fileName = filePath.split(/[\\/]/).pop() || 'unknown'
154-
155-
// Get file stats for size
156-
const stats = await import('fs/promises').then(fs => fs.stat(filePath))
157-
158-
return {
159-
name: fileName,
160-
path: filePath,
161-
content: base64,
162-
size: stats.size
163-
}
135+
) => {
136+
try {
137+
const result = await dialog.showOpenDialog({
138+
properties: ['openFile', ...(options?.multiple ? ['multiSelections' as const] : [])],
139+
filters: options?.filters || [
140+
{ name: 'Images', extensions: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'] },
141+
{ name: 'Documents', extensions: ['pdf', 'doc', 'docx', 'txt'] },
142+
{ name: 'All Files', extensions: ['*'] }
143+
]
164144
})
165-
)
166145

167-
return { success: true, files }
168-
} catch (error) {
169-
console.error('Select files error:', error)
170-
return { success: false, error: error instanceof Error ? error.message : '未知错误' }
146+
if (result.canceled) {
147+
return { success: false, cancelled: true }
148+
}
149+
150+
// Read all selected files and convert to base64
151+
const files = await Promise.all(
152+
result.filePaths.map(async (filePath) => {
153+
const buffer = await readFile(filePath)
154+
const base64 = buffer.toString('base64')
155+
const fileName = filePath.split(/[\\/]/).pop() || 'unknown'
156+
157+
// Get file stats for size
158+
const stats = await import('fs/promises').then((fs) => fs.stat(filePath))
159+
160+
return {
161+
name: fileName,
162+
path: filePath,
163+
content: base64,
164+
size: stats.size
165+
}
166+
})
167+
)
168+
169+
return { success: true, files }
170+
} catch (error) {
171+
console.error('Select files error:', error)
172+
return { success: false, error: error instanceof Error ? error.message : '未知错误' }
173+
}
171174
}
172-
})
175+
)
173176
}

src/preload/index.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ declare global {
6565
defaultPath: string
6666
filters?: Array<{ name: string; extensions: string[] }>
6767
}) => Promise<{ success: boolean; cancelled?: boolean; filePath?: string; error?: string }>
68-
readFile: (filePath: string) => Promise<{ success: boolean; content?: string; error?: string }>
68+
readFile: (
69+
filePath: string
70+
) => Promise<{ success: boolean; content?: string; error?: string }>
6971
selectFiles: (options?: {
7072
multiple?: boolean
7173
filters?: Array<{ name: string; extensions: string[] }>

src/renderer/src/App.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
overflow: hidden;
66
display: flex;
77
flex-direction: column;
8-
}
8+
}

0 commit comments

Comments
 (0)