Files
MujicaUI/examples/gallery/pages_chatsession_more.go
T
2026-10-05 14:24:42 -04:00

342 lines
11 KiB
Go

package main
import (
"fmt"
"time"
"github.com/egoist/mygo/ui"
mujica "mujicaui"
)
func chatDemoWelcomeScreen(c *ui.Context, log func(string)) {
type state struct {
input string
cards, disabled bool
}
s := *ui.Local(c.Root(), "246", func() *state { return &state{cards: true} })
choiceDemo(c, func() {
choiceFlag(c, &s.cards, "Capability cards", log)
choiceFlag(c, &s.disabled, "Disabled", log)
}, func() {
var cards []mujica.CapabilityCard
if s.cards {
cards = chatSampleCards()
}
ui.Column(c).Width(860).Children(func() {
v := mujica.WelcomeScreen(c, mujica.WelcomeScreenOptions{Greeting: "Good afternoon", Subtitle: "How may I serve the court?", Cards: cards, Disabled: s.disabled,
Prompts: func() {
if mujica.SuggestionChips(c, &s.input, []string{"Plan a ball", "Write a sonnet"}, mujica.SuggestionChipsOptions{Disabled: s.disabled}).Chosen != "" {
log(fmt.Sprintf("fill %q", s.input))
}
}})
if v.Example != "" {
log(fmt.Sprintf("ask %q", v.Example))
}
})
})
}
func chatDemoSuggestionChips(c *ui.Context, log func(string)) {
type state struct {
input string
send, disabled bool
}
s := *ui.Local(c.Root(), "247", func() *state { return &state{} })
choiceDemo(c, func() {
choiceFlag(c, &s.send, "Send directly", log)
choiceFlag(c, &s.disabled, "Disabled", log)
}, func() {
v := mujica.SuggestionChips(c, &s.input, []string{"Plan a ball", "Write a sonnet", "Explain the minuet"},
mujica.SuggestionChipsOptions{Send: s.send, Label: "Suggestions", Disabled: s.disabled})
switch {
case v.Sent:
log(fmt.Sprintf("send %q", v.Chosen))
case v.Chosen != "":
log(fmt.Sprintf("fill %q", v.Chosen))
}
ui.Column(c).Width(420).Children(func() {
mujica.TextInput(c, &s.input, mujica.TextInputOptions{Label: "Message", Placeholder: "Message"})
})
})
}
func chatDemoPromptLibrary(c *ui.Context, log func(string)) {
type state struct {
lib mujica.PromptLibraryState
disabled bool
}
s := *ui.Local(c.Root(), "248", func() *state { return &state{} })
templates := []mujica.PromptTemplate{
{ID: "t1", Category: "Letters", Title: "Invitation", Body: "Write an invitation to {{guest}} for the {{event}}."},
{ID: "t2", Category: "Letters", Title: "Thank-you note", Body: "Thank {{host}} for the evening."},
{ID: "t3", Category: "Music", Title: "Recital program", Body: "List pieces for a {{instrument}} recital."},
{ID: "t4", Category: "Planning", Title: "Seating chart", Body: "Seat {{count}} guests by rank."},
}
choiceDemo(c, func() {
choiceFlag(c, &s.disabled, "Disabled", log)
}, func() {
before := s.lib.Selected
v := mujica.PromptLibrary(c, &s.lib, templates, mujica.PromptLibraryOptions{Label: "Prompt library", Disabled: s.disabled})
if s.lib.Selected != before {
log("preview " + s.lib.Selected)
}
if v.Inserted != "" {
log(fmt.Sprintf("insert %q", v.Inserted))
}
})
}
func chatDemoCapabilityCards(c *ui.Context, log func(string)) {
type state struct {
one, disabled bool
}
s := *ui.Local(c.Root(), "249", func() *state { return &state{} })
choiceDemo(c, func() {
choiceFlag(c, &s.one, "One column", log)
choiceFlag(c, &s.disabled, "Disabled", log)
}, func() {
cols := 0
if s.one {
cols = 1
}
ui.Column(c).Width(860).Children(func() {
if v := mujica.CapabilityCards(c, chatSampleCards(), mujica.CapabilityCardsOptions{Columns: cols, Disabled: s.disabled}); v.Example != "" {
log(fmt.Sprintf("ask %q", v.Example))
}
})
})
}
func chatDemoFeedbackForm(c *ui.Context, log func(string)) {
type state struct {
value mujica.FeedbackValue
down, submitting bool
disabled bool
at time.Time
}
s := *ui.Local(c.Root(), "250", func() *state { return &state{down: true} })
choiceDemo(c, func() {
choiceFlag(c, &s.down, "Thumbs down", log)
choiceFlag(c, &s.disabled, "Disabled", log)
}, func() {
rating := mujica.FeedbackUp
if s.down {
rating = mujica.FeedbackDown
}
if s.submitting && choiceDue(c, s.at) {
s.submitting, s.value = false, mujica.FeedbackValue{}
log("feedback sent")
}
ui.Column(c).Width(480).Children(func() {
v := mujica.FeedbackForm(c, &s.value, mujica.FeedbackFormOptions{Rating: rating, Submitting: s.submitting, Disabled: s.disabled})
if v.Submitted {
s.submitting, s.at = true, c.Now()
log(fmt.Sprintf("submit reasons %q, %d characters", s.value.Reasons, len(s.value.Comment)))
}
if v.Cancelled {
s.value = mujica.FeedbackValue{}
log("cancel")
}
})
})
}
func chatDemoDateSeparator(c *ui.Context, log func(string)) {
today := mujica.DateOf(time.Now())
choiceDemo(c, func() {
ui.Text(c, "No parameters; the language follows the window.")
}, func() {
ui.Column(c).Width(520).Children(func() {
for _, d := range []int{0, -1, -12} {
mujica.DateSeparator(c, today.AddDays(d), mujica.DateSeparatorOptions{})
}
})
})
}
func chatDemoThinkingIndicator(c *ui.Context, log func(string)) {
type state struct{ phase int }
s := *ui.Local(c.Root(), "252", func() *state { return &state{} })
phases := []string{"", "Searching the archives", "Reading 3 letters", "Composing a reply"}
choiceDemo(c, func() {
if mujica.Button(c, "Next phase", mujica.ButtonOptions{Variant: mujica.Secondary}).Clicked() {
s.phase = (s.phase + 1) % len(phases)
log(fmt.Sprintf("phase %q", phases[s.phase]))
}
}, func() {
mujica.ThinkingIndicator(c, mujica.ThinkingIndicatorOptions{Phase: phases[s.phase]})
})
}
func chatDemoStopGeneratingButton(c *ui.Context, log func(string)) {
type state struct {
generating, disabled bool
at time.Time
}
s := *ui.Local(c.Root(), "253", func() *state { return &state{} })
choiceDemo(c, func() {
if mujica.Button(c, "Generate", mujica.ButtonOptions{Disabled: s.generating}).Clicked() {
s.generating, s.at = true, c.Now()
log("generate")
}
choiceFlag(c, &s.disabled, "Disabled", log)
}, func() {
if s.generating && c.Now().Sub(s.at) > 8*time.Second {
s.generating = false
log("finished")
} else if s.generating {
c.After(time.Second)
}
if mujica.StopGeneratingButton(c, mujica.StopGeneratingButtonOptions{Generating: s.generating, Disabled: s.disabled}).Changed() {
s.generating = false
log("stop")
}
if !s.generating {
ui.Text(c, "Idle: the button is hidden.").TextColor(mujica.Tokens(c).TextMuted)
}
})
}
func chatDemoSystemPromptEditor(c *ui.Context, log func(string)) {
type state struct {
value, saved string
limit, disabled bool
saving bool
at time.Time
}
s := *ui.Local(c.Root(), "254", func() *state {
return &state{value: "You are a courtly assistant.", saved: "You are a courtly assistant."}
})
choiceDemo(c, func() {
choiceFlag(c, &s.limit, "Limit 60", log)
choiceFlag(c, &s.disabled, "Disabled", log)
}, func() {
if s.saving && choiceDue(c, s.at) {
s.saving, s.saved = false, s.value
log("saved")
}
limit := 0
if s.limit {
limit = 60
}
ui.Column(c).Width(520).Children(func() {
v := mujica.SystemPromptEditor(c, &s.value, mujica.SystemPromptEditorOptions{Default: "You are helpful.", Saved: s.saved,
MaxLength: limit, Saving: s.saving, Disabled: s.disabled})
if v.Save {
s.saving, s.at = true, c.Now()
log(fmt.Sprintf("save %d characters", len(s.value)))
}
if v.Restored {
log("restore default")
}
})
})
}
func chatDemoCostEstimator(c *ui.Context, log func(string)) {
type state struct{ in, out, inPrice, outPrice float64 }
s := *ui.Local(c.Root(), "255", func() *state { return &state{in: 12000, out: 3400, inPrice: 3, outPrice: 15} })
choiceDemo(c, func() {
for _, f := range []struct {
v *float64
label string
}{{&s.in, "Input tokens"}, {&s.out, "Output tokens"}, {&s.inPrice, "Input $/M"}, {&s.outPrice, "Output $/M"}} {
choiceLabeled(c, f.label, func() {
r := mujica.NumberInput(c, f.v, mujica.NumberInputOptions{Min: 0, Max: 1e7, Step: 100, Label: f.label})
r.Element.Width(150)
if r.Changed() {
log(fmt.Sprintf("%s = %v", f.label, *f.v))
}
})
}
}, func() {
ui.Column(c).Width(420).Children(func() {
mujica.CostEstimator(c, mujica.CostEstimatorOptions{InputTokens: int(s.in), OutputTokens: int(s.out), InputPrice: s.inPrice, OutputPrice: s.outPrice})
})
})
}
func chatDemoSharedConversationView(c *ui.Context, log func(string)) {
type state struct{ disabled bool }
s := *ui.Local(c.Root(), "256", func() *state { return &state{} })
choiceDemo(c, func() {
choiceFlag(c, &s.disabled, "Disabled", log)
}, func() {
ui.Column(c).Width(600).Height(420).Children(func() {
if mujica.SharedConversationView(c, chatSampleMessages(time.Now()), mujica.SharedConversationViewOptions{Title: "Banquet seating",
SharedBy: "Lady Ann", SharedAt: time.Now(), Disabled: s.disabled}).Changed() {
c.WriteClipboard("https://example.com/share/banquet")
log("copy link")
}
})
})
}
func chatDemoConversationExport(c *ui.Context, log func(string)) {
type state struct {
export mujica.ConversationExportState
disabled bool
}
s := *ui.Local(c.Root(), "257", func() *state { return &state{} })
choiceDemo(c, func() {
choiceFlag(c, &s.disabled, "Disabled", log)
}, func() {
ui.Column(c).Width(580).Children(func() {
v := mujica.ConversationExport(c, &s.export, chatSampleMessages(time.Now()), mujica.ConversationExportOptions{Title: "Banquet seating",
Selected: []int{1, 3}, Disabled: s.disabled})
if v.Exported {
log(fmt.Sprintf("export %d bytes as format %d (the caller writes the file)", len(v.Content), v.Format))
}
})
})
}
func chatDemoRegenerateMenu(c *ui.Context, log func(string)) {
type state struct{ disabled bool }
s := *ui.Local(c.Root(), "258", func() *state { return &state{} })
choiceDemo(c, func() {
choiceFlag(c, &s.disabled, "Disabled", log)
}, func() {
v := mujica.RegenerateMenu(c, mujica.RegenerateMenuOptions{Models: []string{"Opus", "Sonnet", "Haiku"}, Current: "Opus", Disabled: s.disabled})
if v.Chosen {
log(fmt.Sprintf("retry kind %d model %q variant %q", v.Choice.Kind, v.Choice.Model, v.Choice.Variant))
}
})
}
func chatDemoArtifactCard(c *ui.Context, log func(string)) {
type state struct{ streaming, disabled bool }
s := *ui.Local(c.Root(), "259", func() *state { return &state{} })
choiceDemo(c, func() {
choiceFlag(c, &s.streaming, "Streaming", log)
choiceFlag(c, &s.disabled, "Disabled", log)
}, func() {
for _, a := range []mujica.ArtifactCardOptions{
{Kind: mujica.ArtifactCode, Title: "seating.go", Detail: "Go · 120 lines"},
{Kind: mujica.ArtifactDocument, Title: "Royal decree", Detail: "2 pages"},
{Kind: mujica.ArtifactWeb, Title: "Ball invitation"},
} {
a.Streaming, a.Disabled = s.streaming, s.disabled
if mujica.ArtifactCard(c, a).Changed() {
log("open " + a.Title)
}
}
})
}
func chatDemoChatEmptyState(c *ui.Context, log func(string)) {
type state struct{ kind int }
s := *ui.Local(c.Root(), "260", func() *state { return &state{} })
choiceDemo(c, func() {
mujica.RadioGroup(c, &s.kind, []mujica.RadioItem[int]{{Value: 0, Label: "New"}, {Value: 1, Label: "No results"}, {Value: 2, Label: "Offline"}},
mujica.RadioGroupOptions{Horizontal: true, Label: "Kind"})
}, func() {
ui.Column(c).Width(420).Children(func() {
if mujica.ChatEmptyState(c, mujica.ChatEmptyStateOptions{Kind: mujica.ChatEmptyKind(s.kind), Query: "minuet"}).Action {
log(fmt.Sprintf("action for kind %d", s.kind))
}
})
})
}