From 15b7cd6193408266ec28c69568749155bb5a249a Mon Sep 17 00:00:00 2001 From: ReeInk Date: Sat, 29 Apr 2023 18:10:27 +0800 Subject: [PATCH 1/5] feat: build docker image automatically --- .github/workflows/docker-image.yml | 45 ++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 .github/workflows/docker-image.yml diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml new file mode 100644 index 0000000..112a608 --- /dev/null +++ b/.github/workflows/docker-image.yml @@ -0,0 +1,45 @@ +# https://docs.github.com/en/actions/publishing-packages/publishing-docker-images#publishing-images-to-github-packages +name: Create and publish a Docker image + +on: + push: + branches: + - 'master' + tags: + - 'v*' + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push-image: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Log in to the Container registry + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v4 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + - name: Build and push Docker image + uses: docker/build-push-action@v4 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} From 601c36e6079e44c17567d0bec7917cbb7edfb874 Mon Sep 17 00:00:00 2001 From: ReeInk Date: Sat, 29 Apr 2023 19:53:43 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E4=BD=9C=E4=B8=BA=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.py | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/config.py b/config.py index 30c388e..ea1bb0c 100644 --- a/config.py +++ b/config.py @@ -1,8 +1,11 @@ +from os import environ + # [step 1]>> 例如: API_KEY = "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" (此key无效) -API_KEY = "sk-此处填API密钥" # 可同时填写多个API-KEY,用英文逗号分割,例如API_KEY = "sk-openaikey1,sk-openaikey2,fkxxxx-api2dkey1,fkxxxx-api2dkey2" +API_KEY = environ.get("GPT_ACADEMIC_API_KEY") or "sk-此处填API密钥" +# 可同时填写多个API-KEY,用英文逗号分割,例如API_KEY = "sk-openaikey1,sk-openaikey2,fkxxxx-api2dkey1,fkxxxx-api2dkey2" # [step 2]>> 改为True应用代理,如果直接在海外服务器部署,此处不修改 -USE_PROXY = False +USE_PROXY = environ.get("GPT_ACADEMIC_USE_PROXY") == "true" or False if USE_PROXY: # 填写格式是 [协议]:// [地址] :[端口],填写之前不要忘记把USE_PROXY改成True,如果直接在海外服务器部署,此处不修改 # 例如 "socks5h://localhost:11284" @@ -13,62 +16,70 @@ if USE_PROXY: # 代理网络的地址,打开你的*学*网软件查看代理的协议(socks5/http)、地址(localhost)和端口(11284) proxies = { # [协议]:// [地址] :[端口] - "http": "socks5h://localhost:11284", - "https": "socks5h://localhost:11284", + "http": environ.get("GPT_ACADEMIC_HTTP_PROXY") or "socks5h://localhost:11284", + "https": environ.get("GPT_ACADEMIC_HTTPS_PROXY") or "socks5h://localhost:11284", } else: proxies = None # [step 3]>> 多线程函数插件中,默认允许多少路线程同时访问OpenAI。Free trial users的限制是每分钟3次,Pay-as-you-go users的限制是每分钟3500次 # 一言以蔽之:免费用户填3,OpenAI绑了信用卡的用户可以填 16 或者更高。提高限制请查询:https://platform.openai.com/docs/guides/rate-limits/overview -DEFAULT_WORKER_NUM = 3 +DEFAULT_WORKER_NUM = int(environ.get("GPT_ACADEMIC_DEFAULT_WORKER_NUM") or 3) # [step 4]>> 以下配置可以优化体验,但大部分场合下并不需要修改 # 对话窗的高度 -CHATBOT_HEIGHT = 1115 +CHATBOT_HEIGHT = int(environ.get("GPT_ACADEMIC_CHATBOT_HEIGHT") or 1115) # 代码高亮 -CODE_HIGHLIGHT = True +CODE_HIGHLIGHT = environ.get("GPT_ACADEMIC_CODE_HIGHLIGHT") != "false" # 默认为True # 窗口布局 -LAYOUT = "LEFT-RIGHT" # "LEFT-RIGHT"(左右布局) # "TOP-DOWN"(上下布局) -DARK_MODE = True # "LEFT-RIGHT"(左右布局) # "TOP-DOWN"(上下布局) +LAYOUT = environ.get("GPT_ACADEMIC_LAYOUT") or "LEFT-RIGHT" # "LEFT-RIGHT"(左右布局) # "TOP-DOWN"(上下布局) +DARK_MODE = environ.get("GPT_ACADEMIC_DARK_MODE") == "true" # 是否启用暗色模式,默认为False # 发送请求到OpenAI后,等待多久判定为超时 -TIMEOUT_SECONDS = 30 +TIMEOUT_SECONDS = int(environ.get("GPT_ACADEMIC_TIMEOUT_SECONDS") or 30) # 网页的端口, -1代表随机端口 -WEB_PORT = -1 +WEB_PORT = int(environ.get("GPT_ACADEMIC_WEB_PORT") or -1) # 如果OpenAI不响应(网络卡顿、代理失败、KEY失效),重试的次数限制 -MAX_RETRY = 2 +MAX_RETRY = int(environ.get("GPT_ACADEMIC_MAX_RETRY") or 2) # OpenAI模型选择是(gpt4现在只对申请成功的人开放,体验gpt-4可以试试api2d) -LLM_MODEL = "gpt-3.5-turbo" # 可选 ↓↓↓ +LLM_MODEL = environ.get("GPT_ACADEMIC_LLM_MODEL") or "gpt-3.5-turbo" # 可选 ↓↓↓ AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "newbing"] # 本地LLM模型如ChatGLM的执行方式 CPU/GPU -LOCAL_MODEL_DEVICE = "cpu" # 可选 "cuda" +LOCAL_MODEL_DEVICE = environ.get("GPT_ACADEMIC_LOCAL_MODEL_DEVICE") or "cpu" # 可选 "cuda" # 设置gradio的并行线程数(不需要修改) -CONCURRENT_COUNT = 100 +CONCURRENT_COUNT = int(environ.get("GPT_ACADEMIC_CONCURRENT_COUNT") or 100) # 设置用户名和密码(不需要修改)(相关功能不稳定,与gradio版本和网络都相关,如果本地使用不建议加这个) # [("username", "password"), ("username2", "password2"), ...] AUTHENTICATION = [] +# 如果设置`GPT_ACADEMIC_AUTHENTICATION`环境变量,格式为 "username,password;username2,password2;..." +if environ.get("GPT_ACADEMIC_AUTHENTICATION"): + for i in environ.get("GPT_ACADEMIC_AUTHENTICATION").split(";"): + AUTHENTICATION.append(tuple(i.split(","))) # 重新URL重新定向,实现更换API_URL的作用(常规情况下,不要修改!!) # (高危设置!通过修改此设置,您将把您的API-KEY和对话隐私完全暴露给您设定的中间人!) # 格式 {"https://api.openai.com/v1/chat/completions": "在这里填写重定向的api.openai.com的URL"} # 例如 API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "https://ai.open.com/api/conversation"} API_URL_REDIRECT = {} +# 如果设置`GPT_ACADEMIC_API_URL_REDIRECT`环境变量,格式为 "https://api.openai.com/v1/chat/completions,https://ai.open.com/api/conversation;..." +if environ.get("GPT_ACADEMIC_API_URL_REDIRECT"): + for i in environ.get("GPT_ACADEMIC_API_URL_REDIRECT").split(";"): + API_URL_REDIRECT[i.split(",")[0]] = i.split(",")[1] # 如果需要在二级路径下运行(常规情况下,不要修改!!)(需要配合修改main.py才能生效!) -CUSTOM_PATH = "/" +CUSTOM_PATH = environ.get("GPT_ACADEMIC_CUSTOM_PATH") or "/" # 如果需要使用newbing,把newbing的长长的cookie放到这里 -NEWBING_STYLE = "creative" # ["creative", "balanced", "precise"] -NEWBING_COOKIES = """ +NEWBING_STYLE = environ.get("GPT_ACADEMIC_NEWBING_STYLE") or "creative" # ["creative", "balanced", "precise"] +NEWBING_COOKIES = environ.get("GPT_ACADEMIC_NEWBING_COOKIES") or """ your bing cookies here """ \ No newline at end of file From f187a23dc13985052842604e8f761dd4c5574f2a Mon Sep 17 00:00:00 2001 From: ReeInk Date: Sun, 30 Apr 2023 14:34:35 +0800 Subject: [PATCH 3/5] =?UTF-8?q?Revert=20"=E5=8A=A0=E8=BD=BD=E7=8E=AF?= =?UTF-8?q?=E5=A2=83=E5=8F=98=E9=87=8F=E4=BD=9C=E4=B8=BA=E9=85=8D=E7=BD=AE?= =?UTF-8?q?"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 601c36e6079e44c17567d0bec7917cbb7edfb874. --- config.py | 47 ++++++++++++++++++----------------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/config.py b/config.py index ea1bb0c..30c388e 100644 --- a/config.py +++ b/config.py @@ -1,11 +1,8 @@ -from os import environ - # [step 1]>> 例如: API_KEY = "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" (此key无效) -API_KEY = environ.get("GPT_ACADEMIC_API_KEY") or "sk-此处填API密钥" -# 可同时填写多个API-KEY,用英文逗号分割,例如API_KEY = "sk-openaikey1,sk-openaikey2,fkxxxx-api2dkey1,fkxxxx-api2dkey2" +API_KEY = "sk-此处填API密钥" # 可同时填写多个API-KEY,用英文逗号分割,例如API_KEY = "sk-openaikey1,sk-openaikey2,fkxxxx-api2dkey1,fkxxxx-api2dkey2" # [step 2]>> 改为True应用代理,如果直接在海外服务器部署,此处不修改 -USE_PROXY = environ.get("GPT_ACADEMIC_USE_PROXY") == "true" or False +USE_PROXY = False if USE_PROXY: # 填写格式是 [协议]:// [地址] :[端口],填写之前不要忘记把USE_PROXY改成True,如果直接在海外服务器部署,此处不修改 # 例如 "socks5h://localhost:11284" @@ -16,70 +13,62 @@ if USE_PROXY: # 代理网络的地址,打开你的*学*网软件查看代理的协议(socks5/http)、地址(localhost)和端口(11284) proxies = { # [协议]:// [地址] :[端口] - "http": environ.get("GPT_ACADEMIC_HTTP_PROXY") or "socks5h://localhost:11284", - "https": environ.get("GPT_ACADEMIC_HTTPS_PROXY") or "socks5h://localhost:11284", + "http": "socks5h://localhost:11284", + "https": "socks5h://localhost:11284", } else: proxies = None # [step 3]>> 多线程函数插件中,默认允许多少路线程同时访问OpenAI。Free trial users的限制是每分钟3次,Pay-as-you-go users的限制是每分钟3500次 # 一言以蔽之:免费用户填3,OpenAI绑了信用卡的用户可以填 16 或者更高。提高限制请查询:https://platform.openai.com/docs/guides/rate-limits/overview -DEFAULT_WORKER_NUM = int(environ.get("GPT_ACADEMIC_DEFAULT_WORKER_NUM") or 3) +DEFAULT_WORKER_NUM = 3 # [step 4]>> 以下配置可以优化体验,但大部分场合下并不需要修改 # 对话窗的高度 -CHATBOT_HEIGHT = int(environ.get("GPT_ACADEMIC_CHATBOT_HEIGHT") or 1115) +CHATBOT_HEIGHT = 1115 # 代码高亮 -CODE_HIGHLIGHT = environ.get("GPT_ACADEMIC_CODE_HIGHLIGHT") != "false" # 默认为True +CODE_HIGHLIGHT = True # 窗口布局 -LAYOUT = environ.get("GPT_ACADEMIC_LAYOUT") or "LEFT-RIGHT" # "LEFT-RIGHT"(左右布局) # "TOP-DOWN"(上下布局) -DARK_MODE = environ.get("GPT_ACADEMIC_DARK_MODE") == "true" # 是否启用暗色模式,默认为False +LAYOUT = "LEFT-RIGHT" # "LEFT-RIGHT"(左右布局) # "TOP-DOWN"(上下布局) +DARK_MODE = True # "LEFT-RIGHT"(左右布局) # "TOP-DOWN"(上下布局) # 发送请求到OpenAI后,等待多久判定为超时 -TIMEOUT_SECONDS = int(environ.get("GPT_ACADEMIC_TIMEOUT_SECONDS") or 30) +TIMEOUT_SECONDS = 30 # 网页的端口, -1代表随机端口 -WEB_PORT = int(environ.get("GPT_ACADEMIC_WEB_PORT") or -1) +WEB_PORT = -1 # 如果OpenAI不响应(网络卡顿、代理失败、KEY失效),重试的次数限制 -MAX_RETRY = int(environ.get("GPT_ACADEMIC_MAX_RETRY") or 2) +MAX_RETRY = 2 # OpenAI模型选择是(gpt4现在只对申请成功的人开放,体验gpt-4可以试试api2d) -LLM_MODEL = environ.get("GPT_ACADEMIC_LLM_MODEL") or "gpt-3.5-turbo" # 可选 ↓↓↓ +LLM_MODEL = "gpt-3.5-turbo" # 可选 ↓↓↓ AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "newbing"] # 本地LLM模型如ChatGLM的执行方式 CPU/GPU -LOCAL_MODEL_DEVICE = environ.get("GPT_ACADEMIC_LOCAL_MODEL_DEVICE") or "cpu" # 可选 "cuda" +LOCAL_MODEL_DEVICE = "cpu" # 可选 "cuda" # 设置gradio的并行线程数(不需要修改) -CONCURRENT_COUNT = int(environ.get("GPT_ACADEMIC_CONCURRENT_COUNT") or 100) +CONCURRENT_COUNT = 100 # 设置用户名和密码(不需要修改)(相关功能不稳定,与gradio版本和网络都相关,如果本地使用不建议加这个) # [("username", "password"), ("username2", "password2"), ...] AUTHENTICATION = [] -# 如果设置`GPT_ACADEMIC_AUTHENTICATION`环境变量,格式为 "username,password;username2,password2;..." -if environ.get("GPT_ACADEMIC_AUTHENTICATION"): - for i in environ.get("GPT_ACADEMIC_AUTHENTICATION").split(";"): - AUTHENTICATION.append(tuple(i.split(","))) # 重新URL重新定向,实现更换API_URL的作用(常规情况下,不要修改!!) # (高危设置!通过修改此设置,您将把您的API-KEY和对话隐私完全暴露给您设定的中间人!) # 格式 {"https://api.openai.com/v1/chat/completions": "在这里填写重定向的api.openai.com的URL"} # 例如 API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "https://ai.open.com/api/conversation"} API_URL_REDIRECT = {} -# 如果设置`GPT_ACADEMIC_API_URL_REDIRECT`环境变量,格式为 "https://api.openai.com/v1/chat/completions,https://ai.open.com/api/conversation;..." -if environ.get("GPT_ACADEMIC_API_URL_REDIRECT"): - for i in environ.get("GPT_ACADEMIC_API_URL_REDIRECT").split(";"): - API_URL_REDIRECT[i.split(",")[0]] = i.split(",")[1] # 如果需要在二级路径下运行(常规情况下,不要修改!!)(需要配合修改main.py才能生效!) -CUSTOM_PATH = environ.get("GPT_ACADEMIC_CUSTOM_PATH") or "/" +CUSTOM_PATH = "/" # 如果需要使用newbing,把newbing的长长的cookie放到这里 -NEWBING_STYLE = environ.get("GPT_ACADEMIC_NEWBING_STYLE") or "creative" # ["creative", "balanced", "precise"] -NEWBING_COOKIES = environ.get("GPT_ACADEMIC_NEWBING_COOKIES") or """ +NEWBING_STYLE = "creative" # ["creative", "balanced", "precise"] +NEWBING_COOKIES = """ your bing cookies here """ \ No newline at end of file From e5e3e0aa43d8db8b5d731dbabcb1f44d1fed7808 Mon Sep 17 00:00:00 2001 From: ReeInk Date: Sun, 30 Apr 2023 17:30:31 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E8=AF=BB=E5=8F=96=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E4=BD=9C=E4=B8=BA=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- toolbox.py | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/toolbox.py b/toolbox.py index 5e42164..81ef1ed 100644 --- a/toolbox.py +++ b/toolbox.py @@ -3,6 +3,7 @@ import importlib import traceback import inspect import re +import os from latex2mathml.converter import convert as tex2mathml from functools import wraps, lru_cache @@ -517,13 +518,63 @@ def select_api_key(keys, llm_model): api_key = random.choice(avail_key_list) # 随机负载均衡 return api_key +def read_single_conf_from_env(arg, default_value): + ENV_PREFIX = "GPT_ACADEMIC_" # 环境变量的前缀 + env_arg = ENV_PREFIX + arg # 环境变量的KEY + if arg == "proxies": + # 对于proxies,我们使用多个环境变量来配置 + # HTTP_PROXY: 对应http代理 + # HTTPS_PROXY: 对应https代理 + # ALL_PROXY: 对应http和https代理,优先级较HTTP_PROXY和HTTPS_PROXY更低 + http_proxy = os.environ.get(ENV_PREFIX + "HTTP_PROXY") or os.environ.get("ALL_PROXY") + assert http_proxy is not None, f"请设置环境变量{ENV_PREFIX + 'HTTP_PROXY'}" + https_proxy = os.environ.get(ENV_PREFIX + "HTTPS_PROXY") or os.environ.get("ALL_PROXY") + assert https_proxy is not None, f"请设置环境变量{ENV_PREFIX + 'HTTPS_PROXY'}" + r = { + "http": http_proxy, + "https": https_proxy + } + elif arg == "AVAIL_LLM_MODELS": + r = [] + # 对于AVAIL_LLM_MODELS的环境变量配置,我们允许用户使用;分隔多个模型 + for item in os.environ[env_arg].split(";"): + r.append(item) + elif arg == "AUTHENTICATION": + r = [] + # 对于AUTHENTICATION的环境变量配置,我们允许用户使用;分隔多个账号 + # 格式为:username1:password1;username2:password2 + for item in os.environ[env_arg].split(";"): + r.append(tuple(item.split(":"))) + elif arg == "API_URL_REDIRECT": + r = {} + # 对于API_URL_REDIRECT的环境变量配置,我们允许用户使用;分隔转发地址 + # 格式为:url1:redirect1;url2:redirect2 + for item in os.environ[env_arg].split(";"): + k, v = item.split(":") + r[k] = v + elif isinstance(default_value, bool): + r = bool(os.environ[env_arg]) + elif isinstance(default_value, int): + r = int(os.environ[env_arg]) + elif isinstance(default_value, float): + r = float(os.environ[env_arg]) + elif isinstance(default_value, str): + r = os.environ[env_arg] + else: + raise RuntimeError(f"[CONFIG] 环境变量{arg}不支持自动转换到{type(default_value)}类型") + return r + @lru_cache(maxsize=128) def read_single_conf_with_lru_cache(arg): from colorful import print亮红, print亮绿, print亮蓝 + default_r = getattr(importlib.import_module('config'), arg) try: - r = getattr(importlib.import_module('config_private'), arg) + r = read_single_conf_from_env(arg, default_r) # 优先获取环境变量作为配置 except: - r = getattr(importlib.import_module('config'), arg) + try: + r = getattr(importlib.import_module('config_private'), arg) + except: + r = default_r # 在读取API_KEY时,检查一下是不是忘了改config if arg == 'API_KEY': print亮蓝(f"[API_KEY] 本项目现已支持OpenAI和API2D的api-key。也支持同时填写多个api-key,如API_KEY=\"openai-key1,openai-key2,api2d-key3\"") From 8865b232ca68906f042a89fcdffbf3cf24907878 Mon Sep 17 00:00:00 2001 From: ReeInk Date: Tue, 2 May 2023 00:12:35 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=EF=BC=9A=E8=AF=BB?= =?UTF-8?q?=E5=8F=96=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8F=E9=87=8D=E5=AE=9A?= =?UTF-8?q?=E5=90=91URL=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- toolbox.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/toolbox.py b/toolbox.py index 81ef1ed..20a9abb 100644 --- a/toolbox.py +++ b/toolbox.py @@ -545,13 +545,11 @@ def read_single_conf_from_env(arg, default_value): # 格式为:username1:password1;username2:password2 for item in os.environ[env_arg].split(";"): r.append(tuple(item.split(":"))) - elif arg == "API_URL_REDIRECT": - r = {} - # 对于API_URL_REDIRECT的环境变量配置,我们允许用户使用;分隔转发地址 - # 格式为:url1:redirect1;url2:redirect2 - for item in os.environ[env_arg].split(";"): - k, v = item.split(":") - r[k] = v + elif arg == "API_URL_REDIRECT": + # 对于API_URL_REDIRECT的环境变量,我们允许用户使用json格式配置多个url重定向 + # 格式为一个json字符串,例如:{"https://api.openai.com/v1/chat/completions": "https://ai.open.com/api/conversation"} + import json + r = json.loads(os.environ[env_arg]) elif isinstance(default_value, bool): r = bool(os.environ[env_arg]) elif isinstance(default_value, int):