veylant/internal/provider/openai/stream.go
2026-02-23 13:35:04 +01:00

47 lines
1.1 KiB
Go

package openai
import (
"bufio"
"fmt"
"net/http"
"strings"
)
// PipeSSE reads an OpenAI SSE response body and writes each event line to w,
// flushing after every chunk. It returns when the upstream sends "data: [DONE]"
// or when the response body is exhausted.
//
// The caller is responsible for setting the SSE response headers before
// calling PipeSSE. The function only writes the event payloads.
func PipeSSE(body *bufio.Scanner, w http.ResponseWriter) error {
flusher, ok := w.(http.Flusher)
if !ok {
return fmt.Errorf("response writer does not support flushing (SSE not possible)")
}
for body.Scan() {
line := body.Text()
// Blank lines are SSE field separators — skip them.
if line == "" {
continue
}
// Write the line followed by the SSE double-newline terminator.
if _, err := fmt.Fprintf(w, "%s\n\n", line); err != nil {
return fmt.Errorf("writing SSE chunk: %w", err)
}
flusher.Flush()
// OpenAI signals end-of-stream with this sentinel.
if strings.TrimSpace(line) == "data: [DONE]" {
return nil
}
}
if err := body.Err(); err != nil {
return fmt.Errorf("reading SSE body: %w", err)
}
return nil
}