docs: 更新讨论记录和更新日志 - 添加 spinner 动画知识点
This commit is contained in:
69
taolun.md
69
taolun.md
@@ -138,4 +138,71 @@ os.Stdout.Sync()
|
||||
3. 保留所有历史输出
|
||||
4. 每次刷新缓冲区确保立即显示
|
||||
|
||||
这正是 ollama 等工具的流式输出效果。
|
||||
这正是 ollama 等工具的流式输出效果。
|
||||
|
||||
---
|
||||
|
||||
### 12. 使用 bubbletea v2 的 spinner 组件实现加载动画
|
||||
|
||||
#### 需求分析
|
||||
|
||||
用户希望在使用流式输出时,显示加载动画:
|
||||
- 用户输入后显示 "思考中... ⠋"
|
||||
- 第一个 token 返回后显示 "思考完成."
|
||||
- 流式输出完成后添加空行分隔
|
||||
|
||||
#### 技术选型
|
||||
|
||||
使用 `charm.land/bubbles/v2/spinner` 组件,这是 bubbletea v2 官方提供的 spinner 组件。
|
||||
|
||||
#### 实现方案
|
||||
|
||||
创建独立的 Spinner 结构体,在独立 goroutine 中运行动画:
|
||||
|
||||
```go
|
||||
type Spinner struct {
|
||||
text string
|
||||
state SpinnerState
|
||||
spinner spinner.Model
|
||||
stopCh chan struct{}
|
||||
doneCh chan struct{}
|
||||
}
|
||||
```
|
||||
|
||||
关键点:
|
||||
- 使用 `spinner.MiniDot` 动画样式
|
||||
- 独立 goroutine 使用 ticker 驱动动画帧切换
|
||||
- 使用 `\r` 回车符在同一行刷新动画
|
||||
- Stop 时输出 "思考完成."
|
||||
|
||||
#### 官方示例参考
|
||||
|
||||
```go
|
||||
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case spinner.TickMsg:
|
||||
var cmd tea.Cmd
|
||||
m.spinner, cmd = m.spinner.Update(msg)
|
||||
return m, cmd
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
关键:spinner.Tick() 返回的 TickMsg 需要传给 spinner.Update(),并使用返回值更新 spinner model。
|
||||
|
||||
#### 注意事项
|
||||
|
||||
1. spinner model 更新必须使用返回值:
|
||||
```go
|
||||
s.spinner, _ = s.spinner.Update(msg) // 正确
|
||||
s.spinner.Update(msg) // 错误!动画不会动
|
||||
```
|
||||
|
||||
2. 动画位置:动画在前,文字在后:
|
||||
```go
|
||||
fmt.Printf("\r%s %s", s.spinner.View(), s.text) // ⠋ 思考中...
|
||||
```
|
||||
|
||||
3. 换行控制:
|
||||
- "思考完成." 后需要两个换行符(一个换行 + 一个空行)
|
||||
- 流式输出完成后也需要空行分隔
|
||||
Reference in New Issue
Block a user