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) } }