From 97021a68e0da4620e34abfc5cfc9508a159cde42 Mon Sep 17 00:00:00 2001 From: Hao Wu Date: Sun, 26 Mar 2023 16:22:01 +0800 Subject: [PATCH] auto check locales (#37) * update * use json locale files --- .github/workflows/docker-image.yml | 21 +++-- .python-version | 1 + api/tools/apply_a_similar_change/README.md | 95 ++++++++++++++++++++++ locale_missing_key.py | 40 +++++++++ web/src/locales/en-US.json | 76 +++++++++++++++++ web/src/locales/en-US.ts | 61 -------------- web/src/locales/index.ts | 6 +- web/src/locales/zh-CN.json | 76 +++++++++++++++++ web/src/locales/zh-CN.ts | 77 ------------------ web/src/locales/zh-TW.json | 76 +++++++++++++++++ web/src/locales/zh-TW.ts | 61 -------------- 11 files changed, 379 insertions(+), 211 deletions(-) create mode 100644 .python-version create mode 100644 locale_missing_key.py create mode 100644 web/src/locales/en-US.json delete mode 100644 web/src/locales/en-US.ts create mode 100644 web/src/locales/zh-CN.json delete mode 100644 web/src/locales/zh-CN.ts create mode 100644 web/src/locales/zh-TW.json delete mode 100644 web/src/locales/zh-TW.ts diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 30686179..e1f7c2c1 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -2,9 +2,9 @@ name: e2e test on: push: - branches: '**' + branches: "**" pull_request: - branches: '**' + branches: "**" env: PG_DB: postgres PG_USER: postgres @@ -48,29 +48,33 @@ jobs: - name: Push UI image to GitHub Container Registry run: docker push ghcr.io/swuecho/chat_frontend:latest working-directory: web - + e2e: runs-on: ubuntu-latest needs: [build_api, build_ui] - timeout-minutes: 5 + timeout-minutes: 5 steps: - uses: actions/checkout@v3 - name: Login to GitHub Container Registry run: echo "${{ secrets.GHCR_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + + - name: check locale + run: python locale_missing_key.py web/src/locales --base zh-CN + - name: docker-compose run: docker-compose up -d - - name: show + - name: show docker ps run: docker-compose ps - - name: show + - name: show docker logs run: docker-compose logs - name: Use Node.js uses: actions/setup-node@v3 with: node-version: "16.x" - + # Setup cache for node_modules - name: Cache node modules uses: actions/cache@v3 @@ -79,7 +83,7 @@ jobs: key: ${{ runner.os }}-node-${{ hashFiles('e2e/package-lock.json') }} restore-keys: | ${{ runner.os }}-node- - + - name: Install dependencies run: npm ci working-directory: e2e @@ -90,4 +94,3 @@ jobs: - run: npx playwright test working-directory: e2e - diff --git a/.python-version b/.python-version new file mode 100644 index 00000000..8d7f852b --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.10.4 diff --git a/api/tools/apply_a_similar_change/README.md b/api/tools/apply_a_similar_change/README.md index 2c4eff79..3c7d4b15 100644 --- a/api/tools/apply_a_similar_change/README.md +++ b/api/tools/apply_a_similar_change/README.md @@ -29,3 +29,98 @@ Here's how it works: While this process promises to automate programming tasks, there is still a bottleneck in the validity of the changeset generated in step 2. Although the generated changeset might work for humans, it may not always be strictly valid. This can cause issues in the codebase and lead to bugs. If a smart diff apply tool exists, we can greatly accelerate our development workflows and reduce the risk of errors caused by automated tooling. It's an investment that can pay off many times over in increased efficiency and higher quality codebases. + + +## When chatgpt4 fails + + +idea: sometime, a change is very similar to a previous change, such as another field to a table. +that will also need to add a field to the struct represent that table. etc. + +I have an idea to use chatgpt to automate my coding process. + +1. get the changeset of previous change when add a field A with type Ta +2. let gpt generate a new changeset for add field B with type Tb based on the changeset of adding A. +3. apply the changeset to the git repo. + +the problem is in the step 3. the changeset generated in step 2 is not valid to git (the changeset format is too strict), but human being have no problem apply the change to files. + +could you write a program for me to apply a changeset in a best effort manner? It does not have to be perfect. +apply as much change as possible. + +### Answer From ChatGPT-4: + +I understand that you want a program that applies a changeset to a codebase, even if the changeset is not in a strictly correct format. To do this, you can use the following Python script that works with a best-effort approach: + +```python +import os +import re +import sys +from pathlib import Path + +def parse_changeset(changeset_file): + with open(changeset_file, 'r') as file: + content = file.read() + return content.strip().split('\n') + +def apply_changeset(changeset, repo_path): + current_file = None + for line in changeset: + file_match = re.match(r'^--- (\S+)', line) + if file_match: + current_file = os.path.join(repo_path, file_match.group(1)) + if not os.path.exists(current_file): + print(f"Creating file: {current_file}") + Path(current_file).touch() + continue + + if current_file: + with open(current_file, 'a') as file: + file.write(line + '\n') + +if __name__ == '__main__': + if len(sys.argv) < 3: + print("Usage: python apply_changeset.py ") + sys.exit(1) + + changeset_file = sys.argv[1] + repo_path = sys.argv[2] + + changeset = parse_changeset(changeset_file) + apply_changeset(changeset, repo_path) +``` + +This script takes two command-line arguments: the path to the changeset file and the path to the git repository. The changeset file should contain the changes you want to apply. The script will create new files and append lines to existing files based on the changeset. + +Note that this script assumes the changeset format is similar to a patch file, with lines starting with `---` followed by the file path. However, this script does not handle more complex changes like file deletions or renaming, and it does not account for strict changeset formats. + +You can execute the script with the following command: + +```bash +python apply_changeset.py path/to/changeset_file path/to/repo +``` + +Remember that this is a best-effort approach, and there might be cases where the changeset does not apply correctly. Always review the applied changes and make adjustments as needed. + + +### Answer From Claude+: + +This is definitely an interesting idea, but I would caution against fully automating code generation in this way. There are a few issues I see: + +ChatGPT (or any AI system today) does not have a deep understanding of code semantics. It can generate syntactically valid code, but the generated code may be nonsensical or badly designed. +The changeset format is strict for a reason - it ensures code integrity and a clean history/merge process. Diverging from that can cause a lot of issues down the road. +You would lose a lot of context about why certain design decisions were made by not writing the code yourself. This context is crucial for maintaining a codebase. + +That being said, here is a rough process you could follow to apply an "invalid" changeset: + +Go through the changeset line by line. +For any valid changes (adds/removes/edits that git would accept), apply those directly. +For invalid changes: + +Try to interpret the intent behind the change and implement it manually in a sensible way. +If the intent is unclear, discard that part of the changeset. +In any case, commit the final changes with a message describing what was interpreted/discarded. + +This follows the "best effort" approach you described, applying as much of the changeset as possible in a prudent manner. But again, I would caution against fully automating this process, and suggest leveraging AI systems merely as a tool to augment your own coding process. Keeping a human in the loop will lead to higher quality, more maintainable code overall. + +Hope this helps! Let me know if you have any other questions. diff --git a/locale_missing_key.py b/locale_missing_key.py new file mode 100644 index 00000000..f2495fc5 --- /dev/null +++ b/locale_missing_key.py @@ -0,0 +1,40 @@ +from pathlib import Path +import json +import argparse + +# Recursive function to find missing keys in dictionaries +def find_missing_keys(base_dict, other_dict): + missing_keys = {} + for key in base_dict: + if key not in other_dict: + missing_keys[key] = base_dict[key] + elif isinstance(base_dict[key], dict) and isinstance(other_dict[key], dict): + sub_missing_keys = find_missing_keys(base_dict[key], other_dict[key]) + if sub_missing_keys: + missing_keys[key] = sub_missing_keys + return missing_keys + + + +def check_locales(dir_name: str, base_locale: str = 'zh-CN'): + # Load the zh-CN JSON file + zh_cn_file = Path(dir_name) / f'{base_locale}.json' + with zh_cn_file.open('r') as f: + zh_cn = json.load(f) + + # Look for other JSON files in the current directory + for file in Path(dir_name).glob('*.json'): + cur_locale = file.stem + if cur_locale != base_locale: + with file.open('r') as f: + other_dict = json.load(f) + missing_keys = find_missing_keys(zh_cn, other_dict) + print(f'\n\n please translate to {cur_locale}:', missing_keys) + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Check missing keys in language localization files') + parser.add_argument('dir_name', type=str, help='directory where the JSON files are located') + parser.add_argument('--base', type=str, default='zh-CN', help='base locale to compare against') + args = parser.parse_args() + check_locales(args.dir_name, args.base) + # python check_locales.py /path/to/locales --base en-US diff --git a/web/src/locales/en-US.json b/web/src/locales/en-US.json new file mode 100644 index 00000000..ab0274ca --- /dev/null +++ b/web/src/locales/en-US.json @@ -0,0 +1,76 @@ +{ + "common": { + "help": "The first one is the theme(prompt), and the context includes 10 messages.", + "edit": "Edit", + "delete": "Delete", + "save": "Save", + "reset": "Reset", + "export": "Export", + "import": "Import", + "clear": "Clear", + "yes": "Yes", + "no": "No", + "noData": "No data available", + "wrong": "Something seems to have gone wrong. Please try again later.", + "success": "Operation succeeded", + "failed": "Operation failed", + "verify": "Verify", + "login": "Login", + "logout": "Logout", + "signup": "Sign up", + "email_placeholder": "Please enter your email", + "password_placeholder": "Please enter your password", + "unauthorizedTips": "Please sign up or login" + }, + "chat": { + "placeholder": "What would you like to say... (Shift + Enter = newline)", + "placeholderMobile": "What would you like to say...", + "copy": "Copy", + "copied": "Copied", + "copyCode": "Copy code", + "clearChat": "Clear chat session", + "clearChatConfirm": "Do you want to clear the chat session?", + "exportImage": "Export chat session to image", + "exportImageConfirm": "Do you want to save the chat session as an image?", + "exportSuccess": "Saved successfully", + "exportFailed": "Saving failed", + "usingContext": "Context Mode", + "turnOnContext": "In this mode, messages sent will include previous chat logs.", + "turnOffContext": "In this mode, messages sent will not include previous chat logs.", + "deleteMessage": "Delete message", + "deleteMessageConfirm": "Do you want to delete this message?", + "deleteChatSessionsConfirm": "Are you sure you want to delete this record?", + "clearHistoryConfirm": "Are you sure you want to clear the chat history?", + "contextLength": "Context Length, default 10 (2 at the beginning of the conversation + 8 most recent)", + "stopAnswer": "Stop Answering", + "slider": "Context Length", + "temperature": "Temperature", + "maxTokens": "Max Total Tokens", + "topP": "Top P", + "frequencyPenalty": "Frequency Penalty", + "presencePenalty": "Presence Penalty", + "debug": "Debug Mode" + }, + "setting": { + "setting": "Settings", + "general": "Overview", + "config": "Configuration", + "avatarLink": "Avatar Link", + "name": "Name", + "description": "Description", + "resetUserInfo": "Reset User Info", + "chatHistory": "Chat History", + "theme": "Theme", + "language": "Language", + "api": "API", + "reverseProxy": "Reverse Proxy", + "timeout": "Timeout", + "socks": "Socks", + "admin": "Admin" + }, + "admin": { + "title": "Admin", + "permission": "Permission", + "rateLimit": "Rate Limit" + } +} \ No newline at end of file diff --git a/web/src/locales/en-US.ts b/web/src/locales/en-US.ts deleted file mode 100644 index 0b23efb4..00000000 --- a/web/src/locales/en-US.ts +++ /dev/null @@ -1,61 +0,0 @@ -export default { - common: { - help: 'The first one is the theme(prompt), and the context includes 10 messages.', - edit: 'Edit', - delete: 'Delete', - save: 'Save', - reset: 'Reset', - export: 'Export', - import: 'Import', - clear: 'Clear', - yes: 'Yes', - no: 'No', - noData: 'No data available', - wrong: 'Something seems to have gone wrong. Please try again later.', - success: 'Operation succeeded', - failed: 'Operation failed', - verify: 'Verify', - login: 'Login', - logout: 'Logout', - signup: 'Sign up', - email_placeholder: 'Please enter your email', - password_placeholder: 'Please enter your password', - unauthorizedTips: 'Please sign up or login', - }, - chat: { - placeholder: 'What would you like to say... (Shift + Enter = newline)', - placeholderMobile: 'What would you like to say...', - copy: 'Copy', - copied: 'Copied', - copyCode: 'Copy code', - clearChat: 'Clear chat session', - clearChatConfirm: 'Do you want to clear the chat session?', - exportImage: 'Export chat session to image', - exportImageConfirm: 'Do you want to save the chat session as an image?', - exportSuccess: 'Saved successfully', - exportFailed: 'Saving failed', - usingContext: 'Context Mode', - turnOnContext: 'In this mode, messages sent will include previous chat logs.', - turnOffContext: 'In this mode, messages sent will not include previous chat logs.', - deleteMessage: 'Delete message', - deleteMessageConfirm: 'Do you want to delete this message?', - deleteChatSessionsConfirm: 'Are you sure you want to delete this record?', - clearHistoryConfirm: 'Are you sure you want to clear the chat history?', - }, - setting: { - setting: 'Settings', - general: 'Overview', - config: 'Configuration', - avatarLink: 'Avatar Link', - name: 'Name', - description: 'Description', - resetUserInfo: 'Reset User Info', - chatHistory: 'Chat History', - theme: 'Theme', - language: 'Language', - api: 'API', - reverseProxy: 'Reverse Proxy', - timeout: 'Timeout', - socks: 'Socks', - }, -} diff --git a/web/src/locales/index.ts b/web/src/locales/index.ts index 49eb488a..fd65a342 100644 --- a/web/src/locales/index.ts +++ b/web/src/locales/index.ts @@ -1,8 +1,8 @@ import type { App } from 'vue' import { createI18n } from 'vue-i18n' -import enUS from './en-US' -import zhCN from './zh-CN' -import zhTW from './zh-TW' +import enUS from './en-US.json' +import zhCN from './zh-CN.json' +import zhTW from './zh-TW.json' import { useAppStoreWithOut } from '@/store/modules/app' import type { Language } from '@/store/modules/app/helper' diff --git a/web/src/locales/zh-CN.json b/web/src/locales/zh-CN.json new file mode 100644 index 00000000..d812a0a2 --- /dev/null +++ b/web/src/locales/zh-CN.json @@ -0,0 +1,76 @@ +{ + "common": { + "help": "第一条是主题(prompt), 上下文包括10条信息", + "edit": "编辑", + "delete": "删除", + "save": "保存", + "reset": "重置", + "export": "导出", + "import": "导入", + "clear": "清空", + "yes": "是", + "no": "否", + "noData": "暂无数据", + "wrong": "好像出错了,请稍后再试。", + "success": "操作成功", + "failed": "操作失败", + "verify": "验证", + "login": "登录", + "logout": "登出", + "signup": "注册", + "email_placeholder": "请输入邮箱", + "password_placeholder": "请输入密码", + "unauthorizedTips": "请注册或者登录" + }, + "chat": { + "placeholder": "来说点什么吧...(Shift + Enter = 换行)", + "placeholderMobile": "来说点什么...", + "copy": "复制", + "copied": "复制成功", + "copyCode": "复制代码", + "clearChat": "清空会话", + "clearChatConfirm": "是否清空会话?", + "exportImage": "保存会话到图片", + "exportImageConfirm": "是否将会话保存为图片?", + "exportSuccess": "保存成功", + "exportFailed": "保存失败", + "usingContext": "上下文模式", + "turnOnContext": "当前模式下, 发送消息会携带之前的聊天记录", + "turnOffContext": "当前模式下, 发送消息不会携带之前的聊天记录", + "deleteMessage": "删除消息", + "deleteMessageConfirm": "是否删除此消息?", + "deleteChatSessionsConfirm": "确定删除此记录?", + "clearHistoryConfirm": "确定清空聊天记录?", + "contextLength": "上下文数量, 默认10 (会话开始的2条 + 最近的8条)", + "stopAnswer": "停止回答", + "slider": "上下文数量", + "temperature": "温度", + "maxTokens": "最大问答总token数量", + "topP": "Top P", + "frequencyPenalty": "频率惩罚", + "presencePenalty": "存在惩罚", + "debug": "调试模式" + }, + "admin": { + "title": "管理", + "permission": "权限", + "rateLimit": "限流" + }, + "setting": { + "setting": "设置", + "general": "总览", + "admin": "管理", + "config": "配置", + "avatarLink": "头像链接", + "name": "名称", + "description": "描述", + "resetUserInfo": "重置用户信息", + "chatHistory": "聊天记录", + "theme": "主题", + "language": "语言", + "api": "API", + "reverseProxy": "反向代理", + "timeout": "超时", + "socks": "Socks" + } +} \ No newline at end of file diff --git a/web/src/locales/zh-CN.ts b/web/src/locales/zh-CN.ts deleted file mode 100644 index f1073a7c..00000000 --- a/web/src/locales/zh-CN.ts +++ /dev/null @@ -1,77 +0,0 @@ -export default { - common: { - help: '第一条是主题(prompt), 上下文包括10条信息', - edit: '编辑', - delete: '删除', - save: '保存', - reset: '重置', - export: '导出', - import: '导入', - clear: '清空', - yes: '是', - no: '否', - noData: '暂无数据', - wrong: '好像出错了,请稍后再试。', - success: '操作成功', - failed: '操作失败', - verify: '验证', - login: '登录', - logout: '登出', - signup: '注册', - email_placeholder: '请输入邮箱', - password_placeholder: '请输入密码', - unauthorizedTips: '请注册或者登录', - }, - chat: { - placeholder: '来说点什么吧...(Shift + Enter = 换行)', - placeholderMobile: '来说点什么...', - copy: '复制', - copied: '复制成功', - copyCode: '复制代码', - clearChat: '清空会话', - clearChatConfirm: '是否清空会话?', - exportImage: '保存会话到图片', - exportImageConfirm: '是否将会话保存为图片?', - exportSuccess: '保存成功', - exportFailed: '保存失败', - usingContext: '上下文模式', - turnOnContext: '当前模式下, 发送消息会携带之前的聊天记录', - turnOffContext: '当前模式下, 发送消息不会携带之前的聊天记录', - deleteMessage: '删除消息', - deleteMessageConfirm: '是否删除此消息?', - deleteChatSessionsConfirm: '确定删除此记录?', - clearHistoryConfirm: '确定清空聊天记录?', - contextLength: '上下文数量, 默认10 (会话开始的2条 + 最近的8条)', - stopAnswer: '停止回答', - slider: '上下文数量', - temperature: '温度', - maxTokens: '最大问答总token数量', - topP: 'Top P', - frequencyPenalty: '频率惩罚', - presencePenalty: '存在惩罚', - debug: '调试模式', - }, - admin: { - title: '管理', - permission: '权限', - rateLimit: '限流', - }, - setting: { - setting: '设置', - general: '总览', - admin: '管理', - config: '配置', - avatarLink: '头像链接', - name: '名称', - description: '描述', - resetUserInfo: '重置用户信息', - chatHistory: '聊天记录', - theme: '主题', - language: '语言', - api: 'API', - reverseProxy: '反向代理', - timeout: '超时', - socks: 'Socks', - }, - -} diff --git a/web/src/locales/zh-TW.json b/web/src/locales/zh-TW.json new file mode 100644 index 00000000..a65c08eb --- /dev/null +++ b/web/src/locales/zh-TW.json @@ -0,0 +1,76 @@ +{ + "common": { + "help": "第一個是主題(prompt),上下文包括10條信息", + "edit": "編輯", + "delete": "刪除", + "save": "保存", + "reset": "重置", + "export": "匯出", + "import": "匯入", + "clear": "清空", + "yes": "是", + "no": "否", + "noData": "暫無數據", + "wrong": "好像出錯了,請稍後再試。", + "success": "操作成功", + "failed": "操作失敗", + "verify": "註冊", + "login": "登錄", + "logout": "登出", + "signup": "註冊", + "email_placeholder": "請輸入電子郵件", + "password_placeholder": "請輸入密碼", + "unauthorizedTips": "請註冊或登錄" + }, + "chat": { + "placeholder": "說些什麼...(Shift + Enter = 換行)", + "placeholderMobile": "說些什麼...", + "copy": "複製", + "copied": "複製成功", + "copyCode": "複製代碼", + "clearChat": "清空對話", + "clearChatConfirm": "是否清空對話?", + "exportImage": "導出對話到圖片", + "exportImageConfirm": "是否將對話導出為圖片?", + "exportSuccess": "導出成功", + "exportFailed": "導出失敗", + "usingContext": "上下文模式", + "turnOnContext": "在此模式下,發送的消息將包括以前的聊天記錄。", + "turnOffContext": "在此模式下,發送的消息將不包括以前的聊天記錄。", + "deleteMessage": "刪除消息", + "deleteMessageConfirm": "是否刪除此消息?", + "deleteChatSessionsConfirm": "確定刪除此記錄?", + "clearHistoryConfirm": "確定清空聊天記錄?", + "contextLength": "上下文數量,預設10(會話開始的2條 + 最近的8條)", + "stopAnswer": "停止回答", + "slider": "上下文數量", + "temperature": "溫度", + "maxTokens": "最大問答總token數量", + "topP": "Top P", + "frequencyPenalty": "頻率懲罰", + "presencePenalty": "存在懲罰", + "debug": "調試模式" + }, + "setting": { + "admin": "管理", + "setting": "設置", + "general": "總覽", + "config": "配置", + "avatarLink": "頭像鏈接", + "name": "名稱", + "description": "描述", + "resetUserInfo": "重置用戶信息", + "chatHistory": "聊天記錄", + "theme": "主題", + "language": "語言", + "api": "API", + "reverseProxy": "反向代理", + "timeout": "超時", + "socks": "Socks" + }, + "admin": { + "title": "管理", + "permission": "權限", + "rateLimit": "限流" + } +} \ No newline at end of file diff --git a/web/src/locales/zh-TW.ts b/web/src/locales/zh-TW.ts deleted file mode 100644 index 157c1950..00000000 --- a/web/src/locales/zh-TW.ts +++ /dev/null @@ -1,61 +0,0 @@ -export default { - common: { - help: '第一個是主題(prompt),上下文包括10條信息', - edit: '編輯', - delete: '刪除', - save: '保存', - reset: '重置', - export: '匯出', - import: '匯入', - clear: '清空', - yes: '是', - no: '否', - noData: '暫無數據', - wrong: '好像出錯了,請稍後再試。', - success: '操作成功', - failed: '操作失敗', - verify: '註冊', - login: '登錄', - logout: '登出', - signup: '註冊', - email_placeholder: '請輸入電子郵件', - password_placeholder: '請輸入密碼', - unauthorizedTips: '請註冊或登錄', - }, - chat: { - placeholder: '說些什麼...(Shift + Enter = 換行)', - placeholderMobile: '說些什麼...', - copy: '複製', - copied: '複製成功', - copyCode: '複製代碼', - clearChat: '清空對話', - clearChatConfirm: '是否清空對話?', - exportImage: '導出對話到圖片', - exportImageConfirm: '是否將對話導出為圖片?', - exportSuccess: '導出成功', - exportFailed: '導出失敗', - usingContext: '上下文模式', - turnOnContext: '在此模式下,發送的消息將包括以前的聊天記錄。', - turnOffContext: '在此模式下,發送的消息將不包括以前的聊天記錄。', - deleteMessage: '刪除消息', - deleteMessageConfirm: '是否刪除此消息?', - deleteChatSessionsConfirm: '確定刪除此記錄?', - clearHistoryConfirm: '確定清空聊天記錄?', - }, - setting: { - setting: '設置', - general: '總覽', - config: '配置', - avatarLink: '頭像鏈接', - name: '名稱', - description: '描述', - resetUserInfo: '重置用戶信息', - chatHistory: '聊天記錄', - theme: '主題', - language: '語言', - api: 'API', - reverseProxy: '反向代理', - timeout: '超時', - socks: 'Socks', - }, -}