Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(gittar): optimize ai code-review #6201

Merged
merged 4 commits into from
Jan 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions cmd/gittar/conf/i18n/i18n.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
zh:
mr.note.comment.cannot.be.empty: 评论不能为空
template.mr.ai.cr.tip.reach.max.limit: 这里仅展示前 %d 个文件的审查结果。对于其他未审查到的文件,请移至 "**变更**" 页里,手动点击 "**AI 审查**" 按钮,或者手动选择代码片段开启 "**AI 对话**"。
mr.ai.cr.title: AI 代码审查
file: 文件
snippet: 代码片段
mr.ai.cr.no.suggestion: 你的代码变更看起来不错,暂无审查建议。
template.mr.ai.cr.file.content.max.limit: 文件内容超长,本次审查至第 %d 行。对于其他未审查到的内容,请在 "**变更**" 页里手动选择代码片段开启 "**AI 对话**"。
en:
mr.note.comment.cannot.be.empty: Comment cannot be empty
template.mr.ai.cr.tip.reach.max.limit: Only the first %d files are displayed here. For other files that have not been reviewed, please manually click the "**AI Code Review**" button in the "**Changes**" tab, or manually select the code snippet to start the "**AI Conversation**".
mr.ai.cr.title: AI Code Review
file: File
snippet: Code Snippet
mr.ai.cr.no.suggestion: Your code changes look good, no review suggestions for now.
template.mr.ai.cr.file.content.max.limit: The file content is too long, only the first %d lines are reviewed. For other content that has not been reviewed, please manually select the code snippet in "Changes" tab to start the "AI Conversation".
48 changes: 39 additions & 9 deletions internal/tools/gittar/ai/cr/impl/cr_mr/mr.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,26 @@
package cr_mr

import (
"fmt"
"strings"
"sync"

"github.com/sirupsen/logrus"

"github.com/erda-project/erda-infra/providers/i18n"
"github.com/erda-project/erda/apistructs"
"github.com/erda-project/erda/internal/tools/gittar/ai/cr/impl/cr_mr_file"
"github.com/erda-project/erda/internal/tools/gittar/ai/cr/util/mdutil"
"github.com/erda-project/erda/internal/tools/gittar/ai/cr/util/mrutil"
"github.com/erda-project/erda/internal/tools/gittar/models"
"github.com/erda-project/erda/internal/tools/gittar/pkg/gitmodule"
"github.com/erda-project/erda/pkg/limit_sync_group"
)

const (
MaxDiffFileNum = 5
)

type mrReviewer struct {
req models.AICodeReviewNoteRequest
repo *gitmodule.Repository
Expand All @@ -38,26 +48,32 @@ func init() {
})
}

func (r *mrReviewer) CodeReview() string {
func (r *mrReviewer) CodeReview(i18n i18n.Translator, lang i18n.LanguageCodes) string {
diff := mrutil.GetDiffFromMR(r.repo, r.mr)

// mr has many changed files, we will review only the first ten files one by one. Then, combine the file-level suggestions.

var changedFiles []models.FileCodeReviewer
var reachMaxDiffFileNumLimit bool
for _, diffFile := range diff.Files {
if len(changedFiles) >= 10 {
if len(changedFiles) >= MaxDiffFileNum {
reachMaxDiffFileNumLimit = true
break
}
if len(diffFile.Sections) > 0 {
fr := cr_mr_file.NewFileReviewer(diffFile, r.user, r.mr)
fr, err := cr_mr_file.NewFileReviewer(diffFile.Name, r.repo, r.mr, r.user)
if err != nil {
logrus.Warnf("failed to create file reviewer for file %s, err: %v", diffFile.Name, err)
continue
}
changedFiles = append(changedFiles, fr)
}
}

// parallel do file-level cr
var fileOrder []string
fileSuggestions := make(map[string]string)
wg := limit_sync_group.NewSemaphore(5) // parallel is 5
wg := limit_sync_group.NewSemaphore(MaxDiffFileNum) // parallel is 5
var mu sync.Mutex

wg.Add(len(changedFiles))
Expand All @@ -66,19 +82,33 @@ func (r *mrReviewer) CodeReview() string {
go func(file models.FileCodeReviewer) {
defer wg.Done()

fileSuggestion := file.CodeReview(i18n, lang)
if strings.TrimSpace(fileSuggestion) == "" {
fileSuggestion = i18n.Text(lang, models.I18nKeyMrAICrNoSuggestion)
}
mu.Lock()
fileSuggestions[file.GetFileName()] = file.CodeReview()
fileSuggestions[file.GetFileName()] = fileSuggestion
mu.Unlock()
}(file)
}
wg.Wait()

// combine result
var mrReviewResult string
mrReviewResult = "# AI Code Review\n"
var mrReviewResults []string
mrReviewResults = append(mrReviewResults, fmt.Sprintf("# %s", i18n.Text(lang, models.I18nKeyMrAICrTitle)))
if reachMaxDiffFileNumLimit {
tip := fmt.Sprintf(i18n.Text(lang, models.I18nKeyTemplateMrAICrTipForEachMaxLimit), MaxDiffFileNum)
tip = mdutil.MakeRef(mdutil.MakeItalic(tip))
mrReviewResults = append(mrReviewResults, tip)
}
mrReviewResults = append(mrReviewResults, "")
for _, fileName := range fileOrder {
mrReviewResult += "------\n## File: `" + fileName + "`\n\n" + fileSuggestions[fileName] + "\n"
mrReviewResults = append(mrReviewResults, "------")
mrReviewResults = append(mrReviewResults, fmt.Sprintf("## %s: `%s`", i18n.Text(lang, models.I18nKeyFile), fileName))
mrReviewResults = append(mrReviewResults, "")
mrReviewResults = append(mrReviewResults, fileSuggestions[fileName])
mrReviewResults = append(mrReviewResults, "")
}

return mrReviewResult
return strings.Join(mrReviewResults, "\n")
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
messages:
- role: system
content: Please reply in {{.UserLang}}.

- role: system
content: |
Please give a review suggestions for the selected code, use markdown title for each suggestion. Code examples can be provided when necessary.
The first-level title is: AI Code Review.
Code:
{{.SelectedCode}}

- role: system
content: Please reply in Chinese.
12 changes: 8 additions & 4 deletions internal/tools/gittar/ai/cr/impl/cr_mr_code_snippet/snippet.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@
"github.com/sashabaranov/go-openai"
"gopkg.in/yaml.v3"

"github.com/erda-project/erda-infra/providers/i18n"
"github.com/erda-project/erda/apistructs"
"github.com/erda-project/erda/internal/tools/gittar/ai/cr/util/aiutil"
"github.com/erda-project/erda/internal/tools/gittar/ai/cr/util/i18nutil"
"github.com/erda-project/erda/internal/tools/gittar/models"
"github.com/erda-project/erda/internal/tools/gittar/pkg/gitmodule"
)
Expand All @@ -41,6 +43,7 @@
CodeLanguage string
SelectedCode string
Truncated bool // if there are too many changes, we have to truncate the content according to the model context
UserLang string

user *models.User
}
Expand Down Expand Up @@ -82,15 +85,16 @@
return cs
}

func (cs CodeSnippet) CodeReview() string {
// invoke ai
req := cs.constructAIRequest()
func (cs CodeSnippet) CodeReview(i18n i18n.Translator, lang i18n.LanguageCodes) string {

Check warning on line 88 in internal/tools/gittar/ai/cr/impl/cr_mr_code_snippet/snippet.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/gittar/ai/cr/impl/cr_mr_code_snippet/snippet.go#L88

Added line #L88 was not covered by tests
// construct AI request
req := cs.constructAIRequest(i18n, lang)

Check warning on line 90 in internal/tools/gittar/ai/cr/impl/cr_mr_code_snippet/snippet.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/gittar/ai/cr/impl/cr_mr_code_snippet/snippet.go#L90

Added line #L90 was not covered by tests

// invoke
return aiutil.InvokeAI(req, cs.user)
}

func (cs CodeSnippet) constructAIRequest() openai.ChatCompletionRequest {
func (cs CodeSnippet) constructAIRequest(i18n i18n.Translator, lang i18n.LanguageCodes) openai.ChatCompletionRequest {
cs.UserLang = i18nutil.GetUserLang(lang)

Check warning on line 97 in internal/tools/gittar/ai/cr/impl/cr_mr_code_snippet/snippet.go

View check run for this annotation

Codecov / codecov/patch

internal/tools/gittar/ai/cr/impl/cr_mr_code_snippet/snippet.go#L96-L97

Added lines #L96 - L97 were not covered by tests
msgs := deepcopy.Copy(promptStruct.Messages).([]openai.ChatCompletionMessage)

// invoke ai
Expand Down
27 changes: 0 additions & 27 deletions internal/tools/gittar/ai/cr/impl/cr_mr_file/fc.yaml

This file was deleted.

Loading
Loading