Render processes the given logs and writes the rendered output to w. Errors are returned when an unexpected log entry is encountered.
(logs []byte, w io.Writer, io *iostreams.IOStreams)
| 56 | // Render processes the given logs and writes the rendered output to w. |
| 57 | // Errors are returned when an unexpected log entry is encountered. |
| 58 | func (r *logRenderer) Render(logs []byte, w io.Writer, io *iostreams.IOStreams) (bool, error) { |
| 59 | lines := slices.DeleteFunc(strings.Split(string(logs), "\n"), func(line string) bool { |
| 60 | return line == "" |
| 61 | }) |
| 62 | |
| 63 | for _, line := range lines { |
| 64 | raw, found := strings.CutPrefix(line, "data: ") |
| 65 | if !found { |
| 66 | return false, errors.New("unexpected log format") |
| 67 | } |
| 68 | |
| 69 | // The only log entry type we're interested in is a chat completion chunk, |
| 70 | // which can be verified by a successful unmarshal into the corresponding |
| 71 | // type AND the Object field being equal to "chat.completion.chunk". The |
| 72 | // latter is to avoid accepting an empty JSON object (i.e. "{}"). Also, |
| 73 | // if the entry is not what we expect, we should just skip and avoid |
| 74 | // returning an error. |
| 75 | var entry chatCompletionChunkEntry |
| 76 | err := json.Unmarshal([]byte(raw), &entry) |
| 77 | if err != nil || entry.Object != "chat.completion.chunk" { |
| 78 | continue |
| 79 | } |
| 80 | |
| 81 | if stop, err := renderLogEntry(entry, w, io); err != nil { |
| 82 | return false, fmt.Errorf("failed to process log entry: %w", err) |
| 83 | } else if stop { |
| 84 | return true, nil |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | return false, nil |
| 89 | } |
| 90 | |
| 91 | func renderLogEntry(entry chatCompletionChunkEntry, w io.Writer, io *iostreams.IOStreams) (bool, error) { |
| 92 | cs := io.ColorScheme() |
no test coverage detected