2026-03-20 14:26:24 +08:00
|
|
|
package tui
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"learning-assistant/internal/ai/generators"
|
|
|
|
|
"learning-assistant/internal/clipboard"
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// handleKeyPress 处理按键
|
|
|
|
|
func (m Model) handleKeyPress(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
|
|
|
|
switch m.state {
|
|
|
|
|
case StateInput:
|
|
|
|
|
return m.handleInputKey(msg)
|
|
|
|
|
case StateResult:
|
|
|
|
|
return m.handleResultKey(msg)
|
|
|
|
|
default:
|
|
|
|
|
return m, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// handleInputKey 处理输入状态下的按键
|
|
|
|
|
func (m Model) handleInputKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
|
|
|
|
switch msg.Type {
|
|
|
|
|
case tea.KeyCtrlC:
|
|
|
|
|
return m, tea.Quit
|
|
|
|
|
|
|
|
|
|
case tea.KeyEnter:
|
|
|
|
|
input := strings.TrimSpace(m.inputText)
|
|
|
|
|
if input == "" {
|
|
|
|
|
return m, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 切换到加载状态
|
|
|
|
|
m.state = StateLoading
|
|
|
|
|
|
|
|
|
|
// 启动5个生成器
|
|
|
|
|
return m, m.startGeneration()
|
|
|
|
|
|
|
|
|
|
case tea.KeyBackspace:
|
|
|
|
|
// 退格键处理
|
|
|
|
|
if len(m.inputText) > 0 {
|
|
|
|
|
m.inputText = m.inputText[:len(m.inputText)-1]
|
|
|
|
|
}
|
|
|
|
|
return m, nil
|
|
|
|
|
|
|
|
|
|
case tea.KeyRunes:
|
|
|
|
|
// 普通字符输入
|
|
|
|
|
m.inputText += string(msg.Runes)
|
|
|
|
|
return m, nil
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return m, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// handleResultKey 处理结果状态下的按键
|
|
|
|
|
func (m Model) handleResultKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
|
|
|
|
switch msg.Type {
|
|
|
|
|
case tea.KeyCtrlC, tea.KeyCtrlQ:
|
|
|
|
|
return m, tea.Quit
|
|
|
|
|
|
|
|
|
|
case tea.KeyLeft:
|
|
|
|
|
m.activeTab = (m.activeTab - 1 + len(m.tabs)) % len(m.tabs)
|
|
|
|
|
return m, nil
|
|
|
|
|
|
|
|
|
|
case tea.KeyRight:
|
|
|
|
|
m.activeTab = (m.activeTab + 1) % len(m.tabs)
|
|
|
|
|
return m, nil
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return m, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// startGeneration 开始生成内容
|
|
|
|
|
func (m Model) startGeneration() tea.Cmd {
|
|
|
|
|
resultChan := make(chan generators.GenerateResult, 5)
|
|
|
|
|
|
|
|
|
|
// 启动5个生成器
|
|
|
|
|
generatorTypes := []generators.GeneratorType{
|
|
|
|
|
generators.GeneratorMermaid,
|
|
|
|
|
generators.GeneratorGuodegang,
|
|
|
|
|
generators.GeneratorQuiz,
|
|
|
|
|
generators.GeneratorCard,
|
|
|
|
|
generators.GeneratorScenario,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, genType := range generatorTypes {
|
|
|
|
|
go func(gt generators.GeneratorType) {
|
|
|
|
|
m.generator.Generate(gt, m.inputText, resultChan)
|
|
|
|
|
}(genType)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 立即启动一个命令来监听结果
|
|
|
|
|
return func() tea.Msg {
|
|
|
|
|
for range generatorTypes {
|
|
|
|
|
result := <-resultChan
|
|
|
|
|
if result.Error != nil {
|
|
|
|
|
return errorMessage{
|
|
|
|
|
Type: result.Type,
|
|
|
|
|
Error: result.Error,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return contentMsg{
|
|
|
|
|
Type: result.Type,
|
|
|
|
|
Content: result.Content,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// handleContentResult 处理内容生成结果
|
|
|
|
|
func (m Model) handleContentResult(msg contentMsg) (tea.Model, tea.Cmd) {
|
|
|
|
|
m.loadingStatus[msg.Type] = true
|
|
|
|
|
|
|
|
|
|
switch msg.Type {
|
|
|
|
|
case generators.GeneratorGuodegang:
|
|
|
|
|
m.results[TabGuodegang] = msg.Content
|
|
|
|
|
case generators.GeneratorQuiz:
|
|
|
|
|
m.results[TabQuiz] = msg.Content
|
|
|
|
|
case generators.GeneratorCard:
|
|
|
|
|
m.results[TabCard] = msg.Content
|
|
|
|
|
case generators.GeneratorScenario:
|
|
|
|
|
m.results[TabScenario] = msg.Content
|
|
|
|
|
case generators.GeneratorMermaid:
|
|
|
|
|
// Mermaid复制到剪切板
|
2026-03-20 20:46:45 +08:00
|
|
|
clipboard.Write(msg.Content)
|
2026-03-20 14:26:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查是否全部完成
|
|
|
|
|
allDone := true
|
|
|
|
|
for _, done := range m.loadingStatus {
|
|
|
|
|
if !done {
|
|
|
|
|
allDone = false
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if allDone {
|
|
|
|
|
m.state = StateResult
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return m, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// handleError 处理错误
|
|
|
|
|
func (m Model) handleError(msg errorMessage) (tea.Model, tea.Cmd) {
|
|
|
|
|
m.state = StateError
|
|
|
|
|
m.errorMsg = fmt.Sprintf("生成失败: %v", msg.Error)
|
|
|
|
|
return m, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// handleInput 处理用户输入
|
|
|
|
|
func (m *Model) handleInput(input string) {
|
|
|
|
|
m.inputText = strings.TrimSpace(input)
|
|
|
|
|
}
|