Stream in Go
stream_options.include_usage is Preview (not available yet). Until it ships, leave it out; the code below simply prints no usage line.Print a reply as it is generated, using only the standard library.
package main
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
"strings"
)
func main() {
body, _ := json.Marshal(map[string]any{
"model": "Amara S1.2",
"stream": true,
"stream_options": map[string]bool{"include_usage": true},
"messages": []map[string]string{{"role": "user", "content": "Explain idempotency keys in three sentences."}},
})
req, _ := http.NewRequest("POST", "https://app.syntic.ai/v1/chat/completions", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("SYNTIC_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
var e struct{ Error struct{ Code, Message string } }
json.NewDecoder(resp.Body).Decode(&e)
panic(fmt.Sprintf("%d %s: %s", resp.StatusCode, e.Error.Code, e.Error.Message))
}
scanner := bufio.NewScanner(resp.Body)
scanner.Buffer(make([]byte, 1024*1024), 1024*1024)
for scanner.Scan() {
line := scanner.Text()
if !strings.HasPrefix(line, "data: ") {
continue
}
payload := strings.TrimPrefix(line, "data: ")
if payload == "[DONE]" {
break
}
var chunk struct {
Choices []struct {
Delta struct{ Content string } `json:"delta"`
} `json:"choices"`
Usage *struct{ PromptTokens, CompletionTokens int } `json:"usage"`
Error *struct{ Code, Message string } `json:"error"`
}
if err := json.Unmarshal([]byte(payload), &chunk); err != nil {
continue
}
if chunk.Error != nil {
panic("stream interrupted: " + chunk.Error.Message)
}
if len(chunk.Choices) > 0 {
fmt.Print(chunk.Choices[0].Delta.Content)
}
if chunk.Usage != nil {
fmt.Printf("\n[%d in / %d out tokens]\n", chunk.Usage.PromptTokens, chunk.Usage.CompletionTokens)
}
}
}What the code handles
- Lines that start with
data:carry JSON chunks; other lines (blank lines,: keep-alivecomments) are skipped. data: [DONE]ends the stream.- A chunk with an
errorobject means the stream broke after it started; the text so far may be incomplete, so retry the whole request. - The last chunk before
[DONE]carriesusagewhen you sendstream_options.include_usage.
See Stream format for every field.
Was this page helpful?