MCPcopy Create free account
hub / github.com/experdot/pointer / AIHandler

Class AIHandler

src/main/aiHandler.ts:50–405  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

48}
49
50class AIHandler {
51 // 使用 Map 管理多个并行请求的 AbortController
52 private abortControllers = new Map<string, AbortController>()
53
54 /**
55 * 准备 API 消息数组,处理 systemPrompt 和文件附件
56 */
57 private async prepareApiMessages(
58 messages: ChatMessage[],
59 modelConfig: ModelConfig
60 ): Promise<ChatMessage[]> {
61 const attachmentsDir = path.join(app.getPath('userData'), 'attachments')
62
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 }
80
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 }
99 }
100 }
101
102 return {
103 role: msg.role,
104 content: contentParts
105 }
106 }
107

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected