package parser import "encoding/json" type StreamParser func(line string) type Parser struct { Parse StreamParser Flush func() } // CreateStreamParser 建立串流解析器(向後相容,不傳遞 thinking) func CreateStreamParser(onText func(string), onDone func()) Parser { return CreateStreamParserWithThinking(onText, nil, onDone) } // CreateStreamParserWithThinking 建立串流解析器,支援思考過程輸出。 // onThinking 可為 nil,表示忽略思考過程。 func CreateStreamParserWithThinking(onText func(string), onThinking func(string), onDone func()) Parser { accumulatedText := "" accumulatedThinking := "" done := false parse := func(line string) { if done { return } var obj struct { Type string `json:"type"` Subtype string `json:"subtype"` Message *struct { Content []struct { Type string `json:"type"` Text string `json:"text"` Thinking string `json:"thinking"` } `json:"content"` } `json:"message"` } if err := json.Unmarshal([]byte(line), &obj); err != nil { return } if obj.Type == "assistant" && obj.Message != nil { fullText := "" fullThinking := "" for _, p := range obj.Message.Content { switch p.Type { case "text": if p.Text != "" { fullText += p.Text } case "thinking": if p.Thinking != "" { fullThinking += p.Thinking } } } // 處理思考過程 delta if onThinking != nil && fullThinking != "" { if fullThinking == accumulatedThinking { // 重複的完整思考文字,跳過 } else if len(fullThinking) > len(accumulatedThinking) && fullThinking[:len(accumulatedThinking)] == accumulatedThinking { delta := fullThinking[len(accumulatedThinking):] onThinking(delta) accumulatedThinking = fullThinking } else { onThinking(fullThinking) accumulatedThinking += fullThinking } } // 處理一般文字 delta if fullText == "" { return } // 若此訊息文字等於已累積內容(重複的完整文字),跳過 if fullText == accumulatedText { return } // 若此訊息是已累積內容的延伸,只輸出新的 delta if len(fullText) > len(accumulatedText) && fullText[:len(accumulatedText)] == accumulatedText { delta := fullText[len(accumulatedText):] onText(delta) accumulatedText = fullText } else { // 獨立的 token fragment(一般情況),直接輸出 onText(fullText) accumulatedText += fullText } } if obj.Type == "result" && obj.Subtype == "success" { done = true onDone() } } flush := func() { if !done { done = true onDone() } } return Parser{Parse: parse, Flush: flush} }