From bd03f2f170e158678f8a2f44039a430321627231 Mon Sep 17 00:00:00 2001 From: Manuel Schmid Date: Tue, 18 Mar 2025 17:44:40 +0100 Subject: [PATCH 01/12] feat: add support for multiple locales, add full english translation --- .env.dist | 3 + Dockerfile | 1 + api.py | 53 +- biz/event/event_manager.py | 81 ++- biz/gitlab/webhook_handler.py | 84 ++- biz/utils/code_reviewer.py | 15 +- biz/utils/i18n.py | 18 + biz/utils/im/dingtalk.py | 19 +- biz/utils/im/feishu.py | 19 +- biz/utils/im/im_notifier.py | 5 +- biz/utils/im/wecom.py | 17 +- biz/utils/reporter.py | 5 +- core/llm/client/deepseek.py | 19 +- core/llm/client/openai.py | 5 +- core/llm/client/zhipuai.py | 5 +- core/llm/factory.py | 5 +- doc/faq.md | 10 +- locales/en_US/LC_MESSAGES/messages.mo | Bin 0 -> 10020 bytes locales/en_US/LC_MESSAGES/messages.po | 554 ++++++++++++++++++ locales/en_US/prompt_templates.yml | 22 + locales/zh_CN/LC_MESSAGES/messages.mo | Bin 0 -> 370 bytes locales/zh_CN/LC_MESSAGES/messages.po | 498 ++++++++++++++++ .../zh_CN/prompt_templates.yml | 0 translations_compile.sh | 10 + translations_update.sh | 19 + ui.py | 44 +- 26 files changed, 1342 insertions(+), 169 deletions(-) create mode 100644 biz/utils/i18n.py create mode 100644 locales/en_US/LC_MESSAGES/messages.mo create mode 100644 locales/en_US/LC_MESSAGES/messages.po create mode 100644 locales/en_US/prompt_templates.yml create mode 100644 locales/zh_CN/LC_MESSAGES/messages.mo create mode 100644 locales/zh_CN/LC_MESSAGES/messages.po rename prompt_templates.yml => locales/zh_CN/prompt_templates.yml (100%) create mode 100644 translations_compile.sh create mode 100644 translations_update.sh diff --git a/.env.dist b/.env.dist index 30f48d8..927ba14 100644 --- a/.env.dist +++ b/.env.dist @@ -53,6 +53,9 @@ REPORT_CRONTAB_EXPRESSION=0 18 * * 1-5 # 开启Push Review功能(如果不需要push事件触发Code Review,设置为0) PUSH_REVIEW_ENABLED=1 +# language (supported: zh_CN/en_US) +LANGUAGE=zh_CN + # Dashboard登录用户名和密码 DASHBOARD_USER=admin DASHBOARD_PASSWORD=admin \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 25d7dff..3d0944a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,6 +12,7 @@ COPY api.py /app/api.py COPY ui.py /app/ui.py COPY prompt_templates.yml /app/prompt_templates.yml COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf +COPY locales /app/locales RUN mkdir -p /app/log /app/data # 安装 supervisord 作为进程管理工具 diff --git a/api.py b/api.py index c9c74cd..e3a60c2 100644 --- a/api.py +++ b/api.py @@ -22,6 +22,9 @@ load_dotenv() api_app = Flask(__name__) +from biz.utils.i18n import get_translator +_ = get_translator() + PUSH_REVIEW_ENABLED = os.environ.get('PUSH_REVIEW_ENABLED', '0') == '1' @@ -58,7 +61,7 @@ def daily_report(): # 生成日报内容 report_txt = Reporter().generate_report(json.dumps(commits)) # 发送钉钉通知 - im_notifier.send_notification(content=report_txt, msg_type="markdown", title="代码提交日报") + im_notifier.send_notification(content=report_txt, msg_type="markdown", title=_("代码提交日报")) # 返回生成的日报内容 return json.dumps(report_txt, ensure_ascii=False, indent=4) @@ -161,15 +164,15 @@ def __handle_push_event(webhook_data: dict, gitlab_token: str, gitlab_url: str): logger.info('changes: %s', changes) changes = filter_changes(changes) if not changes: - logger.info('未检测到PUSH代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。') - review_result = "关注的文件没有修改" + logger.info(_('未检测到PUSH代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。')) + review_result = _("关注的文件没有修改") if len(changes) > 0: commits_text = ';'.join(commit.get('message', '').strip() for commit in commits) review_result = review_code(str(changes), commits_text) score = CodeReviewer.parse_review_score(review_text=review_result) # 将review结果提交到Gitlab的 notes - handler.add_push_notes(f'Auto Review Result: \n{review_result}') + handler.add_push_notes(_('Auto Review Result: \n{}').format(review_result)) event_manager['push_reviewed'].send(PushReviewEntity( project_name=webhook_data['project']['name'], @@ -182,9 +185,9 @@ def __handle_push_event(webhook_data: dict, gitlab_token: str, gitlab_url: str): )) except Exception as e: - error_message = f'服务出现未知错误: {str(e)}\n{traceback.format_exc()}' + error_message = _('服务出现未知错误: {}').format(f'{str(e)}\n{traceback.format_exc()}') im_notifier.send_notification(content=error_message) - logger.error('出现未知错误: %s', error_message) + logger.error(_('出现未知错误: {}').format(error_message)) def __handle_merge_request_event(webhook_data: dict, gitlab_token: str, gitlab_url: str): @@ -198,21 +201,21 @@ def __handle_merge_request_event(webhook_data: dict, gitlab_token: str, gitlab_u try: # 解析Webhook数据 handler = MergeRequestHandler(webhook_data, gitlab_token, gitlab_url) - logger.info('Merge Request Hook event received') + logger.info(_('Merge Request Hook event received')) - if (handler.action in ['open', 'update']): # 仅仅在MR创建或更新时进行Code Review + if handler.action in ['open', 'update']: # 仅仅在MR创建或更新时进行Code Review # 获取Merge Request的changes changes = handler.get_merge_request_changes() - logger.info('changes: %s', changes) + logger.info(_('changes: {}').format(changes)) changes = filter_changes(changes) if not changes: - logger.info('未检测到有关代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。') + logger.info(_('未检测到有关代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。')) return # 获取Merge Request的commits commits = handler.get_merge_request_commits() if not commits: - logger.error('Failed to get commits') + logger.error(_('Failed to get commits')) return # review 代码 @@ -220,7 +223,7 @@ def __handle_merge_request_event(webhook_data: dict, gitlab_token: str, gitlab_u review_result = review_code(str(changes), commits_text) # 将review结果提交到Gitlab的 notes - handler.add_merge_request_notes(f'Auto Review Result: \n{review_result}') + handler.add_merge_request_notes(_('Auto Review Result: \n{}').format(review_result)) # dispatch merge_request_reviewed event event_manager['merge_request_reviewed'].send( @@ -238,12 +241,13 @@ def __handle_merge_request_event(webhook_data: dict, gitlab_token: str, gitlab_u ) else: - logger.info(f"Merge Request Hook event, action={handler.action}, ignored.") + logger.info(_("Merge Request Hook event, action={}, ignored.").format(handler.action)) except Exception as e: - error_message = f'AI Code Review 服务出现未知错误: {str(e)}\n{traceback.format_exc()}' + error_message = _('AI Code Review 服务出现未知错误: {}').format(f'{str(e)}\n{traceback.format_exc()}') im_notifier.send_notification(content=error_message) - logger.error('出现未知错误: %s', error_message) + logger.error(_('出现未知错误: {}').format(error_message)) + def __handle_system_hook(webhook_data: dict, gitlab_token: str, gitlab_url: str): ''' @@ -254,19 +258,19 @@ def __handle_system_hook(webhook_data: dict, gitlab_token: str, gitlab_url: str) :return: ''' try: - logger.info('System Hook event received') + logger.info(_('System Hook event received')) handler = SystemHookHandler(webhook_data, gitlab_token, gitlab_url) changes = handler.get_repository_changes() - logger.info('changes: %s', changes) + logger.info(_('changes: {}').format(changes)) changes = filter_changes(changes) if not changes: - logger.info('未检测到有关代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。') + logger.info(_('未检测到有关代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。')) return commits = handler.get_repository_commits() # review 代码 commits_text = ';'.join(commit['title'] for commit in commits) review_result = review_code(str(changes), commits_text) - logger.info(f'Payload: {json.dumps(webhook_data)}') + logger.info(_('Payload: {}').format(json.dumps(webhook_data))) # dispatch system_hook_reviewed event event_manager['system_hook_reviewed'].send( SystemHookReviewEntity( @@ -279,9 +283,10 @@ def __handle_system_hook(webhook_data: dict, gitlab_token: str, gitlab_url: str) ) ) except Exception as e: - error_message = f'AI Code Review 服务出现未知错误: {str(e)}\n{traceback.format_exc()}' + error_message = _('AI Code Review 服务出现未知错误: {}'.format(f'{str(e)}\n{traceback.format_exc()}')) im_notifier.send_notification(content=error_message) - logger.error('出现未知错误: %s', error_message) + logger.error(_('出现未知错误: {}').format(error_message)) + def filter_changes(changes: list): ''' @@ -307,12 +312,12 @@ def review_code(changes_text: str, commits_text: str = '') -> str: review_max_length = int(os.getenv('REVIEW_MAX_LENGTH', 5000)) # 如果changes为空,打印日志 if not changes_text: - logger.info('代码为空, diffs_text = %', str(changes_text)) - return '代码为空' + logger.info(_('代码为空, diffs_text = {}').format(str(changes_text))) + return _('代码为空') if len(changes_text) > review_max_length: changes_text = changes_text[:review_max_length] - logger.info(f'文本超长,截段后content: {changes_text}') + logger.info(_('文本超长,截段后content: {}').format(changes_text)) review_result = CodeReviewer().review_code(changes_text, commits_text).strip() if review_result.startswith("```markdown") and review_result.endswith("```"): return review_result[11:-3].strip() diff --git a/biz/event/event_manager.py b/biz/event/event_manager.py index 8fa541d..0e7e2f7 100644 --- a/biz/event/event_manager.py +++ b/biz/event/event_manager.py @@ -8,6 +8,9 @@ from biz.service.review_service import ReviewService from biz.utils.im import im_notifier +from biz.utils.i18n import get_translator +_ = get_translator() + # 定义全局事件管理器(事件信号) event_manager = { "merge_request_reviewed": Signal(), @@ -19,24 +22,33 @@ # 定义事件处理函数 def on_merge_request_reviewed(mr_review_entity: MergeRequestReviewEntity): # 发送IM消息通知 - im_msg = f""" -### 🔀 {mr_review_entity.project_name}: Merge Request + im_msg = _(""" +### 🔀 {project_name}: Merge Request #### 合并请求信息: -- **提交者:** {mr_review_entity.author} +- **提交者:** {author} -- **源分支**: {mr_review_entity.source_branch} -- **目标分支**: {mr_review_entity.target_branch} -- **更新时间**: {mr_review_entity.updated_at} -- **提交信息:** {mr_review_entity.commit_messages} +- **源分支**: {source_branch} +- **目标分支**: {target_branch} +- **更新时间**: {updated_at} +- **提交信息:** {commit_messages} -- [查看合并详情]({mr_review_entity.url}) +- [查看合并详情]({url}) - **AI Review 结果:** -{mr_review_entity.review_result} - """ - im_notifier.send_notification(content=im_msg, msg_type='markdown', title='Merge Request Review', +{review_result} + """).format( + project_name=mr_review_entity.project_name, + author=mr_review_entity.author, + source_branch=mr_review_entity.source_branch, + target_branch=mr_review_entity.target_branch, + updated_at=mr_review_entity.updated_at, + commit_messages=mr_review_entity.commit_messages, + url=mr_review_entity.url, + review_result=mr_review_entity.review_result + ) + im_notifier.send_notification(content=im_msg, msg_type='markdown', title=_('Merge Request Review'), project_name=mr_review_entity.project_name) # 记录到数据库 @@ -45,25 +57,31 @@ def on_merge_request_reviewed(mr_review_entity: MergeRequestReviewEntity): def on_push_reviewed(entity: PushReviewEntity): # 发送IM消息通知 - im_msg = f"### 🚀 {entity.project_name}: Push\n\n" - im_msg += "#### 提交记录:\n" + im_msg = _("### 🚀 {project_name}: Push\n\n").format(project_name=entity.project_name) + im_msg += _("#### 提交记录:\n") for commit in entity.commits: message = commit.get('message', '').strip() - author = commit.get('author', 'Unknown Author') + author = commit.get('author', _('Unknown Author')) timestamp = commit.get('timestamp', '') url = commit.get('url', '#') im_msg += ( - f"- **提交信息**: {message}\n" - f"- **提交者**: {author}\n" - f"- **时间**: {timestamp}\n" - f"- [查看提交详情]({url})\n\n" + _("- **提交信息**: {message}\n" + "- **提交者**: {author}\n" + "- **时间**: {timestamp}\n" + "- [查看提交详情]({url})\n\n").format( + message=message, + author=author, + timestamp=timestamp, + url=url + ) ) if entity.review_result: - im_msg += f"#### AI Review 结果: \n {entity.review_result}\n\n" + im_msg += _("#### AI Review 结果: \n {review_result}\n\n").format(review_result=entity.review_result) im_notifier.send_notification(content=im_msg, msg_type='markdown', - title=f"{entity.project_name} Push Event", project_name=entity.project_name) + title=_("{project_name} Push Event").format(project_name=entity.project_name), + project_name=entity.project_name) # 记录到数据库 ReviewService().insert_push_review_log(entity) @@ -71,25 +89,30 @@ def on_push_reviewed(entity: PushReviewEntity): def on_system_hook_reviewed(entity: SystemHookReviewEntity): # 发送IM消息通知 - im_msg = f"### 🚀 {entity.project_name}: System Hook\n\n" - im_msg += "#### 提交记录:\n" + im_msg = _("### 🚀 {project_name}: System Hook\n\n").format(project_name=entity.project_name) + im_msg += _("#### 提交记录:\n") for commit in entity.commits: message = commit.get('message', '').strip() - author = commit.get('author_name', 'Unknown Author') + author = commit.get('author_name', _('Unknown Author')) timestamp = commit.get('committed_date', '') im_msg += ( - f"- **提交信息**: {message}\n" - f"- **提交者**: {author}\n" - f"- **时间**: {timestamp}\n" + _("- **提交信息**: {message}\n" + "- **提交者**: {author}\n" + "- **时间**: {timestamp}\n").format( + message=message, + author=author, + timestamp=timestamp + ) ) if entity.review_result: - im_msg += f"#### AI Review 结果: \n {entity.review_result}\n\n" + im_msg += _("#### AI Review 结果: \n {review_result}\n\n").format(review_result=entity.review_result) im_notifier.send_notification(content=im_msg, msg_type='markdown', - title=f"{entity.project_name} Push Event", project_name=entity.project_name) + title=_("{project_name} Push Event").format(project_name=entity.project_name), + project_name=entity.project_name) # 连接事件处理函数到事件信号 event_manager["merge_request_reviewed"].connect(on_merge_request_reviewed) event_manager["push_reviewed"].connect(on_push_reviewed) -event_manager["system_hook_reviewed"].connect(on_system_hook_reviewed) +event_manager["system_hook_reviewed"].connect(on_system_hook_reviewed) \ No newline at end of file diff --git a/biz/gitlab/webhook_handler.py b/biz/gitlab/webhook_handler.py index 8388b1b..1f73241 100644 --- a/biz/gitlab/webhook_handler.py +++ b/biz/gitlab/webhook_handler.py @@ -5,7 +5,8 @@ import requests from biz.utils.log import logger - +from biz.utils.i18n import get_translator +_ = get_translator() class MergeRequestHandler: def __init__(self, webhook_data: dict, gitlab_token: str, gitlab_url: str): @@ -35,7 +36,7 @@ def parse_merge_request_event(self): def get_merge_request_changes(self) -> list: # 检查是否为 Merge Request Hook 事件 if self.event_type != 'merge_request': - logger.warn(f"Invalid event type: {self.event_type}. Only 'merge_request' event is supported now.") + logger.warn(_("Invalid event type: {}. Only 'merge_request' event is supported now.").format(self.event_type)) return [] # Gitlab merge request changes API可能存在延迟,多次尝试 @@ -50,8 +51,7 @@ def get_merge_request_changes(self) -> list: } response = requests.get(url, headers=headers, verify=False) logger.debug( - f"Get changes response from GitLab (attempt {attempt + 1}): {response.status_code}, {response.text}, URL: {url}") - + _("Get changes response from GitLab (attempt {}): {}, {}, URL: {}").format(attempt + 1, response.status_code, response.text, url)) # 检查请求是否成功 if response.status_code == 200: changes = response.json().get('changes', []) @@ -59,13 +59,13 @@ def get_merge_request_changes(self) -> list: return changes else: logger.info( - f"Changes is empty, retrying in {retry_delay} seconds... (attempt {attempt + 1}/{max_retries}), URL: {url}") + _("Changes is empty, retrying in {} seconds... (attempt {}/{}), URL: {}").format(retry_delay, attempt + 1, max_retries, url)) time.sleep(retry_delay) else: - logger.warn(f"Failed to get changes from GitLab (URL: {url}): {response.status_code}, {response.text}") + logger.warn(_("Failed to get changes from GitLab (URL: {}): {}, {}").format(url, response.status_code, response.text)) return [] - logger.warning(f"Max retries ({max_retries}) reached. Changes is still empty.") + logger.warning(_("Max retries ({}) reached. Changes is still empty.").format(max_retries)) return [] # 达到最大重试次数后返回空列表 def get_merge_request_commits(self) -> list: @@ -80,12 +80,11 @@ def get_merge_request_commits(self) -> list: 'Private-Token': self.gitlab_token } response = requests.get(url, headers=headers, verify=False) - logger.debug(f"Get commits response from gitlab: {response.status_code}, {response.text}") - # 检查请求是否成功 + logger.debug(_("Get commits response from gitlab: {}, {}").format(response.status_code, response.text)) # 检查请求是否成功 if response.status_code == 200: return response.json() else: - logger.warn(f"Failed to get commits: {response.status_code}, {response.text}") + logger.warn(_("Failed to get commits: {}, {}").format(response.status_code, response.text)) return [] def add_merge_request_notes(self, review_result): @@ -99,11 +98,11 @@ def add_merge_request_notes(self, review_result): 'body': review_result } response = requests.post(url, headers=headers, json=data, verify=False) - logger.debug(f"Add notes to gitlab {url}: {response.status_code}, {response.text}") + logger.debug(_("Add notes to gitlab {}: {}, {}").format(url, response.status_code, response.text)) if response.status_code == 201: logger.info("Note successfully added to merge request.") else: - logger.error(f"Failed to add note: {response.status_code}") + logger.error(_("Failed to add note: {}").format(response.status_code)) logger.error(response.text) @@ -133,7 +132,7 @@ def parse_push_event(self): def get_push_commits(self) -> list: # 检查是否为 Push 事件 if self.event_type != 'push': - logger.warn(f"Invalid event type: {self.event_type}. Only 'push' event is supported now.") + logger.warn(_("Invalid event type: {}. Only 'push' event is supported now.").format(self.event_type)) return [] # 提取提交信息 @@ -147,19 +146,19 @@ def get_push_commits(self) -> list: } commit_details.append(commit_info) - logger.info(f"Collected {len(commit_details)} commits from push event.") + logger.info(_("Collected {} commits from push event.").format(len(commit_details))) return commit_details def add_push_notes(self, message: str): # 添加评论到 GitLab Push 请求的提交中(此处假设是在最后一次提交上添加注释) if not self.commit_list: - logger.warn("No commits found to add notes to.") + logger.warn(_("No commits found to add notes to.")) return # 获取最后一个提交的ID last_commit_id = self.commit_list[-1].get('id') if not last_commit_id: - logger.error("Last commit ID not found.") + logger.error(_("Last commit ID not found.")) return url = urljoin(f"{self.gitlab_url}/", @@ -182,12 +181,12 @@ def add_push_notes(self, message: str): def get_push_changes(self) -> list: # 检查是否为 Push 事件 if self.event_type != 'push': - logger.warn(f"Invalid event type: {self.event_type}. Only 'push' event is supported now.") + logger.warn(_("Invalid event type: {}. Only 'push' event is supported now.").format(self.event_type)) return [] # 如果没有提交,返回空列表 if not self.commit_list: - logger.info("No commits found in push event.") + logger.info(_("No commits found in push event.")) return [] headers = { 'Private-Token': self.gitlab_token @@ -201,12 +200,11 @@ def get_push_changes(self) -> list: response = requests.get(url, headers=headers, verify=False) logger.debug( - f"Get changes response from GitLab for push event: {response.status_code}, {response.text}, URL: {url}") + _("Get changes response from GitLab for push event: {}, {}, URL: {}").format(response.status_code, response.text, url)) if response.status_code == 200: return response.json().get('diffs', []) else: - logger.warn( - f"Failed to get changes for push event: {response.status_code}, {response.text}, URL: {url}") + logger.warn(_("Failed to get changes for push event: {}, {}, URL: {}").format(response.status_code, response.text, url)) return [] else: return [] @@ -222,39 +220,39 @@ def __init__(self, webhook_data: dict, gitlab_token: str, gitlab_url: str): self.parse_event_type() def parse_event_type(self): - # 提取 event_type - self.event_type = self.webhook_data.get('event_name', None) - if self.event_type == 'repository_update': + # Extract event_type + self.event_type = self.webhook_data.get(_('event_name'), None) + if self.event_type == _('repository_update'): self.parse_repository_update_event() def parse_repository_update_event(self): - # 解析 repository_update 事件的相关参数 + # Parse repository_update event parameters self.project_id = self.webhook_data.get('project', {}).get('id') self.changes = self.webhook_data.get('changes', []) def get_repository_changes(self) -> list: - # 检查是否为 repository_update 事件 + # Check if the event is repository_update if self.event_type != 'repository_update': - logger.warn(f"Invalid event type: {self.event_type}. Only 'repository_update' event is supported now.") + logger.warn(_("Invalid event type: {}. Only 'repository_update' event is supported now.").format(self.event_type)) return [] if not self.changes: - logger.warn("No changes found in webhook data.") + logger.warn(_("No changes found in webhook data.")) return [] headers = {'Private-Token': self.gitlab_token} all_diffs = [] - max_retries = 3 # 最大重试次数 - retry_delay = 10 # 重试间隔时间(秒) + max_retries = 3 # Maximum retry attempts + retry_delay = 10 # Retry delay in seconds for change in self.changes: before = change.get('before') after = change.get('after') - ref = change.get('ref', 'unknown branch') + ref = change.get('ref', _('unknown branch')) if not before or not after: - logger.warn(f"Missing before or after commit ID for ref {ref}.") + logger.warn(_("Missing before or after commit ID for ref {}.").format(ref)) continue url = f"{urljoin(f'{self.gitlab_url}/', f'api/v4/projects/{self.project_id}/repository/compare')}?from={before}&to={after}" @@ -262,7 +260,7 @@ def get_repository_changes(self) -> list: for attempt in range(max_retries): response = requests.get(url, headers=headers, verify=False) logger.debug( - f"Get changes response from GitLab for repository_update (attempt {attempt + 1}): {response.status_code}, {response.text}, URL: {url}") + _("Get changes response from GitLab for repository_update (attempt {}): {}, {}, URL: {}").format(attempt + 1, response.status_code, response.text, url)) if response.status_code == 200: diffs = response.json().get('diffs', []) @@ -271,21 +269,21 @@ def get_repository_changes(self) -> list: break else: logger.warn( - f"Failed to get changes for ref {ref}: {response.status_code}, {response.text}, retrying in {retry_delay} seconds...") + _("Failed to get changes for ref {}: {}, {}, retrying in {} seconds...").format(ref, response.status_code, response.text, retry_delay)) time.sleep(retry_delay) if not all_diffs: - logger.warning(f"Max retries ({max_retries}) reached. Unable to retrieve repository changes.") + logger.warning(_("Max retries ({}) reached. Unable to retrieve repository changes.").format(max_retries)) return all_diffs def get_repository_commits(self) -> list: - # 获取 repository_update 事件中的提交信息 - if self.event_type != 'repository_update': - logger.warn(f"Invalid event type: {self.event_type}. Only 'repository_update' event is supported now.") + # Get commits from repository_update event + if self.event_type != _('repository_update'): + logger.warn(_("Invalid event type: {}. Only 'repository_update' event is supported now.").format(self.event_type)) return [] if not self.changes: - logger.warn("No changes found in webhook data.") + logger.warn(_("No changes found in webhook data.")) return [] headers = {'Private-Token': self.gitlab_token} @@ -294,16 +292,16 @@ def get_repository_commits(self) -> list: for change in self.changes: before = change.get('before') after = change.get('after') - ref = change.get('ref', 'unknown branch') + ref = change.get('ref', _('unknown branch')) if not before or not after: - logger.warn(f"Missing before or after commit ID for ref {ref}.") + logger.warn(_("Missing before or after commit ID for ref {}.").format(ref)) continue url = f"{urljoin(f'{self.gitlab_url}/', f'api/v4/projects/{self.project_id}/repository/commits')}?ref_name={ref}" response = requests.get(url, headers=headers, verify=False) logger.debug( - f"Get commits response from GitLab for repository_update: {response.status_code}, {response.text}, URL: {url}") + _("Get commits response from GitLab for repository_update: {}, {}, URL: {}").format(response.status_code, response.text, url)) if response.status_code == 200: commits = response.json() @@ -311,6 +309,6 @@ def get_repository_commits(self) -> list: all_commits.extend(commits) else: logger.warn( - f"Failed to get commits for ref {ref}: {response.status_code}, {response.text}") + _("Failed to get commits for ref {}: {}, {}").format(ref, response.status_code, response.text)) return all_commits \ No newline at end of file diff --git a/biz/utils/code_reviewer.py b/biz/utils/code_reviewer.py index 18cd592..9ba0c40 100644 --- a/biz/utils/code_reviewer.py +++ b/biz/utils/code_reviewer.py @@ -5,6 +5,8 @@ from biz.utils.log import logger from core.llm.factory import Factory +from biz.utils.i18n import get_translator +_ = get_translator() class CodeReviewer: @@ -14,16 +16,17 @@ def __init__(self): def _load_prompts(self) -> dict: """加载提示词配置""" - prompt_templates_file = "prompt_templates.yml" + lang = os.environ.get('LANGUAGE', 'zh_CN') + prompt_templates_file = os.path.join("locales", lang, "prompt_templates.yml") with open(prompt_templates_file, "r") as file: prompt_templates = yaml.safe_load(file) system_prompt = prompt_templates['system_prompt'] user_prompt = prompt_templates['user_prompt'] if not system_prompt or not user_prompt: - logger.warning(f"未找到提示词配置{prompt_templates_file}") + logger.warning(_("未找到提示词配置{}").format(prompt_templates_file)) # 抛出异常 - raise Exception(f"未找到提示词配置{prompt_templates_file},或配置格式不正确") + raise Exception(_("未找到提示词配置{},或配置格式不正确").format(prompt_templates_file)) return { "code_review": { @@ -54,11 +57,11 @@ def review_code(self, diffs_text: str, commits_text: str = "") -> str: return self.call_llm(messages) def call_llm(self, messages: list) -> str: - logger.info(f"向AI发送代码Review请求, message:{messages})") + logger.info(_("向AI发送代码Review请求, message: {}").format(messages)) review_result = self.client.completions( messages=messages ) - logger.info(f"收到AI返回结果:{review_result}") + logger.info(_("收到AI返回结果: {}").format(review_result)) return review_result @staticmethod @@ -66,7 +69,7 @@ def parse_review_score(review_text: str) -> int: """解析AI返回的Review结果,返回评分""" if not review_text: return 0 # 如果review_text为空,返回 0 - match = re.search(r"总分[::]\s*(\d+)分?", review_text) + match = re.search(_("总分[::]\s*(\d+)分?"), review_text) if match: return int(match.group(1)) # 提取数值部分并转换为整数 diff --git a/biz/utils/i18n.py b/biz/utils/i18n.py new file mode 100644 index 0000000..d63fe56 --- /dev/null +++ b/biz/utils/i18n.py @@ -0,0 +1,18 @@ +import gettext +import os +from typing import Callable + +def init_language(lang_code = None) -> Callable[[str], str]: + if lang_code is None: + lang_code = os.environ.get('LANGUAGE', 'zh_CN') + print(f"Using language: {lang_code}") + lang = gettext.translation("messages", localedir="locales", languages=[lang_code], fallback=True) + lang.install() + global _ + _ = lang.gettext + return _ + +def get_translator() -> Callable[[str], str]: + return _ + +init_language() \ No newline at end of file diff --git a/biz/utils/im/dingtalk.py b/biz/utils/im/dingtalk.py index 38e8cf5..3c306fd 100644 --- a/biz/utils/im/dingtalk.py +++ b/biz/utils/im/dingtalk.py @@ -1,14 +1,11 @@ -import base64 -import hashlib -import hmac import json import os -import time -import urllib.parse import requests from biz.utils.log import logger +from biz.utils.i18n import get_translator +_ = get_translator() class DingTalkNotifier: @@ -28,7 +25,7 @@ def _get_webhook_url(self, project_name=None): if self.default_webhook_url: return self.default_webhook_url else: - raise ValueError("未提供项目名称,且未设置默认的钉钉 Webhook URL。") + raise ValueError(_("未提供项目名称,且未设置默认的钉钉 Webhook URL。")) # 遍历所有环境变量(忽略大小写),找到项目对应的 Webhook URL target_key = f"DINGTALK_WEBHOOK_URL_{project_name.upper()}" @@ -41,11 +38,11 @@ def _get_webhook_url(self, project_name=None): return self.default_webhook_url # 如果既未找到匹配项,也没有默认值,抛出异常 - raise ValueError(f"未找到项目 '{project_name}' 对应的钉钉Webhook URL,且未设置默认的 Webhook URL。") + raise ValueError(_("未找到项目 '{}' 对应的钉钉Webhook URL,且未设置默认的 Webhook URL。").format(project_name)) def send_message(self, content: str, msg_type='text', title='通知', is_at_all=False, project_name=None): if not self.enabled: - logger.info("钉钉推送未启用") + logger.info(_("钉钉推送未启用")) return try: @@ -78,8 +75,8 @@ def send_message(self, content: str, msg_type='text', title='通知', is_at_all= response = requests.post(url=post_url, data=json.dumps(message), headers=headers) response_data = response.json() if response_data.get('errmsg') == 'ok': - logger.info(f"钉钉消息发送成功! webhook_url:{post_url}") + logger.info(_("钉钉消息发送成功! webhook_url: {}").format(post_url)) else: - logger.error(f"钉钉消息发送失败! webhook_url:{post_url},errmsg:{response_data.get('errmsg')}") + logger.error(_("钉钉消息发送失败! webhook_url: {}, errmsg: {}").format(post_url, response_data.get('errmsg'))) except Exception as e: - logger.error(f"钉钉消息发送失败! ", e) + logger.error(_("钉钉消息发送失败!"), e) diff --git a/biz/utils/im/feishu.py b/biz/utils/im/feishu.py index 681a78d..9676833 100644 --- a/biz/utils/im/feishu.py +++ b/biz/utils/im/feishu.py @@ -1,9 +1,8 @@ -import json import requests import os -import re from biz.utils.log import logger - +from biz.utils.i18n import get_translator +_ = get_translator() class FeishuNotifier: def __init__(self, webhook_url=None): @@ -26,7 +25,7 @@ def _get_webhook_url(self, project_name=None): if self.default_webhook_url: return self.default_webhook_url else: - raise ValueError("未提供项目名称,且未设置默认的 飞书 Webhook URL。") + raise ValueError(_("未提供项目名称,且未设置默认的 飞书 Webhook URL。")) # 遍历所有环境变量(忽略大小写),找到项目对应的 Webhook URL target_key = f"FEISHU_WEBHOOK_URL_{project_name.upper()}" @@ -39,7 +38,7 @@ def _get_webhook_url(self, project_name=None): return self.default_webhook_url # 如果既未找到匹配项,也没有默认值,抛出异常 - raise ValueError(f"未找到项目 '{project_name}' 对应的 Feishu Webhook URL,且未设置默认的 Webhook URL。") + raise ValueError(_("未找到项目 '{project_name}' 对应的 Feishu Webhook URL,且未设置默认的 Webhook URL。")) def send_message(self, content, msg_type='text', title=None, is_at_all=False, project_name=None): """ @@ -51,7 +50,7 @@ def send_message(self, content, msg_type='text', title=None, is_at_all=False, pr :param project_name: 项目名称 """ if not self.enabled: - logger.info("飞书推送未启用") + logger.info(_("飞书推送未启用")) return try: @@ -111,14 +110,14 @@ def send_message(self, content, msg_type='text', title=None, is_at_all=False, pr ) if response.status_code != 200: - logger.error(f"飞书消息发送失败! webhook_url:{post_url}, error_msg:{response.text}") + logger.error(_("飞书消息发送失败! webhook_url: {post_url}, error_msg: {post_url}").format(post_url=post_url, error_msg=response.text)) return result = response.json() if result.get('msg') != "success": - logger.error(f"发送飞书消息失败! webhook_url:{post_url},errmsg:{result}") + logger.error(_("发送飞书消息失败! webhook_url: {post_url}, errmsg: {result}").format(post_url=post_url, result=result)) else: - logger.info(f"飞书消息发送成功! webhook_url:{post_url}") + logger.info(_("飞书消息发送成功! webhook_url: {post_url}").format(post_url=post_url)) except Exception as e: - logger.error(f"飞书消息发送失败! ", e) + logger.error(_("飞书消息发送失败!"), e) diff --git a/biz/utils/im/im_notifier.py b/biz/utils/im/im_notifier.py index a250d89..f64a0c2 100644 --- a/biz/utils/im/im_notifier.py +++ b/biz/utils/im/im_notifier.py @@ -1,9 +1,10 @@ from biz.utils.im.dingtalk import DingTalkNotifier from biz.utils.im.feishu import FeishuNotifier from biz.utils.im.wecom import WeComNotifier +from biz.utils.i18n import get_translator +_ = get_translator() - -def send_notification(content, msg_type='text', title="通知", is_at_all=False, project_name=None): +def send_notification(content, msg_type='text', title=_("通知"), is_at_all=False, project_name=None): """ 发送通知消息到配置的平台(钉钉和企业微信) :param content: 消息内容 diff --git a/biz/utils/im/wecom.py b/biz/utils/im/wecom.py index 16a6793..96dc069 100644 --- a/biz/utils/im/wecom.py +++ b/biz/utils/im/wecom.py @@ -3,7 +3,8 @@ import os import re from biz.utils.log import logger - +from biz.utils.i18n import get_translator +_ = get_translator() class WeComNotifier: def __init__(self, webhook_url=None): @@ -26,7 +27,7 @@ def _get_webhook_url(self, project_name=None): if self.default_webhook_url: return self.default_webhook_url else: - raise ValueError("未提供项目名称,且未设置默认的企业微信 Webhook URL。") + raise ValueError(_("未提供项目名称,且未设置默认的企业微信 Webhook URL。")) # 遍历所有环境变量(忽略大小写),找到项目对应的 Webhook URL target_key = f"WECOM_WEBHOOK_URL_{project_name.upper()}" @@ -39,7 +40,7 @@ def _get_webhook_url(self, project_name=None): return self.default_webhook_url # 如果既未找到匹配项,也没有默认值,抛出异常 - raise ValueError(f"未找到项目 '{project_name}' 对应的企业微信 Webhook URL,且未设置默认的 Webhook URL。") + raise ValueError(_("未找到项目 '{}' 对应的企业微信 Webhook URL,且未设置默认的 Webhook URL。").format(project_name)) def format_markdown_content(self, content, title=None): """ @@ -69,7 +70,7 @@ def send_message(self, content, msg_type='text', title=None, is_at_all=False, pr :param is_at_all: 是否@所有人 """ if not self.enabled: - logger.info("企业微信推送未启用") + logger.info(_("企业微信推送未启用")) return try: @@ -98,14 +99,14 @@ def send_message(self, content, msg_type='text', title=None, is_at_all=False, pr ) if response.status_code != 200: - logger.error(f"企业微信消息发送失败! webhook_url:{post_url}, error_msg:{response.text}") + logger.error(_("企业微信消息发送失败! webhook_url:{}, error_msg:{}").format(post_url, response.text)) return result = response.json() if result.get('errcode') != 0: - logger.error(f"企业微信消息发送失败! webhook_url:{post_url},errmsg:{result}") + logger.error(_("企业微信消息发送失败! webhook_url: {post_url}, errmsg: {result}").format(post_url=post_url, result=result)) else: - logger.info(f"企业微信消息发送成功! webhook_url:{post_url}") + logger.info(_("企业微信消息发送成功! webhook_url: {}").format(post_url)) except Exception as e: - logger.error(f"企业微信消息发送失败! ", e) + logger.error(_("企业微信消息发送失败!"), e) diff --git a/biz/utils/reporter.py b/biz/utils/reporter.py index 5265052..f37898e 100644 --- a/biz/utils/reporter.py +++ b/biz/utils/reporter.py @@ -1,5 +1,6 @@ from core.llm.factory import Factory - +from biz.utils.i18n import get_translator +_ = get_translator() class Reporter: def __init__(self): @@ -9,6 +10,6 @@ def generate_report(self, data: str) -> str: # 根据data生成报告 return self.client.completions( messages=[ - {"role": "user", "content": f"下面是以json格式记录员工代码提交信息。请总结这些信息,生成每个员工的工作日报摘要。员工姓名直接用json内容中的author属性值,不要进行转换。特别要求:以Markdown格式返回。\n{data}"}, + {"role": "user", "content": _("下面是以json格式记录员工代码提交信息。请总结这些信息,生成每个员工的工作日报摘要。员工姓名直接用json内容中的author属性值,不要进行转换。特别要求:以Markdown格式返回。\n{}").format(data)}, ], ) diff --git a/core/llm/client/deepseek.py b/core/llm/client/deepseek.py index 175a795..185031a 100644 --- a/core/llm/client/deepseek.py +++ b/core/llm/client/deepseek.py @@ -7,7 +7,8 @@ from core.llm.client.base import BaseClient from core.llm.types import NotGiven, NOT_GIVEN - +from biz.utils.i18n import get_translator +_ = get_translator() class DeepSeekClient(BaseClient): def __init__(self, api_key: str = None): @@ -16,7 +17,7 @@ def __init__(self, api_key: str = None): self.api_key = api_key or os.getenv("DEEPSEEK_API_KEY") self.base_url = os.getenv("DEEPSEEK_API_BASE_URL", "https://api.deepseek.com") if not self.api_key: - raise ValueError("API key is required. Please provide it or set it in the environment variables.") + raise ValueError(_("API key is required. Please provide it or set it in the environment variables.")) self.client = OpenAI(api_key=self.api_key, base_url=self.base_url) # DeepSeek supports OpenAI API SDK self.default_model = os.getenv("DEEPSEEK_API_MODEL", "deepseek-chat") @@ -27,7 +28,7 @@ def completions(self, ) -> str: try: model = model or self.default_model - logger.debug(f"Sending request to DeepSeek API. Model: {model}, Messages: {messages}") + logger.debug(_("Sending request to DeepSeek API. Model: {model}, Messages: {messages}").format(model=model, messages=messages)) completion = self.client.chat.completions.create( model=model, @@ -35,17 +36,17 @@ def completions(self, ) if not completion or not completion.choices: - logger.error("Empty response from DeepSeek API") - return "AI服务返回为空,请稍后重试" + logger.error(_("Empty response from DeepSeek API")) + return _("AI服务返回为空,请稍后重试") return completion.choices[0].message.content except Exception as e: - logger.error(f"DeepSeek API error: {str(e)}") + logger.error(_("DeepSeek API error: {e}").format(e=str(e))) # 检查是否是认证错误 if "401" in str(e): - return "DeepSeek API认证失败,请检查API密钥是否正确" + return _("DeepSeek API认证失败,请检查API密钥是否正确") elif "404" in str(e): - return "DeepSeek API接口未找到,请检查API地址是否正确" + return _("DeepSeek API接口未找到,请检查API地址是否正确") else: - return f"调用DeepSeek API时出错: {str(e)}" + return _("调用DeepSeek API时出错: {e}").format(e=str(e)) diff --git a/core/llm/client/openai.py b/core/llm/client/openai.py index 56ccda8..6bc07f8 100644 --- a/core/llm/client/openai.py +++ b/core/llm/client/openai.py @@ -6,7 +6,8 @@ from core.llm.client.base import BaseClient from core.llm.types import NotGiven, NOT_GIVEN - +from biz.utils.i18n import get_translator +_ = get_translator() class OpenAIClient(BaseClient): def __init__(self, api_key: str = None): @@ -15,7 +16,7 @@ def __init__(self, api_key: str = None): self.api_key = api_key or os.getenv("OPENAI_API_KEY") self.base_url = os.getenv("OPENAI_API_BASE_URL", "https://api.openai.com") if not self.api_key: - raise ValueError("API key is required. Please provide it or set it in the environment variables.") + raise ValueError(_("API key is required. Please provide it or set it in the environment variables.")) self.client = OpenAI(api_key=self.api_key, base_url=self.base_url) self.default_model = os.getenv("OPENAI_API_MODEL", "gpt-4o-mini") diff --git a/core/llm/client/zhipuai.py b/core/llm/client/zhipuai.py index 427f73f..8b842f0 100644 --- a/core/llm/client/zhipuai.py +++ b/core/llm/client/zhipuai.py @@ -6,7 +6,8 @@ from core.llm.client.base import BaseClient from core.llm.types import NotGiven, NOT_GIVEN - +from biz.utils.i18n import get_translator +_ = get_translator() class ZhipuAIClient(BaseClient): def __init__(self, api_key: str = None): @@ -14,7 +15,7 @@ def __init__(self, api_key: str = None): load_dotenv() self.api_key = api_key or os.getenv("ZHIPUAI_API_KEY") if not self.api_key: - raise ValueError("API key is required. Please provide it or set it in the environment variables.") + raise ValueError(_("API key is required. Please provide it or set it in the environment variables.")) self.client = ZhipuAI(api_key=api_key) self.default_model = os.getenv("ZHIPUAI_API_MODEL", "GLM-4-Flash") diff --git a/core/llm/factory.py b/core/llm/factory.py index 852c41a..f241904 100644 --- a/core/llm/factory.py +++ b/core/llm/factory.py @@ -7,7 +7,8 @@ from core.llm.client.ollama_client import OllamaClient from core.llm.client.openai import OpenAIClient from core.llm.client.zhipuai import ZhipuAIClient - +from biz.utils.i18n import get_translator +_ = get_translator() class Factory: @staticmethod @@ -25,4 +26,4 @@ def getClient(provider: str = None) -> BaseClient: if provider_func: return provider_func() else: - raise Exception(f'Unknown chat model provider: {provider}') + raise Exception(_('Unknown chat model provider: {provider}')) diff --git a/doc/faq.md b/doc/faq.md index 46b67cd..d2ed260 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -66,4 +66,12 @@ DINGTALK_WEBHOOK_URL=https://oapi.dingtalk.com/robot/send?access_token={access_t ``` OLLAMA_API_BASE_URL=http://127.0.0.1:11434 # 错误 OLLAMA_API_BASE_URL=http://{宿主机/外网IP地址}:11434 # 正确 -``` \ No newline at end of file +``` + +#### 5. 翻译 +更改翻译后无法正确应用,我该怎么办? +该应用程序使用 python 原生 gettext 实现来加载各种语言的翻译。如果您更改了翻译文件,但是应用程序没有正确应用新的翻译,您可以尝试以下步骤: +1. 更新翻译: `bash translations_update.sh` +2. 通过向具有空 msgstr 的新行添加值来手动调整 `locales//LC_Messages/messages.po` 中缺失的翻译 +3. 编译翻译:`bash translations_compile.sh` +4. 重新启动您的应用程序 \ No newline at end of file diff --git a/locales/en_US/LC_MESSAGES/messages.mo b/locales/en_US/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..011c93fc14735c7d7b1a723b444e3ff862f39b4d GIT binary patch literal 10020 zcmeHMZEPIJc^)T@lU`Fhahk+!(q@IQggz!ZLwqISRy zz@Gxcz~2D>7`XAHjNvES0lXbp4{QK70{;{^0lX9V2Cxda1f=%=2z(FtFF^dUpW`Ke z2K*K9Zs14I=`+C30LeZN02_gOfHbZd;1=L7fYk2JyBPZvuo_6?ivg>F`+z?ME&yR_ z_WZ}>`wjs&lzK^L7s=g~qWRxE?zTzY|FIXasWLZtwm8kml*Hfqw#= z0+K#+KpIERdwwSx(ep0=NsottTY(3Fcay&XcLIM5W076&!pmVAwgres>=7W%ZwJr@ zJ_mdN_*)>!sfF-n;9em4-CIDK@4xe|?}D+ug6k^alRyi|f!Ba!pML=E0B*#j;U{|< zNPaf}B>!Cm-Vgi_AY6e(FbNxg4+2TAZvZh=b{I&0Gy^2RdlN`{`~XODe+z_buus6L z$nQQ6r1nn&Ka27229kX1&l$rX8^u3#VP}C~0A2;63Hv7?jhBq|D4+#c3!DU!UVj6m zcE1GDcyHs-8Mq602i`LTM5wZ7(HJ4d4gu-;aUlNKyZ8swvOJLVWS?iO2CxZ8&pUu* zuL0oKfD6D~z!03Y1-J(o1D*#y3M>NafYlhpGe8~q6!6Eu+kyAqEA^=cVrXm|@I$~h z@BULj(oX@BA5H>EuhT#dd>2UaUEnrgHIfn8`x`)#HwgSH@C5Knz+VAx13rk8j=zu~ z{*(WZZ+#Fa)D{Q5^KtL@P9WLZKS-~~a3bV{&J94aDftB*WQPqnNguK~<%4FNq%R!^ zJ&{|;zV$dC!bv)R0A~~@Oe+rZUy7+MILXFe#z_ZUT-e}YaV7IJ(uD9Ex<&S-7=bI4 z4)Rr+U-FH=#7VwQ2hAbHTO(cI*p8F@v6?P$JR(8(F#UwNSrbmOIr+mKI5DN-AisW8 z{uI7QaZk3V{6Yt&K;%eqfq(b;KY%p16#sO5nEr(}ZrsTK^~}@=AIg}bJ70WrwKUM(#|GIZKO$`FGs6p3PmKaYyH)p)jwmb|)rtmtQN4?2A@c z^C2Z`_ZsGKNItqe>5T1nr{=4xqkPCRvSvc<+-oX&qIXy{$e)^X&mIW0u@$`7E^FhS zdfPp|;J&+W;=p4l{%HB-ZzrLM6?jJID?2Y7z@sQcStDU8b&S^4= zyvJ6IEXOE};0-Ql0Zf5-74o{`|a&s`)qRvQ?0|@ zUokahZ%VZyES9wmU%fUlH&GsfHg&y(e#E|M$H4|6WK2A!jrfHbCtq!x`efP+$GjR^qa1UN{#uns= z-E$+DbM$hi7o5{0?umJ4@^$ykbNQLMvd)FM*9!Ba&TDTK-kz=OIlsU7(rj7J1{w&) zVPy;**6KEmG!Lr69#gcGn&hwuVuvR@6LiCtrrM3s(V%L?xvnwRlR@u#T(fs6d-*2M zJez%Sm3>6iS?uwE4&_Swf>!KalC@&|M!jE2X-Tg3)0EqT8I|4_;VpVstHx=SCi|usNqV&)(rh2GP%~H8|3H}tz}rTR%I|{C`lR~qs+nLs-7fI^@c|i z8l2|{Z$eO}&^}EF`AuGiqg#HmWAQ-?ZoQ_`9eN+kqjN+Lk~H%#;W0KBGW}2_hxek= z9A=(J2}N_44i!&-2mYB`p8cj}=@E`J>L{ zcpfF;$ZUS<0%_pv-{;INTEGfF6OG%~G~UDWWT*4=G&+UmD${t(S!aNtsT zmb)^VyL8gIHb(hWOWMDf5xXd87sO)4xcqOih~oXb<> zOj1*ZmpSJTk@HQTVb0Z~&cX50c%r;(Xt=9}%iFSpyvGolSZ;hh3ay`c+N$34bn?E< zxbX;crxszDSfecN-ol7{9Yb-azh79~S3GtdMsdg9aOZxAYLDV-BX0{k-*DMbs+@8j z3iIQ|edGD7b0pg@s;eG}HyxJ^Wvn8+z4}_}Rh(JEvXWPouW75eGrvT}I{7?*Ox3L3 zEZ-voh|0c56jKmUn7algJWoK=KpP~471c^F84d^zhDxyK??!s@rGxkjD0C}gu|~gk zN-9nH^E@qBa+lT`u?)kY`u@OgTE=>IxMe|d$ZP51$82jy{0SNFm{=KAH476=IxT@YPZjTT2vVkOR`jVg^V+9<$eE2I|C?WM!GWE;+E9_Wg1+ z^{S2Sl(il?AUB)V|CAl@cGkO$9?1=OnzmtgY9=kg4zwG#lENNW-XYZ`JrL`M%YdDU z4h z&AVZ*WDWNQk9}&Qk89n6{vZZINhYz97n}yB96M0Ej7;FP>A{){DTP9hcMCRPeQ_QO z>RZa z%6i)&Pz4mWBveDUEJ!*-M;a$>BRrl_6B<&z$BPox8AaZw%t)lAPfoxZR9z#2=A;q( z948Z8t$($emk^KRCG+rlF+91jVS7~McgjLqx0gU*Y4|MVB~>T374(&C&0ivc6xyA|qH9B?4AyLv zvXRF+rwv`hat(#48`P@BVik3a8;L{~saTSC-hOf&``mCHD~XztRZ0|~aA{N0?*Te6 z)>uwu#8s%FfgO&eR1;o9L6cOw6@07USrl3NoP#2q4hR7&9!t|O=_smslh059W5DEQuZF(L6#$~ zLk6{sno7QdR11(GD||L^c^(TURgR9u#ba8KvpSj| zOg$o2n8Bw%{QG_%j{=daEwQF5=RqEUO;D&UhLxD0emT}JP(+aNGE)%)i14!w0}FM% zr-s{RR!234g@b&^x=!SO>+n`ZLMZko^l1Y9yS1Jy_6Stk@%^H-UZCB}ja$&i6qz$f zI}OV+xp;uPuVz5xB81u#2Tb1rS1~A{wlN2~QSz`rXv1Ob2nCXi-ry6lx~UL6Ty;~z z>XG`}l~i9aV%JpkX5@LhJuYH`%!qN)XD6(@D#o>jb;R&)UczcC+@gRrNABAgWmJ6R zD#fvvwKDjKAbc*VMnozAr;oJmXEB~u28I8mReYjZiwY4lXsRi-UqR%E98~$P|E^%l z4$O~5*62IqN|qwW^TQb1B28xv@HP?34fF}FlyWIkrBL*-fu@x~kRd_jfEZ~G6f;&b zBxd|ZC9c$Noh-g0Xq^T@AEgLhUEuHm(f4Ox#!VC_&lzcMDU8W+y}Hb9TzB5*afQC6 S60} literal 0 HcmV?d00001 diff --git a/locales/en_US/LC_MESSAGES/messages.po b/locales/en_US/LC_MESSAGES/messages.po new file mode 100644 index 0000000..f652f9f --- /dev/null +++ b/locales/en_US/LC_MESSAGES/messages.po @@ -0,0 +1,554 @@ +# Language locales/en translations for PACKAGE package. +# Copyright (C) 2025 THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2025. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-03-18 17:24+0100\n" +"PO-Revision-Date: 2025-03-18 15:05+0100\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: locales/en_US\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: api.py:63 +msgid "代码提交日报" +msgstr "Code Submission Daily Report" + +#: api.py:166 +msgid "未检测到PUSH代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。" +msgstr "" +"No changes detected in the pushed code. The modified files may not meet " +"SUPPORTED_EXTENSIONS." + +#: api.py:167 +msgid "关注的文件没有修改" +msgstr "No changes in the monitored files" + +#: api.py:174 api.py:225 +msgid "" +"Auto Review Result: \n" +"{}" +msgstr "" +"Auto Review Result: \n" +"{}" + +#: api.py:187 +msgid "服务出现未知错误: {}" +msgstr "An unknown error occurred in the service: {}" + +#: api.py:189 api.py:248 api.py:287 +msgid "出现未知错误: {}" +msgstr "An unknown error occurred: {}" + +#: api.py:203 +msgid "Merge Request Hook event received" +msgstr "Merge Request Hook event received" + +#: api.py:208 api.py:263 +msgid "changes: {}" +msgstr "Changes: {}" + +#: api.py:211 api.py:266 +msgid "未检测到有关代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。" +msgstr "" +"No relevant code changes detected. The modified files may not meet " +"SUPPORTED_EXTENSIONS." + +#: api.py:217 +msgid "Failed to get commits" +msgstr "Failed to retrieve commits" + +#: api.py:243 +msgid "Merge Request Hook event, action={}, ignored." +msgstr "Merge Request Hook event, action={}, ignored." + +#: api.py:246 api.py:285 +msgid "AI Code Review 服务出现未知错误: {}" +msgstr "AI Code Review service encountered an unknown error: {}" + +#: api.py:260 +msgid "System Hook event received" +msgstr "System Hook event received" + +#: api.py:272 +msgid "Payload: {}" +msgstr "Payload: {}" + +#: api.py:314 +msgid "代码为空, diffs_text = {}" +msgstr "Code is empty, diffs_text = {}" + +#: api.py:315 +msgid "代码为空" +msgstr "Code is empty" + +#: api.py:319 +msgid "文本超长,截段后content: {}" +msgstr "Text is too long, truncated content: {}" + +#: biz/event/event_manager.py:25 +#, python-brace-format +msgid "" +"\n" +"### 🔀 {project_name}: Merge Request\n" +"\n" +"#### 合并请求信息:\n" +"- **提交者:** {author}\n" +"\n" +"- **源分支**: {source_branch}\n" +"- **目标分支**: {target_branch}\n" +"- **更新时间**: {updated_at}\n" +"- **提交信息:** {commit_messages}\n" +"\n" +"- [查看合并详情]({url})\n" +"\n" +"- **AI Review 结果:** \n" +"\n" +"{review_result}\n" +" " +msgstr "" +"\n" +"### 🔀 {project_name}: Merge Request\n" +"\n" +"#### Merge Request Information:\n" +"- **Author:** {author}\n" +"\n" +"- **Source Branch**: {source_branch}\n" +"- **Target Branch**: {target_branch}\n" +"- **Updated At**: {updated_at}\n" +"- **Commit Messages:** {commit_messages}\n" +"\n" +"- [View Merge Details]({url})\n" +"\n" +"- **AI Review Results:** \n" +"\n" +"{review_result}\n" +" " + +#: biz/event/event_manager.py:51 +msgid "Merge Request Review" +msgstr "Merge Request Review" + +#: biz/event/event_manager.py:60 +#, python-brace-format +msgid "" +"### 🚀 {project_name}: Push\n" +"\n" +msgstr "" +"### 🚀 {project_name}: Push\n" +"\n" + +#: biz/event/event_manager.py:61 biz/event/event_manager.py:93 +msgid "#### 提交记录:\n" +msgstr "#### Commit Records:\n" + +#: biz/event/event_manager.py:65 biz/event/event_manager.py:97 +msgid "Unknown Author" +msgstr "Unknown Author" + +#: biz/event/event_manager.py:69 +#, python-brace-format +msgid "" +"- **提交信息**: {message}\n" +"- **提交者**: {author}\n" +"- **时间**: {timestamp}\n" +"- [查看提交详情]({url})\n" +"\n" +msgstr "" +"- **Commit Message**: {message}\n" +"- **Author**: {author}\n" +"- **Timestamp**: {timestamp}\n" +"- [View Commit Details]({url})\n" +"\n" + +#: biz/event/event_manager.py:81 biz/event/event_manager.py:109 +#, python-brace-format +msgid "" +"#### AI Review 结果: \n" +" {review_result}\n" +"\n" +msgstr "" + +#: biz/event/event_manager.py:83 biz/event/event_manager.py:111 +#, python-brace-format +msgid "{project_name} Push Event" +msgstr "" + +#: biz/event/event_manager.py:92 +#, python-brace-format +msgid "" +"### 🚀 {project_name}: System Hook\n" +"\n" +msgstr "" + +#: biz/event/event_manager.py:100 +#, python-brace-format +msgid "" +"- **提交信息**: {message}\n" +"- **提交者**: {author}\n" +"- **时间**: {timestamp}\n" +msgstr "" + +#: biz/gitlab/webhook_handler.py:39 +msgid "Invalid event type: {}. Only 'merge_request' event is supported now." +msgstr "Invalid event type: {}. Only 'merge_request' event is supported now." + +#: biz/gitlab/webhook_handler.py:54 +msgid "Get changes response from GitLab (attempt {}): {}, {}, URL: {}" +msgstr "Get changes response from GitLab (attempt {}): {}, {}, URL: {}" + +#: biz/gitlab/webhook_handler.py:62 +msgid "Changes is empty, retrying in {} seconds... (attempt {}/{}), URL: {}" +msgstr "Changes are empty, retrying in {} seconds... (attempt {}/{}), URL: {}" + +#: biz/gitlab/webhook_handler.py:65 +msgid "Failed to get changes from GitLab (URL: {}): {}, {}" +msgstr "Failed to retrieve changes from GitLab (URL: {}): {}, {}" + +#: biz/gitlab/webhook_handler.py:68 +msgid "Max retries ({}) reached. Changes is still empty." +msgstr "Max retries ({}) reached. Changes are still empty." + +#: biz/gitlab/webhook_handler.py:83 +msgid "Get commits response from gitlab: {}, {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:87 +msgid "Failed to get commits: {}, {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:101 +msgid "Add notes to gitlab {}: {}, {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:105 +msgid "Failed to add note: {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:135 biz/gitlab/webhook_handler.py:184 +msgid "Invalid event type: {}. Only 'push' event is supported now." +msgstr "" + +#: biz/gitlab/webhook_handler.py:149 +msgid "Collected {} commits from push event." +msgstr "" + +#: biz/gitlab/webhook_handler.py:155 +msgid "No commits found to add notes to." +msgstr "" + +#: biz/gitlab/webhook_handler.py:161 +msgid "Last commit ID not found." +msgstr "" + +#: biz/gitlab/webhook_handler.py:189 +msgid "No commits found in push event." +msgstr "" + +#: biz/gitlab/webhook_handler.py:203 +msgid "Get changes response from GitLab for push event: {}, {}, URL: {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:207 +msgid "Failed to get changes for push event: {}, {}, URL: {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:224 +msgid "event_name" +msgstr "" + +#: biz/gitlab/webhook_handler.py:225 biz/gitlab/webhook_handler.py:281 +msgid "repository_update" +msgstr "" + +#: biz/gitlab/webhook_handler.py:236 biz/gitlab/webhook_handler.py:282 +msgid "" +"Invalid event type: {}. Only 'repository_update' event is supported now." +msgstr "" + +#: biz/gitlab/webhook_handler.py:240 biz/gitlab/webhook_handler.py:286 +msgid "No changes found in webhook data." +msgstr "" + +#: biz/gitlab/webhook_handler.py:252 biz/gitlab/webhook_handler.py:295 +msgid "unknown branch" +msgstr "" + +#: biz/gitlab/webhook_handler.py:255 biz/gitlab/webhook_handler.py:298 +msgid "Missing before or after commit ID for ref {}." +msgstr "" + +#: biz/gitlab/webhook_handler.py:263 +msgid "" +"Get changes response from GitLab for repository_update (attempt {}): {}, {}, " +"URL: {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:272 +msgid "Failed to get changes for ref {}: {}, {}, retrying in {} seconds..." +msgstr "Failed to get changes for ref {}: {}, {}, retrying in {} seconds..." + +#: biz/gitlab/webhook_handler.py:276 +msgid "Max retries ({}) reached. Unable to retrieve repository changes." +msgstr "" + +#: biz/gitlab/webhook_handler.py:304 +msgid "Get commits response from GitLab for repository_update: {}, {}, URL: {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:312 +msgid "Failed to get commits for ref {}: {}, {}" +msgstr "" + +#: biz/utils/code_reviewer.py:27 +msgid "未找到提示词配置{}" +msgstr "Prompt configuration {} not found" + +#: biz/utils/code_reviewer.py:29 +msgid "未找到提示词配置{},或配置格式不正确" +msgstr "Prompt configuration {} not found or format is incorrect" + +#: biz/utils/code_reviewer.py:60 +msgid "向AI发送代码Review请求, message: {}" +msgstr "Sending code review request to AI, message: {}" + +#: biz/utils/code_reviewer.py:64 +msgid "收到AI返回结果: {}" +msgstr "Received AI response: {}" + +#: biz/utils/code_reviewer.py:72 +msgid "总分[::]\\s*(\\d+)分?" +msgstr "Total Score[::]\\s*(\\d+)? points" + +#: biz/utils/im/dingtalk.py:28 +msgid "未提供项目名称,且未设置默认的钉钉 Webhook URL。" +msgstr "Project name not provided, and no default DingTalk Webhook URL set." + +#: biz/utils/im/dingtalk.py:41 +msgid "未找到项目 '{}' 对应的钉钉Webhook URL,且未设置默认的 Webhook URL。" +msgstr "" +"No DingTalk Webhook URL found for project '{}', and no default Webhook URL " +"set." + +#: biz/utils/im/dingtalk.py:45 +msgid "钉钉推送未启用" +msgstr "DingTalk notifications are not enabled." + +#: biz/utils/im/dingtalk.py:78 +msgid "钉钉消息发送成功! webhook_url: {}" +msgstr "DingTalk message sent successfully! Webhook URL: {}" + +#: biz/utils/im/dingtalk.py:80 +msgid "钉钉消息发送失败! webhook_url: {}, errmsg: {}" +msgstr "DingTalk message failed to send! Webhook URL: {}, error message: {}" + +#: biz/utils/im/dingtalk.py:82 +msgid "钉钉消息发送失败!" +msgstr "DingTalk message failed to send!" + +#: biz/utils/im/feishu.py:28 +msgid "未提供项目名称,且未设置默认的 飞书 Webhook URL。" +msgstr "Project name not provided, and no default Feishu Webhook URL set." + +#: biz/utils/im/feishu.py:41 +#, python-brace-format +msgid "" +"未找到项目 '{project_name}' 对应的 Feishu Webhook URL,且未设置默认的 " +"Webhook URL。" +msgstr "" +"No Feishu Webhook URL found for project '{project_name}', and no default " +"Webhook URL set." + +#: biz/utils/im/feishu.py:53 +msgid "飞书推送未启用" +msgstr "Feishu push is not enabled" + +#: biz/utils/im/feishu.py:113 +#, python-brace-format +msgid "飞书消息发送失败! webhook_url: {post_url}, error_msg: {post_url}" +msgstr "" +"Feishu message failed to send! Webhook URL: {post_url}, error message: " +"{post_url}" + +#: biz/utils/im/feishu.py:118 +#, python-brace-format +msgid "发送飞书消息失败! webhook_url: {post_url}, errmsg: {result}" +msgstr "" +"Feishu message failed to send! webhook_url: {post_url}, errmsg: {post_url}" + +#: biz/utils/im/feishu.py:120 +#, python-brace-format +msgid "飞书消息发送成功! webhook_url: {post_url}" +msgstr "Feishu message sent successfully! Webhook URL: {post_url}" + +#: biz/utils/im/feishu.py:123 +msgid "飞书消息发送失败!" +msgstr "Feishu message failed to send!" + +#: biz/utils/im/im_notifier.py:7 +msgid "通知" +msgstr "Notification" + +#: biz/utils/im/wecom.py:30 +msgid "未提供项目名称,且未设置默认的企业微信 Webhook URL。" +msgstr "Project name not provided, and no default WeCom Webhook URL set." + +#: biz/utils/im/wecom.py:43 +msgid "" +"未找到项目 '{}' 对应的企业微信 Webhook URL,且未设置默认的 Webhook URL。" +msgstr "" +"No WeCom Webhook URL found for project '{}', and no default Webhook URL set." + +#: biz/utils/im/wecom.py:73 +msgid "企业微信推送未启用" +msgstr "WeCom notifications are not enabled." + +#: biz/utils/im/wecom.py:102 +msgid "企业微信消息发送失败! webhook_url:{}, error_msg:{}" +msgstr "WeCom message failed to send! Webhook URL: {}, error message: {}" + +#: biz/utils/im/wecom.py:107 +#, python-brace-format +msgid "企业微信消息发送失败! webhook_url: {post_url}, errmsg: {result}" +msgstr "" +"WeCom message failed to send! Webhook URL: {post_url}, error message: " +"{result}" + +#: biz/utils/im/wecom.py:109 +msgid "企业微信消息发送成功! webhook_url: {}" +msgstr "WeCom message sent successfully! Webhook URL: {}" + +#: biz/utils/im/wecom.py:112 +msgid "企业微信消息发送失败!" +msgstr "WeCom message failed to send!" + +#: biz/utils/reporter.py:13 +msgid "" +"下面是以json格式记录员工代码提交信息。请总结这些信息,生成每个员工的工作日报" +"摘要。员工姓名直接用json内容中的author属性值,不要进行转换。特别要求:以" +"Markdown格式返回。\n" +"{}" +msgstr "" +"The following is a JSON record of employee code submissions. Please " +"summarize this information to generate each employee's daily work report " +"summary. Use the `author` attribute value from the JSON content directly " +"without conversion. Special requirement: Return in Markdown format.\n" +"{}" + +#: core/llm/client/deepseek.py:20 core/llm/client/openai.py:19 +#: core/llm/client/zhipuai.py:18 +msgid "" +"API key is required. Please provide it or set it in the environment " +"variables." +msgstr "" +"API key is required. Please provide it or set it in the environment " +"variables." + +#: core/llm/client/deepseek.py:31 +#, python-brace-format +msgid "Sending request to DeepSeek API. Model: {model}, Messages: {messages}" +msgstr "Sending request to DeepSeek API. Model: {model}, Messages: {messages}" + +#: core/llm/client/deepseek.py:39 +msgid "Empty response from DeepSeek API" +msgstr "Empty response from DeepSeek API" + +#: core/llm/client/deepseek.py:40 +msgid "AI服务返回为空,请稍后重试" +msgstr "AI service returned empty, please try again later" + +#: core/llm/client/deepseek.py:45 +#, python-brace-format +msgid "DeepSeek API error: {e}" +msgstr "DeepSeek API error: {e}" + +#: core/llm/client/deepseek.py:48 +msgid "DeepSeek API认证失败,请检查API密钥是否正确" +msgstr "" +"DeepSeek API authentication failed, please check if the API key is correct" + +#: core/llm/client/deepseek.py:50 +msgid "DeepSeek API接口未找到,请检查API地址是否正确" +msgstr "" +"DeepSeek API endpoint not found, please check if the API address is correct" + +#: core/llm/client/deepseek.py:52 +#, python-brace-format +msgid "调用DeepSeek API时出错: {e}" +msgstr "Error occurred while calling DeepSeek API: {e}" + +#: core/llm/factory.py:29 +#, python-brace-format +msgid "Unknown chat model provider: {provider}" +msgstr "Unknown chat model provider: {provider}" + +#: ui.py:53 ui.py:68 +msgid "登录" +msgstr "Login" + +#: ui.py:57 +msgid "" +"安全提示:检测到默认用户名和密码为 'admin',存在安全风险!\n" +"\n" +"请立即修改:\n" +"1. 打开 `.env` 文件\n" +"2. 修改 `DASHBOARD_USER` 和 `DASHBOARD_PASSWORD` 变量\n" +"3. 保存并重启应用" +msgstr "" +"Security Alert: The default username and password are detected as 'admin', " +"which poses a security risk!\n" +"\n" +"Please update them immediately:\n" +"1. Open the `.env` file\n" +"2. Change the `DASHBOARD_USER` and `DASHBOARD_PASSWORD` variables\n" +"3. Save and restart the application" + +#: ui.py:63 +msgid "当前用户名: `{}`, 当前密码: `{}`" +msgstr "Current Username: `{}`, Current Password: `{}`" + +#: ui.py:65 ui.py:109 +msgid "用户名" +msgstr "Username" + +#: ui.py:66 +msgid "密码" +msgstr "Password" + +#: ui.py:74 +msgid "用户名或密码错误" +msgstr "Incorrect username or password" + +#: ui.py:79 +msgid "#### 审查日志" +msgstr "#### Review Log" + +#: ui.py:88 +msgid "Merge Request" +msgstr "Merge Request" + +#: ui.py:88 +msgid "Push" +msgstr "Push" + +#: ui.py:96 +msgid "开始日期" +msgstr "Start Date" + +#: ui.py:98 +msgid "结束日期" +msgstr "End Date" + +#: ui.py:123 +msgid "**总记录数:** {},**平均分:** {}" +msgstr "**Total Records:** {},**Average Score:** {}" + +#: ui.py:137 +msgid "查看" +msgstr "Open" diff --git a/locales/en_US/prompt_templates.yml b/locales/en_US/prompt_templates.yml new file mode 100644 index 0000000..4f0514c --- /dev/null +++ b/locales/en_US/prompt_templates.yml @@ -0,0 +1,22 @@ +system_prompt: |- + You are an experienced software development engineer, focusing on code standardization, functionality, security, and stability. The task is to review the employee's code with the following requirements: + + ### Code Review Objectives: + 1. Correctness and robustness of functionality (40 points): Ensure the code logic is correct and can handle various edge cases and exceptional inputs. + 2. Security and potential risks (30 points): Check for security vulnerabilities (such as SQL injection, XSS attacks, etc.) and assess potential risks. + 3. Compliance with best practices (20 points): Evaluate whether the code follows industry best practices, including code structure, naming conventions, and clarity of comments. + 4. Performance and resource efficiency (5 points): Analyze the performance of the code and assess whether there is any resource wastage or performance bottlenecks. + 5. Clarity and accuracy of commit information (5 points): Check if the commit information is clear and accurate, and if it facilitates future maintenance and collaboration. + + ### Output Format: + Please output the code review report in Markdown format, including the following content: + 1. Problem description and optimization suggestions (if any): List the problems in the code, briefly explain their impact, and provide optimization suggestions. + 2. Scoring details: Provide specific scores for each scoring criterion. + 3. Total score: Format as "Total score: XX points" (e.g., Total score: 80 points), ensuring it can be parsed by the regular expression r"Total score[::]\s*(\d+) points?". +user_prompt: |- + Below is the code submitted by an employee to the GitLab repository. Please strictly review for serious issues and evaluate the code quality, providing a brief evaluation and score. + Code changes: + {diffs_text} + + Commit history: + {commits_text} diff --git a/locales/zh_CN/LC_MESSAGES/messages.mo b/locales/zh_CN/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..09fc6b4404daed73fd4a00dfeb647c63670216cd GIT binary patch literal 370 zcmYL_!A=4(6h%j)E@sKvMfduogCQYR7lrweISpCc&fK6u@ literal 0 HcmV?d00001 diff --git a/locales/zh_CN/LC_MESSAGES/messages.po b/locales/zh_CN/LC_MESSAGES/messages.po new file mode 100644 index 0000000..08f95b9 --- /dev/null +++ b/locales/zh_CN/LC_MESSAGES/messages.po @@ -0,0 +1,498 @@ +# Language locales/zh translations for PACKAGE package. +# Copyright (C) 2025 THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2025. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-03-18 17:24+0100\n" +"PO-Revision-Date: 2025-03-18 15:05+0100\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: locales/zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: api.py:63 +msgid "代码提交日报" +msgstr "" + +#: api.py:166 +msgid "未检测到PUSH代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。" +msgstr "" + +#: api.py:167 +msgid "关注的文件没有修改" +msgstr "" + +#: api.py:174 api.py:225 +msgid "" +"Auto Review Result: \n" +"{}" +msgstr "" + +#: api.py:187 +msgid "服务出现未知错误: {}" +msgstr "" + +#: api.py:189 api.py:248 api.py:287 +msgid "出现未知错误: {}" +msgstr "" + +#: api.py:203 +msgid "Merge Request Hook event received" +msgstr "" + +#: api.py:208 api.py:263 +msgid "changes: {}" +msgstr "" + +#: api.py:211 api.py:266 +msgid "未检测到有关代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。" +msgstr "" + +#: api.py:217 +msgid "Failed to get commits" +msgstr "" + +#: api.py:243 +msgid "Merge Request Hook event, action={}, ignored." +msgstr "" + +#: api.py:246 api.py:285 +msgid "AI Code Review 服务出现未知错误: {}" +msgstr "" + +#: api.py:260 +msgid "System Hook event received" +msgstr "" + +#: api.py:272 +msgid "Payload: {}" +msgstr "" + +#: api.py:314 +msgid "代码为空, diffs_text = {}" +msgstr "" + +#: api.py:315 +msgid "代码为空" +msgstr "" + +#: api.py:319 +msgid "文本超长,截段后content: {}" +msgstr "" + +#: biz/event/event_manager.py:25 +#, python-brace-format +msgid "" +"\n" +"### 🔀 {project_name}: Merge Request\n" +"\n" +"#### 合并请求信息:\n" +"- **提交者:** {author}\n" +"\n" +"- **源分支**: {source_branch}\n" +"- **目标分支**: {target_branch}\n" +"- **更新时间**: {updated_at}\n" +"- **提交信息:** {commit_messages}\n" +"\n" +"- [查看合并详情]({url})\n" +"\n" +"- **AI Review 结果:** \n" +"\n" +"{review_result}\n" +" " +msgstr "" + +#: biz/event/event_manager.py:51 +msgid "Merge Request Review" +msgstr "" + +#: biz/event/event_manager.py:60 +#, python-brace-format +msgid "" +"### 🚀 {project_name}: Push\n" +"\n" +msgstr "" + +#: biz/event/event_manager.py:61 biz/event/event_manager.py:93 +msgid "#### 提交记录:\n" +msgstr "" + +#: biz/event/event_manager.py:65 biz/event/event_manager.py:97 +msgid "Unknown Author" +msgstr "" + +#: biz/event/event_manager.py:69 +#, python-brace-format +msgid "" +"- **提交信息**: {message}\n" +"- **提交者**: {author}\n" +"- **时间**: {timestamp}\n" +"- [查看提交详情]({url})\n" +"\n" +msgstr "" + +#: biz/event/event_manager.py:81 biz/event/event_manager.py:109 +#, python-brace-format +msgid "" +"#### AI Review 结果: \n" +" {review_result}\n" +"\n" +msgstr "" + +#: biz/event/event_manager.py:83 biz/event/event_manager.py:111 +#, python-brace-format +msgid "{project_name} Push Event" +msgstr "" + +#: biz/event/event_manager.py:92 +#, python-brace-format +msgid "" +"### 🚀 {project_name}: System Hook\n" +"\n" +msgstr "" + +#: biz/event/event_manager.py:100 +#, python-brace-format +msgid "" +"- **提交信息**: {message}\n" +"- **提交者**: {author}\n" +"- **时间**: {timestamp}\n" +msgstr "" + +#: biz/gitlab/webhook_handler.py:39 +msgid "Invalid event type: {}. Only 'merge_request' event is supported now." +msgstr "" + +#: biz/gitlab/webhook_handler.py:54 +msgid "Get changes response from GitLab (attempt {}): {}, {}, URL: {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:62 +msgid "Changes is empty, retrying in {} seconds... (attempt {}/{}), URL: {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:65 +msgid "Failed to get changes from GitLab (URL: {}): {}, {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:68 +msgid "Max retries ({}) reached. Changes is still empty." +msgstr "" + +#: biz/gitlab/webhook_handler.py:83 +msgid "Get commits response from gitlab: {}, {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:87 +msgid "Failed to get commits: {}, {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:101 +msgid "Add notes to gitlab {}: {}, {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:105 +msgid "Failed to add note: {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:135 biz/gitlab/webhook_handler.py:184 +msgid "Invalid event type: {}. Only 'push' event is supported now." +msgstr "" + +#: biz/gitlab/webhook_handler.py:149 +msgid "Collected {} commits from push event." +msgstr "" + +#: biz/gitlab/webhook_handler.py:155 +msgid "No commits found to add notes to." +msgstr "" + +#: biz/gitlab/webhook_handler.py:161 +msgid "Last commit ID not found." +msgstr "" + +#: biz/gitlab/webhook_handler.py:189 +msgid "No commits found in push event." +msgstr "" + +#: biz/gitlab/webhook_handler.py:203 +msgid "Get changes response from GitLab for push event: {}, {}, URL: {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:207 +msgid "Failed to get changes for push event: {}, {}, URL: {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:224 +msgid "event_name" +msgstr "" + +#: biz/gitlab/webhook_handler.py:225 biz/gitlab/webhook_handler.py:281 +msgid "repository_update" +msgstr "" + +#: biz/gitlab/webhook_handler.py:236 biz/gitlab/webhook_handler.py:282 +msgid "" +"Invalid event type: {}. Only 'repository_update' event is supported now." +msgstr "" + +#: biz/gitlab/webhook_handler.py:240 biz/gitlab/webhook_handler.py:286 +msgid "No changes found in webhook data." +msgstr "" + +#: biz/gitlab/webhook_handler.py:252 biz/gitlab/webhook_handler.py:295 +msgid "unknown branch" +msgstr "" + +#: biz/gitlab/webhook_handler.py:255 biz/gitlab/webhook_handler.py:298 +msgid "Missing before or after commit ID for ref {}." +msgstr "" + +#: biz/gitlab/webhook_handler.py:263 +msgid "" +"Get changes response from GitLab for repository_update (attempt {}): {}, {}, " +"URL: {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:272 +msgid "Failed to get changes for ref {}: {}, {}, retrying in {} seconds..." +msgstr "" + +#: biz/gitlab/webhook_handler.py:276 +msgid "Max retries ({}) reached. Unable to retrieve repository changes." +msgstr "" + +#: biz/gitlab/webhook_handler.py:304 +msgid "Get commits response from GitLab for repository_update: {}, {}, URL: {}" +msgstr "" + +#: biz/gitlab/webhook_handler.py:312 +msgid "Failed to get commits for ref {}: {}, {}" +msgstr "" + +#: biz/utils/code_reviewer.py:27 +msgid "未找到提示词配置{}" +msgstr "" + +#: biz/utils/code_reviewer.py:29 +msgid "未找到提示词配置{},或配置格式不正确" +msgstr "" + +#: biz/utils/code_reviewer.py:60 +msgid "向AI发送代码Review请求, message: {}" +msgstr "" + +#: biz/utils/code_reviewer.py:64 +msgid "收到AI返回结果: {}" +msgstr "" + +#: biz/utils/code_reviewer.py:72 +msgid "总分[::]\\s*(\\d+)分?" +msgstr "" + +#: biz/utils/im/dingtalk.py:28 +msgid "未提供项目名称,且未设置默认的钉钉 Webhook URL。" +msgstr "" + +#: biz/utils/im/dingtalk.py:41 +msgid "未找到项目 '{}' 对应的钉钉Webhook URL,且未设置默认的 Webhook URL。" +msgstr "" + +#: biz/utils/im/dingtalk.py:45 +msgid "钉钉推送未启用" +msgstr "" + +#: biz/utils/im/dingtalk.py:78 +msgid "钉钉消息发送成功! webhook_url: {}" +msgstr "" + +#: biz/utils/im/dingtalk.py:80 +msgid "钉钉消息发送失败! webhook_url: {}, errmsg: {}" +msgstr "" + +#: biz/utils/im/dingtalk.py:82 +msgid "钉钉消息发送失败!" +msgstr "" + +#: biz/utils/im/feishu.py:28 +msgid "未提供项目名称,且未设置默认的 飞书 Webhook URL。" +msgstr "" + +#: biz/utils/im/feishu.py:41 +#, python-brace-format +msgid "" +"未找到项目 '{project_name}' 对应的 Feishu Webhook URL,且未设置默认的 " +"Webhook URL。" +msgstr "" + +#: biz/utils/im/feishu.py:53 +msgid "飞书推送未启用" +msgstr "" + +#: biz/utils/im/feishu.py:113 +#, python-brace-format +msgid "飞书消息发送失败! webhook_url: {post_url}, error_msg: {post_url}" +msgstr "" + +#: biz/utils/im/feishu.py:118 +#, python-brace-format +msgid "发送飞书消息失败! webhook_url: {post_url}, errmsg: {result}" +msgstr "" + +#: biz/utils/im/feishu.py:120 +#, python-brace-format +msgid "飞书消息发送成功! webhook_url: {post_url}" +msgstr "" + +#: biz/utils/im/feishu.py:123 +msgid "飞书消息发送失败!" +msgstr "" + +#: biz/utils/im/im_notifier.py:7 +msgid "通知" +msgstr "" + +#: biz/utils/im/wecom.py:30 +msgid "未提供项目名称,且未设置默认的企业微信 Webhook URL。" +msgstr "" + +#: biz/utils/im/wecom.py:43 +msgid "" +"未找到项目 '{}' 对应的企业微信 Webhook URL,且未设置默认的 Webhook URL。" +msgstr "" + +#: biz/utils/im/wecom.py:73 +msgid "企业微信推送未启用" +msgstr "" + +#: biz/utils/im/wecom.py:102 +msgid "企业微信消息发送失败! webhook_url:{}, error_msg:{}" +msgstr "" + +#: biz/utils/im/wecom.py:107 +#, python-brace-format +msgid "企业微信消息发送失败! webhook_url: {post_url}, errmsg: {result}" +msgstr "" + +#: biz/utils/im/wecom.py:109 +msgid "企业微信消息发送成功! webhook_url: {}" +msgstr "" + +#: biz/utils/im/wecom.py:112 +msgid "企业微信消息发送失败!" +msgstr "" + +#: biz/utils/reporter.py:13 +msgid "" +"下面是以json格式记录员工代码提交信息。请总结这些信息,生成每个员工的工作日报" +"摘要。员工姓名直接用json内容中的author属性值,不要进行转换。特别要求:以" +"Markdown格式返回。\n" +"{}" +msgstr "" + +#: core/llm/client/deepseek.py:20 core/llm/client/openai.py:19 +#: core/llm/client/zhipuai.py:18 +msgid "" +"API key is required. Please provide it or set it in the environment " +"variables." +msgstr "" + +#: core/llm/client/deepseek.py:31 +#, python-brace-format +msgid "Sending request to DeepSeek API. Model: {model}, Messages: {messages}" +msgstr "" + +#: core/llm/client/deepseek.py:39 +msgid "Empty response from DeepSeek API" +msgstr "" + +#: core/llm/client/deepseek.py:40 +msgid "AI服务返回为空,请稍后重试" +msgstr "" + +#: core/llm/client/deepseek.py:45 +#, python-brace-format +msgid "DeepSeek API error: {e}" +msgstr "" + +#: core/llm/client/deepseek.py:48 +msgid "DeepSeek API认证失败,请检查API密钥是否正确" +msgstr "" + +#: core/llm/client/deepseek.py:50 +msgid "DeepSeek API接口未找到,请检查API地址是否正确" +msgstr "" + +#: core/llm/client/deepseek.py:52 +#, python-brace-format +msgid "调用DeepSeek API时出错: {e}" +msgstr "" + +#: core/llm/factory.py:29 +#, python-brace-format +msgid "Unknown chat model provider: {provider}" +msgstr "" + +#: ui.py:53 ui.py:68 +msgid "登录" +msgstr "登录" + +#: ui.py:57 +msgid "" +"安全提示:检测到默认用户名和密码为 'admin',存在安全风险!\n" +"\n" +"请立即修改:\n" +"1. 打开 `.env` 文件\n" +"2. 修改 `DASHBOARD_USER` 和 `DASHBOARD_PASSWORD` 变量\n" +"3. 保存并重启应用" +msgstr "" + +#: ui.py:63 +msgid "当前用户名: `{}`, 当前密码: `{}`" +msgstr "" + +#: ui.py:65 ui.py:109 +msgid "用户名" +msgstr "" + +#: ui.py:66 +msgid "密码" +msgstr "" + +#: ui.py:74 +msgid "用户名或密码错误" +msgstr "" + +#: ui.py:79 +msgid "#### 审查日志" +msgstr "" + +#: ui.py:88 +msgid "Merge Request" +msgstr "" + +#: ui.py:88 +msgid "Push" +msgstr "" + +#: ui.py:96 +msgid "开始日期" +msgstr "" + +#: ui.py:98 +msgid "结束日期" +msgstr "" + +#: ui.py:123 +msgid "**总记录数:** {},**平均分:** {}" +msgstr "" + +#: ui.py:137 +msgid "查看" +msgstr "" diff --git a/prompt_templates.yml b/locales/zh_CN/prompt_templates.yml similarity index 100% rename from prompt_templates.yml rename to locales/zh_CN/prompt_templates.yml diff --git a/translations_compile.sh b/translations_compile.sh new file mode 100644 index 0000000..3738e3c --- /dev/null +++ b/translations_compile.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# This script compiles messages.po translation files to messages.mo. + +# Compile the .po files into .mo files. +for lang in locales/*; do + if [ -f "$lang/LC_MESSAGES/messages.po" ]; then + msgfmt $lang/LC_MESSAGES/messages.po -o $lang/LC_MESSAGES/messages.mo + fi +done \ No newline at end of file diff --git a/translations_update.sh b/translations_update.sh new file mode 100644 index 0000000..4433bc4 --- /dev/null +++ b/translations_update.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# This script updates .po translation files. + +# Generate the .pot file. +shopt -s globstar +xgettext -d messages -o messages.pot **/*.py + +# Merge the .pot file into existing .po file for each language in locales directory (if exists): +for lang in locales/*; do + if [ -f "$lang/LC_MESSAGES/messages.po" ]; then + msgmerge --no-fuzzy-matching -U $lang/LC_MESSAGES/messages.po messages.pot + else + msginit --no-translator -i messages.pot -o $lang/LC_MESSAGES/messages.po -l $lang + fi +done + +# Cleanup +rm messages.pot \ No newline at end of file diff --git a/ui.py b/ui.py index 2fee07d..de18159 100644 --- a/ui.py +++ b/ui.py @@ -9,6 +9,10 @@ load_dotenv() +from biz.utils.i18n import get_translator + +_ = get_translator() + # 从环境变量中读取用户名和密码 DASHBOARD_USER = os.getenv("DASHBOARD_USER", "admin") DASHBOARD_PASSWORD = os.getenv("DASHBOARD_PASSWORD", "admin") @@ -16,10 +20,12 @@ DASHBOARD_USER: DASHBOARD_PASSWORD } + # 登录验证函数 def authenticate(username, password): return username in USER_CREDENTIALS and USER_CREDENTIALS[username] == password + # 获取数据函数 def get_data(service_func, authors=None, updated_at_gte=None, updated_at_lte=None, columns=None): df = service_func(authors=authors, updated_at_gte=updated_at_gte, updated_at_lte=updated_at_lte) @@ -36,41 +42,43 @@ def get_data(service_func, authors=None, updated_at_gte=None, updated_at_lte=Non data = df[columns] return data + # Streamlit 配置 st.set_page_config(layout="wide") + # 登录界面 def login_page(): # 使用 st.columns 创建居中布局 col1, col2, col3 = st.columns([1, 2, 1]) with col2: - st.title("登录") + st.title(_("登录")) # 如果用户名和密码都为 'admin',提示用户修改密码 if DASHBOARD_USER == "admin" and DASHBOARD_PASSWORD == "admin": - st.warning( + st.warning(_( "安全提示:检测到默认用户名和密码为 'admin',存在安全风险!\n\n" "请立即修改:\n" "1. 打开 `.env` 文件\n" "2. 修改 `DASHBOARD_USER` 和 `DASHBOARD_PASSWORD` 变量\n" "3. 保存并重启应用" - ) - st.write(f"当前用户名: `{DASHBOARD_USER}`, 当前密码: `{DASHBOARD_PASSWORD}`") + )) + st.write(_("当前用户名: `{}`, 当前密码: `{}`").format(DASHBOARD_USER, DASHBOARD_PASSWORD)) - username = st.text_input("用户名") - password = st.text_input("密码", type="password") + username = st.text_input(_("用户名")) + password = st.text_input(_("密码"), type="password") - if st.button("登录"): + if st.button(_("登录")): if authenticate(username, password): st.session_state["authenticated"] = True st.session_state["username"] = username st.rerun() # 重新运行应用以显示主要内容 else: - st.error("用户名或密码错误") + st.error(_("用户名或密码错误")) # 主要内容 def main_page(): - st.markdown("#### 审查日志") + st.markdown(_("#### 审查日志")) current_date = datetime.date.today() start_date_default = current_date - datetime.timedelta(days=7) @@ -79,18 +87,17 @@ def main_page(): show_push_tab = os.environ.get('PUSH_REVIEW_ENABLED', '0') == '1' if show_push_tab: - mr_tab, push_tab = st.tabs(["Merge Request", "Push"]) + mr_tab, push_tab = st.tabs([_("Merge Request"), _("Push")]) else: mr_tab = st.container() - def display_data(tab, service_func, columns, column_config): with tab: col1, col2, col3 = st.columns(3) with col1: - start_date = st.date_input("开始日期", start_date_default, key=f"{tab}_start_date") + start_date = st.date_input(_("开始日期"), start_date_default, key=f"{tab}_start_date") with col2: - end_date = st.date_input("结束日期", current_date, key=f"{tab}_end_date") + end_date = st.date_input(_("结束日期"), current_date, key=f"{tab}_end_date") start_datetime = datetime.datetime.combine(start_date, datetime.time.min) end_datetime = datetime.datetime.combine(end_date, datetime.time.max) @@ -101,7 +108,7 @@ def display_data(tab, service_func, columns, column_config): unique_authors = sorted(df["author"].dropna().unique().tolist()) if not df.empty else [] with col3: - authors = st.multiselect("用户名", unique_authors, default=[], key=f"{tab}_authors") + authors = st.multiselect(_("用户名"), unique_authors, default=[], key=f"{tab}_authors") data = get_data(service_func, authors=authors, updated_at_gte=int(start_datetime.timestamp()), updated_at_lte=int(end_datetime.timestamp()), columns=columns) @@ -115,8 +122,7 @@ def display_data(tab, service_func, columns, column_config): total_records = len(df) average_score = df["score"].mean() if not df.empty else 0 - st.markdown(f"**总记录数:** {total_records},**平均分:** {average_score:.2f}") - + st.markdown(_("**总记录数:** {},**平均分:** {}").format(total_records, f'{average_score:.2f}')) # Merge Request 数据展示 mr_columns = ["project_name", "author", "source_branch", "target_branch", "updated_at", "commit_messages", "score", @@ -130,7 +136,7 @@ def display_data(tab, service_func, columns, column_config): ), "url": st.column_config.LinkColumn( max_chars=100, - display_text=r"查看" + display_text=_(r"查看") ), } @@ -149,6 +155,8 @@ def display_data(tab, service_func, columns, column_config): } display_data(push_tab, ReviewService().get_push_review_logs, push_columns, push_column_config) + + # 应用入口 if "authenticated" not in st.session_state: st.session_state["authenticated"] = False @@ -156,4 +164,4 @@ def display_data(tab, service_func, columns, column_config): if st.session_state["authenticated"]: main_page() else: - login_page() \ No newline at end of file + login_page() From 8b61897b8daa16c67ecc4b0f244f88ce25e6b5a7 Mon Sep 17 00:00:00 2001 From: Manuel Schmid Date: Tue, 18 Mar 2025 17:45:57 +0100 Subject: [PATCH 02/12] feat: optimize docker image build speed installing dependencies early prevents then from being installed every time there is a file update --- .env.dist | 4 ++-- Dockerfile | 16 ++++++++-------- doc/faq.md | 1 + docker-compose.yml | 3 +++ 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.env.dist b/.env.dist index 927ba14..a856701 100644 --- a/.env.dist +++ b/.env.dist @@ -47,8 +47,8 @@ LOG_LEVEL=DEBUG REPORT_CRONTAB_EXPRESSION=0 18 * * 1-5 #Gitlab配置 -#GITLAB_URL={YOUR_GITLAB_URL} #部分老版本Gitlab webhook不传递URL,需要开启此配置,示例:https://gitlab.example.com -#GITLAB_ACCESS_TOKEN={YOUR_GITLAB_ACCESS_TOKEN} #系统会优先使用此GITLAB_ACCESS_TOKEN,如果未配置,则使用Webhook 传递的Secret Token +GITLAB_URL={YOUR_GITLAB_URL} #部分老版本Gitlab webhook不传递URL,需要开启此配置,示例:https://gitlab.example.com +GITLAB_ACCESS_TOKEN={YOUR_GITLAB_ACCESS_TOKEN} #系统会优先使用此GITLAB_ACCESS_TOKEN,如果未配置,则使用Webhook 传递的Secret Token # 开启Push Review功能(如果不需要push事件触发Code Review,设置为0) PUSH_REVIEW_ENABLED=1 diff --git a/Dockerfile b/Dockerfile index 3d0944a..a2f7943 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,14 +6,6 @@ WORKDIR /app # 复制项目文件&创建必要的文件夹 COPY requirements.txt . -COPY biz /app/biz -COPY core /app/core -COPY api.py /app/api.py -COPY ui.py /app/ui.py -COPY prompt_templates.yml /app/prompt_templates.yml -COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf -COPY locales /app/locales -RUN mkdir -p /app/log /app/data # 安装 supervisord 作为进程管理工具 RUN apt-get update && apt-get install -y --no-install-recommends supervisor && rm -rf /var/lib/apt/lists/* @@ -21,6 +13,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends supervisor && r # 安装依赖 RUN pip install --no-cache-dir -r requirements.txt +COPY biz /app/biz +COPY core /app/core +COPY api.py /app/api.py +COPY ui.py /app/ui.py +COPY locales /app/locales +COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf +RUN mkdir -p /app/log /app/data + # 暴露 Flask 和 Streamlit 的端口 EXPOSE 5001 5002 diff --git a/doc/faq.md b/doc/faq.md index d2ed260..92d236f 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -58,6 +58,7 @@ DINGTALK_WEBHOOK_URL=https://oapi.dingtalk.com/robot/send?access_token={access_t **可能原因** 配置127.0.0.1:11434连接Ollama。由于docker容器的网络模式为bridge,容器内的127.0.0.1并不是宿主机的127.0.0.1,所以连接失败。 +对于Docker Desktop,请使用此地址连接Ollama: http://host.docker.internal:11434。 **解决方案** diff --git a/docker-compose.yml b/docker-compose.yml index 27a1d94..51e0beb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,8 @@ services: flask-app: + build: + context: . + dockerfile: Dockerfile image: sunmh207/ai-codereview-gitlab:1.2.2 ports: - "5001:5001" From c7c5c4ca9f0893fd3be11d7f1ea6cbb5ef4459c9 Mon Sep 17 00:00:00 2001 From: Manuel Schmid Date: Tue, 18 Mar 2025 17:58:26 +0100 Subject: [PATCH 03/12] feat: update translations after merge from main --- locales/en_US/LC_MESSAGES/messages.mo | Bin 10020 -> 11042 bytes locales/en_US/LC_MESSAGES/messages.po | 210 +++++++++++--------------- locales/zh_CN/LC_MESSAGES/messages.po | 192 ++++++++++------------- 3 files changed, 169 insertions(+), 233 deletions(-) diff --git a/locales/en_US/LC_MESSAGES/messages.mo b/locales/en_US/LC_MESSAGES/messages.mo index 011c93fc14735c7d7b1a723b444e3ff862f39b4d..f4e717174b5a2f1446102a5794c953a8de653e0c 100644 GIT binary patch delta 2897 zcmdtjTWl0n9LMofgwpPo3RSSs7N%TExfN=u<$kTbEVR@Xii)IJx&vLi-D!8HkftHa z113rgY6dXIL=qG=U1Lg8qV`{RD8Nz9tXXP3*0ZZ{dtip1v z$3E=EdH6M!VSd1vW~|1kxE~+DSFu(@U7#_G3nrMkQHCoxU4=_=5G_25lkgfY#-FeX zr{@_n5!g2V@D%cA&T}ZmOSk}s@qV0` zZ%h%+MMa_x_1sQmF6L<*jfb!RUqVgfEqoY%ME*?Wy~fPOH5gQ=yJ-B3E^5Y+@tKwM zp*ngFHSjUi!0%xr-atjFoc&mcHtM;`WQVji7+iZz&xLBf*KfCV(>;5016 zM&BJcgY!XDZXCra_%2rCXBfe8gl9V@upO_W2A<8nG+;Nb!*{S1Z{cPPO(Oo9$x)_D zzL?ih6F7ysK7^X!RkZL+|N3pD4>N{Lnv6wQjn$}ybffMc_V1rWP2>_*Vm^ZuWU&Q> z#D5))HhNKLkFY#;!JI>N@F6M(uA_?q;#-3$R7dBr8NWwm_Y%Uy7-lPK&mB~9pY^YQ zfg3pg6+^f>Mao(<4j_v%Cvh=;fJ^WeGPYSn?=;N@R8mDzk$Dr@1#=da-9xw>^I44| z6T$~Eg5~@j-F$1^?pGB?o3M#uN z@FQinh5B6s7H6^Fs0s8<&qOMP1R-T!p)r#i7f>tw3Ki1ZxCWcZz(sfv>BGE_dhRAF zgnwWKhUg@lfd(*#^L@lUfX|@rA42{9A}Yte#o2oQZ_}91g)%-@dY}yz`hI*2-^PuY z!?HHv7F>(RaSaaRdMxKNxE*8oD1MBJ*bFjK6Dmh`$5i4NY|(YbH|;bu!w%G*9z^;y zFQbJQQ3HH~RaibZlM_#%I^2Vg;1OJk-(eQAu5?+)Q4v(0Xv>ySM~cQbk5e_HEjpnn zv+Jq!lV0IU)Sl;3^>$cPO-LUd6(!i%bSv}v`OWlV)Fu$=t!T$usut&$R64|M{#h#$ z?R2jiU_hd*Pt2ydbn&Dq-^qqi8XccXnURM=uiK3)JiWokgBrfaMo~mdI zlvoexgrdDuc`0@%67eaDoQYAI~kr%<`Ax+Dz8-LQT4Vp zsDn{dmCaNoqDm8W8+ENt{F3df_qv6;z&{uIb|^Pg^x^WZOj>wmIQ!tJl1RjgJFcCy zT*ulKbz|Wj*5KY{)cI8J)Z|j{Q0~fE>z!E4?sV-47p+dGrzh$rt(^&{$Lj4*c3Jjr zJMLC^S934qh5ZiIg|{zIGQQVIMqMW{(814o!wK8_B~a)+AIR~p2dYZy!qFI=YHZsb z>G;m*`N4+5P}`B4HP z)v9>3KOXU32)>bOiYAlM_%5qH>TYC-;m%GwsWo@oantOKjGXy_6^;LOS$E%Ox+BX} z9~Gu0JP>oj5l!5*Fdx%uciPe2tSlXwW!745wAy|BHd9Ra_sX3ePZHCP?r1!+a&YgQ z`PQCjEN1m4ob=qn$$@xhSHg)q{mIxsg?GBR{>+KIoN@oSV;%o`w`O@&Q_kJBV}*a; gu{--Qy=cpSwPQ2AlH&dUk6rUl9pwX~((?UsdNZI^cXMPUJ3sC5BL>8E82YzsoE2_;m!1_DyGm8K!O zqJW8zNHR#cF##hXA;BOd1TG*d>4iyeggXfklt3sk#6%K^iShr;EM6FIJlQk9bI#1p zIrE-(=BvK16RBI_tS^kxLyb_6WSZ^3z%&k&i`ize46{pEPXG5Dvl%!e*K8(M;XI7t zySNn>;5D3!e_;Y^rkg#Fqu7Cm{C>)QqS3^_16+o4^UNIFitV@;8*l=P@F_N9DBr(P z0vFSFF{taX0eywrKkwSFpis04|W3U@D}R2f{@v4jAA?UTPuwy?#JtR7Kyg)EA%Hki1X zA;rXx-LZ1i0_LN}+fWgSql10v@iEj^eTXmM5!8adK|RRb^!b7!;;##;xmpWp#>Mz4 zhLv>KhLglgp$#!R!Ld5zl&wVV@kSiQPcVj0Q1_|l<_UZQm3-e~C;pi3hf0Y5Y6fbF zTQ`oNgI7=?x{XV*ijAXbn^DO(hRWg#xCH-1(!pM2A1bg3wXiM7!`dNKE}cLn-x<_G z&ZTJR#!ry^u$g3*lCKi=hi;4zfj-m(BV}g%Y%d4?V#l!>FC&-OFQ_M0xLTkG>+vvZ zVc(;!`xW)TsSJlz(^!MqOtc4iW$k0G=1sGMsPjjWpG|Nex^^G6P^&as2=h?qH=-go zhOgsUT!VRJY7cJ0Ry>6*%x@29v@;OpF$QoK_TwaGVNH#{peXWi)_~J+eR{kfwZK7C zG9E@P>`QcT0(Jj;*nm;KN{aXvEYtfxPGcPd$8Z@=VFor)RbKM(j!GgW*mG3Y?G;Vh zm2S78!u_mhVXsno^SniOqN1wYP-$g;FKk+o!mbZPf~pm(@CJGx8HKomx`L`GWKx$? ziLO_a#Co;rs0#BdR2354i$b&4^FP&mF1*~)P)Z@zt3p2fQ2(9 sncTiRIdr~0G(E^{1I+aEf6r1^R^;ZFwft+QO7}qdzW+U2VMRFaZ+FGoyZ`_I diff --git a/locales/en_US/LC_MESSAGES/messages.po b/locales/en_US/LC_MESSAGES/messages.po index f652f9f..1a7f791 100644 --- a/locales/en_US/LC_MESSAGES/messages.po +++ b/locales/en_US/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-03-18 17:24+0100\n" +"POT-Creation-Date: 2025-03-18 17:56+0100\n" "PO-Revision-Date: 2025-03-18 15:05+0100\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" @@ -16,21 +16,55 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: api.py:63 +#: api.py:64 msgid "代码提交日报" msgstr "Code Submission Daily Report" -#: api.py:166 +#: api.py:113 +msgid "Invalid JSON" +msgstr "Invalid JSON" + +#: api.py:123 +msgid "Missing GitLab access token" +msgstr "Missing GitLab access token" + +#: api.py:126 +msgid "Received event: {}" +msgstr "Received event: {}" + +#: api.py:127 +msgid "Payload: {}" +msgstr "Payload: {}" + +#: api.py:135 api.py:141 +msgid "Request received(object_kind={}), will process asynchronously." +msgstr "Request received(object_kind={}), will process asynchronously." + +#: api.py:143 +msgid "" +"Only merge_request and push events are supported (both Webhook and System " +"Hook), but received: {}." +msgstr "" + +#: api.py:147 +msgid "Invalid data format" +msgstr "Invalid data format" + +#: api.py:156 api.py:218 +msgid "Failed to get commits" +msgstr "Failed to retrieve commits" + +#: api.py:167 msgid "未检测到PUSH代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。" msgstr "" "No changes detected in the pushed code. The modified files may not meet " "SUPPORTED_EXTENSIONS." -#: api.py:167 +#: api.py:168 msgid "关注的文件没有修改" msgstr "No changes in the monitored files" -#: api.py:174 api.py:225 +#: api.py:175 api.py:226 msgid "" "Auto Review Result: \n" "{}" @@ -38,61 +72,49 @@ msgstr "" "Auto Review Result: \n" "{}" -#: api.py:187 +#: api.py:188 msgid "服务出现未知错误: {}" msgstr "An unknown error occurred in the service: {}" -#: api.py:189 api.py:248 api.py:287 +#: api.py:190 api.py:249 msgid "出现未知错误: {}" msgstr "An unknown error occurred: {}" -#: api.py:203 +#: api.py:204 msgid "Merge Request Hook event received" msgstr "Merge Request Hook event received" -#: api.py:208 api.py:263 +#: api.py:209 msgid "changes: {}" msgstr "Changes: {}" -#: api.py:211 api.py:266 +#: api.py:212 msgid "未检测到有关代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。" msgstr "" "No relevant code changes detected. The modified files may not meet " "SUPPORTED_EXTENSIONS." -#: api.py:217 -msgid "Failed to get commits" -msgstr "Failed to retrieve commits" - -#: api.py:243 +#: api.py:244 msgid "Merge Request Hook event, action={}, ignored." msgstr "Merge Request Hook event, action={}, ignored." -#: api.py:246 api.py:285 +#: api.py:247 msgid "AI Code Review 服务出现未知错误: {}" msgstr "AI Code Review service encountered an unknown error: {}" -#: api.py:260 -msgid "System Hook event received" -msgstr "System Hook event received" - -#: api.py:272 -msgid "Payload: {}" -msgstr "Payload: {}" - -#: api.py:314 +#: api.py:276 msgid "代码为空, diffs_text = {}" msgstr "Code is empty, diffs_text = {}" -#: api.py:315 +#: api.py:277 msgid "代码为空" msgstr "Code is empty" -#: api.py:319 +#: api.py:281 msgid "文本超长,截段后content: {}" msgstr "Text is too long, truncated content: {}" -#: biz/event/event_manager.py:25 +#: biz/event/event_manager.py:20 #, python-brace-format msgid "" "\n" @@ -131,11 +153,11 @@ msgstr "" "{review_result}\n" " " -#: biz/event/event_manager.py:51 +#: biz/event/event_manager.py:46 msgid "Merge Request Review" msgstr "Merge Request Review" -#: biz/event/event_manager.py:60 +#: biz/event/event_manager.py:55 #, python-brace-format msgid "" "### 🚀 {project_name}: Push\n" @@ -144,15 +166,15 @@ msgstr "" "### 🚀 {project_name}: Push\n" "\n" -#: biz/event/event_manager.py:61 biz/event/event_manager.py:93 +#: biz/event/event_manager.py:56 msgid "#### 提交记录:\n" msgstr "#### Commit Records:\n" -#: biz/event/event_manager.py:65 biz/event/event_manager.py:97 +#: biz/event/event_manager.py:60 msgid "Unknown Author" msgstr "Unknown Author" -#: biz/event/event_manager.py:69 +#: biz/event/event_manager.py:64 #, python-brace-format msgid "" "- **提交信息**: {message}\n" @@ -167,7 +189,7 @@ msgstr "" "- [View Commit Details]({url})\n" "\n" -#: biz/event/event_manager.py:81 biz/event/event_manager.py:109 +#: biz/event/event_manager.py:76 #, python-brace-format msgid "" "#### AI Review 结果: \n" @@ -175,26 +197,11 @@ msgid "" "\n" msgstr "" -#: biz/event/event_manager.py:83 biz/event/event_manager.py:111 +#: biz/event/event_manager.py:78 #, python-brace-format msgid "{project_name} Push Event" msgstr "" -#: biz/event/event_manager.py:92 -#, python-brace-format -msgid "" -"### 🚀 {project_name}: System Hook\n" -"\n" -msgstr "" - -#: biz/event/event_manager.py:100 -#, python-brace-format -msgid "" -"- **提交信息**: {message}\n" -"- **提交者**: {author}\n" -"- **时间**: {timestamp}\n" -msgstr "" - #: biz/gitlab/webhook_handler.py:39 msgid "Invalid event type: {}. Only 'merge_request' event is supported now." msgstr "Invalid event type: {}. Only 'merge_request' event is supported now." @@ -221,90 +228,51 @@ msgstr "" #: biz/gitlab/webhook_handler.py:87 msgid "Failed to get commits: {}, {}" -msgstr "" +msgstr "Failed to get commits: {}, {}" #: biz/gitlab/webhook_handler.py:101 msgid "Add notes to gitlab {}: {}, {}" -msgstr "" +msgstr "Add notes to gitlab {}: {}, {}" #: biz/gitlab/webhook_handler.py:105 msgid "Failed to add note: {}" -msgstr "" +msgstr "Failed to add note: {}" -#: biz/gitlab/webhook_handler.py:135 biz/gitlab/webhook_handler.py:184 +#: biz/gitlab/webhook_handler.py:135 biz/gitlab/webhook_handler.py:224 msgid "Invalid event type: {}. Only 'push' event is supported now." -msgstr "" +msgstr "Invalid event type: {}. Only 'push' event is supported now." #: biz/gitlab/webhook_handler.py:149 msgid "Collected {} commits from push event." -msgstr "" +msgstr "Collected {} commits from push event." #: biz/gitlab/webhook_handler.py:155 msgid "No commits found to add notes to." -msgstr "" +msgstr "No commits found to add notes to." #: biz/gitlab/webhook_handler.py:161 msgid "Last commit ID not found." -msgstr "" +msgstr "Last commit ID not found." #: biz/gitlab/webhook_handler.py:189 -msgid "No commits found in push event." -msgstr "" - -#: biz/gitlab/webhook_handler.py:203 -msgid "Get changes response from GitLab for push event: {}, {}, URL: {}" -msgstr "" - -#: biz/gitlab/webhook_handler.py:207 -msgid "Failed to get changes for push event: {}, {}, URL: {}" -msgstr "" - -#: biz/gitlab/webhook_handler.py:224 -msgid "event_name" -msgstr "" - -#: biz/gitlab/webhook_handler.py:225 biz/gitlab/webhook_handler.py:281 -msgid "repository_update" -msgstr "" - -#: biz/gitlab/webhook_handler.py:236 biz/gitlab/webhook_handler.py:282 msgid "" -"Invalid event type: {}. Only 'repository_update' event is supported now." -msgstr "" - -#: biz/gitlab/webhook_handler.py:240 biz/gitlab/webhook_handler.py:286 -msgid "No changes found in webhook data." -msgstr "" - -#: biz/gitlab/webhook_handler.py:252 biz/gitlab/webhook_handler.py:295 -msgid "unknown branch" -msgstr "" - -#: biz/gitlab/webhook_handler.py:255 biz/gitlab/webhook_handler.py:298 -msgid "Missing before or after commit ID for ref {}." +"Get commits response from GitLab for repository_commits: {response." +"status_code}, {}, URL: {url}" msgstr "" -#: biz/gitlab/webhook_handler.py:263 +#: biz/gitlab/webhook_handler.py:212 msgid "" -"Get changes response from GitLab for repository_update (attempt {}): {}, {}, " -"URL: {}" +"Get changes response from GitLab for repository_compare: {}, {response." +"text}, URL: {}" msgstr "" -#: biz/gitlab/webhook_handler.py:272 -msgid "Failed to get changes for ref {}: {}, {}, retrying in {} seconds..." -msgstr "Failed to get changes for ref {}: {}, {}, retrying in {} seconds..." +#: biz/gitlab/webhook_handler.py:218 +msgid "Failed to get changes for repository_compare: {}, {}" +msgstr "Failed to get changes for repository_compare: {}, {}" -#: biz/gitlab/webhook_handler.py:276 -msgid "Max retries ({}) reached. Unable to retrieve repository changes." -msgstr "" - -#: biz/gitlab/webhook_handler.py:304 -msgid "Get commits response from GitLab for repository_update: {}, {}, URL: {}" -msgstr "" - -#: biz/gitlab/webhook_handler.py:312 -msgid "Failed to get commits for ref {}: {}, {}" -msgstr "" +#: biz/gitlab/webhook_handler.py:229 +msgid "No commits found in push event." +msgstr "No commits found in push event." #: biz/utils/code_reviewer.py:27 msgid "未找到提示词配置{}" @@ -488,11 +456,11 @@ msgstr "Error occurred while calling DeepSeek API: {e}" msgid "Unknown chat model provider: {provider}" msgstr "Unknown chat model provider: {provider}" -#: ui.py:53 ui.py:68 +#: ui.py:55 ui.py:70 msgid "登录" msgstr "Login" -#: ui.py:57 +#: ui.py:59 msgid "" "安全提示:检测到默认用户名和密码为 'admin',存在安全风险!\n" "\n" @@ -509,46 +477,46 @@ msgstr "" "2. Change the `DASHBOARD_USER` and `DASHBOARD_PASSWORD` variables\n" "3. Save and restart the application" -#: ui.py:63 +#: ui.py:65 msgid "当前用户名: `{}`, 当前密码: `{}`" msgstr "Current Username: `{}`, Current Password: `{}`" -#: ui.py:65 ui.py:109 +#: ui.py:67 ui.py:111 msgid "用户名" msgstr "Username" -#: ui.py:66 +#: ui.py:68 msgid "密码" msgstr "Password" -#: ui.py:74 +#: ui.py:76 msgid "用户名或密码错误" msgstr "Incorrect username or password" -#: ui.py:79 +#: ui.py:81 msgid "#### 审查日志" msgstr "#### Review Log" -#: ui.py:88 +#: ui.py:90 msgid "Merge Request" msgstr "Merge Request" -#: ui.py:88 +#: ui.py:90 msgid "Push" msgstr "Push" -#: ui.py:96 +#: ui.py:98 msgid "开始日期" msgstr "Start Date" -#: ui.py:98 +#: ui.py:100 msgid "结束日期" msgstr "End Date" -#: ui.py:123 +#: ui.py:125 msgid "**总记录数:** {},**平均分:** {}" msgstr "**Total Records:** {},**Average Score:** {}" -#: ui.py:137 +#: ui.py:139 msgid "查看" msgstr "Open" diff --git a/locales/zh_CN/LC_MESSAGES/messages.po b/locales/zh_CN/LC_MESSAGES/messages.po index 08f95b9..95ef3ee 100644 --- a/locales/zh_CN/LC_MESSAGES/messages.po +++ b/locales/zh_CN/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-03-18 17:24+0100\n" +"POT-Creation-Date: 2025-03-18 17:56+0100\n" "PO-Revision-Date: 2025-03-18 15:05+0100\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" @@ -16,77 +16,99 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: api.py:63 +#: api.py:64 msgid "代码提交日报" msgstr "" -#: api.py:166 -msgid "未检测到PUSH代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。" +#: api.py:113 +msgid "Invalid JSON" +msgstr "" + +#: api.py:123 +msgid "Missing GitLab access token" +msgstr "" + +#: api.py:126 +msgid "Received event: {}" +msgstr "" + +#: api.py:127 +msgid "Payload: {}" +msgstr "" + +#: api.py:135 api.py:141 +msgid "Request received(object_kind={}), will process asynchronously." +msgstr "" + +#: api.py:143 +msgid "" +"Only merge_request and push events are supported (both Webhook and System " +"Hook), but received: {}." +msgstr "" + +#: api.py:147 +msgid "Invalid data format" +msgstr "" + +#: api.py:156 api.py:218 +msgid "Failed to get commits" msgstr "" #: api.py:167 +msgid "未检测到PUSH代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。" +msgstr "" + +#: api.py:168 msgid "关注的文件没有修改" msgstr "" -#: api.py:174 api.py:225 +#: api.py:175 api.py:226 msgid "" "Auto Review Result: \n" "{}" msgstr "" -#: api.py:187 +#: api.py:188 msgid "服务出现未知错误: {}" msgstr "" -#: api.py:189 api.py:248 api.py:287 +#: api.py:190 api.py:249 msgid "出现未知错误: {}" msgstr "" -#: api.py:203 +#: api.py:204 msgid "Merge Request Hook event received" msgstr "" -#: api.py:208 api.py:263 +#: api.py:209 msgid "changes: {}" msgstr "" -#: api.py:211 api.py:266 +#: api.py:212 msgid "未检测到有关代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。" msgstr "" -#: api.py:217 -msgid "Failed to get commits" -msgstr "" - -#: api.py:243 +#: api.py:244 msgid "Merge Request Hook event, action={}, ignored." msgstr "" -#: api.py:246 api.py:285 +#: api.py:247 msgid "AI Code Review 服务出现未知错误: {}" msgstr "" -#: api.py:260 -msgid "System Hook event received" -msgstr "" - -#: api.py:272 -msgid "Payload: {}" -msgstr "" - -#: api.py:314 +#: api.py:276 msgid "代码为空, diffs_text = {}" msgstr "" -#: api.py:315 +#: api.py:277 msgid "代码为空" msgstr "" -#: api.py:319 +#: api.py:281 msgid "文本超长,截段后content: {}" msgstr "" -#: biz/event/event_manager.py:25 +#: biz/event/event_manager.py:20 #, python-brace-format msgid "" "\n" @@ -108,26 +130,26 @@ msgid "" " " msgstr "" -#: biz/event/event_manager.py:51 +#: biz/event/event_manager.py:46 msgid "Merge Request Review" msgstr "" -#: biz/event/event_manager.py:60 +#: biz/event/event_manager.py:55 #, python-brace-format msgid "" "### 🚀 {project_name}: Push\n" "\n" msgstr "" -#: biz/event/event_manager.py:61 biz/event/event_manager.py:93 +#: biz/event/event_manager.py:56 msgid "#### 提交记录:\n" msgstr "" -#: biz/event/event_manager.py:65 biz/event/event_manager.py:97 +#: biz/event/event_manager.py:60 msgid "Unknown Author" msgstr "" -#: biz/event/event_manager.py:69 +#: biz/event/event_manager.py:64 #, python-brace-format msgid "" "- **提交信息**: {message}\n" @@ -137,7 +159,7 @@ msgid "" "\n" msgstr "" -#: biz/event/event_manager.py:81 biz/event/event_manager.py:109 +#: biz/event/event_manager.py:76 #, python-brace-format msgid "" "#### AI Review 结果: \n" @@ -145,26 +167,11 @@ msgid "" "\n" msgstr "" -#: biz/event/event_manager.py:83 biz/event/event_manager.py:111 +#: biz/event/event_manager.py:78 #, python-brace-format msgid "{project_name} Push Event" msgstr "" -#: biz/event/event_manager.py:92 -#, python-brace-format -msgid "" -"### 🚀 {project_name}: System Hook\n" -"\n" -msgstr "" - -#: biz/event/event_manager.py:100 -#, python-brace-format -msgid "" -"- **提交信息**: {message}\n" -"- **提交者**: {author}\n" -"- **时间**: {timestamp}\n" -msgstr "" - #: biz/gitlab/webhook_handler.py:39 msgid "Invalid event type: {}. Only 'merge_request' event is supported now." msgstr "" @@ -201,7 +208,7 @@ msgstr "" msgid "Failed to add note: {}" msgstr "" -#: biz/gitlab/webhook_handler.py:135 biz/gitlab/webhook_handler.py:184 +#: biz/gitlab/webhook_handler.py:135 biz/gitlab/webhook_handler.py:224 msgid "Invalid event type: {}. Only 'push' event is supported now." msgstr "" @@ -218,62 +225,23 @@ msgid "Last commit ID not found." msgstr "" #: biz/gitlab/webhook_handler.py:189 -msgid "No commits found in push event." -msgstr "" - -#: biz/gitlab/webhook_handler.py:203 -msgid "Get changes response from GitLab for push event: {}, {}, URL: {}" -msgstr "" - -#: biz/gitlab/webhook_handler.py:207 -msgid "Failed to get changes for push event: {}, {}, URL: {}" -msgstr "" - -#: biz/gitlab/webhook_handler.py:224 -msgid "event_name" -msgstr "" - -#: biz/gitlab/webhook_handler.py:225 biz/gitlab/webhook_handler.py:281 -msgid "repository_update" -msgstr "" - -#: biz/gitlab/webhook_handler.py:236 biz/gitlab/webhook_handler.py:282 msgid "" -"Invalid event type: {}. Only 'repository_update' event is supported now." -msgstr "" - -#: biz/gitlab/webhook_handler.py:240 biz/gitlab/webhook_handler.py:286 -msgid "No changes found in webhook data." -msgstr "" - -#: biz/gitlab/webhook_handler.py:252 biz/gitlab/webhook_handler.py:295 -msgid "unknown branch" -msgstr "" - -#: biz/gitlab/webhook_handler.py:255 biz/gitlab/webhook_handler.py:298 -msgid "Missing before or after commit ID for ref {}." +"Get commits response from GitLab for repository_commits: {response." +"status_code}, {}, URL: {url}" msgstr "" -#: biz/gitlab/webhook_handler.py:263 +#: biz/gitlab/webhook_handler.py:212 msgid "" -"Get changes response from GitLab for repository_update (attempt {}): {}, {}, " -"URL: {}" -msgstr "" - -#: biz/gitlab/webhook_handler.py:272 -msgid "Failed to get changes for ref {}: {}, {}, retrying in {} seconds..." -msgstr "" - -#: biz/gitlab/webhook_handler.py:276 -msgid "Max retries ({}) reached. Unable to retrieve repository changes." +"Get changes response from GitLab for repository_compare: {}, {response." +"text}, URL: {}" msgstr "" -#: biz/gitlab/webhook_handler.py:304 -msgid "Get commits response from GitLab for repository_update: {}, {}, URL: {}" +#: biz/gitlab/webhook_handler.py:218 +msgid "Failed to get changes for repository_compare: {}, {}" msgstr "" -#: biz/gitlab/webhook_handler.py:312 -msgid "Failed to get commits for ref {}: {}, {}" +#: biz/gitlab/webhook_handler.py:229 +msgid "No commits found in push event." msgstr "" #: biz/utils/code_reviewer.py:27 @@ -439,11 +407,11 @@ msgstr "" msgid "Unknown chat model provider: {provider}" msgstr "" -#: ui.py:53 ui.py:68 +#: ui.py:55 ui.py:70 msgid "登录" msgstr "登录" -#: ui.py:57 +#: ui.py:59 msgid "" "安全提示:检测到默认用户名和密码为 'admin',存在安全风险!\n" "\n" @@ -453,46 +421,46 @@ msgid "" "3. 保存并重启应用" msgstr "" -#: ui.py:63 +#: ui.py:65 msgid "当前用户名: `{}`, 当前密码: `{}`" msgstr "" -#: ui.py:65 ui.py:109 +#: ui.py:67 ui.py:111 msgid "用户名" msgstr "" -#: ui.py:66 +#: ui.py:68 msgid "密码" msgstr "" -#: ui.py:74 +#: ui.py:76 msgid "用户名或密码错误" msgstr "" -#: ui.py:79 +#: ui.py:81 msgid "#### 审查日志" msgstr "" -#: ui.py:88 +#: ui.py:90 msgid "Merge Request" msgstr "" -#: ui.py:88 +#: ui.py:90 msgid "Push" msgstr "" -#: ui.py:96 +#: ui.py:98 msgid "开始日期" msgstr "" -#: ui.py:98 +#: ui.py:100 msgid "结束日期" msgstr "" -#: ui.py:123 +#: ui.py:125 msgid "**总记录数:** {},**平均分:** {}" msgstr "" -#: ui.py:137 +#: ui.py:139 msgid "查看" msgstr "" From 390422d27259ad94869006895a02ff236db05cea Mon Sep 17 00:00:00 2001 From: Manuel Schmid Date: Thu, 20 Mar 2025 02:18:38 +0100 Subject: [PATCH 04/12] feat: add multi-stage build for prod and worker --- .github/workflows/build_container.yml | 36 +++++++++++++++++++++------ 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build_container.yml b/.github/workflows/build_container.yml index 1aa7cbe..fe514c3 100644 --- a/.github/workflows/build_container.yml +++ b/.github/workflows/build_container.yml @@ -4,11 +4,12 @@ on: push: branches: - main + - origin/feature/github-actions-docker-build tags: - v* jobs: - build-and-push-image: + build-and-push-images: runs-on: ubuntu-latest permissions: @@ -26,8 +27,8 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Extract metadata (tags, labels) for Docker - id: meta + - name: Extract metadata (tags, labels) for Docker (prod) + id: meta_prod uses: docker/metadata-action@v5 with: images: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }} @@ -37,12 +38,33 @@ jobs: type=semver,pattern={{major}} type=edge,branch=main - - name: Build and push Docker image + - name: Extract metadata (tags, labels) for Docker (worker) + id: meta_worker + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }} + tags: | + type=semver,pattern={{version}},suffix=-worker + type=semver,pattern={{major}}.{{minor}},suffix=-worker + type=semver,pattern={{major}},suffix=-worker + type=edge,branch=main,suffix=-worker + + - name: Build and push prod Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + push: true + tags: ${{ steps.meta_prod.outputs.tags }} + labels: ${{ steps.meta_prod.outputs.labels }} + target: prod + + - name: Build and push worker Docker image uses: docker/build-push-action@v6 with: context: . file: ./Dockerfile push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - target: prod \ No newline at end of file + tags: ${{ steps.meta_worker.outputs.tags }} + labels: ${{ steps.meta_worker.outputs.labels }} + target: worker From 9477839d1e43bed1c165997cc39c51e7ba01312d Mon Sep 17 00:00:00 2001 From: Manuel Schmid Date: Thu, 20 Mar 2025 02:24:41 +0100 Subject: [PATCH 05/12] docs: update repository references --- .github/workflows/build_container.yml | 1 - api.py | 5 ++--- docker-compose.yml | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build_container.yml b/.github/workflows/build_container.yml index fe514c3..f53d17b 100644 --- a/.github/workflows/build_container.yml +++ b/.github/workflows/build_container.yml @@ -4,7 +4,6 @@ on: push: branches: - main - - origin/feature/github-actions-docker-build tags: - v* diff --git a/api.py b/api.py index 0d3e3f5..5dfb5b1 100644 --- a/api.py +++ b/api.py @@ -30,9 +30,8 @@ @api_app.route('/') def home(): return """

The code review api server is running.

-

GitHub project address: - https://github.com/sunmh207/AI-Codereview-Gitlab

-

Gitee project address: https://gitee.com/sunminghui/ai-codereview-gitlab

+

GitHub project address: + https://github.com/mashb1t/ai-codereview-gitlab

""" diff --git a/docker-compose.yml b/docker-compose.yml index 22b5573..bdd27c8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: context: . dockerfile: Dockerfile target: dev - image: sunmh207/ai-codereview-gitlab:1.2.3 + image: mashb1t/ai-codereview-gitlab:1 ports: - "5001:5001" - "5002:5002" @@ -29,7 +29,7 @@ services: context: . dockerfile: Dockerfile target: worker - # image: sunmh207/ai-codereview-gitlab:1.2.3-worker + image: mashb1t/ai-codereview-gitlab:1-worker volumes_from: - app env_file: From 4b97b46294315cbebfbd75176a72cc2db6e2f7c6 Mon Sep 17 00:00:00 2001 From: Manuel Schmid Date: Thu, 20 Mar 2025 02:43:59 +0100 Subject: [PATCH 06/12] feat: add multiarch build for amd64 and arm64/v8 --- .../{build_container.yml => build_images.yml} | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) rename .github/workflows/{build_container.yml => build_images.yml} (77%) diff --git a/.github/workflows/build_container.yml b/.github/workflows/build_images.yml similarity index 77% rename from .github/workflows/build_container.yml rename to .github/workflows/build_images.yml index f53d17b..48c5499 100644 --- a/.github/workflows/build_container.yml +++ b/.github/workflows/build_images.yml @@ -19,6 +19,13 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 + - name: Set up QEMU for multi-arch builds + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v3 + - name: Log in to the Container registry uses: docker/login-action@v3 with: @@ -26,6 +33,7 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} + # Extract tags with suffixes for prod and worker - name: Extract metadata (tags, labels) for Docker (prod) id: meta_prod uses: docker/metadata-action@v5 @@ -48,22 +56,26 @@ jobs: type=semver,pattern={{major}},suffix=-worker type=edge,branch=main,suffix=-worker - - name: Build and push prod Docker image + # Build and push multi-arch prod image + - name: Build and push prod Docker image (Multi-Arch) uses: docker/build-push-action@v6 with: context: . file: ./Dockerfile push: true + platforms: linux/amd64,linux/arm64/v8 tags: ${{ steps.meta_prod.outputs.tags }} labels: ${{ steps.meta_prod.outputs.labels }} target: prod - - name: Build and push worker Docker image + # Build and push multi-arch worker image + - name: Build and push worker Docker image (Multi-Arch) uses: docker/build-push-action@v6 with: context: . file: ./Dockerfile push: true + platforms: linux/amd64,linux/arm64/v8 tags: ${{ steps.meta_worker.outputs.tags }} labels: ${{ steps.meta_worker.outputs.labels }} target: worker From 4718bd98c8a1752945cd0ad4aa41fec7917f86b8 Mon Sep 17 00:00:00 2001 From: Manuel Schmid <9307310+mashb1t@users.noreply.github.com> Date: Thu, 20 Mar 2025 03:28:25 +0100 Subject: [PATCH 07/12] docs: add LICENSE --- LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. From 436b41cd11df7e5f8cd46029c0bbcf983ff3900c Mon Sep 17 00:00:00 2001 From: Manuel Schmid Date: Thu, 20 Mar 2025 03:43:04 +0100 Subject: [PATCH 08/12] docs: add github files for improved collaboration --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/bug_report.yml | 105 +++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.yml | 40 ++++++++ .github/dependabot.yml | 6 ++ 4 files changed, 152 insertions(+) create mode 100644 .github/CODEOWNERS create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/dependabot.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..9967050 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @mashb1t \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..53756ca --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,105 @@ +name: Bug Report +description: You think something is broken +title: "[Bug]: " +labels: ["bug", "triage"] + +body: + - type: markdown + attributes: + value: | + > The title of the bug report should be short and descriptive. + > Use relevant keywords for searchability. + > Do not leave it blank, but also do not put an entire error log in it. + - type: checkboxes + attributes: + label: Checklist + description: | + Please perform basic debugging to see if your configuration is the cause of the issue. + Basic debug procedure +  1. Update - sometimes things just need to be updated +  2. Backup and revert your .env adjustments - check if the issue is caused by bad configuration +  3. Try a fresh installation in a different directory - see if a clean installation solves the issue + Before making a issue report please, check that the issue hasn't been reported recently. + options: + - label: The issue exists on a clean installation + - label: The issue exists in the current version + - label: The issue has not been reported before + - label: The issue has been reported before but has not been fixed yet + - type: markdown + attributes: + value: | + > Please fill this form with as much information as possible. Don't forget to add information about "Which OS" and provide screenshots if possible + - type: textarea + id: what-did + attributes: + label: What happened? + description: Tell us what happened in a very clear and simple way + placeholder: | + application crashes on bootup. + validations: + required: true + - type: textarea + id: steps + attributes: + label: Steps to reproduce the problem + description: Please provide us with precise step by step instructions on how to reproduce the bug + placeholder: | + 1. Go to ... + 2. Press ... + 3. ... + validations: + required: true + - type: textarea + id: what-should + attributes: + label: What should have happened? + description: Tell us what you think the normal behavior should be + placeholder: | + It should have ... + validations: + required: true + - type: dropdown + id: browsers + attributes: + label: What browsers do you use to access the dashboard? + multiple: true + options: + - Mozilla Firefox + - Google Chrome + - Brave + - Apple Safari + - Microsoft Edge + - Android + - iOS + - Other + - type: dropdown + id: hosting + attributes: + label: Where are you running the app? + multiple: false + options: + - Locally + - Locally with virtualization (e.g. Docker) + - Cloud (e.g. AWS, GCP, Azure) + - type: input + id: operating-system + attributes: + label: What operating system are you using? + placeholder: | + Windows 11 / MacOS 15.3.2 + - type: textarea + id: logs + attributes: + label: Console logs + description: Please provide **full** cmd/terminal logs from the moment you started UI to the end of it, after the bug occurred. If it's very long, provide a link to pastebin or similar service. + render: Shell + validations: + required: true + - type: textarea + id: misc + attributes: + label: Additional information + description: | + Please provide us with any relevant additional info or context. + Examples: +  I have updated packages recently. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..90e594e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,40 @@ +name: Feature request +description: Suggest an idea for this project +title: "[Feature Request]: " +labels: ["enhancement", "triage"] + +body: + - type: checkboxes + attributes: + label: Is there an existing issue for this? + description: Please search to see if an issue already exists for the feature you want, and that it's not implemented in a recent build/commit. + options: + - label: I have searched the existing issues and checked the recent builds/commits + required: true + - type: markdown + attributes: + value: | + *Please fill this form with as much information as possible, provide screenshots and/or illustrations of the feature if possible* + - type: textarea + id: feature + attributes: + label: What would your feature do? + description: Tell us about your feature in a very clear and simple way, and what problem it would solve + validations: + required: true + - type: textarea + id: workflow + attributes: + label: Proposed workflow + description: Please provide us with step by step information on how you'd like the feature to be accessed and used + value: | + 1. Go to .... + 2. Press .... + 3. ... + validations: + required: true + - type: textarea + id: misc + attributes: + label: Additional information + description: Add any other context or screenshots about the feature request here. \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..adee0ed --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" \ No newline at end of file From bafc92a146c3a8f75edcd1c3e22b7d3059b23930 Mon Sep 17 00:00:00 2001 From: Manuel Schmid Date: Fri, 28 Mar 2025 15:38:54 +0100 Subject: [PATCH 09/12] fix: correctly log in cronjob --- api.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api.py b/api.py index 1b7b7cb..ad4cbf7 100644 --- a/api.py +++ b/api.py @@ -41,6 +41,10 @@ def daily_report(): start_time = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0).timestamp() end_time = datetime.now().replace(hour=23, minute=59, second=59, microsecond=0).timestamp() + # import translator once more due to separate cronjob process + from biz.utils.i18n import get_translator + _ = get_translator() + try: if PUSH_REVIEW_ENABLED: df = ReviewService().get_push_review_logs(updated_at_gte=start_time, updated_at_lte=end_time) From be05b3b71db88de76304f041f1cdeee3962e1c9d Mon Sep 17 00:00:00 2001 From: Manuel Schmid Date: Fri, 28 Mar 2025 15:40:38 +0100 Subject: [PATCH 10/12] feat: adjust regex in prompt template --- locales/en_US/LC_MESSAGES/messages.po | 2 +- locales/en_US/prompt_templates.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/locales/en_US/LC_MESSAGES/messages.po b/locales/en_US/LC_MESSAGES/messages.po index 603e046..4964286 100644 --- a/locales/en_US/LC_MESSAGES/messages.po +++ b/locales/en_US/LC_MESSAGES/messages.po @@ -427,7 +427,7 @@ msgstr "Received AI return result: {review_result}" #: biz/utils/code_reviewer.py:99 msgid "总分[::]\\s*\\**(\\d+)分?" -msgstr "Total [sS]core[::]\\s*\\**(\\d+)? points" +msgstr "Total [sS]core[::]\\s*\\**(\\d+) points" #: biz/utils/im/dingtalk.py:30 msgid "未提供项目名称,且未设置默认的钉钉 Webhook URL。" diff --git a/locales/en_US/prompt_templates.yml b/locales/en_US/prompt_templates.yml index c365f25..7f8892c 100644 --- a/locales/en_US/prompt_templates.yml +++ b/locales/en_US/prompt_templates.yml @@ -13,7 +13,7 @@ code_review_prompt: Please output the code review report in Markdown format, including the following: 1. Issue Description & Optimization Suggestions (if any): List issues found in the code, briefly explain their impact, and provide optimization recommendations. 2. Scoring Breakdown: Provide specific scores for each evaluation criterion. - 3. Total score: Format as "Total score: XX points" (example: Total score: 80 points), and ensure it can be parsed by the regular expression r"总分[::]\s*(\d+)分?". + 3. Total score: Format as "Total score: XX points" (example: Total score: 80 points), and ensure it can be parsed by the regular expression r"Total score[::]\s*(\d+) points". user_prompt: |- Below is the code submitted by an employee to the GitLab repository. Please conduct a strict review of any critical issues and evaluate the code quality with a brief assessment and scoring. Code changes: From baed4b0370d8ecff1f8534312565be711c399abb Mon Sep 17 00:00:00 2001 From: Manuel Schmid Date: Fri, 28 Mar 2025 17:24:38 +0100 Subject: [PATCH 11/12] fix: add git clone to docker setup instructions again --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0623485..5f2b9e2 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,8 @@ GITLAB_ACCESS_TOKEN={YOUR_GITLAB_ACCESS_TOKEN} **2. 启动服务** ```bash +git clone https://github.com/mashb1t/ai-codereview-gitlab.git +cd ai-codereview-gitlab docker-compose up -d ``` From fbe52c5df05f5b2dc2cff6aabb91e9f3975b150c Mon Sep 17 00:00:00 2001 From: Manuel Schmid Date: Fri, 28 Mar 2025 17:43:54 +0100 Subject: [PATCH 12/12] i18n: add translation for latest updates --- locales/en_US/LC_MESSAGES/messages.mo | Bin 14295 -> 14260 bytes locales/en_US/LC_MESSAGES/messages.po | 230 +++++++++++++------------- locales/en_US/prompt_templates.yml | 65 ++++---- locales/zh_CN/LC_MESSAGES/messages.po | 196 +++++++++++----------- 4 files changed, 243 insertions(+), 248 deletions(-) diff --git a/locales/en_US/LC_MESSAGES/messages.mo b/locales/en_US/LC_MESSAGES/messages.mo index e835484e83af4bee27dbfb070daefc1665930e7f..e7d3981e8362156cba817e30bf396f5629a36665 100644 GIT binary patch delta 3575 zcmd7Tdu&uy9>DR_p#m+4WeP2i0;jl0Tc)zL1(yn_rD%a#kV1_mCNQOv_Xk5ff*rUJ58-OOgiSa%Cq3~$;B>y9!%27# zyRLG0OC}beyr>Xmg%v0-3Zd+fi88^XR{wjrnD2e)z!J8J%~Opy6I)Q;zZ2!T*dMu& zEq(*P!!J+<{1a~%zed@izoTsRKdt_WBv@AFK$%btN={pGHuj+G;AbckA3Gs^{|e+4 z%8Q!uRRagv7~2%CHz0qD-I_HEu^)VGkDIN7#&4a2+n^ z<_0{5GEOEp)iA!Q;i8I;E?kM9;wqfUa%JF0kU6Oi%)8ig{m`+VDr7y?2961&p?eXiG`^mpJg+=olCA2r^>;g{#@QF0$dUZFZ?u>TcY9HZkmco|8Tn#^Anc2CX4 zg}4e=qlry8i1G(%2?=M;Dv0u2H&){bl$2aW4wSNSv-Ibo6y;i!9o<_LORxAO9ksqVz#Oz13*l=J^Sm6pv9A0zKpUn1#MBgu!nXg0DrY7Mdo)q(fn39QBJ za?Un3;+=Q|@4!J^ge8o+4t=-=KSW8vj5(45@?XLQGf@jrs`M_r4h^e+Bg)Q%Q6|`h zqwyV-t^Wu$UPT!&Z*KZOsrymx+lk|GAIc7$L@CzuIF<3$6)x_@EY99MT#GW1Ze*ua zfRNK6jjnXXW1e(atq{G|b)%&WE(1$jMyyR;r9WCh#**<*B@NRwT#S}b+0<*4KnONhIO8bWG9 z@;=l^oBACgRlAWGLHxXB(UD_yauQPoDz(%=NNS`>4TMuyNLaqPhr=a!V&?7~uH#CK#0b{|#j}|+0yNA~Yf_}GQo-fXgx8=0kvX=Y2 zQ5|4h^J)9c!WMr}TXShQT&;fpMu&Dqewsz4dC?wN(s%mB{^z$Po_Zp==Xj#4H?e!i zz>)0(&vYnj!Pf7GcO(xymU#Q6q3-^DuO)iB`%jz6=eDOGFdK3=2tSgpR>*5+o0WkpH!m9?+XoOGIf{R-xly14|>AUq3&uAr5E-Gqq;sE zjJU&*prPvnhTGHPaXaM&zaZbYn!8Ju4kJnN*|Vb8jnDzV#}^Kn8D*>E&zBvs+3Wne z*%@}~FnU4(uQO^sQZd_nw<2$hQ~M%qE+d%Ev3Y1tS==`Fvy5q}46pDSawJ2Bmnmwe MZi)EZGNnrOZ!{Ns?f?J) delta 3809 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 O4ccp3;_cF3XZ#27#T0k| diff --git a/locales/en_US/LC_MESSAGES/messages.po b/locales/en_US/LC_MESSAGES/messages.po index 4964286..aeead34 100644 --- a/locales/en_US/LC_MESSAGES/messages.po +++ b/locales/en_US/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-03-22 17:29+0100\n" +"POT-Creation-Date: 2025-03-28 17:40+0100\n" "PO-Revision-Date: 2025-03-18 15:05+0100\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" @@ -16,51 +16,67 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: api.py:52 api.py:53 +#: api.py:55 api.py:56 msgid "No data to process." msgstr "No data to process." -#: api.py:63 +#: api.py:66 msgid "代码提交日报" msgstr "Code Submission Daily Report" -#: api.py:68 +#: api.py:71 msgid "Failed to generate daily report: {}" msgstr "Failed to generate daily report: {}" -#: api.py:96 +#: api.py:99 msgid "Scheduler started successfully." msgstr "Scheduler started successfully." -#: api.py:101 +#: api.py:104 msgid "Error setting up scheduler: {}" msgstr "Error setting up scheduler: {}" -#: api.py:112 +#: api.py:115 msgid "Invalid JSON" msgstr "Invalid JSON" -#: api.py:121 api.py:124 +#: api.py:125 +msgid "Invalid data format" +msgstr "Invalid data format" + +#: api.py:131 api.py:167 api.py:170 msgid "Missing GitLab URL" msgstr "Missing GitLab URL" -#: api.py:135 -msgid "Missing GitLab access token" -msgstr "Missing GitLab access token" - -#: api.py:140 +#: api.py:137 api.py:186 msgid "Received event: {}" msgstr "Received event: {}" -#: api.py:141 +#: api.py:138 api.py:187 msgid "Payload: {}" msgstr "Payload: {}" -#: api.py:148 api.py:155 +#: api.py:144 api.py:150 +msgid "GitHub request received(event_type={}), will process asynchronously." +msgstr "GitHub request received(event_type={}), will process asynchronously." + +#: api.py:154 +msgid "" +"Only pull_request and push events are supported for GitHub webhook, but " +"received:: {}." +msgstr "" +"Only pull_request and push events are supported for GitHub webhook, but " +"received:: {}." + +#: api.py:181 +msgid "Missing GitLab access token" +msgstr "Missing GitLab access token" + +#: api.py:194 api.py:201 msgid "Request received(object_kind={}), will process asynchronously." msgstr "Request received(object_kind={}), will process asynchronously." -#: api.py:159 +#: api.py:205 msgid "" "Only merge_request and push events are supported (both Webhook and System " "Hook), but received: {}." @@ -68,69 +84,37 @@ msgstr "" "Only merge_request and push events are supported (both Webhook and System " "Hook), but received: {}." -#: api.py:164 -msgid "Invalid data format" -msgstr "Invalid data format" - -#: biz/cmd/review.py:54 -msgid "输入无效,请输入 {} 类型的值。" -msgstr "Invalid input, please enter a value of type {}." - -#: biz/cmd/review.py:64 -msgid "请选择开发语言:" -msgstr "Please select the development language:" - -#: biz/cmd/review.py:70 -msgid "请输入数字 (1-{}): " -msgstr "Please enter a number (1-{}):" - -#: biz/cmd/review.py:74 -msgid "❌ 无效的选择,请输入 1 到 {} 之间的数字" -msgstr "❌ Invalid selection, please enter a number between 1 and {}" - -#: biz/cmd/review.py:78 -msgid "请输入代码项目的根目录路径: " -msgstr "Please enter the root directory path of the code project:" - -#: biz/cmd/review.py:81 -msgid "❌ 目录不存在,请输入有效路径" -msgstr "❌ The directory does not exist, please enter a valid path" - -#: biz/cmd/review.py:83 -msgid "请输入目录树的最大深度" -msgstr "Please enter the maximum depth of the directory tree" - -#: biz/cmd/review.py:84 -msgid "是否仅获取目录?(y/n)" -msgstr "Get directories only? (y/n)" - -#: biz/cmd/review.py:107 biz/utils/code_reviewer.py:67 -msgid "代码为空, diffs_text = {}" -msgstr "Code is empty, diffs_text = {}" +#: biz/cmd/review.py:11 +msgid "" +"\n" +"欢迎使用 Codebase Review 工具!\n" +msgstr "" +"\n" +"欢迎使用 Codebase Review 工具!\n" -#: biz/cmd/review.py:108 biz/utils/code_reviewer.py:68 -msgid "代码为空" -msgstr "Code is empty" +#: biz/cmd/review.py:17 +msgid "Review 目录结构规范" +msgstr "Review Directory Structure Specification" -#: biz/cmd/review.py:129 -msgid "请输入 'y' 或 'n' 确认。" -msgstr "Please enter 'y' or 'n' to confirm." +#: biz/cmd/review.py:18 +msgid "Review 代码分支命名规范" +msgstr "Review code branch naming conventions" -#: biz/cmd/review.py:138 -msgid "目录结构:\n" -msgstr "Directory structure:\n" +#: biz/cmd/review.py:19 +msgid "Review 代码复杂度" +msgstr "Review code complexity" -#: biz/cmd/review.py:141 -msgid "是否确认发送 Review 请求?(y/n): " -msgstr "Do you confirm to send Review request? (y/n):" +#: biz/cmd/review.py:22 +msgid "📌 请选择功能:" +msgstr "📌 Please select a function:" -#: biz/cmd/review.py:147 -msgid "Review 结果:\n" -msgstr "Review Results:\n" +#: biz/cmd/review.py:27 +msgid "请输入数字 (1-3): " +msgstr "Please enter a number (1-3):" -#: biz/cmd/review.py:149 -msgid "用户取消操作,退出程序。" -msgstr "The user cancels the operation and exits the program." +#: biz/cmd/review.py:30 +msgid "❌ 无效的选择,请输入 1-3" +msgstr "❌ Invalid selection, please enter 1-3" #: biz/event/event_manager.py:20 #, python-brace-format @@ -223,59 +207,59 @@ msgstr "" msgid "{project_name} Push Event" msgstr "{project_name} Push Event" -#: biz/gitlab/webhook_handler.py:84 +#: biz/gitlab/webhook_handler.py:82 msgid "Invalid event type: {}. Only 'merge_request' event is supported now." msgstr "Invalid event type: {}. Only 'merge_request' event is supported now." -#: biz/gitlab/webhook_handler.py:99 +#: biz/gitlab/webhook_handler.py:97 msgid "Get changes response from GitLab (attempt {}): {}, {}, URL: {}" msgstr "Get changes response from GitLab (attempt {}): {}, {}, URL: {}" -#: biz/gitlab/webhook_handler.py:107 +#: biz/gitlab/webhook_handler.py:105 msgid "Changes is empty, retrying in {} seconds... (attempt {}/{}), URL: {}" msgstr "Changes are empty, retrying in {} seconds... (attempt {}/{}), URL: {}" -#: biz/gitlab/webhook_handler.py:110 +#: biz/gitlab/webhook_handler.py:108 msgid "Failed to get changes from GitLab (URL: {}): {}, {}" msgstr "Failed to retrieve changes from GitLab (URL: {}): {}, {}" -#: biz/gitlab/webhook_handler.py:113 +#: biz/gitlab/webhook_handler.py:111 msgid "Max retries ({}) reached. Changes is still empty." msgstr "Max retries ({}) reached. Changes are still empty." -#: biz/gitlab/webhook_handler.py:128 +#: biz/gitlab/webhook_handler.py:126 msgid "Get commits response from gitlab: {}, {}" -msgstr "" +msgstr "Get commits response from gitlab: {}, {}" -#: biz/gitlab/webhook_handler.py:132 +#: biz/gitlab/webhook_handler.py:130 msgid "Failed to get commits: {}, {}" msgstr "Failed to get commits: {}, {}" -#: biz/gitlab/webhook_handler.py:146 +#: biz/gitlab/webhook_handler.py:144 msgid "Add notes to gitlab {}: {}, {}" msgstr "Add notes to gitlab {}: {}, {}" -#: biz/gitlab/webhook_handler.py:150 +#: biz/gitlab/webhook_handler.py:148 msgid "Failed to add note: {}" msgstr "Failed to add note: {}" -#: biz/gitlab/webhook_handler.py:180 biz/gitlab/webhook_handler.py:269 +#: biz/gitlab/webhook_handler.py:178 biz/gitlab/webhook_handler.py:267 msgid "Invalid event type: {}. Only 'push' event is supported now." msgstr "Invalid event type: {}. Only 'push' event is supported now." -#: biz/gitlab/webhook_handler.py:194 +#: biz/gitlab/webhook_handler.py:192 msgid "Collected {} commits from push event." msgstr "Collected {} commits from push event." -#: biz/gitlab/webhook_handler.py:200 +#: biz/gitlab/webhook_handler.py:198 msgid "No commits found to add notes to." msgstr "No commits found to add notes to." -#: biz/gitlab/webhook_handler.py:206 +#: biz/gitlab/webhook_handler.py:204 msgid "Last commit ID not found." msgstr "Last commit ID not found." -#: biz/gitlab/webhook_handler.py:234 +#: biz/gitlab/webhook_handler.py:232 msgid "" "Get commits response from GitLab for repository_commits: {response." "status_code}, {}, URL: {url}" @@ -283,7 +267,7 @@ msgstr "" "Get commits response from GitLab for repository_commits: {response." "status_code}, {}, URL: {url}" -#: biz/gitlab/webhook_handler.py:257 +#: biz/gitlab/webhook_handler.py:255 msgid "" "Get changes response from GitLab for repository_compare: {}, {response." "text}, URL: {}" @@ -291,11 +275,11 @@ msgstr "" "Get changes response from GitLab for repository_compare: {}, {response." "text}, URL: {}" -#: biz/gitlab/webhook_handler.py:263 +#: biz/gitlab/webhook_handler.py:261 msgid "Failed to get changes for repository_compare: {}, {}" msgstr "Failed to get changes for repository_compare: {}, {}" -#: biz/gitlab/webhook_handler.py:274 +#: biz/gitlab/webhook_handler.py:272 msgid "No commits found in push event." msgstr "No commits found in push event." @@ -341,26 +325,32 @@ msgstr "" msgid "调用DeepSeek API时出错: {e}" msgstr "Error occurred while calling DeepSeek API: {e}" -#: biz/llm/factory.py:28 +#: biz/llm/factory.py:27 +#, python-brace-format +msgid "Successfully loaded LLM provider: {provider}" +msgstr "Successfully loaded LLM provider: {provider}" + +#: biz/llm/factory.py:30 #, python-brace-format msgid "Unknown chat model provider: {provider}" msgstr "Unknown chat model provider: {provider}" -#: biz/queue/worker.py:26 biz/queue/worker.py:91 +#: biz/queue/worker.py:30 biz/queue/worker.py:95 biz/queue/worker.py:138 +#: biz/queue/worker.py:202 msgid "Failed to get commits" msgstr "Failed to retrieve commits" -#: biz/queue/worker.py:37 +#: biz/queue/worker.py:41 biz/queue/worker.py:149 msgid "未检测到PUSH代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。" msgstr "" "No changes detected in the pushed code. The modified files may not meet " "SUPPORTED_EXTENSIONS." -#: biz/queue/worker.py:38 +#: biz/queue/worker.py:42 biz/queue/worker.py:150 msgid "关注的文件没有修改" msgstr "No changes in the monitored files" -#: biz/queue/worker.py:45 biz/queue/worker.py:99 +#: biz/queue/worker.py:49 biz/queue/worker.py:103 biz/queue/worker.py:210 msgid "" "Auto Review Result: \n" "{}" @@ -368,64 +358,74 @@ msgstr "" "Auto Review Result: \n" "{}" -#: biz/queue/worker.py:60 +#: biz/queue/worker.py:64 biz/queue/worker.py:171 biz/queue/worker.py:228 msgid "服务出现未知错误: {}" msgstr "An unknown error occurred in the service: {}" -#: biz/queue/worker.py:62 biz/queue/worker.py:125 +#: biz/queue/worker.py:66 biz/queue/worker.py:129 biz/queue/worker.py:173 +#: biz/queue/worker.py:230 msgid "出现未知错误: {}" msgstr "An unknown error occurred: {}" -#: biz/queue/worker.py:77 +#: biz/queue/worker.py:81 msgid "Merge Request Hook event received" msgstr "Merge Request Hook event received" -#: biz/queue/worker.py:82 +#: biz/queue/worker.py:86 biz/queue/worker.py:146 biz/queue/worker.py:193 msgid "changes: {}" msgstr "Changes: {}" -#: biz/queue/worker.py:85 +#: biz/queue/worker.py:89 biz/queue/worker.py:196 msgid "未检测到有关代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。" msgstr "" "No relevant code changes detected. The modified files may not meet " "SUPPORTED_EXTENSIONS." -#: biz/queue/worker.py:120 +#: biz/queue/worker.py:124 msgid "Merge Request Hook event, action={}, ignored." msgstr "Merge Request Hook event, action={}, ignored." -#: biz/queue/worker.py:123 +#: biz/queue/worker.py:127 msgid "AI Code Review 服务出现未知错误: {}" msgstr "AI Code Review service encountered an unknown error: {}" -#: biz/utils/code_reviewer.py:33 -#, python-brace-format -msgid "提示词配置 `{prompt_key}` 为空或格式不正确" -msgstr "" -"The prompt word configuration `{prompt_key}` is empty or the format is " -"incorrect" +#: biz/queue/worker.py:135 +msgid "GitHub Push event received" +msgstr "GitHub Push event received" + +#: biz/queue/worker.py:188 +msgid "GitHub Pull Request event received" +msgstr "GitHub Pull Request event received" -#: biz/utils/code_reviewer.py:40 +#: biz/utils/code_reviewer.py:45 #, python-brace-format msgid "加载提示词配置失败: {e}" msgstr "Failed to load prompt configuration: {e}" -#: biz/utils/code_reviewer.py:41 +#: biz/utils/code_reviewer.py:46 #, python-brace-format msgid "提示词配置加载失败: {e}" msgstr "Failed to load prompt configuration: {e}" -#: biz/utils/code_reviewer.py:45 +#: biz/utils/code_reviewer.py:50 #, python-brace-format msgid "向 AI 发送代码 Review 请求, messages: {messages}" msgstr "Send code review request to AI, messages: {messages}" -#: biz/utils/code_reviewer.py:47 +#: biz/utils/code_reviewer.py:52 #, python-brace-format msgid "收到 AI 返回结果: {review_result}" msgstr "Received AI return result: {review_result}" -#: biz/utils/code_reviewer.py:99 +#: biz/utils/code_reviewer.py:79 +msgid "代码为空, diffs_text = {}" +msgstr "Code is empty, diffs_text = {}" + +#: biz/utils/code_reviewer.py:80 +msgid "代码为空" +msgstr "Code is empty" + +#: biz/utils/code_reviewer.py:111 msgid "总分[::]\\s*\\**(\\d+)分?" msgstr "Total [sS]core[::]\\s*\\**(\\d+) points" @@ -597,7 +597,7 @@ msgstr "Incorrect username or password" #: ui.py:83 ui.py:108 ui.py:133 ui.py:157 msgid "没有数据可供展示" -msgstr "" +msgstr "No data to display" #: ui.py:180 msgid "#### 审查日志" diff --git a/locales/en_US/prompt_templates.yml b/locales/en_US/prompt_templates.yml index 7f8892c..1b22dac 100644 --- a/locales/en_US/prompt_templates.yml +++ b/locales/en_US/prompt_templates.yml @@ -1,46 +1,43 @@ code_review_prompt: system_prompt: |- - You are a senior software development engineer, specializing in code quality, functionality, security, and stability. Your task is to review an employee's code with the following specific requirements: + You are a senior software developer, focusing on code standardization, functionality, security, and stability. The task is to review an employee's code, with the following specific requirements: ### Code Review Objectives: - 1. Correctness & Robustness (40 points): Ensure the code logic is correct and capable of handling various edge cases and exceptional inputs. - 2. Security & Potential Risks (30 points): Check the code for security vulnerabilities (such as SQL injection, XSS attacks, etc.) and evaluate potential risks. - 3. Adherence to Best Practices (20 points): Assess whether the code follows industry best practices, including code structure, naming conventions, and clarity of comments. - 4. Performance & Resource Efficiency (5 points): Analyze the performance of the code and assess whether there is any resource wastage or performance bottleneck. - 5. Clarity and Accuracy of Commit Messages (5 points): Review whether the commit messages are clear and accurate, and whether they facilitate future maintenance and collaboration. + 1. Correctness and robustness of functional implementation (40 points): Ensure that the code logic is correct and can handle various edge cases and unexpected inputs. + 2. Security and potential risks (30 points): Check whether the code contains security vulnerabilities (such as SQL injection, XSS attacks, etc.) and assess their potential risks. + 3. Adherence to best practices (20 points): Evaluate whether the code follows industry best practices, including code structure, naming conventions, and clarity of comments. + 4. Performance and resource utilization efficiency (5 points): Analyze the code's performance and evaluate whether there is any resource wastage or performance bottlenecks. + 5. Clarity and accuracy of commit information (5 points): Check whether the commit messages are clear and accurate, facilitating subsequent maintenance and collaboration. ### Output Format: Please output the code review report in Markdown format, including the following: - 1. Issue Description & Optimization Suggestions (if any): List issues found in the code, briefly explain their impact, and provide optimization recommendations. - 2. Scoring Breakdown: Provide specific scores for each evaluation criterion. - 3. Total score: Format as "Total score: XX points" (example: Total score: 80 points), and ensure it can be parsed by the regular expression r"Total score[::]\s*(\d+) points". + 1. Problem descriptions and optimization suggestions (if any): List the issues present in the code, briefly explain their impact, and provide optimization suggestions. + 2. Detailed scoring: Provide specific scores for each scoring criterion. + 3. Total Score: Format as "Total score: XX points" (for example: Total score: 80 points), ensuring that the total score can be parsed using the regex r"Total score[::]\s*(\d+) points". + + ### Special Instructions: + The entire review should maintain a {{ style }} style. + {% if style == 'professional' %} + When reviewing, please use standard engineering terminology and maintain a professional and rigorous tone. + {% elif style == 'sarcastic' %} + When reviewing, feel free to use sarcastic language, but ensure that the technical critique remains accurate. + {% elif style == 'gentle' %} + When reviewing, please use gentle wording such as "suggest" or "could consider". + {% elif style == 'humorous' %} + When reviewing, please: + 1. Incorporate appropriate humorous elements in the technical critique. + 2. Use related emojis appropriately (but not excessively): + - 🐛 indicates bugs + - 💥 indicates serious issues + - 🎯 indicates suggestions for improvement + - 🔍 indicates areas that require closer inspection + {% endif %} + user_prompt: |- - Below is the code submitted by an employee to the GitLab repository. Please conduct a strict review of any critical issues and evaluate the code quality with a brief assessment and scoring. + Below is the code submitted by an employee to the GitLab repository. Please review the following code in a {{ style }} style. + Code changes: {diffs_text} Commit history: - {commits_text} - -codebase_review_prompt: - system_prompt: |- - You are a senior software architect. Your task is to review a codebase with the following requirements: - - ### Specific Requirements: - 1. Organizational Logic: Evaluate whether the directory structure is clear and conforms to common project organizational standards (e.g., MVC, layered architecture, etc.). - 2. Naming Conventions: Check whether directory and file names are clear, consistent, and follow naming conventions (e.g., lowercase letters, hyphen-separated, etc.). - 3. Modularity: Assess whether the code is reasonably divided by functionality or modules, and whether there is excessive coupling or redundancy. - 4. Maintainability: Analyze whether the directory structure is easy to expand and maintain, and whether it is suitable for team collaboration. - 5. Suggestions for Improvement: Propose specific optimization suggestions based on identified issues. - - ### Output Format: - 1. Please present the review results in the following format: - 2. Strengths: List the strengths of the directory structure. - 3. Potential Issues: Point out possible problems in the directory structure. - 4. Suggestions for Improvement: Provide concrete optimization suggestions. - - user_prompt: |- - Below is a {language} codebase. Please review it and provide a detailed evaluation. - - Directory Structure: - {directory_structure} \ No newline at end of file + {{commits_text}} \ No newline at end of file diff --git a/locales/zh_CN/LC_MESSAGES/messages.po b/locales/zh_CN/LC_MESSAGES/messages.po index 4c0ab42..f3702a3 100644 --- a/locales/zh_CN/LC_MESSAGES/messages.po +++ b/locales/zh_CN/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-03-22 17:29+0100\n" +"POT-Creation-Date: 2025-03-28 17:40+0100\n" "PO-Revision-Date: 2025-03-18 15:05+0100\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" @@ -16,118 +16,98 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: api.py:52 api.py:53 +#: api.py:55 api.py:56 msgid "No data to process." msgstr "" -#: api.py:63 +#: api.py:66 msgid "代码提交日报" msgstr "" -#: api.py:68 +#: api.py:71 msgid "Failed to generate daily report: {}" msgstr "" -#: api.py:96 +#: api.py:99 msgid "Scheduler started successfully." msgstr "" -#: api.py:101 +#: api.py:104 msgid "Error setting up scheduler: {}" msgstr "" -#: api.py:112 +#: api.py:115 msgid "Invalid JSON" msgstr "" -#: api.py:121 api.py:124 -msgid "Missing GitLab URL" +#: api.py:125 +msgid "Invalid data format" msgstr "" -#: api.py:135 -msgid "Missing GitLab access token" +#: api.py:131 api.py:167 api.py:170 +msgid "Missing GitLab URL" msgstr "" -#: api.py:140 +#: api.py:137 api.py:186 msgid "Received event: {}" msgstr "" -#: api.py:141 +#: api.py:138 api.py:187 msgid "Payload: {}" msgstr "" -#: api.py:148 api.py:155 -msgid "Request received(object_kind={}), will process asynchronously." +#: api.py:144 api.py:150 +msgid "GitHub request received(event_type={}), will process asynchronously." msgstr "" -#: api.py:159 +#: api.py:154 msgid "" -"Only merge_request and push events are supported (both Webhook and System " -"Hook), but received: {}." -msgstr "" - -#: api.py:164 -msgid "Invalid data format" -msgstr "" - -#: biz/cmd/review.py:54 -msgid "输入无效,请输入 {} 类型的值。" -msgstr "" - -#: biz/cmd/review.py:64 -msgid "请选择开发语言:" +"Only pull_request and push events are supported for GitHub webhook, but " +"received:: {}." msgstr "" -#: biz/cmd/review.py:70 -msgid "请输入数字 (1-{}): " -msgstr "" - -#: biz/cmd/review.py:74 -msgid "❌ 无效的选择,请输入 1 到 {} 之间的数字" -msgstr "" - -#: biz/cmd/review.py:78 -msgid "请输入代码项目的根目录路径: " -msgstr "" - -#: biz/cmd/review.py:81 -msgid "❌ 目录不存在,请输入有效路径" +#: api.py:181 +msgid "Missing GitLab access token" msgstr "" -#: biz/cmd/review.py:83 -msgid "请输入目录树的最大深度" +#: api.py:194 api.py:201 +msgid "Request received(object_kind={}), will process asynchronously." msgstr "" -#: biz/cmd/review.py:84 -msgid "是否仅获取目录?(y/n)" +#: api.py:205 +msgid "" +"Only merge_request and push events are supported (both Webhook and System " +"Hook), but received: {}." msgstr "" -#: biz/cmd/review.py:107 biz/utils/code_reviewer.py:67 -msgid "代码为空, diffs_text = {}" +#: biz/cmd/review.py:11 +msgid "" +"\n" +"欢迎使用 Codebase Review 工具!\n" msgstr "" -#: biz/cmd/review.py:108 biz/utils/code_reviewer.py:68 -msgid "代码为空" +#: biz/cmd/review.py:17 +msgid "Review 目录结构规范" msgstr "" -#: biz/cmd/review.py:129 -msgid "请输入 'y' 或 'n' 确认。" +#: biz/cmd/review.py:18 +msgid "Review 代码分支命名规范" msgstr "" -#: biz/cmd/review.py:138 -msgid "目录结构:\n" +#: biz/cmd/review.py:19 +msgid "Review 代码复杂度" msgstr "" -#: biz/cmd/review.py:141 -msgid "是否确认发送 Review 请求?(y/n): " +#: biz/cmd/review.py:22 +msgid "📌 请选择功能:" msgstr "" -#: biz/cmd/review.py:147 -msgid "Review 结果:\n" +#: biz/cmd/review.py:27 +msgid "请输入数字 (1-3): " msgstr "" -#: biz/cmd/review.py:149 -msgid "用户取消操作,退出程序。" +#: biz/cmd/review.py:30 +msgid "❌ 无效的选择,请输入 1-3" msgstr "" #: biz/event/event_manager.py:20 @@ -194,75 +174,75 @@ msgstr "" msgid "{project_name} Push Event" msgstr "" -#: biz/gitlab/webhook_handler.py:84 +#: biz/gitlab/webhook_handler.py:82 msgid "Invalid event type: {}. Only 'merge_request' event is supported now." msgstr "" -#: biz/gitlab/webhook_handler.py:99 +#: biz/gitlab/webhook_handler.py:97 msgid "Get changes response from GitLab (attempt {}): {}, {}, URL: {}" msgstr "" -#: biz/gitlab/webhook_handler.py:107 +#: biz/gitlab/webhook_handler.py:105 msgid "Changes is empty, retrying in {} seconds... (attempt {}/{}), URL: {}" msgstr "" -#: biz/gitlab/webhook_handler.py:110 +#: biz/gitlab/webhook_handler.py:108 msgid "Failed to get changes from GitLab (URL: {}): {}, {}" msgstr "" -#: biz/gitlab/webhook_handler.py:113 +#: biz/gitlab/webhook_handler.py:111 msgid "Max retries ({}) reached. Changes is still empty." msgstr "" -#: biz/gitlab/webhook_handler.py:128 +#: biz/gitlab/webhook_handler.py:126 msgid "Get commits response from gitlab: {}, {}" msgstr "" -#: biz/gitlab/webhook_handler.py:132 +#: biz/gitlab/webhook_handler.py:130 msgid "Failed to get commits: {}, {}" msgstr "" -#: biz/gitlab/webhook_handler.py:146 +#: biz/gitlab/webhook_handler.py:144 msgid "Add notes to gitlab {}: {}, {}" msgstr "" -#: biz/gitlab/webhook_handler.py:150 +#: biz/gitlab/webhook_handler.py:148 msgid "Failed to add note: {}" msgstr "" -#: biz/gitlab/webhook_handler.py:180 biz/gitlab/webhook_handler.py:269 +#: biz/gitlab/webhook_handler.py:178 biz/gitlab/webhook_handler.py:267 msgid "Invalid event type: {}. Only 'push' event is supported now." msgstr "" -#: biz/gitlab/webhook_handler.py:194 +#: biz/gitlab/webhook_handler.py:192 msgid "Collected {} commits from push event." msgstr "" -#: biz/gitlab/webhook_handler.py:200 +#: biz/gitlab/webhook_handler.py:198 msgid "No commits found to add notes to." msgstr "" -#: biz/gitlab/webhook_handler.py:206 +#: biz/gitlab/webhook_handler.py:204 msgid "Last commit ID not found." msgstr "" -#: biz/gitlab/webhook_handler.py:234 +#: biz/gitlab/webhook_handler.py:232 msgid "" "Get commits response from GitLab for repository_commits: {response." "status_code}, {}, URL: {url}" msgstr "" -#: biz/gitlab/webhook_handler.py:257 +#: biz/gitlab/webhook_handler.py:255 msgid "" "Get changes response from GitLab for repository_compare: {}, {response." "text}, URL: {}" msgstr "" -#: biz/gitlab/webhook_handler.py:263 +#: biz/gitlab/webhook_handler.py:261 msgid "Failed to get changes for repository_compare: {}, {}" msgstr "" -#: biz/gitlab/webhook_handler.py:274 +#: biz/gitlab/webhook_handler.py:272 msgid "No commits found in push event." msgstr "" @@ -304,83 +284,101 @@ msgstr "" msgid "调用DeepSeek API时出错: {e}" msgstr "" -#: biz/llm/factory.py:28 +#: biz/llm/factory.py:27 +#, python-brace-format +msgid "Successfully loaded LLM provider: {provider}" +msgstr "" + +#: biz/llm/factory.py:30 #, python-brace-format msgid "Unknown chat model provider: {provider}" msgstr "" -#: biz/queue/worker.py:26 biz/queue/worker.py:91 +#: biz/queue/worker.py:30 biz/queue/worker.py:95 biz/queue/worker.py:138 +#: biz/queue/worker.py:202 msgid "Failed to get commits" msgstr "" -#: biz/queue/worker.py:37 +#: biz/queue/worker.py:41 biz/queue/worker.py:149 msgid "未检测到PUSH代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。" msgstr "" -#: biz/queue/worker.py:38 +#: biz/queue/worker.py:42 biz/queue/worker.py:150 msgid "关注的文件没有修改" msgstr "" -#: biz/queue/worker.py:45 biz/queue/worker.py:99 +#: biz/queue/worker.py:49 biz/queue/worker.py:103 biz/queue/worker.py:210 msgid "" "Auto Review Result: \n" "{}" msgstr "" -#: biz/queue/worker.py:60 +#: biz/queue/worker.py:64 biz/queue/worker.py:171 biz/queue/worker.py:228 msgid "服务出现未知错误: {}" msgstr "" -#: biz/queue/worker.py:62 biz/queue/worker.py:125 +#: biz/queue/worker.py:66 biz/queue/worker.py:129 biz/queue/worker.py:173 +#: biz/queue/worker.py:230 msgid "出现未知错误: {}" msgstr "" -#: biz/queue/worker.py:77 +#: biz/queue/worker.py:81 msgid "Merge Request Hook event received" msgstr "" -#: biz/queue/worker.py:82 +#: biz/queue/worker.py:86 biz/queue/worker.py:146 biz/queue/worker.py:193 msgid "changes: {}" msgstr "" -#: biz/queue/worker.py:85 +#: biz/queue/worker.py:89 biz/queue/worker.py:196 msgid "未检测到有关代码的修改,修改文件可能不满足SUPPORTED_EXTENSIONS。" msgstr "" -#: biz/queue/worker.py:120 +#: biz/queue/worker.py:124 msgid "Merge Request Hook event, action={}, ignored." msgstr "" -#: biz/queue/worker.py:123 +#: biz/queue/worker.py:127 msgid "AI Code Review 服务出现未知错误: {}" msgstr "" -#: biz/utils/code_reviewer.py:33 -#, python-brace-format -msgid "提示词配置 `{prompt_key}` 为空或格式不正确" +#: biz/queue/worker.py:135 +msgid "GitHub Push event received" msgstr "" -#: biz/utils/code_reviewer.py:40 +#: biz/queue/worker.py:188 +msgid "GitHub Pull Request event received" +msgstr "" + +#: biz/utils/code_reviewer.py:45 #, python-brace-format msgid "加载提示词配置失败: {e}" msgstr "" -#: biz/utils/code_reviewer.py:41 +#: biz/utils/code_reviewer.py:46 #, python-brace-format msgid "提示词配置加载失败: {e}" msgstr "" -#: biz/utils/code_reviewer.py:45 +#: biz/utils/code_reviewer.py:50 #, python-brace-format msgid "向 AI 发送代码 Review 请求, messages: {messages}" msgstr "" -#: biz/utils/code_reviewer.py:47 +#: biz/utils/code_reviewer.py:52 #, python-brace-format msgid "收到 AI 返回结果: {review_result}" msgstr "" -#: biz/utils/code_reviewer.py:99 +#: biz/utils/code_reviewer.py:79 +msgid "代码为空, diffs_text = {}" +msgstr "" + +#: biz/utils/code_reviewer.py:80 +msgid "代码为空" +msgstr "" + +#: biz/utils/code_reviewer.py:111 msgid "总分[::]\\s*\\**(\\d+)分?" msgstr ""