feat: 提交详情能看 diff,也能丢给 AI 审这一次改动。文件检查可单独排除路径,TODO 只认大写,避免把 todo 表和模块当成待办标记。
热力图按容器宽度铺满一年,不再横向滚动。托盘右键换成可换皮肤的弹层;更新下载显示进度,退出后再由脚本拉起安装器,避免还占着 exe。
This commit is contained in:
62
ai.go
62
ai.go
@@ -11,6 +11,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"view/service"
|
||||
"view/service/ai"
|
||||
)
|
||||
|
||||
@@ -145,6 +146,49 @@ type aiStreamEvent struct {
|
||||
// SendAIMessage 发送一条用户消息并启动流式回复。
|
||||
// conversationID 为 0 时自动创建会话;scenario: chat | project | git | todo | ticket。
|
||||
func (a *App) SendAIMessage(conversationID, projectID int64, scenario, content string) (AIConversation, error) {
|
||||
return a.startAIChat(conversationID, projectID, scenario, content, "", "")
|
||||
}
|
||||
|
||||
// SendAIDiffMessage 针对某次提交的 diff 发起 AI 分析;后续同会话追问仍带上该 diff。
|
||||
func (a *App) SendAIDiffMessage(conversationID, projectID int64, hash, content string) (AIConversation, error) {
|
||||
hash = strings.TrimSpace(hash)
|
||||
if hash == "" {
|
||||
return AIConversation{}, errors.New("GIT_REF_NOT_FOUND")
|
||||
}
|
||||
if e := a.ready(); e != nil {
|
||||
return AIConversation{}, e
|
||||
}
|
||||
if projectID <= 0 && conversationID > 0 {
|
||||
convs, _ := a.store.ListAIConversations(0)
|
||||
for _, c := range convs {
|
||||
if c.ID == conversationID {
|
||||
projectID = c.ProjectID
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
p, e := a.store.GetProject(projectID)
|
||||
if e != nil {
|
||||
return AIConversation{}, e
|
||||
}
|
||||
d, e := (GitAnalyzer{}).CommitDetail(a.ctx, p.Path, hash)
|
||||
if e != nil {
|
||||
return AIConversation{}, e
|
||||
}
|
||||
title := strings.TrimSpace(d.Message)
|
||||
if title == "" {
|
||||
title = content
|
||||
}
|
||||
if r := []rune(title); len(r) > 36 {
|
||||
title = string(r[:36]) + "…"
|
||||
}
|
||||
if !strings.HasPrefix(strings.ToLower(title), "diff") {
|
||||
title = "Diff: " + title
|
||||
}
|
||||
return a.startAIChat(conversationID, projectID, "diff", content, service.FormatCommitDiffForAI(d, 0), title)
|
||||
}
|
||||
|
||||
func (a *App) startAIChat(conversationID, projectID int64, scenario, content, extraSystem, title string) (AIConversation, error) {
|
||||
if e := a.ready(); e != nil {
|
||||
return AIConversation{}, e
|
||||
}
|
||||
@@ -166,7 +210,9 @@ func (a *App) SendAIMessage(conversationID, projectID int64, scenario, content s
|
||||
|
||||
var conv AIConversation
|
||||
if conversationID == 0 {
|
||||
title := content
|
||||
if strings.TrimSpace(title) == "" {
|
||||
title = content
|
||||
}
|
||||
if r := []rune(title); len(r) > 40 {
|
||||
title = string(r[:40]) + "…"
|
||||
}
|
||||
@@ -197,9 +243,19 @@ func (a *App) SendAIMessage(conversationID, projectID int64, scenario, content s
|
||||
a.aiStreams[conv.ID] = cancel
|
||||
a.mu.Unlock()
|
||||
|
||||
// 组装消息:场景系统提示词 + 最近历史 + 本条用户消息。
|
||||
sys := a.buildAIContext(projectID, scenario, st.Locale)
|
||||
if extraSystem != "" {
|
||||
sys = strings.TrimRight(sys, "\n") + "\n\n" + extraSystem
|
||||
if scenario == "diff" {
|
||||
if st.Locale == "en" {
|
||||
sys += "\nTask: Review this commit's diff. Cover intent, risks, missing tests, and brief improvements. Use only the diff above; do not invent changes.\n"
|
||||
} else {
|
||||
sys += "\n任务:审查这次提交的 diff,说明改动意图、潜在风险、遗漏测试,并给出简要改进建议。只依据上面的 diff,不要编造未出现的改动。\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
history, _ := a.store.ListAIMessages(conv.ID)
|
||||
msgs := []ai.Message{{Role: "system", Content: a.buildAIContext(projectID, scenario, st.Locale)}}
|
||||
msgs := []ai.Message{{Role: "system", Content: sys}}
|
||||
if len(history) > 20 {
|
||||
history = history[len(history)-20:]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user