Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
65 lines
1.3 KiB
Go
65 lines
1.3 KiB
Go
package chat
|
|
|
|
import (
|
|
"bufio"
|
|
"io"
|
|
"strings"
|
|
)
|
|
|
|
// SSEEvent 表示一个 Server-Sent Events 事件
|
|
type SSEEvent struct {
|
|
Data []byte
|
|
Done bool
|
|
}
|
|
|
|
// SSEReader 用于读取 SSE 流
|
|
type SSEReader struct {
|
|
scanner *bufio.Scanner
|
|
}
|
|
|
|
// NewSSEReader 创建 SSE 读取器
|
|
func NewSSEReader(reader io.Reader) *SSEReader {
|
|
scanner := bufio.NewScanner(reader)
|
|
// 设置更大的缓冲区以处理长行(思维链内容可能很长)
|
|
buf := make([]byte, 1024*1024)
|
|
scanner.Buffer(buf, 1024*1024)
|
|
return &SSEReader{scanner: scanner}
|
|
}
|
|
|
|
// ReadEvent 读取下一个 SSE 事件
|
|
func (r *SSEReader) ReadEvent() (*SSEEvent, error) {
|
|
for r.scanner.Scan() {
|
|
line := r.scanner.Text()
|
|
|
|
// 空行,跳过
|
|
if line == "" {
|
|
continue
|
|
}
|
|
|
|
// 检查是否为结束标记
|
|
if line == "data: [DONE]" {
|
|
return &SSEEvent{Done: true}, nil
|
|
}
|
|
|
|
// 解析 data 行
|
|
if strings.HasPrefix(line, "data: ") {
|
|
jsonStr := line[6:]
|
|
return &SSEEvent{Data: []byte(jsonStr)}, nil
|
|
}
|
|
|
|
// 增强兼容性(data:后面没有紧接着一个空格)
|
|
if strings.HasPrefix(line, "data:") {
|
|
jsonStr := line[5:]
|
|
return &SSEEvent{Data: []byte(jsonStr)}, nil
|
|
}
|
|
|
|
// 其他行(如 event:, id: 等)跳过
|
|
}
|
|
|
|
if err := r.scanner.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return nil, io.EOF
|
|
}
|