Categorygithub.com/jclem/sseparser
modulepackage
0.5.0
Repository: https://github.com/jclem/sseparser.git
Documentation: pkg.go.dev

# README

SSE Parser

This package provides functionality for parsing server-sent event streams, defined by the SSE specification.

Usage

In this example, we make a streaming chat completion request to the OpenAI platform API, and scan for response chunks:

package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/jclem/sseparser"
)

func main() {
	openaiKey := os.Getenv("OPENAI_KEY")

	if openaiKey == "" {
		log.Fatal("OPENAI_KEY environment variable must be set")
	}

	params := map[string]interface{}{
		"model":  "gpt-3.5-turbo",
		"stream": true,
		"messages": []map[string]string{
			{
				"role":    "user",
				"content": "Hello, how are you?",
			},
		},
	}

	body, err := json.Marshal(params)
	if err != nil {
		log.Fatal(err)
	}

	req, err := http.NewRequest("POST", "https://api.openai.com/v1/chat/completions", bytes.NewReader(body))
	if err != nil {
		log.Fatal(err)
	}

	req.Header.Set("Authorization", "Bearer "+openaiKey)
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatal(err)
	}

	if resp.StatusCode != 200 {
		log.Fatal(resp.Status)
	}

	defer resp.Body.Close()

	// We create a new stream scanner that reads the HTTP response body.
	scanner := sseparser.NewStreamScanner(resp.Body)

	for {
		// Then, we call `UnmarshalNext`, and log each completion chunk, until we
		// encounter an error or reach the end of the stream.
		var e event
		_, err := scanner.UnmarshalNext(&e)
		if err != nil {
			if errors.Is(err, sseparser.ErrStreamEOF) {
				os.Exit(0)
			}

			log.Fatal(err)
		}

		if len(e.Data.Choices) > 0 {
			fmt.Print(e.Data.Choices[0].Delta.Content)
		}
	}
}

// The event struct uses tags to specify how to unmarshal the event data.
type event struct {
	Data chunk `sse:"data"`
}

type chunk struct {
	Choices []choice
}

// The chunk struct implements the `sseparser.UnmarshalerSSEValue` interface,
// which makes it easy to unmarshal event field values which in this case are
// complete JSON payloads.
func (c *chunk) UnmarshalSSEValue(v string) error {
	if v == "[DONE]" {
		return nil
	}

	return json.Unmarshal([]byte(v), c)
}

type choice struct {
	Delta delta
}

type delta struct {
	Content string
}

# Functions

NewStreamScanner scans a [io.Reader] for SSEs.
ParseComment parses a byte slice into a [Comment].
ParseEvent parses an input into an Event.
ParseField parses a byte slice into a [Field].
ParseStream parses a byte slice into a [Stream].

# Variables

ErrStreamEOF is returned when the end of the stream is reached.

# Structs

Field is an SSE field: A field name and an optional value.
StreamScanner scans an [io.Reader] for SSEs.

# Interfaces

UnmarshalerSSE is an interface implemented by types into which an SSE can be unmarshaled.
UnmarshalerSSEValue is an interface implemented by types into which an SSE field value can be unmarshaled.

# Type aliases

Comment is a comment in an SSE.
Event is a server-sent event (SSE), which is a set of zero or more comments and/or fields.
Stream is a SSE stream, which is a set of zero or more [Event].