Skip to content

Commit 80992ad

Browse files
committed
feat: Integrate eventsource-parser for improved SSE data handling in AIHandler, enhancing streaming response processing
1 parent b7c0b89 commit 80992ad

File tree

3 files changed

+61
-46
lines changed

3 files changed

+61
-46
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"antd": "^5.26.0",
3333
"dayjs": "^1.11.13",
3434
"electron-updater": "^6.3.9",
35+
"eventsource-parser": "^3.0.3",
3536
"html2canvas": "^1.4.1",
3637
"katex": "^0.16.11",
3738
"mermaid": "^10.9.1",

pnpm-lock.yaml

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/aiHandler.ts

Lines changed: 51 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ipcMain } from 'electron'
2+
import { createParser } from 'eventsource-parser'
23

34
export interface LLMConfig {
45
apiHost: string
@@ -97,58 +98,61 @@ class AIHandler {
9798
let fullResponse = ''
9899
let fullReasoning = ''
99100

101+
// 使用 eventsource-parser 来解析 SSE 数据
102+
const parser = createParser({
103+
onEvent: (eventData) => {
104+
if (eventData.data === '[DONE]') {
105+
event.sender.send('ai-stream-data', {
106+
requestId: request.requestId,
107+
type: 'complete',
108+
content: fullResponse,
109+
reasoning_content: fullReasoning || undefined
110+
} as AIStreamChunk)
111+
return
112+
}
113+
114+
try {
115+
const parsed = JSON.parse(eventData.data)
116+
const delta = parsed.choices?.[0]?.delta
117+
const content = delta?.content
118+
const reasoning_content =
119+
delta?.reasoning_content ||
120+
delta?.reasoning ||
121+
parsed.reasoning_content ||
122+
parsed?.reasoning
123+
124+
if (content) {
125+
fullResponse += content
126+
event.sender.send('ai-stream-data', {
127+
requestId: request.requestId,
128+
type: 'chunk',
129+
content: content
130+
} as AIStreamChunk)
131+
}
132+
133+
if (reasoning_content) {
134+
fullReasoning += reasoning_content
135+
event.sender.send('ai-stream-data', {
136+
requestId: request.requestId,
137+
type: 'reasoning_content',
138+
reasoning_content: reasoning_content
139+
} as AIStreamChunk)
140+
}
141+
} catch (e) {
142+
// 忽略解析错误,继续处理下一行
143+
console.warn('Failed to parse streaming data:', e)
144+
}
145+
}
146+
})
147+
100148
try {
101149
while (true) {
102150
const { done, value } = await reader.read()
103151

104152
if (done) break
105153

106154
const chunk = decoder.decode(value, { stream: true })
107-
const lines = chunk.split('\n').filter((line) => line.trim() !== '')
108-
109-
for (const line of lines) {
110-
if (line.startsWith('data: ')) {
111-
const data = line.slice(6).trim()
112-
113-
if (data === '[DONE]') {
114-
event.sender.send('ai-stream-data', {
115-
requestId: request.requestId,
116-
type: 'complete',
117-
content: fullResponse,
118-
reasoning_content: fullReasoning || undefined
119-
} as AIStreamChunk)
120-
return
121-
}
122-
123-
try {
124-
const parsed = JSON.parse(data)
125-
const delta = parsed.choices?.[0]?.delta
126-
const content = delta?.content
127-
const reasoning_content = delta?.reasoning_content || parsed.reasoning_content
128-
129-
if (content) {
130-
fullResponse += content
131-
event.sender.send('ai-stream-data', {
132-
requestId: request.requestId,
133-
type: 'chunk',
134-
content: content
135-
} as AIStreamChunk)
136-
}
137-
138-
if (reasoning_content) {
139-
fullReasoning += reasoning_content
140-
event.sender.send('ai-stream-data', {
141-
requestId: request.requestId,
142-
type: 'reasoning_content',
143-
reasoning_content: reasoning_content
144-
} as AIStreamChunk)
145-
}
146-
} catch (e) {
147-
// 忽略解析错误,继续处理下一行
148-
console.warn('Failed to parse streaming data:', e)
149-
}
150-
}
151-
}
155+
parser.feed(chunk)
152156
}
153157

154158
event.sender.send('ai-stream-data', {
@@ -238,7 +242,8 @@ class AIHandler {
238242

239243
const data = await response.json()
240244
const content = data.choices?.[0]?.message?.content || ''
241-
const reasoning_content = data.choices?.[0]?.message?.reasoning_content
245+
const reasoning_content =
246+
data.choices?.[0]?.message?.reasoning_content || data.choices?.[0]?.message?.reasoning
242247

243248
return {
244249
success: true,

0 commit comments

Comments
 (0)