2023-11-05 00:44:06 -06:00
|
|
|
package cli
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2023-11-05 01:40:55 -06:00
|
|
|
"strings"
|
2023-11-05 00:44:06 -06:00
|
|
|
"time"
|
2023-11-15 22:02:43 -07:00
|
|
|
|
|
|
|
"github.com/gookit/color"
|
2023-11-05 00:44:06 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
// ShowWaitAnimation "draws" an animated ellipses to stdout until something is
|
|
|
|
// received on the signal channel. An empty string sent to the channel to
|
|
|
|
// noftify the caller that the animation has completed (carriage returned).
|
|
|
|
func ShowWaitAnimation(signal chan any) {
|
|
|
|
animationStep := 0
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case _ = <-signal:
|
|
|
|
fmt.Print("\r")
|
|
|
|
signal <- ""
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
modSix := animationStep % 6
|
|
|
|
if modSix == 3 || modSix == 0 {
|
|
|
|
fmt.Print("\r")
|
|
|
|
}
|
|
|
|
if modSix < 3 {
|
|
|
|
fmt.Print(".")
|
|
|
|
} else {
|
|
|
|
fmt.Print(" ")
|
|
|
|
}
|
|
|
|
animationStep++
|
|
|
|
time.Sleep(250 * time.Millisecond)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// HandledDelayedResponse writes a waiting animation (abusing \r) and the
|
2023-11-05 01:40:55 -06:00
|
|
|
// (possibly chunked) content received on the response channel to stdout.
|
|
|
|
// Blocks until the channel is closed.
|
|
|
|
func HandleDelayedResponse(response chan string) string {
|
2023-11-05 00:44:06 -06:00
|
|
|
waitSignal := make(chan any)
|
|
|
|
go ShowWaitAnimation(waitSignal)
|
|
|
|
|
2023-11-05 01:40:55 -06:00
|
|
|
sb := strings.Builder{}
|
|
|
|
|
2023-11-05 00:44:06 -06:00
|
|
|
firstChunk := true
|
|
|
|
for chunk := range response {
|
|
|
|
if firstChunk {
|
2023-11-05 11:19:30 -07:00
|
|
|
// notify wait animation that we've received data
|
2023-11-05 00:44:06 -06:00
|
|
|
waitSignal <- ""
|
2023-11-05 11:19:30 -07:00
|
|
|
// wait for signal that wait animation has completed
|
2023-11-05 00:44:06 -06:00
|
|
|
<-waitSignal
|
|
|
|
firstChunk = false
|
|
|
|
}
|
|
|
|
fmt.Print(chunk)
|
2023-11-05 01:40:55 -06:00
|
|
|
sb.WriteString(chunk)
|
2023-11-05 00:44:06 -06:00
|
|
|
}
|
2023-11-05 01:40:55 -06:00
|
|
|
|
|
|
|
return sb.String()
|
2023-11-05 00:44:06 -06:00
|
|
|
}
|
2023-11-05 01:50:07 -07:00
|
|
|
|
|
|
|
func (m *Message) RenderTTY(paddingDown bool) {
|
2023-11-15 22:02:43 -07:00
|
|
|
var messageAge string
|
|
|
|
if m.CreatedAt.IsZero() {
|
|
|
|
messageAge = "now"
|
|
|
|
} else {
|
|
|
|
now := time.Now()
|
|
|
|
messageAge = humanTimeElapsedSince(now.Sub(m.CreatedAt))
|
|
|
|
}
|
|
|
|
|
|
|
|
var roleStyle color.Style
|
|
|
|
switch m.Role {
|
|
|
|
case "system":
|
|
|
|
roleStyle = color.Style{color.HiRed}
|
|
|
|
case "user":
|
|
|
|
roleStyle = color.Style{color.HiGreen}
|
|
|
|
case "assistant":
|
|
|
|
roleStyle = color.Style{color.HiBlue}
|
|
|
|
default:
|
|
|
|
roleStyle = color.Style{color.FgWhite}
|
|
|
|
}
|
|
|
|
roleStyle.Add(color.Bold)
|
|
|
|
|
|
|
|
headerColor := color.FgYellow
|
|
|
|
separator := headerColor.Sprint("===")
|
|
|
|
timestamp := headerColor.Sprint(messageAge)
|
|
|
|
role := roleStyle.Sprint(m.FriendlyRole())
|
|
|
|
|
|
|
|
fmt.Printf("%s %s - %s %s\n\n", separator, role, timestamp, separator)
|
2023-11-05 01:50:07 -07:00
|
|
|
if m.OriginalContent != "" {
|
|
|
|
fmt.Print(m.OriginalContent)
|
|
|
|
}
|
|
|
|
if paddingDown {
|
|
|
|
fmt.Print("\n\n")
|
|
|
|
}
|
|
|
|
}
|