package main // ai_scope.go 提供页面级 AI 总结的上下文聚合: // 启动台 / 运行日志 / 排期日历 / 配置 / 笔记 五个全局 scope, // 结果统一存入 day_briefs(projectID=0),复用 RegenerateAISummary 流程。 import ( "fmt" "strings" "time" ) // scopeSummaryKinds 是页面级总结的合法 kind 集合。 var scopeSummaryKinds = map[string]bool{ "launchpad": true, "logs": true, "calendar": true, "config": true, "notes": true, } // writeScopeContext 按 scope 聚合当前应用数据,写入系统提示词。 func (a *App) writeScopeContext(b *strings.Builder, scope string) { switch scope { case "launchpad": a.writeLaunchpadContext(b) case "logs": a.writeLogsContext(b) case "calendar": a.writeCalendarContext(b) case "config": a.writeConfigContext(b) case "notes": a.writeNotesContext(b) } } func (a *App) writeLaunchpadContext(b *strings.Builder) { entries, e := a.ListLaunchEntries() b.WriteString("\n## 本机运行服务与已保存应用\n") if e != nil || len(entries) == 0 { b.WriteString("- 无\n") return } n := 0 for _, x := range entries { if n >= 40 { break } n++ state := "已停止" if x.Running { state = "运行中" } saved := "扫描到" if x.ID > 0 { saved = "我的应用" } ports := x.Ports if len(ports) == 0 && x.Port > 0 { ports = []int{x.Port} } fmt.Fprintf(b, "- [%s|%s] %s(类型 %s,端口 %v,PID %d)CPU %.1f%%,内存 %.0fMB,IO %.0fKB/s\n", saved, state, x.Name, x.Kind, ports, x.PID, x.CPU, x.MemMB, x.IOKBs) } } func (a *App) writeLogsContext(b *strings.Builder) { logs, e := a.store.Logs("all") b.WriteString("\n## 最近运行日志(新→旧)\n") if e != nil || len(logs) == 0 { b.WriteString("- 无\n") return } counts := map[string]int{} for _, l := range logs { counts[l.Level]++ } fmt.Fprintf(b, "- 总量统计:错误 %d 条,警告 %d 条,信息 %d 条\n", counts["error"], counts["warning"], counts["info"]) for i, l := range logs { if i >= 200 { break } detail := l.Detail if r := []rune(detail); len(r) > 120 { detail = string(r[:120]) + "…" } fmt.Fprintf(b, "- %s [%s|%s] %s %s\n", strings.Replace(l.CreatedAt, "T", " ", 1), l.Level, l.Category, l.Message, detail) } } func (a *App) writeCalendarContext(b *strings.Builder) { now := time.Now() today := now.Format("2006-01-02") limit := now.AddDate(0, 0, 30).Format("2006-01-02") fmt.Fprintf(b, "\n## 排期视角(今天 %s,展望 30 天)\n", today) todos, _ := a.store.ListTodos("all", 0) tickets, _ := a.store.ListTickets("all", 0) type item struct{ kind, title, status, priority, due, project string } var overdue, upcoming []item push := func(kind, title, status, priority, due, project string, doneLike bool) { if doneLike { return } d := due if len(d) > 10 { d = d[:10] } it := item{kind, title, status, priority, due, project} switch { case d != "" && d < today: overdue = append(overdue, it) case d != "" && d <= limit: upcoming = append(upcoming, it) } } for _, x := range todos { push("待办", x.Title, x.Status, x.Priority, x.DueAt, x.ProjectName, x.Status == "done") } for _, x := range tickets { push("工单", x.Title, x.Status, x.Priority, x.DueAt, x.ProjectName, x.Status == "resolved" || x.Status == "closed") } b.WriteString("\n## 已逾期\n") if len(overdue) == 0 { b.WriteString("- 无\n") } for i, x := range overdue { if i >= 20 { break } fmt.Fprintf(b, "- [%s|%s|%s] %s(截止 %s,项目 %s)\n", x.kind, x.status, x.priority, x.title, x.due, orDash(x.project)) } b.WriteString("\n## 未来 30 天到期\n") if len(upcoming) == 0 { b.WriteString("- 无\n") } for i, x := range upcoming { if i >= 40 { break } fmt.Fprintf(b, "- [%s|%s|%s] %s(截止 %s,项目 %s)\n", x.kind, x.status, x.priority, x.title, x.due, orDash(x.project)) } } func (a *App) writeConfigContext(b *strings.Builder) { st, e := a.store.Settings() if e != nil { return } keyState := func(k string) string { if strings.TrimSpace(k) != "" { return "已配置" } return "未配置" } b.WriteString("\n## 当前应用配置\n") fmt.Fprintf(b, "- 界面:主题 %s,语言 %s,加载动画 %s,玻璃透明度 %d%%\n", st.Theme, st.Locale, st.LoadingStyle, st.GlassOpacity) fmt.Fprintf(b, "- 统计:Git 统计范围 %s,列表自动刷新 %v\n", st.GitScope, st.AutoRefresh) fmt.Fprintf(b, "- 系统集成:关闭窗口最小化到托盘 %v\n", st.MinimizeToTray) fmt.Fprintf(b, "- 自动更新统计:开启 %v,模式 %s,间隔 %d,触发时间 %s\n", st.AutoUpdateEnabled, st.AutoUpdateMode, st.AutoUpdateInterval, st.AutoUpdateTime) fmt.Fprintf(b, "- AI:当前服务商 %s,星火 Key %s,DeepSeek Key %s,Key 云同步 %v\n", st.AIProvider, keyState(st.SparkKey), keyState(st.DeepSeekKey), st.SyncAPIKeys) fmt.Fprintf(b, "- 图片存储模式:%s\n", st.ImageMode) if rules, e := a.store.Rules(); e == nil { custom := 0 for _, r := range rules { if !r.Builtin { custom++ } } fmt.Fprintf(b, "- 排除规则:共 %d 条(自定义 %d 条)\n", len(rules), custom) } if projects, e := a.store.ListProjects(0); e == nil { fmt.Fprintf(b, "- 项目:共 %d 个\n", len(projects)) } if a.syncUserID() > 0 { fmt.Fprintf(b, "- 云同步:已登录(%s)\n", a.store.Meta("sync_username")) } else { b.WriteString("- 云同步:未登录\n") } } func (a *App) writeNotesContext(b *strings.Builder) { notes, e := a.store.ListNotes(200) b.WriteString("\n## 全部笔记(新→旧)\n") if e != nil || len(notes) == 0 { b.WriteString("- 无\n") return } for i, n := range notes { if i >= 100 { break } content := strings.TrimSpace(n.Content) if r := []rune(content); len(r) > 400 { content = string(r[:400]) + "…" } fmt.Fprintf(b, "\n### 笔记 %d(更新于 %s)\n%s\n", i+1, strings.Replace(n.UpdatedAt, "T", " ", 1), content) } } // scopeInstruction 页面级总结指令(与 summaryInstruction 同构,按 locale 切换)。 func scopeInstruction(kind, locale string) (string, bool) { if locale == "en" { switch kind { case "launchpad": return "Based on the services above, summarize what is running on this machine (within 200 words): notable resource hogs, suspicious or duplicated services, and cleanup suggestions. Output a short Markdown list.", true case "logs": return "Based on the logs above, summarize recent application activity (within 200 words): recurring errors or warnings with likely causes, notable events, and suggested follow-ups. Output a short Markdown list.", true case "calendar": return "Based on the schedule above, summarize the coming month (within 200 words): overdue items to rescue first, busy periods, and scheduling advice. Only reference listed items. Output a short Markdown list.", true case "config": return "Based on the configuration above, review the app setup (within 200 words): risky or missing settings (e.g. AI keys, auto update, sync), and concrete tuning suggestions. Output a short Markdown list.", true case "notes": return "Based on the notes above, produce a digest (within 200 words): main themes, actionable items hidden in notes, and anything worth converting into todos. Only reference listed notes. Output a short Markdown list.", true } return "", false } switch kind { case "launchpad": return "基于以上服务清单,用不超过 250 字总结本机运行情况:资源占用突出的服务、可疑或重复的进程、值得关停或固化为常用应用的建议。直接输出 Markdown 列表,不要大标题。", true case "logs": return "基于以上日志,用不超过 250 字总结应用近期运行状况:反复出现的错误/警告及可能原因、值得关注的事件、建议的后续动作。直接输出 Markdown 列表,不要大标题。", true case "calendar": return "基于以上排期数据,用不超过 250 字总结未来一个月的日程:需要优先补救的逾期项、任务密集的时间段、排期调整建议。只能引用上面列出的条目,不要编造。直接输出 Markdown 列表,不要大标题。", true case "config": return "基于以上配置,用不超过 250 字点评当前应用设置:存在风险或缺失的配置(如 AI Key、自动统计、云同步),以及具体的调优建议。直接输出 Markdown 列表,不要大标题。", true case "notes": return "基于以上笔记,用不超过 250 字生成一份笔记摘要:主要主题、笔记里隐藏的待办事项、值得转成正式待办的内容。只能引用上面列出的笔记,不要编造。直接输出 Markdown 列表,不要大标题。", true } return "", false }