tui: add response waiting spinner

This commit is contained in:
Matt Low 2024-03-14 05:58:31 +00:00
parent 377a4f1dfa
commit c4b78aa0c6

View File

@ -11,10 +11,12 @@ import (
"context" "context"
"fmt" "fmt"
"strings" "strings"
"time"
cmdutil "git.mlow.ca/mlow/lmcli/pkg/cmd/util" cmdutil "git.mlow.ca/mlow/lmcli/pkg/cmd/util"
"git.mlow.ca/mlow/lmcli/pkg/lmcli" "git.mlow.ca/mlow/lmcli/pkg/lmcli"
models "git.mlow.ca/mlow/lmcli/pkg/lmcli/model" models "git.mlow.ca/mlow/lmcli/pkg/lmcli/model"
"github.com/charmbracelet/bubbles/spinner"
"github.com/charmbracelet/bubbles/textarea" "github.com/charmbracelet/bubbles/textarea"
"github.com/charmbracelet/bubbles/viewport" "github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
@ -53,6 +55,7 @@ type model struct {
// ui elements // ui elements
content viewport.Model content viewport.Model
input textarea.Model input textarea.Model
spinner spinner.Model
} }
type message struct { type message struct {
@ -97,6 +100,7 @@ var (
func (m model) Init() tea.Cmd { func (m model) Init() tea.Cmd {
return tea.Batch( return tea.Batch(
textarea.Blink, textarea.Blink,
m.spinner.Tick,
m.loadConversation(m.convShortname), m.loadConversation(m.convShortname),
m.waitForChunk(), m.waitForChunk(),
m.waitForReply(), m.waitForReply(),
@ -218,22 +222,28 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.err = error(msg) m.err = error(msg)
} }
if len(cmds) > 0 {
return m, tea.Batch(cmds...)
}
var cmd tea.Cmd var cmd tea.Cmd
m.spinner, cmd = m.spinner.Update(msg)
if cmd != nil {
cmds = append(cmds, cmd)
}
inputCaptured := false
m.input, cmd = m.input.Update(msg) m.input, cmd = m.input.Update(msg)
if cmd != nil { if cmd != nil {
return m, cmd inputCaptured = true
cmds = append(cmds, cmd)
} }
m.content, cmd = m.content.Update(msg) if !inputCaptured {
if cmd != nil { m.content, cmd = m.content.Update(msg)
return m, cmd if cmd != nil {
cmds = append(cmds, cmd)
}
} }
return m, cmd return m, tea.Batch(cmds...)
} }
func (m model) View() string { func (m model) View() string {
@ -343,9 +353,14 @@ func (m *model) footerView() string {
saving = segmentStyle.Copy().Bold(true).Foreground(lipgloss.Color("1")).Render("❌💾") saving = segmentStyle.Copy().Bold(true).Foreground(lipgloss.Color("1")).Render("❌💾")
} }
status := m.status
if m.waitingForReply {
status += m.spinner.View()
}
leftSegments := []string{ leftSegments := []string{
saving, saving,
segmentStyle.Render(m.status), segmentStyle.Render(status),
} }
rightSegments := []string{ rightSegments := []string{
segmentStyle.Render(fmt.Sprintf("Model: %s", *m.ctx.Config.Defaults.Model)), segmentStyle.Render(fmt.Sprintf("Model: %s", *m.ctx.Config.Defaults.Model)),
@ -391,7 +406,19 @@ func initialModel(ctx *lmcli.Context, convShortname string) model {
m.input.SetHeight(4) m.input.SetHeight(4)
m.input.Focus() m.input.Focus()
m.updateContent() m.spinner = spinner.New(spinner.WithSpinner(
spinner.Spinner{
Frames: []string{
". ",
".. ",
"...",
".. ",
". ",
" ",
},
FPS: time.Second / 3,
},
))
m.waitingForReply = false m.waitingForReply = false
m.status = "Press ctrl+s to send" m.status = "Press ctrl+s to send"
@ -453,7 +480,7 @@ func (m *model) handleInputKey(msg tea.KeyMsg) tea.Cmd {
m.content.GotoBottom() m.content.GotoBottom()
m.waitingForReply = true m.waitingForReply = true
m.status = "Waiting for response, press ctrl+c to cancel..." m.status = "Press ctrl+c to cancel"
return m.promptLLM() return m.promptLLM()
} }
return nil return nil