Files
YunShu/onboard.go

155 lines
3.6 KiB
Go
Raw Permalink Normal View History

package main
import (
"fmt"
"os"
"path/filepath"
"hub.gaomia.site/titor/YunShu/pkg/style"
"hub.gaomia.site/titor/YunShu/pkg/termui"
)
const userMDTemplate = `# 用户画像
> 这里记录关于你的信息通过对话自动更新你也可以手动修改
## 基本信息
- **称呼**
- **常驻地**
- **温度单位**摄氏度 (C)
## 偏好
- 过敏源
- 兴趣
- 出行习惯
## 备注
自由添加不会被自动覆盖
`
const soulMDTemplate = `# AI 灵魂
> 这里是 AI 的灵魂设定你可以修改下面的话改变我的性格和说话方式
## 人设
你是一个友好亲切的个人助理说话简洁直接偶尔可以幽默
## 注意事项
- 尊重用户的隐私
- 不主动推荐第三方服务
- 对不确定的事情要坦诚不编造
`
func runOnboard() {
fmt.Println()
fmt.Println(style.Cyan.Render("☁ 云枢·Agent · 初始化配置"))
fmt.Println()
fmt.Println("配置说明 · 以下信息将保存在", style.Dim.Render(ConfigDir()))
fmt.Println()
host := termui.TextInput("LLM 接口地址",
termui.WithRequired(true),
termui.WithHelp("支持 OpenAI 兼容格式"),
termui.WithDefault("https://ark.cn-beijing.volces.com/api/v3/chat/completions"),
termui.WithValidator(termui.And(termui.NonEmpty, termui.IsURL)),
)
key := termui.PasswordInput("API Key",
termui.WithRequired(true),
termui.WithHelp("输入已隐藏"),
termui.WithValidator(termui.NonEmpty),
)
model := termui.TextInput("模型名称",
termui.WithHelp("默认: doubao-seed-2-0-pro-260215"),
termui.WithDefault("doubao-seed-2-0-pro-260215"),
)
fmt.Println()
ok := termui.Confirm("保存配置?", true)
if !ok {
fmt.Println(style.Yellow.Render("取消配置"))
return
}
cfg := &Config{
LLM: LLMConfig{
Host: host,
Model: model,
Key: key,
},
}
if err := SaveConfig(cfg); err != nil {
fmt.Fprintln(os.Stderr, style.Red.Render("保存配置失败: "+err.Error()))
os.Exit(1)
}
CopyDefaultDir("agents", "agents")
CopyDefaultDir("skills", "skills")
CopyDefaultDir("data", "data")
ensureUserConfig()
fmt.Println()
testOk := termui.Confirm("测试连通性?", true)
if testOk {
testLLM()
}
fmt.Println()
fmt.Println(style.Green.Render("✔ 配置完成!"))
fmt.Println(" 配置文件:", style.Dim.Render(filepath.Join(ConfigDir(), "config.yml")))
fmt.Println()
fmt.Println(" 运行示例:")
fmt.Println(" " + style.Cyan.Render("yunshu \"北京今天天气\""))
fmt.Println(" " + style.Cyan.Render("yunshu"))
}
func testLLM() {
fmt.Print(style.Dim.Render("测试中 ..."))
oldKey, oldHost, oldModel := llmKey, llmHost, llmModel
defer func() {
llmKey, llmHost, llmModel = oldKey, oldHost, oldModel
}()
cfg, err := LoadConfig()
if err != nil {
fmt.Println(style.Red.Render("\r⚠ 读取配置失败: " + err.Error()))
return
}
llmKey, llmHost, llmModel = cfg.LLM.Key, cfg.LLM.Host, cfg.LLM.Model
msg := Message{Role: RoleUser, Content: "ping"}
_, err = CallLLM([]Message{msg}, nil)
if err != nil {
fmt.Println(style.Red.Render("\r⚠ 连接失败: " + err.Error()))
return
}
fmt.Println(style.Green.Render("\r✔ 连接成功!"))
}
func ensureUserConfig() {
dir := ConfigDir()
os.MkdirAll(filepath.Join(dir, "notes"), 0755)
os.MkdirAll(filepath.Join(dir, "config"), 0755)
userPath := filepath.Join(dir, "config", "user.md")
if _, err := os.Stat(userPath); os.IsNotExist(err) {
os.WriteFile(userPath, []byte(userMDTemplate), 0644)
}
soulPath := filepath.Join(dir, "config", "soul.md")
if _, err := os.Stat(soulPath); os.IsNotExist(err) {
os.WriteFile(soulPath, []byte(soulMDTemplate), 0644)
}
}