Skip to content

Commit 171ff52

Browse files
authored
Merge pull request #6 from Robbings/dev
实现大模型支持,并完善配置文档
2 parents 50b80e0 + a967c76 commit 171ff52

File tree

12 files changed

+305
-123
lines changed

12 files changed

+305
-123
lines changed

README.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,89 @@
5454
<img src="doc/img/img.png" style="width:500px;"/>
5555
</p>
5656

57+
### 3. 更多种大模型接入
58+
1. 可通过实现项目接口快速接入自定义模型,具体配置方式参见[config.md](doc/config.md)
59+
2. 项目通过[UnionLLM](https://github.com/EvalsOne/UnionLLM/)进行多模型支持,
60+
兼容[LiteLLM](https://docs.litellm.ai/docs),默认支持模型如下表所示。
61+
62+
<table style="width:100%; text-align:center; border-collapse:collapse;">
63+
<tr>
64+
<td>OpenAI</td>
65+
<td>Azure</td>
66+
<td>AWS - SageMaker</td>
67+
<td>AWS - Bedrock</td>
68+
</tr>
69+
<tr>
70+
<td>Google - Vertex_AI</td>
71+
<td>Google - Palm</td>
72+
<td>Google AI Studio - Gemini</td>
73+
<td>Mistral AI API</td>
74+
</tr>
75+
<tr>
76+
<td>Cloudflare AI Workers</td>
77+
<td>Cohere</td>
78+
<td>Anthropic</td>
79+
<td>Empower</td>
80+
</tr>
81+
<tr>
82+
<td>Huggingface</td>
83+
<td>Replicate</td>
84+
<td>Together_AI</td>
85+
<td>OpenRouter</td>
86+
</tr>
87+
<tr>
88+
<td>AI21</td>
89+
<td>Baseten</td>
90+
<td>Vllm</td>
91+
<td>NLP_Cloud</td>
92+
</tr>
93+
<tr>
94+
<td>Aleph Alpha</td>
95+
<td>Petals</td>
96+
<td>Ollama</td>
97+
<td>Deepinfra</td>
98+
</tr>
99+
<tr>
100+
<td>Perplexity-AI</td>
101+
<td>Groq AI</td>
102+
<td>DeepSeek</td>
103+
<td>Anyscale</td>
104+
</tr>
105+
<tr>
106+
<td>IBM - Watsonx.ai</td>
107+
<td>Voyage AI</td>
108+
<td>Xinference [Xorbits Inference]</td>
109+
<td>FriendliAI</td>
110+
</tr>
111+
<tr>
112+
<td>Galadriel</td>
113+
<td>智谱AI</td>
114+
<td>月之暗面 Moonshot</td>
115+
<td>百度文心一言</td>
116+
</tr>
117+
<tr>
118+
<td>阿里巴巴通义千问</td>
119+
<td>MiniMax</td>
120+
<td>讯飞星火</td>
121+
<td>百川智能</td>
122+
</tr>
123+
<tr>
124+
<td>昆仑天工</td>
125+
<td>零一万物</td>
126+
<td>阶跃星辰</td>
127+
<td>字节豆包</td>
128+
</tr>
129+
<tr>
130+
<td>深度求索 DeepSeek</td>
131+
<td>More</td>
132+
<td></td>
133+
<td></td>
134+
</tr>
135+
</table>
136+
137+
138+
139+
57140

58141
# 部署 📖
59142

@@ -70,6 +153,7 @@ pip install -r requirements.txt
70153
```bash
71154
vim config/config.py
72155
```
156+
73157
4.**运行**
74158
```bash
75159
python3 app.py
@@ -94,6 +178,7 @@ todo dockerfile
94178
# 待办清单 📌
95179

96180
- ✅ 使用 GPT 进行Code Review
181+
- ✅ 实现多模型支持
97182
- [ ] 尝试接入私有化大模型解决代码安全问题
98183
- [ ] 可以配置更多的触发方式
99184
- ✅ Merge Request
@@ -127,4 +212,6 @@ todo dockerfile
127212
**This project is licensed under the [MIT License](https://chat.openai.com/c/9be6b422-f10c-4379-b152-e756230d54f8#:~:text=%E7%9A%84%E5%AE%8C%E6%95%B4%E6%96%87%E6%9C%AC%EF%BC%9A-,MIT%20License,-%E4%BD%A0%E5%8F%AF%E4%BB%A5%E8%AE%BF%E9%97%AE).**
128213

129214

215+
## Star History
130216

217+
[![Star History Chart](https://api.star-history.com/svg?repos=mimo-x/Code-Review-GPT-Gitlab&type=Date)](https://star-history.com/#mimo-x/Code-Review-GPT-Gitlab&Date)

app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
app = Flask(__name__)
77
app.config['debug'] = True
88

9-
# 路由组
9+
# router group
1010
app.register_blueprint(git, url_prefix='/git')
1111

1212

app/gitlab_utils.py

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,16 @@ def get_merge_request_id(branch_name, project_id):
1212
:param project_id: 项目id
1313
:return: 如果分支存在 mr 则返回mrid / 如果不存在mr 则返回 ""
1414
"""
15-
# 构建API请求URL
1615
url = f"{gitlab_server_url}/api/v4/projects/{project_id}/merge_requests"
1716

18-
# 发送API请求,检查是否有与分支相关的Merge Request
1917
params = {
2018
"source_branch": branch_name,
2119
"state": "opened" # 可以根据需求选择合适的状态(opened、closed、merged等)
2220
}
21+
2322
headers = {"Private-Token": gitlab_private_token}
2423
response = requests.get(url, params=params, headers=headers)
2524

26-
# 解析JSON响应并检查是否有相关的Merge Request
2725
if response.status_code == 200:
2826
merge_requests = response.json()
2927
if len(merge_requests) > 0:
@@ -38,27 +36,19 @@ def get_merge_request_id(branch_name, project_id):
3836

3937
@retry(stop_max_attempt_number=3, wait_fixed=2000)
4038
def get_commit_list(merge_request_iid, project_id):
41-
# Create API URL for the merge request commits
4239
api_url = f"{gitlab_server_url}/api/v4/projects/{project_id}/merge_requests/{merge_request_iid}/commits"
43-
# Set the private token in the header
40+
4441
headers = {"PRIVATE-TOKEN": gitlab_private_token}
45-
46-
# Make a GET request to the API URL
4742
response = requests.get(api_url, headers=headers)
43+
4844
commit_list = []
49-
# If the response code is 200, the API call was successful
5045
if response.status_code == 200:
51-
# Get the commits from the response
5246
commits = response.json()
53-
# Iterate through the commits and print the commit ID and message
5447
for commit in commits:
5548
print(f"Commit ID: {commit['id']}, Message: {commit['message']}")
56-
# Append the commit ID to the list
5749
commit_list.append(commit['id'])
5850
else:
59-
# Log an error if the API call was unsuccessful
6051
log.error(f"Failed to fetch commits. Status code: {response.status_code}")
61-
# Return the list of commit IDs
6252
return commit_list
6353

6454

@@ -117,40 +107,38 @@ def add_comment_to_mr(project_id, merge_request_id, comment):
117107

118108

119109
@retry(stop_max_attempt_number=3, wait_fixed=2000)
120-
def get_mr_comment_info(project_id, mr_iid, ):
121-
url = f"{gitlab_server_url}/api/v4/projects/{project_id}/merge_requests/{mr_iid}/notes"
110+
def get_merge_request_comments(project_id, merge_request_iid):
111+
url = f"{gitlab_server_url}/api/v4/projects/{project_id}/merge_requests/{merge_request_iid}/notes"
122112

123-
# 发送API请求
124113
headers = {"Private-Token": gitlab_private_token}
125114
response = requests.get(url, headers=headers)
126115

127-
comments_info = ""
128-
# 解析JSON响应
116+
comments_content = ""
129117
if response.status_code == 200:
130118
comments = response.json()
131119
for comment in comments:
132-
author = comment['author']['username']
133-
comment_text = comment['body']
134-
print(f"Author: {author}")
135-
print(f"Comment: {comment_text}")
136-
comments_info += comment_text
120+
author_username = comment['author']['username']
121+
comment_body = comment['body']
122+
print(f"Author: {author_username}")
123+
print(f"Comment: {comment_body}")
124+
comments_content += comment_body
137125

138126
else:
139127
print(f" 获取mr comment 失败, Status code: {response.status_code}")
140-
return comments_info
128+
return comments_content
141129

142130

143131
@retry(stop_max_attempt_number=3, wait_fixed=2000)
144132
def get_commit_change_file(push_info):
145133
# 获取提交列表
146-
commits = push_info['commits']
147-
add_file = []
148-
modify_file = []
134+
commit_list = push_info['commits']
135+
added_files_list = []
136+
modified_files_list = []
149137
# 遍历提交
150-
for commit in commits:
138+
for commit in commit_list:
151139
added_files = commit.get('added', [])
152140
modified_files = commit.get('modified', [])
153-
add_file += added_files
154-
modify_file += modified_files
141+
added_files_list += added_files
142+
modified_files_list += modified_files
155143

156-
return add_file + modify_file
144+
return added_files_list + modified_files_list

app/gitlab_webhook.py

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import threading
33
from os import abort
44
from flask import Blueprint, request, jsonify
5-
from config.config import WEBHOOK_VERIFY_TOKEN
5+
# from config.config import WEBHOOK_VERIFY_TOKEN
66
from service.chat_review import review_code, review_code_for_mr, review_code_for_add_commit
77
from utils.logger import log
88
from app.gitlab_utils import get_commit_list, get_merge_request_id, get_commit_change_file
@@ -20,54 +20,54 @@ def question():
2020
def webhook():
2121
if request.method == 'GET':
2222
# 获取gitlab的webhook的token
23-
verify_token = request.headers.get('X-Gitlab-Token')
23+
webhook_token = request.headers.get('X-Gitlab-Token')
2424

2525
# gitlab的webhook的token验证
26-
if verify_token == WEBHOOK_VERIFY_TOKEN:
27-
return jsonify({'status': 'success'}), 200
28-
else:
29-
return jsonify({'status': 'bad token'}), 401
26+
# if webhook_token == WEBHOOK_VERIFY_TOKEN:
27+
return jsonify({'status': 'success'}), 200
28+
#else:
29+
# return jsonify({'status': 'bad token'}), 401
3030

3131
elif request.method == 'POST':
3232
"""
3333
webhook的主要逻辑,获取gitlab的推送信息
3434
"""
3535
# 获取gitlab的推送信息
36-
gitlab_message = request.data.decode('utf-8')
36+
gitlab_payload = request.data.decode('utf-8')
3737
# 将gitlab的推送信息转换为字典
38-
gitlab_message = json.loads(gitlab_message)
39-
log.info(f"🌈 :{gitlab_message}")
38+
gitlab_payload = json.loads(gitlab_payload)
39+
log.info(f"🌈 :{gitlab_payload}")
4040
# 获取项目的类型
41-
object_kind = gitlab_message.get('object_kind')
41+
event_type = gitlab_payload.get('object_kind')
4242

4343
# 首次发起mr时候触发
44-
if object_kind == 'merge_request' and gitlab_message.get("object_attributes").get(
45-
"state") == "opened" and gitlab_message.get("object_attributes").get("merge_status") == "preparing":
44+
if event_type == 'merge_request' and gitlab_payload.get("object_attributes").get(
45+
"state") == "opened" and gitlab_payload.get("object_attributes").get("merge_status") == "preparing":
4646
# 验证通过,获取commit的信息
47-
log.info("首次merge_request ", gitlab_message)
47+
log.info("首次merge_request ", gitlab_payload)
4848
# 获取项目id
49-
project_id = gitlab_message.get('project')['id']
49+
project_id = gitlab_payload.get('project')['id']
5050
# 获取merge request ID
51-
merge_id = gitlab_message.get("object_attributes")["iid"]
51+
merge_request_id = gitlab_payload.get("object_attributes")["iid"]
5252

53-
thread = threading.Thread(target=review_code_for_mr, args=(project_id, merge_id, gitlab_message))
53+
thread = threading.Thread(target=review_code_for_mr, args=(project_id, merge_request_id, gitlab_payload))
5454
thread.start()
5555

5656
return jsonify({'status': 'success'}), 200
57-
elif object_kind == 'push':
57+
elif event_type == 'push':
5858
# 获取merge request ID
59-
merge_id = get_merge_request_id(gitlab_message.get('ref').split("/")[-1], gitlab_message.get("project_id"))
59+
merge_request_id = get_merge_request_id(gitlab_payload.get('ref').split("/")[-1], gitlab_payload.get("project_id"))
6060
# 获取项目id
61-
project_id = gitlab_message.get('project')['id']
62-
if not merge_id:
61+
project_id = gitlab_payload.get('project')['id']
62+
if not merge_request_id:
6363
send_dingtalk_message_by_sign(
64-
f"Project_Name:{gitlab_message['project']['name']}\n备注:分支 {gitlab_message.get('ref')} 没有处于open状态的 Merge Request 不进行 Code Review。")
65-
return jsonify({'status': f'非存在MR分支,{gitlab_message}'}), 200
64+
f"Project_Name:{gitlab_payload['project']['name']}\n备注:分支 {gitlab_payload.get('ref')} 没有处于open状态的 Merge Request 不进行 Code Review。")
65+
return jsonify({'status': f'非存在MR分支,{gitlab_payload}'}), 200
6666

67-
change_files = get_commit_change_file(gitlab_message)
67+
changed_files = get_commit_change_file(gitlab_payload)
6868

6969
thread = threading.Thread(target=review_code_for_add_commit,
70-
args=(project_id, merge_id, change_files, gitlab_message))
70+
args=(project_id, merge_request_id, changed_files, gitlab_payload))
7171
thread.start()
7272

7373
return jsonify({'status': 'success'}), 200
@@ -76,7 +76,7 @@ def webhook():
7676
log.error("不是merge")
7777
return jsonify({'status': '操作不为push'}), 200
7878

79-
return jsonify({'status': f'未匹配到规则,{gitlab_message}'}), 200
79+
return jsonify({'status': f'未匹配到规则,{gitlab_payload}'}), 200
8080

8181
else:
8282
abort(400)

config/config.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,20 @@
22
# model list
33
model_quester_anster = "text-davinci-003"
44
model_gpt_35_turbo = "gpt-3.5-turbo"
5+
model_gpt_4o = "gpt-4o"
56
model_programming_translate = "code-davinci-002"
67

7-
# gpt key
8-
openai_api_key = "your openai key"
8+
# api 接口封装类
9+
llm_api_impl = "llm_api.llm_api_default.LLMApiDefault"
910

10-
# openai api
11-
openai_baseurl = "https://api.openai.com/v1"
12-
13-
# gpt model
14-
openai_model_name = model_gpt_35_turbo
11+
# api 配置默使用认UnionLLM,参考:https://github.com/EvalsOne/UnionLLM/tree/main/docs
12+
# UnionLLM兼容LiteLLM,参考LiteLLM文档:https://docs.litellm.ai/docs
13+
api_config = {
14+
"OPENAI_API_KEY": "your openai key",
15+
"OPENAI_API_BASE": "https://api.openai.com/v1",
16+
"MODEL_NAME": model_gpt_4o,
17+
"PROVIDER": "openai",
18+
}
1519

1620
# Prompt
1721
gpt_message = """
@@ -39,7 +43,7 @@
3943

4044
# ------------------Gitlab info--------------------------
4145
# Gitlab url
42-
gitlab_server_url = "https://gitlab.example.com"
46+
gitlab_server_url = "https://gitlab.com"
4347

4448
# Gitlab private token
4549
gitlab_private_token = "gitlab private token"

doc/config.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Config.py 配置指南
2+
## 大模型配置
3+
- `llm_api_impl`:大模型API接口实现
4+
- 默认`llm_api_default`使用`UnionLLM`进行多模型支持,`UnionLLM`兼容`LiteLLM`
5+
支持模型和参数配置方式参见:[UnionLLM仓库](https://github.com/EvalsOne/UnionLLM/)[LiteLLM文档](https://docs.litellm.ai/docs)
6+
- 主流模型只需要修改`api_config`即可接入,无需修改该参数
7+
- 实现默认不支持的大模型接入,可实现`llm_api_interface`接口,并将类名传入该参数。
8+
- `api_config`: 大模型API配置
9+
- 具体配置参见[UnionLLM仓库](https://github.com/EvalsOne/UnionLLM/)[LiteLLM文档](https://docs.litellm.ai/docs)
10+
- `MODEL_NAME` 传入模型名称
11+
- `PROVIDER` 传入模型提供商
12+
- 该配置会自动传给`llm_api_impl``set_config`方法,用于初始化大模型API。
13+
14+
15+
## Gitlab配置
16+
- `gitlab_server_url`: Gitlab服务器地址
17+
- `gitlab_private_token`: Gitlab私有令牌
18+
- `maximum_files`: Gitlab Merge Request最大文件数
19+
20+
## 消息通知配置
21+
- `dingtalk_webhook`: 钉钉机器人Webhook
22+
- `dingtalk_secret`: 钉钉机器人密钥

0 commit comments

Comments
 (0)