merge frontier branch (#1620)
* Zhipu sdk update 适配最新的智谱SDK,支持GLM4v (#1502) * 适配 google gemini 优化为从用户input中提取文件 * 适配最新的智谱SDK、支持glm-4v * requirements.txt fix * pending history check --------- Co-authored-by: binary-husky <qingxu.fu@outlook.com> * Update "生成多种Mermaid图表" plugin: Separate out the file reading function (#1520) * Update crazy_functional.py with new functionality deal with PDF * Update crazy_functional.py and Mermaid.py for plugin_kwargs * Update crazy_functional.py with new chart type: mind map * Update SELECT_PROMPT and i_say_show_user messages * Update ArgsReminder message in get_crazy_functions() function * Update with read md file and update PROMPTS * Return the PROMPTS as the test found that the initial version worked best * Update Mermaid chart generation function * version 3.71 * 解决issues #1510 * Remove unnecessary text from sys_prompt in 解析历史输入 function * Remove sys_prompt message in 解析历史输入 function * Update bridge_all.py: supports gpt-4-turbo-preview (#1517) * Update bridge_all.py: supports gpt-4-turbo-preview supports gpt-4-turbo-preview * Update bridge_all.py --------- Co-authored-by: binary-husky <96192199+binary-husky@users.noreply.github.com> * Update config.py: supports gpt-4-turbo-preview (#1516) * Update config.py: supports gpt-4-turbo-preview supports gpt-4-turbo-preview * Update config.py --------- Co-authored-by: binary-husky <96192199+binary-husky@users.noreply.github.com> * Refactor 解析历史输入 function to handle file input * Update Mermaid chart generation functionality * rename files and functions --------- Co-authored-by: binary-husky <qingxu.fu@outlook.com> Co-authored-by: hongyi-zhao <hongyi.zhao@gmail.com> Co-authored-by: binary-husky <96192199+binary-husky@users.noreply.github.com> * 接入mathpix ocr功能 (#1468) * Update Latex输出PDF结果.py 借助mathpix实现了PDF翻译中文并重新编译PDF * Update config.py add mathpix appid & appkey * Add 'PDF翻译中文并重新编译PDF' feature to plugins. --------- Co-authored-by: binary-husky <96192199+binary-husky@users.noreply.github.com> * fix zhipuai * check picture * remove glm-4 due to bug * 修改config * 检查MATHPIX_APPID * Remove unnecessary code and update function_plugins dictionary * capture non-standard token overflow * bug fix #1524 * change mermaid style * 支持mermaid 滚动放大缩小重置,鼠标滚动和拖拽 (#1530) * 支持mermaid 滚动放大缩小重置,鼠标滚动和拖拽 * 微调未果 先stage一下 * update --------- Co-authored-by: binary-husky <qingxu.fu@outlook.com> Co-authored-by: binary-husky <96192199+binary-husky@users.noreply.github.com> * ver 3.72 * change live2d * save the status of ``clear btn` in cookie * 前端选择保持 * js ui bug fix * reset btn bug fix * update live2d tips * fix missing get_token_num method * fix live2d toggle switch * fix persistent custom btn with cookie * fix zhipuai feedback with core functionality * Refactor button update and clean up functions * tailing space removal * Fix missing MATHPIX_APPID and MATHPIX_APPKEY configuration * Prompt fix、脑图提示词优化 (#1537) * 适配 google gemini 优化为从用户input中提取文件 * 脑图提示词优化 * Fix missing MATHPIX_APPID and MATHPIX_APPKEY configuration --------- Co-authored-by: binary-husky <qingxu.fu@outlook.com> * 优化“PDF翻译中文并重新编译PDF”插件 (#1602) * Add gemini_endpoint to API_URL_REDIRECT (#1560) * Add gemini_endpoint to API_URL_REDIRECT * Update gemini-pro and gemini-pro-vision model_info endpoints * Update to support new claude models (#1606) * Add anthropic library and update claude models * 更新bridge_claude.py文件,添加了对图片输入的支持。修复了一些bug。 * 添加Claude_3_Models变量以限制图片数量 * Refactor code to improve readability and maintainability * minor claude bug fix * more flexible one-api support * reformat config * fix one-api new access bug * dummy * compat non-standard api * version 3.73 --------- Co-authored-by: XIao <46100050+Kilig947@users.noreply.github.com> Co-authored-by: Menghuan1918 <menghuan2003@outlook.com> Co-authored-by: hongyi-zhao <hongyi.zhao@gmail.com> Co-authored-by: Hao Ma <893017927@qq.com> Co-authored-by: zeyuan huang <599012428@qq.com>
This commit is contained in:
parent
cd18663800
commit
c3140ce344
@ -47,7 +47,7 @@ def backup_and_download(current_version, remote_version):
|
|||||||
shutil.copytree('./', backup_dir, ignore=lambda x, y: ['history'])
|
shutil.copytree('./', backup_dir, ignore=lambda x, y: ['history'])
|
||||||
proxies = get_conf('proxies')
|
proxies = get_conf('proxies')
|
||||||
try: r = requests.get('https://github.com/binary-husky/chatgpt_academic/archive/refs/heads/master.zip', proxies=proxies, stream=True)
|
try: r = requests.get('https://github.com/binary-husky/chatgpt_academic/archive/refs/heads/master.zip', proxies=proxies, stream=True)
|
||||||
except: r = requests.get('https://public.gpt-academic.top/publish/master.zip', proxies=proxies, stream=True)
|
except: r = requests.get('https://public.agent-matrix.com/publish/master.zip', proxies=proxies, stream=True)
|
||||||
zip_file_path = backup_dir+'/master.zip'
|
zip_file_path = backup_dir+'/master.zip'
|
||||||
with open(zip_file_path, 'wb+') as f:
|
with open(zip_file_path, 'wb+') as f:
|
||||||
f.write(r.content)
|
f.write(r.content)
|
||||||
@ -113,7 +113,7 @@ def auto_update(raise_error=False):
|
|||||||
import json
|
import json
|
||||||
proxies = get_conf('proxies')
|
proxies = get_conf('proxies')
|
||||||
try: response = requests.get("https://raw.githubusercontent.com/binary-husky/chatgpt_academic/master/version", proxies=proxies, timeout=5)
|
try: response = requests.get("https://raw.githubusercontent.com/binary-husky/chatgpt_academic/master/version", proxies=proxies, timeout=5)
|
||||||
except: response = requests.get("https://public.gpt-academic.top/publish/version", proxies=proxies, timeout=5)
|
except: response = requests.get("https://public.agent-matrix.com/publish/version", proxies=proxies, timeout=5)
|
||||||
remote_json_data = json.loads(response.text)
|
remote_json_data = json.loads(response.text)
|
||||||
remote_version = remote_json_data['version']
|
remote_version = remote_json_data['version']
|
||||||
if remote_json_data["show_feature"]:
|
if remote_json_data["show_feature"]:
|
||||||
|
75
config.py
75
config.py
@ -30,7 +30,32 @@ if USE_PROXY:
|
|||||||
else:
|
else:
|
||||||
proxies = None
|
proxies = None
|
||||||
|
|
||||||
# ------------------------------------ 以下配置可以优化体验, 但大部分场合下并不需要修改 ------------------------------------
|
# [step 3]>> 模型选择是 (注意: LLM_MODEL是默认选中的模型, 它*必须*被包含在AVAIL_LLM_MODELS列表中 )
|
||||||
|
LLM_MODEL = "gpt-3.5-turbo-16k" # 可选 ↓↓↓
|
||||||
|
AVAIL_LLM_MODELS = ["gpt-4-1106-preview", "gpt-4-turbo-preview", "gpt-4-vision-preview",
|
||||||
|
"gpt-3.5-turbo-1106", "gpt-3.5-turbo-16k", "gpt-3.5-turbo", "azure-gpt-3.5",
|
||||||
|
"gpt-4", "gpt-4-32k", "azure-gpt-4", "glm-4", "glm-3-turbo",
|
||||||
|
"gemini-pro", "chatglm3"
|
||||||
|
]
|
||||||
|
# --- --- --- ---
|
||||||
|
# P.S. 其他可用的模型还包括
|
||||||
|
# AVAIL_LLM_MODELS = [
|
||||||
|
# "qianfan", "deepseekcoder",
|
||||||
|
# "spark", "sparkv2", "sparkv3", "sparkv3.5",
|
||||||
|
# "qwen-turbo", "qwen-plus", "qwen-max", "qwen-local",
|
||||||
|
# "moonshot-v1-128k", "moonshot-v1-32k", "moonshot-v1-8k",
|
||||||
|
# "gpt-3.5-turbo-0613", "gpt-3.5-turbo-16k-0613", "gpt-3.5-turbo-0125"
|
||||||
|
# "claude-3-sonnet-20240229","claude-3-opus-20240229", "claude-2.1", "claude-instant-1.2",
|
||||||
|
# "moss", "llama2", "chatglm_onnx", "internlm", "jittorllms_pangualpha", "jittorllms_llama",
|
||||||
|
# ]
|
||||||
|
# --- --- --- ---
|
||||||
|
# 此外,为了更灵活地接入one-api多模型管理界面,您还可以在接入one-api时,
|
||||||
|
# 使用"one-api-*"前缀直接使用非标准方式接入的模型,例如
|
||||||
|
# AVAIL_LLM_MODELS = ["one-api-claude-3-sonnet-20240229(max_token=100000)"]
|
||||||
|
# --- --- --- ---
|
||||||
|
|
||||||
|
|
||||||
|
# --------------- 以下配置可以优化体验 ---------------
|
||||||
|
|
||||||
# 重新URL重新定向,实现更换API_URL的作用(高危设置! 常规情况下不要修改! 通过修改此设置,您将把您的API-KEY和对话隐私完全暴露给您设定的中间人!)
|
# 重新URL重新定向,实现更换API_URL的作用(高危设置! 常规情况下不要修改! 通过修改此设置,您将把您的API-KEY和对话隐私完全暴露给您设定的中间人!)
|
||||||
# 格式: API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "在这里填写重定向的api.openai.com的URL"}
|
# 格式: API_URL_REDIRECT = {"https://api.openai.com/v1/chat/completions": "在这里填写重定向的api.openai.com的URL"}
|
||||||
@ -85,22 +110,6 @@ MAX_RETRY = 2
|
|||||||
DEFAULT_FN_GROUPS = ['对话', '编程', '学术', '智能体']
|
DEFAULT_FN_GROUPS = ['对话', '编程', '学术', '智能体']
|
||||||
|
|
||||||
|
|
||||||
# 模型选择是 (注意: LLM_MODEL是默认选中的模型, 它*必须*被包含在AVAIL_LLM_MODELS列表中 )
|
|
||||||
LLM_MODEL = "gpt-3.5-turbo-16k" # 可选 ↓↓↓
|
|
||||||
AVAIL_LLM_MODELS = ["gpt-4-1106-preview", "gpt-4-turbo-preview", "gpt-4-vision-preview",
|
|
||||||
"gpt-3.5-turbo-1106", "gpt-3.5-turbo-16k", "gpt-3.5-turbo", "azure-gpt-3.5",
|
|
||||||
"gpt-4", "gpt-4-32k", "azure-gpt-4", "glm-4", "glm-3-turbo",
|
|
||||||
"gemini-pro", "chatglm3", "claude-2"]
|
|
||||||
# P.S. 其他可用的模型还包括 [
|
|
||||||
# "moonshot-v1-128k", "moonshot-v1-32k", "moonshot-v1-8k",
|
|
||||||
# "qwen-turbo", "qwen-plus", "qwen-max",
|
|
||||||
# "zhipuai", "qianfan", "deepseekcoder", "llama2", "qwen-local", "gpt-3.5-turbo-0613", "moss",
|
|
||||||
# "gpt-3.5-turbo-16k-0613", "gpt-3.5-random", "api2d-gpt-3.5-turbo", 'api2d-gpt-3.5-turbo-16k',
|
|
||||||
# "spark", "sparkv2", "sparkv3", "sparkv3.5",
|
|
||||||
# "chatglm_onnx", "claude-1-100k", "claude-2", "internlm", "jittorllms_pangualpha", "jittorllms_llama"
|
|
||||||
# ]
|
|
||||||
|
|
||||||
|
|
||||||
# 定义界面上“询问多个GPT模型”插件应该使用哪些模型,请从AVAIL_LLM_MODELS中选择,并在不同模型之间用`&`间隔,例如"gpt-3.5-turbo&chatglm3&azure-gpt-4"
|
# 定义界面上“询问多个GPT模型”插件应该使用哪些模型,请从AVAIL_LLM_MODELS中选择,并在不同模型之间用`&`间隔,例如"gpt-3.5-turbo&chatglm3&azure-gpt-4"
|
||||||
MULTI_QUERY_LLM_MODELS = "gpt-3.5-turbo&chatglm3"
|
MULTI_QUERY_LLM_MODELS = "gpt-3.5-turbo&chatglm3"
|
||||||
|
|
||||||
@ -129,6 +138,7 @@ CHATGLM_PTUNING_CHECKPOINT = "" # 例如"/home/hmp/ChatGLM2-6B/ptuning/output/6b
|
|||||||
LOCAL_MODEL_DEVICE = "cpu" # 可选 "cuda"
|
LOCAL_MODEL_DEVICE = "cpu" # 可选 "cuda"
|
||||||
LOCAL_MODEL_QUANT = "FP16" # 默认 "FP16" "INT4" 启用量化INT4版本 "INT8" 启用量化INT8版本
|
LOCAL_MODEL_QUANT = "FP16" # 默认 "FP16" "INT4" 启用量化INT4版本 "INT8" 启用量化INT8版本
|
||||||
|
|
||||||
|
|
||||||
# 设置gradio的并行线程数(不需要修改)
|
# 设置gradio的并行线程数(不需要修改)
|
||||||
CONCURRENT_COUNT = 100
|
CONCURRENT_COUNT = 100
|
||||||
|
|
||||||
@ -174,14 +184,8 @@ AZURE_ENGINE = "填入你亲手写的部署名" # 读 docs\use_azure.
|
|||||||
AZURE_CFG_ARRAY = {}
|
AZURE_CFG_ARRAY = {}
|
||||||
|
|
||||||
|
|
||||||
# 使用Newbing (不推荐使用,未来将删除)
|
# 阿里云实时语音识别 配置难度较高
|
||||||
NEWBING_STYLE = "creative" # ["creative", "balanced", "precise"]
|
# 参考 https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md
|
||||||
NEWBING_COOKIES = """
|
|
||||||
put your new bing cookies here
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
# 阿里云实时语音识别 配置难度较高 仅建议高手用户使用 参考 https://github.com/binary-husky/gpt_academic/blob/master/docs/use_audio.md
|
|
||||||
ENABLE_AUDIO = False
|
ENABLE_AUDIO = False
|
||||||
ALIYUN_TOKEN="" # 例如 f37f30e0f9934c34a992f6f64f7eba4f
|
ALIYUN_TOKEN="" # 例如 f37f30e0f9934c34a992f6f64f7eba4f
|
||||||
ALIYUN_APPKEY="" # 例如 RoPlZrM88DnAFkZK
|
ALIYUN_APPKEY="" # 例如 RoPlZrM88DnAFkZK
|
||||||
@ -200,18 +204,14 @@ ZHIPUAI_API_KEY = ""
|
|||||||
ZHIPUAI_MODEL = "" # 此选项已废弃,不再需要填写
|
ZHIPUAI_MODEL = "" # 此选项已废弃,不再需要填写
|
||||||
|
|
||||||
|
|
||||||
# # 火山引擎YUNQUE大模型
|
|
||||||
# YUNQUE_SECRET_KEY = ""
|
|
||||||
# YUNQUE_ACCESS_KEY = ""
|
|
||||||
# YUNQUE_MODEL = ""
|
|
||||||
|
|
||||||
|
|
||||||
# Claude API KEY
|
# Claude API KEY
|
||||||
ANTHROPIC_API_KEY = ""
|
ANTHROPIC_API_KEY = ""
|
||||||
|
|
||||||
|
|
||||||
# 月之暗面 API KEY
|
# 月之暗面 API KEY
|
||||||
MOONSHOT_API_KEY = ""
|
MOONSHOT_API_KEY = ""
|
||||||
|
|
||||||
|
|
||||||
# Mathpix 拥有执行PDF的OCR功能,但是需要注册账号
|
# Mathpix 拥有执行PDF的OCR功能,但是需要注册账号
|
||||||
MATHPIX_APPID = ""
|
MATHPIX_APPID = ""
|
||||||
MATHPIX_APPKEY = ""
|
MATHPIX_APPKEY = ""
|
||||||
@ -270,7 +270,11 @@ PLUGIN_HOT_RELOAD = False
|
|||||||
# 自定义按钮的最大数量限制
|
# 自定义按钮的最大数量限制
|
||||||
NUM_CUSTOM_BASIC_BTN = 4
|
NUM_CUSTOM_BASIC_BTN = 4
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
--------------- 配置关联关系说明 ---------------
|
||||||
|
|
||||||
在线大模型配置关联关系示意图
|
在线大模型配置关联关系示意图
|
||||||
│
|
│
|
||||||
├── "gpt-3.5-turbo" 等openai模型
|
├── "gpt-3.5-turbo" 等openai模型
|
||||||
@ -294,7 +298,7 @@ NUM_CUSTOM_BASIC_BTN = 4
|
|||||||
│ ├── XFYUN_API_SECRET
|
│ ├── XFYUN_API_SECRET
|
||||||
│ └── XFYUN_API_KEY
|
│ └── XFYUN_API_KEY
|
||||||
│
|
│
|
||||||
├── "claude-1-100k" 等claude模型
|
├── "claude-3-opus-20240229" 等claude模型
|
||||||
│ └── ANTHROPIC_API_KEY
|
│ └── ANTHROPIC_API_KEY
|
||||||
│
|
│
|
||||||
├── "stack-claude"
|
├── "stack-claude"
|
||||||
@ -315,9 +319,10 @@ NUM_CUSTOM_BASIC_BTN = 4
|
|||||||
├── "Gemini"
|
├── "Gemini"
|
||||||
│ └── GEMINI_API_KEY
|
│ └── GEMINI_API_KEY
|
||||||
│
|
│
|
||||||
└── "newbing" Newbing接口不再稳定,不推荐使用
|
└── "one-api-...(max_token=...)" 用一种更方便的方式接入one-api多模型管理界面
|
||||||
├── NEWBING_STYLE
|
├── AVAIL_LLM_MODELS
|
||||||
└── NEWBING_COOKIES
|
├── API_KEY
|
||||||
|
└── API_URL_REDIRECT
|
||||||
|
|
||||||
|
|
||||||
本地大模型示意图
|
本地大模型示意图
|
||||||
|
@ -38,12 +38,12 @@ def get_core_functions():
|
|||||||
|
|
||||||
"总结绘制脑图": {
|
"总结绘制脑图": {
|
||||||
# 前缀,会被加在你的输入之前。例如,用来描述你的要求,例如翻译、解释代码、润色等等
|
# 前缀,会被加在你的输入之前。例如,用来描述你的要求,例如翻译、解释代码、润色等等
|
||||||
"Prefix": r"",
|
"Prefix": '''"""\n\n''',
|
||||||
# 后缀,会被加在你的输入之后。例如,配合前缀可以把你的输入内容用引号圈起来
|
# 后缀,会被加在你的输入之后。例如,配合前缀可以把你的输入内容用引号圈起来
|
||||||
"Suffix":
|
"Suffix":
|
||||||
# dedent() 函数用于去除多行字符串的缩进
|
# dedent() 函数用于去除多行字符串的缩进
|
||||||
dedent("\n"+r'''
|
dedent("\n\n"+r'''
|
||||||
==============================
|
"""
|
||||||
|
|
||||||
使用mermaid flowchart对以上文本进行总结,概括上述段落的内容以及内在逻辑关系,例如:
|
使用mermaid flowchart对以上文本进行总结,概括上述段落的内容以及内在逻辑关系,例如:
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ def get_core_functions():
|
|||||||
C --> |"箭头名2"| F["节点名6"]
|
C --> |"箭头名2"| F["节点名6"]
|
||||||
```
|
```
|
||||||
|
|
||||||
警告:
|
注意:
|
||||||
(1)使用中文
|
(1)使用中文
|
||||||
(2)节点名字使用引号包裹,如["Laptop"]
|
(2)节点名字使用引号包裹,如["Laptop"]
|
||||||
(3)`|` 和 `"`之间不要存在空格
|
(3)`|` 和 `"`之间不要存在空格
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from toolbox import update_ui, trimmed_format_exc, get_conf, get_log_folder, promote_file_to_downloadzone
|
from toolbox import update_ui, trimmed_format_exc, get_conf, get_log_folder, promote_file_to_downloadzone, check_repeat_upload, map_file_to_sha256
|
||||||
from toolbox import CatchException, report_exception, update_ui_lastest_msg, zip_result, gen_time_str
|
from toolbox import CatchException, report_exception, update_ui_lastest_msg, zip_result, gen_time_str
|
||||||
from functools import partial
|
from functools import partial
|
||||||
import glob, os, requests, time, json, tarfile
|
import glob, os, requests, time, json, tarfile
|
||||||
@ -438,47 +438,101 @@ def PDF翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, h
|
|||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
return
|
return
|
||||||
|
|
||||||
# <-------------- convert pdf into tex ------------->
|
hash_tag = map_file_to_sha256(file_manifest[0])
|
||||||
project_folder = pdf2tex_project(file_manifest[0])
|
|
||||||
|
|
||||||
# Translate English Latex to Chinese Latex, and compile it
|
# <-------------- check repeated pdf ------------->
|
||||||
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)]
|
chatbot.append([f"检查PDF是否被重复上传", "正在检查..."])
|
||||||
if len(file_manifest) == 0:
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.tex文件: {txt}")
|
repeat, project_folder = check_repeat_upload(file_manifest[0], hash_tag)
|
||||||
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
|
||||||
return
|
|
||||||
|
|
||||||
# <-------------- if is a zip/tar file ------------->
|
except_flag = False
|
||||||
project_folder = desend_to_extracted_folder_if_exist(project_folder)
|
|
||||||
|
|
||||||
# <-------------- move latex project away from temp folder ------------->
|
if repeat:
|
||||||
project_folder = move_project(project_folder)
|
yield from update_ui_lastest_msg(f"发现重复上传,请查收结果(压缩包)...", chatbot=chatbot, history=history)
|
||||||
|
|
||||||
# <-------------- if merge_translate_zh is already generated, skip gpt req ------------->
|
try:
|
||||||
if not os.path.exists(project_folder + '/merge_translate_zh.tex'):
|
trans_html_file = [f for f in glob.glob(f'{project_folder}/**/*.trans.html', recursive=True)][0]
|
||||||
yield from Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin_kwargs,
|
promote_file_to_downloadzone(trans_html_file, rename_file=None, chatbot=chatbot)
|
||||||
chatbot, history, system_prompt, mode='translate_zh',
|
|
||||||
switch_prompt=_switch_prompt_)
|
|
||||||
|
|
||||||
# <-------------- compile PDF ------------->
|
translate_pdf = [f for f in glob.glob(f'{project_folder}/**/merge_translate_zh.pdf', recursive=True)][0]
|
||||||
success = yield from 编译Latex(chatbot, history, main_file_original='merge',
|
promote_file_to_downloadzone(translate_pdf, rename_file=None, chatbot=chatbot)
|
||||||
main_file_modified='merge_translate_zh', mode='translate_zh',
|
|
||||||
work_folder_original=project_folder, work_folder_modified=project_folder,
|
|
||||||
work_folder=project_folder)
|
|
||||||
|
|
||||||
# <-------------- zip PDF ------------->
|
comparison_pdf = [f for f in glob.glob(f'{project_folder}/**/comparison.pdf', recursive=True)][0]
|
||||||
zip_res = zip_result(project_folder)
|
promote_file_to_downloadzone(comparison_pdf, rename_file=None, chatbot=chatbot)
|
||||||
if success:
|
|
||||||
chatbot.append((f"成功啦", '请查收结果(压缩包)...'))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history);
|
|
||||||
time.sleep(1) # 刷新界面
|
|
||||||
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
|
||||||
else:
|
|
||||||
chatbot.append((f"失败了",
|
|
||||||
'虽然PDF生成失败了, 但请查收结果(压缩包), 内含已经翻译的Tex文档, 您可以到Github Issue区, 用该压缩包进行反馈。如系统是Linux,请检查系统字体(见Github wiki) ...'))
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history);
|
|
||||||
time.sleep(1) # 刷新界面
|
|
||||||
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
|
||||||
|
|
||||||
# <-------------- we are done ------------->
|
zip_res = zip_result(project_folder)
|
||||||
return success
|
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
except:
|
||||||
|
report_exception(chatbot, history, b=f"发现重复上传,但是无法找到相关文件")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
|
||||||
|
chatbot.append([f"没有相关文件", '尝试重新翻译PDF...'])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
|
||||||
|
except_flag = True
|
||||||
|
|
||||||
|
|
||||||
|
elif not repeat or except_flag:
|
||||||
|
yield from update_ui_lastest_msg(f"未发现重复上传", chatbot=chatbot, history=history)
|
||||||
|
|
||||||
|
# <-------------- convert pdf into tex ------------->
|
||||||
|
chatbot.append([f"解析项目: {txt}", "正在将PDF转换为tex项目,请耐心等待..."])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
project_folder = pdf2tex_project(file_manifest[0])
|
||||||
|
if project_folder is None:
|
||||||
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"PDF转换为tex项目失败")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# <-------------- translate latex file into Chinese ------------->
|
||||||
|
yield from update_ui_lastest_msg("正在tex项目将翻译为中文...", chatbot=chatbot, history=history)
|
||||||
|
file_manifest = [f for f in glob.glob(f'{project_folder}/**/*.tex', recursive=True)]
|
||||||
|
if len(file_manifest) == 0:
|
||||||
|
report_exception(chatbot, history, a=f"解析项目: {txt}", b=f"找不到任何.tex文件: {txt}")
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
|
||||||
|
return
|
||||||
|
|
||||||
|
# <-------------- if is a zip/tar file ------------->
|
||||||
|
project_folder = desend_to_extracted_folder_if_exist(project_folder)
|
||||||
|
|
||||||
|
# <-------------- move latex project away from temp folder ------------->
|
||||||
|
project_folder = move_project(project_folder)
|
||||||
|
|
||||||
|
# <-------------- set a hash tag for repeat-checking ------------->
|
||||||
|
with open(pj(project_folder, hash_tag + '.tag'), 'w') as f:
|
||||||
|
f.write(hash_tag)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
|
# <-------------- if merge_translate_zh is already generated, skip gpt req ------------->
|
||||||
|
if not os.path.exists(project_folder + '/merge_translate_zh.tex'):
|
||||||
|
yield from Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin_kwargs,
|
||||||
|
chatbot, history, system_prompt, mode='translate_zh',
|
||||||
|
switch_prompt=_switch_prompt_)
|
||||||
|
|
||||||
|
# <-------------- compile PDF ------------->
|
||||||
|
yield from update_ui_lastest_msg("正在将翻译好的项目tex项目编译为PDF...", chatbot=chatbot, history=history)
|
||||||
|
success = yield from 编译Latex(chatbot, history, main_file_original='merge',
|
||||||
|
main_file_modified='merge_translate_zh', mode='translate_zh',
|
||||||
|
work_folder_original=project_folder, work_folder_modified=project_folder,
|
||||||
|
work_folder=project_folder)
|
||||||
|
|
||||||
|
# <-------------- zip PDF ------------->
|
||||||
|
zip_res = zip_result(project_folder)
|
||||||
|
if success:
|
||||||
|
chatbot.append((f"成功啦", '请查收结果(压缩包)...'))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history);
|
||||||
|
time.sleep(1) # 刷新界面
|
||||||
|
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
||||||
|
else:
|
||||||
|
chatbot.append((f"失败了",
|
||||||
|
'虽然PDF生成失败了, 但请查收结果(压缩包), 内含已经翻译的Tex文档, 您可以到Github Issue区, 用该压缩包进行反馈。如系统是Linux,请检查系统字体(见Github wiki) ...'))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history);
|
||||||
|
time.sleep(1) # 刷新界面
|
||||||
|
promote_file_to_downloadzone(file=zip_res, chatbot=chatbot)
|
||||||
|
|
||||||
|
# <-------------- we are done ------------->
|
||||||
|
return success
|
||||||
|
@ -8,10 +8,10 @@
|
|||||||
具备多线程调用能力的函数:在函数插件中被调用,灵活而简洁
|
具备多线程调用能力的函数:在函数插件中被调用,灵活而简洁
|
||||||
2. predict_no_ui_long_connection(...)
|
2. predict_no_ui_long_connection(...)
|
||||||
"""
|
"""
|
||||||
import tiktoken, copy
|
import tiktoken, copy, re
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from toolbox import get_conf, trimmed_format_exc, apply_gpt_academic_string_mask
|
from toolbox import get_conf, trimmed_format_exc, apply_gpt_academic_string_mask, read_one_api_model_name
|
||||||
|
|
||||||
from .bridge_chatgpt import predict_no_ui_long_connection as chatgpt_noui
|
from .bridge_chatgpt import predict_no_ui_long_connection as chatgpt_noui
|
||||||
from .bridge_chatgpt import predict as chatgpt_ui
|
from .bridge_chatgpt import predict as chatgpt_ui
|
||||||
@ -61,6 +61,9 @@ API_URL_REDIRECT, AZURE_ENDPOINT, AZURE_ENGINE = get_conf("API_URL_REDIRECT", "A
|
|||||||
openai_endpoint = "https://api.openai.com/v1/chat/completions"
|
openai_endpoint = "https://api.openai.com/v1/chat/completions"
|
||||||
api2d_endpoint = "https://openai.api2d.net/v1/chat/completions"
|
api2d_endpoint = "https://openai.api2d.net/v1/chat/completions"
|
||||||
newbing_endpoint = "wss://sydney.bing.com/sydney/ChatHub"
|
newbing_endpoint = "wss://sydney.bing.com/sydney/ChatHub"
|
||||||
|
gemini_endpoint = "https://generativelanguage.googleapis.com/v1beta/models"
|
||||||
|
claude_endpoint = "https://api.anthropic.com"
|
||||||
|
|
||||||
if not AZURE_ENDPOINT.endswith('/'): AZURE_ENDPOINT += '/'
|
if not AZURE_ENDPOINT.endswith('/'): AZURE_ENDPOINT += '/'
|
||||||
azure_endpoint = AZURE_ENDPOINT + f'openai/deployments/{AZURE_ENGINE}/chat/completions?api-version=2023-05-15'
|
azure_endpoint = AZURE_ENDPOINT + f'openai/deployments/{AZURE_ENGINE}/chat/completions?api-version=2023-05-15'
|
||||||
# 兼容旧版的配置
|
# 兼容旧版的配置
|
||||||
@ -75,7 +78,8 @@ except:
|
|||||||
if openai_endpoint in API_URL_REDIRECT: openai_endpoint = API_URL_REDIRECT[openai_endpoint]
|
if openai_endpoint in API_URL_REDIRECT: openai_endpoint = API_URL_REDIRECT[openai_endpoint]
|
||||||
if api2d_endpoint in API_URL_REDIRECT: api2d_endpoint = API_URL_REDIRECT[api2d_endpoint]
|
if api2d_endpoint in API_URL_REDIRECT: api2d_endpoint = API_URL_REDIRECT[api2d_endpoint]
|
||||||
if newbing_endpoint in API_URL_REDIRECT: newbing_endpoint = API_URL_REDIRECT[newbing_endpoint]
|
if newbing_endpoint in API_URL_REDIRECT: newbing_endpoint = API_URL_REDIRECT[newbing_endpoint]
|
||||||
|
if gemini_endpoint in API_URL_REDIRECT: gemini_endpoint = API_URL_REDIRECT[gemini_endpoint]
|
||||||
|
if claude_endpoint in API_URL_REDIRECT: claude_endpoint = API_URL_REDIRECT[claude_endpoint]
|
||||||
|
|
||||||
# 获取tokenizer
|
# 获取tokenizer
|
||||||
tokenizer_gpt35 = LazyloadTiktoken("gpt-3.5-turbo")
|
tokenizer_gpt35 = LazyloadTiktoken("gpt-3.5-turbo")
|
||||||
@ -291,7 +295,7 @@ model_info = {
|
|||||||
"gemini-pro": {
|
"gemini-pro": {
|
||||||
"fn_with_ui": genai_ui,
|
"fn_with_ui": genai_ui,
|
||||||
"fn_without_ui": genai_noui,
|
"fn_without_ui": genai_noui,
|
||||||
"endpoint": None,
|
"endpoint": gemini_endpoint,
|
||||||
"max_token": 1024 * 32,
|
"max_token": 1024 * 32,
|
||||||
"tokenizer": tokenizer_gpt35,
|
"tokenizer": tokenizer_gpt35,
|
||||||
"token_cnt": get_token_num_gpt35,
|
"token_cnt": get_token_num_gpt35,
|
||||||
@ -299,7 +303,7 @@ model_info = {
|
|||||||
"gemini-pro-vision": {
|
"gemini-pro-vision": {
|
||||||
"fn_with_ui": genai_ui,
|
"fn_with_ui": genai_ui,
|
||||||
"fn_without_ui": genai_noui,
|
"fn_without_ui": genai_noui,
|
||||||
"endpoint": None,
|
"endpoint": gemini_endpoint,
|
||||||
"max_token": 1024 * 32,
|
"max_token": 1024 * 32,
|
||||||
"tokenizer": tokenizer_gpt35,
|
"tokenizer": tokenizer_gpt35,
|
||||||
"token_cnt": get_token_num_gpt35,
|
"token_cnt": get_token_num_gpt35,
|
||||||
@ -349,25 +353,57 @@ for model in AVAIL_LLM_MODELS:
|
|||||||
model_info.update({model: mi})
|
model_info.update({model: mi})
|
||||||
|
|
||||||
# -=-=-=-=-=-=- 以下部分是新加入的模型,可能附带额外依赖 -=-=-=-=-=-=-
|
# -=-=-=-=-=-=- 以下部分是新加入的模型,可能附带额外依赖 -=-=-=-=-=-=-
|
||||||
if "claude-1-100k" in AVAIL_LLM_MODELS or "claude-2" in AVAIL_LLM_MODELS:
|
# claude家族
|
||||||
|
claude_models = ["claude-instant-1.2","claude-2.0","claude-2.1","claude-3-sonnet-20240229","claude-3-opus-20240229"]
|
||||||
|
if any(item in claude_models for item in AVAIL_LLM_MODELS):
|
||||||
from .bridge_claude import predict_no_ui_long_connection as claude_noui
|
from .bridge_claude import predict_no_ui_long_connection as claude_noui
|
||||||
from .bridge_claude import predict as claude_ui
|
from .bridge_claude import predict as claude_ui
|
||||||
model_info.update({
|
model_info.update({
|
||||||
"claude-1-100k": {
|
"claude-instant-1.2": {
|
||||||
"fn_with_ui": claude_ui,
|
"fn_with_ui": claude_ui,
|
||||||
"fn_without_ui": claude_noui,
|
"fn_without_ui": claude_noui,
|
||||||
"endpoint": None,
|
"endpoint": claude_endpoint,
|
||||||
"max_token": 8196,
|
"max_token": 100000,
|
||||||
"tokenizer": tokenizer_gpt35,
|
"tokenizer": tokenizer_gpt35,
|
||||||
"token_cnt": get_token_num_gpt35,
|
"token_cnt": get_token_num_gpt35,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
model_info.update({
|
model_info.update({
|
||||||
"claude-2": {
|
"claude-2.0": {
|
||||||
"fn_with_ui": claude_ui,
|
"fn_with_ui": claude_ui,
|
||||||
"fn_without_ui": claude_noui,
|
"fn_without_ui": claude_noui,
|
||||||
"endpoint": None,
|
"endpoint": claude_endpoint,
|
||||||
"max_token": 8196,
|
"max_token": 100000,
|
||||||
|
"tokenizer": tokenizer_gpt35,
|
||||||
|
"token_cnt": get_token_num_gpt35,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
model_info.update({
|
||||||
|
"claude-2.1": {
|
||||||
|
"fn_with_ui": claude_ui,
|
||||||
|
"fn_without_ui": claude_noui,
|
||||||
|
"endpoint": claude_endpoint,
|
||||||
|
"max_token": 200000,
|
||||||
|
"tokenizer": tokenizer_gpt35,
|
||||||
|
"token_cnt": get_token_num_gpt35,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
model_info.update({
|
||||||
|
"claude-3-sonnet-20240229": {
|
||||||
|
"fn_with_ui": claude_ui,
|
||||||
|
"fn_without_ui": claude_noui,
|
||||||
|
"endpoint": claude_endpoint,
|
||||||
|
"max_token": 200000,
|
||||||
|
"tokenizer": tokenizer_gpt35,
|
||||||
|
"token_cnt": get_token_num_gpt35,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
model_info.update({
|
||||||
|
"claude-3-opus-20240229": {
|
||||||
|
"fn_with_ui": claude_ui,
|
||||||
|
"fn_without_ui": claude_noui,
|
||||||
|
"endpoint": claude_endpoint,
|
||||||
|
"max_token": 200000,
|
||||||
"tokenizer": tokenizer_gpt35,
|
"tokenizer": tokenizer_gpt35,
|
||||||
"token_cnt": get_token_num_gpt35,
|
"token_cnt": get_token_num_gpt35,
|
||||||
},
|
},
|
||||||
@ -675,22 +711,28 @@ if "deepseekcoder" in AVAIL_LLM_MODELS: # deepseekcoder
|
|||||||
})
|
})
|
||||||
except:
|
except:
|
||||||
print(trimmed_format_exc())
|
print(trimmed_format_exc())
|
||||||
# if "skylark" in AVAIL_LLM_MODELS:
|
# -=-=-=-=-=-=- one-api 对齐支持 -=-=-=-=-=-=-
|
||||||
# try:
|
for model in [m for m in AVAIL_LLM_MODELS if m.startswith("one-api-")]:
|
||||||
# from .bridge_skylark2 import predict_no_ui_long_connection as skylark_noui
|
# 为了更灵活地接入one-api多模型管理界面,设计了此接口,例子:AVAIL_LLM_MODELS = ["one-api-mixtral-8x7b(max_token=6666)"]
|
||||||
# from .bridge_skylark2 import predict as skylark_ui
|
# 其中
|
||||||
# model_info.update({
|
# "one-api-" 是前缀(必要)
|
||||||
# "skylark": {
|
# "mixtral-8x7b" 是模型名(必要)
|
||||||
# "fn_with_ui": skylark_ui,
|
# "(max_token=6666)" 是配置(非必要)
|
||||||
# "fn_without_ui": skylark_noui,
|
try:
|
||||||
# "endpoint": None,
|
_, max_token_tmp = read_one_api_model_name(model)
|
||||||
# "max_token": 4096,
|
except:
|
||||||
# "tokenizer": tokenizer_gpt35,
|
print(f"one-api模型 {model} 的 max_token 配置不是整数,请检查配置文件。")
|
||||||
# "token_cnt": get_token_num_gpt35,
|
continue
|
||||||
# }
|
model_info.update({
|
||||||
# })
|
model: {
|
||||||
# except:
|
"fn_with_ui": chatgpt_ui,
|
||||||
# print(trimmed_format_exc())
|
"fn_without_ui": chatgpt_noui,
|
||||||
|
"endpoint": openai_endpoint,
|
||||||
|
"max_token": max_token_tmp,
|
||||||
|
"tokenizer": tokenizer_gpt35,
|
||||||
|
"token_cnt": get_token_num_gpt35,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
# <-- 用于定义和切换多个azure模型 -->
|
# <-- 用于定义和切换多个azure模型 -->
|
||||||
|
@ -21,7 +21,7 @@ import random
|
|||||||
|
|
||||||
# config_private.py放自己的秘密如API和代理网址
|
# config_private.py放自己的秘密如API和代理网址
|
||||||
# 读取时首先看是否存在私密的config_private配置文件(不受git管控),如果有,则覆盖原config文件
|
# 读取时首先看是否存在私密的config_private配置文件(不受git管控),如果有,则覆盖原config文件
|
||||||
from toolbox import get_conf, update_ui, is_any_api_key, select_api_key, what_keys, clip_history, trimmed_format_exc, is_the_upload_folder
|
from toolbox import get_conf, update_ui, is_any_api_key, select_api_key, what_keys, clip_history, trimmed_format_exc, is_the_upload_folder, read_one_api_model_name
|
||||||
proxies, TIMEOUT_SECONDS, MAX_RETRY, API_ORG, AZURE_CFG_ARRAY = \
|
proxies, TIMEOUT_SECONDS, MAX_RETRY, API_ORG, AZURE_CFG_ARRAY = \
|
||||||
get_conf('proxies', 'TIMEOUT_SECONDS', 'MAX_RETRY', 'API_ORG', 'AZURE_CFG_ARRAY')
|
get_conf('proxies', 'TIMEOUT_SECONDS', 'MAX_RETRY', 'API_ORG', 'AZURE_CFG_ARRAY')
|
||||||
|
|
||||||
@ -358,6 +358,9 @@ def generate_payload(inputs, llm_kwargs, history, system_prompt, stream):
|
|||||||
model = llm_kwargs['llm_model']
|
model = llm_kwargs['llm_model']
|
||||||
if llm_kwargs['llm_model'].startswith('api2d-'):
|
if llm_kwargs['llm_model'].startswith('api2d-'):
|
||||||
model = llm_kwargs['llm_model'][len('api2d-'):]
|
model = llm_kwargs['llm_model'][len('api2d-'):]
|
||||||
|
if llm_kwargs['llm_model'].startswith('one-api-'):
|
||||||
|
model = llm_kwargs['llm_model'][len('one-api-'):]
|
||||||
|
model, _ = read_one_api_model_name(model)
|
||||||
|
|
||||||
if model == "gpt-3.5-random": # 随机选择, 绕过openai访问频率限制
|
if model == "gpt-3.5-random": # 随机选择, 绕过openai访问频率限制
|
||||||
model = random.choice([
|
model = random.choice([
|
||||||
|
@ -11,13 +11,12 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import json
|
|
||||||
import time
|
import time
|
||||||
import gradio as gr
|
|
||||||
import logging
|
|
||||||
import traceback
|
import traceback
|
||||||
import requests
|
from toolbox import get_conf, update_ui, trimmed_format_exc, encode_image, every_image_file_in_path
|
||||||
import importlib
|
|
||||||
|
picture_system_prompt = "\n当回复图像时,必须说明正在回复哪张图像。所有图像仅在最后一个问题中提供,即使它们在历史记录中被提及。请使用'这是第X张图像:'的格式来指明您正在描述的是哪张图像。"
|
||||||
|
Claude_3_Models = ["claude-3-sonnet-20240229", "claude-3-opus-20240229"]
|
||||||
|
|
||||||
# config_private.py放自己的秘密如API和代理网址
|
# config_private.py放自己的秘密如API和代理网址
|
||||||
# 读取时首先看是否存在私密的config_private配置文件(不受git管控),如果有,则覆盖原config文件
|
# 读取时首先看是否存在私密的config_private配置文件(不受git管控),如果有,则覆盖原config文件
|
||||||
@ -56,7 +55,8 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
|
|||||||
"""
|
"""
|
||||||
from anthropic import Anthropic
|
from anthropic import Anthropic
|
||||||
watch_dog_patience = 5 # 看门狗的耐心, 设置5秒即可
|
watch_dog_patience = 5 # 看门狗的耐心, 设置5秒即可
|
||||||
prompt = generate_payload(inputs, llm_kwargs, history, system_prompt=sys_prompt, stream=True)
|
if inputs == "": inputs = "空空如也的输入栏"
|
||||||
|
message = generate_payload(inputs, llm_kwargs, history, stream=True, image_paths=None)
|
||||||
retry = 0
|
retry = 0
|
||||||
if len(ANTHROPIC_API_KEY) == 0:
|
if len(ANTHROPIC_API_KEY) == 0:
|
||||||
raise RuntimeError("没有设置ANTHROPIC_API_KEY选项")
|
raise RuntimeError("没有设置ANTHROPIC_API_KEY选项")
|
||||||
@ -65,15 +65,16 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
|
|||||||
try:
|
try:
|
||||||
# make a POST request to the API endpoint, stream=False
|
# make a POST request to the API endpoint, stream=False
|
||||||
from .bridge_all import model_info
|
from .bridge_all import model_info
|
||||||
anthropic = Anthropic(api_key=ANTHROPIC_API_KEY)
|
anthropic = Anthropic(api_key=ANTHROPIC_API_KEY, base_url=model_info[llm_kwargs['llm_model']]['endpoint'])
|
||||||
# endpoint = model_info[llm_kwargs['llm_model']]['endpoint']
|
# endpoint = model_info[llm_kwargs['llm_model']]['endpoint']
|
||||||
# with ProxyNetworkActivate()
|
# with ProxyNetworkActivate()
|
||||||
stream = anthropic.completions.create(
|
stream = anthropic.messages.create(
|
||||||
prompt=prompt,
|
messages=message,
|
||||||
max_tokens_to_sample=4096, # The maximum number of tokens to generate before stopping.
|
max_tokens=4096, # The maximum number of tokens to generate before stopping.
|
||||||
model=llm_kwargs['llm_model'],
|
model=llm_kwargs['llm_model'],
|
||||||
stream=True,
|
stream=True,
|
||||||
temperature = llm_kwargs['temperature']
|
temperature = llm_kwargs['temperature'],
|
||||||
|
system=sys_prompt
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -84,11 +85,15 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
|
|||||||
result = ''
|
result = ''
|
||||||
try:
|
try:
|
||||||
for completion in stream:
|
for completion in stream:
|
||||||
result += completion.completion
|
if completion.type == "message_start" or completion.type == "content_block_start":
|
||||||
if not console_slience: print(completion.completion, end='')
|
continue
|
||||||
|
elif completion.type == "message_stop" or completion.type == "content_block_stop" or completion.type == "message_delta":
|
||||||
|
break
|
||||||
|
result += completion.delta.text
|
||||||
|
if not console_slience: print(completion.delta.text, end='')
|
||||||
if observe_window is not None:
|
if observe_window is not None:
|
||||||
# 观测窗,把已经获取的数据显示出去
|
# 观测窗,把已经获取的数据显示出去
|
||||||
if len(observe_window) >= 1: observe_window[0] += completion.completion
|
if len(observe_window) >= 1: observe_window[0] += completion.delta.text
|
||||||
# 看门狗,如果超过期限没有喂狗,则终止
|
# 看门狗,如果超过期限没有喂狗,则终止
|
||||||
if len(observe_window) >= 2:
|
if len(observe_window) >= 2:
|
||||||
if (time.time()-observe_window[1]) > watch_dog_patience:
|
if (time.time()-observe_window[1]) > watch_dog_patience:
|
||||||
@ -98,6 +103,10 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def make_media_input(history,inputs,image_paths):
|
||||||
|
for image_path in image_paths:
|
||||||
|
inputs = inputs + f'<br/><br/><div align="center"><img src="file={os.path.abspath(image_path)}"></div>'
|
||||||
|
return inputs
|
||||||
|
|
||||||
def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None):
|
def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None):
|
||||||
"""
|
"""
|
||||||
@ -109,6 +118,7 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
chatbot 为WebUI中显示的对话列表,修改它,然后yeild出去,可以直接修改对话界面内容
|
chatbot 为WebUI中显示的对话列表,修改它,然后yeild出去,可以直接修改对话界面内容
|
||||||
additional_fn代表点击的哪个按钮,按钮见functional.py
|
additional_fn代表点击的哪个按钮,按钮见functional.py
|
||||||
"""
|
"""
|
||||||
|
if inputs == "": inputs = "空空如也的输入栏"
|
||||||
from anthropic import Anthropic
|
from anthropic import Anthropic
|
||||||
if len(ANTHROPIC_API_KEY) == 0:
|
if len(ANTHROPIC_API_KEY) == 0:
|
||||||
chatbot.append((inputs, "没有设置ANTHROPIC_API_KEY"))
|
chatbot.append((inputs, "没有设置ANTHROPIC_API_KEY"))
|
||||||
@ -119,13 +129,23 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
from core_functional import handle_core_functionality
|
from core_functional import handle_core_functionality
|
||||||
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
|
inputs, history = handle_core_functionality(additional_fn, inputs, history, chatbot)
|
||||||
|
|
||||||
raw_input = inputs
|
have_recent_file, image_paths = every_image_file_in_path(chatbot)
|
||||||
logging.info(f'[raw_input] {raw_input}')
|
if len(image_paths) > 20:
|
||||||
chatbot.append((inputs, ""))
|
chatbot.append((inputs, "图片数量超过api上限(20张)"))
|
||||||
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应")
|
||||||
|
return
|
||||||
|
|
||||||
|
if any([llm_kwargs['llm_model'] == model for model in Claude_3_Models]) and have_recent_file:
|
||||||
|
if inputs == "" or inputs == "空空如也的输入栏": inputs = "请描述给出的图片"
|
||||||
|
system_prompt += picture_system_prompt # 由于没有单独的参数保存包含图片的历史,所以只能通过提示词对第几张图片进行定位
|
||||||
|
chatbot.append((make_media_input(history,inputs, image_paths), ""))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面
|
||||||
|
else:
|
||||||
|
chatbot.append((inputs, ""))
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面
|
||||||
|
|
||||||
try:
|
try:
|
||||||
prompt = generate_payload(inputs, llm_kwargs, history, system_prompt, stream)
|
message = generate_payload(inputs, llm_kwargs, history, stream, image_paths)
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
chatbot[-1] = (inputs, f"您提供的api-key不满足要求,不包含任何可用于{llm_kwargs['llm_model']}的api-key。您可能选择了错误的模型或请求源。")
|
chatbot[-1] = (inputs, f"您提供的api-key不满足要求,不包含任何可用于{llm_kwargs['llm_model']}的api-key。您可能选择了错误的模型或请求源。")
|
||||||
yield from update_ui(chatbot=chatbot, history=history, msg="api-key不满足要求") # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history, msg="api-key不满足要求") # 刷新界面
|
||||||
@ -138,17 +158,17 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
try:
|
try:
|
||||||
# make a POST request to the API endpoint, stream=True
|
# make a POST request to the API endpoint, stream=True
|
||||||
from .bridge_all import model_info
|
from .bridge_all import model_info
|
||||||
anthropic = Anthropic(api_key=ANTHROPIC_API_KEY)
|
anthropic = Anthropic(api_key=ANTHROPIC_API_KEY, base_url=model_info[llm_kwargs['llm_model']]['endpoint'])
|
||||||
# endpoint = model_info[llm_kwargs['llm_model']]['endpoint']
|
# endpoint = model_info[llm_kwargs['llm_model']]['endpoint']
|
||||||
# with ProxyNetworkActivate()
|
# with ProxyNetworkActivate()
|
||||||
stream = anthropic.completions.create(
|
stream = anthropic.messages.create(
|
||||||
prompt=prompt,
|
messages=message,
|
||||||
max_tokens_to_sample=4096, # The maximum number of tokens to generate before stopping.
|
max_tokens=4096, # The maximum number of tokens to generate before stopping.
|
||||||
model=llm_kwargs['llm_model'],
|
model=llm_kwargs['llm_model'],
|
||||||
stream=True,
|
stream=True,
|
||||||
temperature = llm_kwargs['temperature']
|
temperature = llm_kwargs['temperature'],
|
||||||
|
system=system_prompt
|
||||||
)
|
)
|
||||||
|
|
||||||
break
|
break
|
||||||
except:
|
except:
|
||||||
retry += 1
|
retry += 1
|
||||||
@ -160,8 +180,12 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
gpt_replying_buffer = ""
|
gpt_replying_buffer = ""
|
||||||
|
|
||||||
for completion in stream:
|
for completion in stream:
|
||||||
|
if completion.type == "message_start" or completion.type == "content_block_start":
|
||||||
|
continue
|
||||||
|
elif completion.type == "message_stop" or completion.type == "content_block_stop" or completion.type == "message_delta":
|
||||||
|
break
|
||||||
try:
|
try:
|
||||||
gpt_replying_buffer = gpt_replying_buffer + completion.completion
|
gpt_replying_buffer = gpt_replying_buffer + completion.delta.text
|
||||||
history[-1] = gpt_replying_buffer
|
history[-1] = gpt_replying_buffer
|
||||||
chatbot[-1] = (history[-2], history[-1])
|
chatbot[-1] = (history[-2], history[-1])
|
||||||
yield from update_ui(chatbot=chatbot, history=history, msg='正常') # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history, msg='正常') # 刷新界面
|
||||||
@ -173,56 +197,51 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
yield from update_ui(chatbot=chatbot, history=history, msg="Json异常" + tb_str) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history, msg="Json异常" + tb_str) # 刷新界面
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def generate_payload(inputs, llm_kwargs, history, stream, image_paths):
|
||||||
|
|
||||||
|
|
||||||
# https://github.com/jtsang4/claude-to-chatgpt/blob/main/claude_to_chatgpt/adapter.py
|
|
||||||
def convert_messages_to_prompt(messages):
|
|
||||||
prompt = ""
|
|
||||||
role_map = {
|
|
||||||
"system": "Human",
|
|
||||||
"user": "Human",
|
|
||||||
"assistant": "Assistant",
|
|
||||||
}
|
|
||||||
for message in messages:
|
|
||||||
role = message["role"]
|
|
||||||
content = message["content"]
|
|
||||||
transformed_role = role_map[role]
|
|
||||||
prompt += f"\n\n{transformed_role.capitalize()}: {content}"
|
|
||||||
prompt += "\n\nAssistant: "
|
|
||||||
return prompt
|
|
||||||
|
|
||||||
def generate_payload(inputs, llm_kwargs, history, system_prompt, stream):
|
|
||||||
"""
|
"""
|
||||||
整合所有信息,选择LLM模型,生成http请求,为发送请求做准备
|
整合所有信息,选择LLM模型,生成http请求,为发送请求做准备
|
||||||
"""
|
"""
|
||||||
from anthropic import Anthropic, HUMAN_PROMPT, AI_PROMPT
|
|
||||||
|
|
||||||
conversation_cnt = len(history) // 2
|
conversation_cnt = len(history) // 2
|
||||||
|
|
||||||
messages = [{"role": "system", "content": system_prompt}]
|
messages = []
|
||||||
|
|
||||||
if conversation_cnt:
|
if conversation_cnt:
|
||||||
for index in range(0, 2*conversation_cnt, 2):
|
for index in range(0, 2*conversation_cnt, 2):
|
||||||
what_i_have_asked = {}
|
what_i_have_asked = {}
|
||||||
what_i_have_asked["role"] = "user"
|
what_i_have_asked["role"] = "user"
|
||||||
what_i_have_asked["content"] = history[index]
|
what_i_have_asked["content"] = [{"type": "text", "text": history[index]}]
|
||||||
what_gpt_answer = {}
|
what_gpt_answer = {}
|
||||||
what_gpt_answer["role"] = "assistant"
|
what_gpt_answer["role"] = "assistant"
|
||||||
what_gpt_answer["content"] = history[index+1]
|
what_gpt_answer["content"] = [{"type": "text", "text": history[index+1]}]
|
||||||
if what_i_have_asked["content"] != "":
|
if what_i_have_asked["content"][0]["text"] != "":
|
||||||
if what_gpt_answer["content"] == "": continue
|
if what_i_have_asked["content"][0]["text"] == "": continue
|
||||||
if what_gpt_answer["content"] == timeout_bot_msg: continue
|
if what_i_have_asked["content"][0]["text"] == timeout_bot_msg: continue
|
||||||
messages.append(what_i_have_asked)
|
messages.append(what_i_have_asked)
|
||||||
messages.append(what_gpt_answer)
|
messages.append(what_gpt_answer)
|
||||||
else:
|
else:
|
||||||
messages[-1]['content'] = what_gpt_answer['content']
|
messages[-1]['content'][0]['text'] = what_gpt_answer['content'][0]['text']
|
||||||
|
|
||||||
what_i_ask_now = {}
|
if any([llm_kwargs['llm_model'] == model for model in Claude_3_Models]) and image_paths:
|
||||||
what_i_ask_now["role"] = "user"
|
base64_images = []
|
||||||
what_i_ask_now["content"] = inputs
|
for image_path in image_paths:
|
||||||
|
base64_images.append(encode_image(image_path))
|
||||||
|
what_i_ask_now = {}
|
||||||
|
what_i_ask_now["role"] = "user"
|
||||||
|
what_i_ask_now["content"] = []
|
||||||
|
for base64_image in base64_images:
|
||||||
|
what_i_ask_now["content"].append({
|
||||||
|
"type": "image",
|
||||||
|
"source": {
|
||||||
|
"type": "base64",
|
||||||
|
"media_type": "image/jpeg",
|
||||||
|
"data": base64_image,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
what_i_ask_now["content"].append({"type": "text", "text": inputs})
|
||||||
|
else:
|
||||||
|
what_i_ask_now = {}
|
||||||
|
what_i_ask_now["role"] = "user"
|
||||||
|
what_i_ask_now["content"] = [{"type": "text", "text": inputs}]
|
||||||
messages.append(what_i_ask_now)
|
messages.append(what_i_ask_now)
|
||||||
prompt = convert_messages_to_prompt(messages)
|
return messages
|
||||||
|
|
||||||
return prompt
|
|
||||||
|
|
||||||
|
|
@ -20,7 +20,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
|
|||||||
if get_conf("GEMINI_API_KEY") == "":
|
if get_conf("GEMINI_API_KEY") == "":
|
||||||
raise ValueError(f"请配置 GEMINI_API_KEY。")
|
raise ValueError(f"请配置 GEMINI_API_KEY。")
|
||||||
|
|
||||||
genai = GoogleChatInit()
|
genai = GoogleChatInit(llm_kwargs)
|
||||||
watch_dog_patience = 5 # 看门狗的耐心, 设置5秒即可
|
watch_dog_patience = 5 # 看门狗的耐心, 设置5秒即可
|
||||||
gpt_replying_buffer = ''
|
gpt_replying_buffer = ''
|
||||||
stream_response = genai.generate_chat(inputs, llm_kwargs, history, sys_prompt)
|
stream_response = genai.generate_chat(inputs, llm_kwargs, history, sys_prompt)
|
||||||
@ -70,7 +70,7 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
|
|
||||||
chatbot.append((inputs, ""))
|
chatbot.append((inputs, ""))
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
genai = GoogleChatInit()
|
genai = GoogleChatInit(llm_kwargs)
|
||||||
retry = 0
|
retry = 0
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
|
@ -114,8 +114,10 @@ def html_local_img(__file, layout="left", max_width=None, max_height=None, md=Tr
|
|||||||
|
|
||||||
|
|
||||||
class GoogleChatInit:
|
class GoogleChatInit:
|
||||||
def __init__(self):
|
def __init__(self, llm_kwargs):
|
||||||
self.url_gemini = "https://generativelanguage.googleapis.com/v1beta/models/%m:streamGenerateContent?key=%k"
|
from .bridge_all import model_info
|
||||||
|
endpoint = model_info[llm_kwargs['llm_model']]['endpoint']
|
||||||
|
self.url_gemini = endpoint + "/%m:streamGenerateContent?key=%k"
|
||||||
|
|
||||||
def generate_chat(self, inputs, llm_kwargs, history, system_prompt):
|
def generate_chat(self, inputs, llm_kwargs, history, system_prompt):
|
||||||
headers, payload = self.generate_message_payload(
|
headers, payload = self.generate_message_payload(
|
||||||
|
@ -8,6 +8,7 @@ pydantic==2.5.2
|
|||||||
protobuf==3.18
|
protobuf==3.18
|
||||||
transformers>=4.27.1
|
transformers>=4.27.1
|
||||||
scipdf_parser>=0.52
|
scipdf_parser>=0.52
|
||||||
|
anthropic>=0.18.1
|
||||||
python-markdown-math
|
python-markdown-math
|
||||||
pymdown-extensions
|
pymdown-extensions
|
||||||
websocket-client
|
websocket-client
|
||||||
@ -16,7 +17,6 @@ prompt_toolkit
|
|||||||
latex2mathml
|
latex2mathml
|
||||||
python-docx
|
python-docx
|
||||||
mdtex2html
|
mdtex2html
|
||||||
anthropic
|
|
||||||
pyautogen
|
pyautogen
|
||||||
colorama
|
colorama
|
||||||
Markdown
|
Markdown
|
||||||
|
@ -62,7 +62,7 @@ def select_api_key(keys, llm_model):
|
|||||||
avail_key_list = []
|
avail_key_list = []
|
||||||
key_list = keys.split(',')
|
key_list = keys.split(',')
|
||||||
|
|
||||||
if llm_model.startswith('gpt-'):
|
if llm_model.startswith('gpt-') or llm_model.startswith('one-api-'):
|
||||||
for k in key_list:
|
for k in key_list:
|
||||||
if is_openai_api_key(k): avail_key_list.append(k)
|
if is_openai_api_key(k): avail_key_list.append(k)
|
||||||
|
|
||||||
|
34
shared_utils/map_names.py
Normal file
34
shared_utils/map_names.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import re
|
||||||
|
mapping_dic = {
|
||||||
|
# "qianfan": "qianfan(文心一言大模型)",
|
||||||
|
# "zhipuai": "zhipuai(智谱GLM4超级模型🔥)",
|
||||||
|
# "gpt-4-1106-preview": "gpt-4-1106-preview(新调优版本GPT-4🔥)",
|
||||||
|
# "gpt-4-vision-preview": "gpt-4-vision-preview(识图模型GPT-4V)",
|
||||||
|
}
|
||||||
|
|
||||||
|
rev_mapping_dic = {}
|
||||||
|
for k, v in mapping_dic.items():
|
||||||
|
rev_mapping_dic[v] = k
|
||||||
|
|
||||||
|
def map_model_to_friendly_names(m):
|
||||||
|
if m in mapping_dic:
|
||||||
|
return mapping_dic[m]
|
||||||
|
return m
|
||||||
|
|
||||||
|
def map_friendly_names_to_model(m):
|
||||||
|
if m in rev_mapping_dic:
|
||||||
|
return rev_mapping_dic[m]
|
||||||
|
return m
|
||||||
|
|
||||||
|
def read_one_api_model_name(model: str):
|
||||||
|
"""return real model name and max_token.
|
||||||
|
"""
|
||||||
|
max_token_pattern = r"\(max_token=(\d+)\)"
|
||||||
|
match = re.search(max_token_pattern, model)
|
||||||
|
if match:
|
||||||
|
max_token_tmp = match.group(1) # 获取 max_token 的值
|
||||||
|
max_token_tmp = int(max_token_tmp)
|
||||||
|
model = re.sub(max_token_pattern, "", model) # 从原字符串中删除 "(max_token=...)"
|
||||||
|
else:
|
||||||
|
max_token_tmp = 4096
|
||||||
|
return model, max_token_tmp
|
65
toolbox.py
65
toolbox.py
@ -25,6 +25,9 @@ from shared_utils.text_mask import apply_gpt_academic_string_mask
|
|||||||
from shared_utils.text_mask import build_gpt_academic_masked_string
|
from shared_utils.text_mask import build_gpt_academic_masked_string
|
||||||
from shared_utils.text_mask import apply_gpt_academic_string_mask_langbased
|
from shared_utils.text_mask import apply_gpt_academic_string_mask_langbased
|
||||||
from shared_utils.text_mask import build_gpt_academic_masked_string_langbased
|
from shared_utils.text_mask import build_gpt_academic_masked_string_langbased
|
||||||
|
from shared_utils.map_names import map_friendly_names_to_model
|
||||||
|
from shared_utils.map_names import map_model_to_friendly_names
|
||||||
|
from shared_utils.map_names import read_one_api_model_name
|
||||||
from shared_utils.handle_upload import html_local_file
|
from shared_utils.handle_upload import html_local_file
|
||||||
from shared_utils.handle_upload import html_local_img
|
from shared_utils.handle_upload import html_local_img
|
||||||
from shared_utils.handle_upload import file_manifest_filter_type
|
from shared_utils.handle_upload import file_manifest_filter_type
|
||||||
@ -919,6 +922,18 @@ def have_any_recent_upload_image_files(chatbot):
|
|||||||
else:
|
else:
|
||||||
return False, None # most_recent_uploaded is too old
|
return False, None # most_recent_uploaded is too old
|
||||||
|
|
||||||
|
# Claude3 model supports graphic context dialogue, reads all images
|
||||||
|
def every_image_file_in_path(chatbot):
|
||||||
|
if chatbot is None:
|
||||||
|
return False, [] # chatbot is None
|
||||||
|
most_recent_uploaded = chatbot._cookies.get("most_recent_uploaded", None)
|
||||||
|
if not most_recent_uploaded:
|
||||||
|
return False, [] # most_recent_uploaded is None
|
||||||
|
path = most_recent_uploaded["path"]
|
||||||
|
file_manifest = get_pictures_list(path)
|
||||||
|
if len(file_manifest) == 0:
|
||||||
|
return False, []
|
||||||
|
return True, file_manifest
|
||||||
|
|
||||||
# Function to encode the image
|
# Function to encode the image
|
||||||
def encode_image(image_path):
|
def encode_image(image_path):
|
||||||
@ -939,3 +954,53 @@ def check_packages(packages=[]):
|
|||||||
spam_spec = importlib.util.find_spec(p)
|
spam_spec = importlib.util.find_spec(p)
|
||||||
if spam_spec is None:
|
if spam_spec is None:
|
||||||
raise ModuleNotFoundError
|
raise ModuleNotFoundError
|
||||||
|
|
||||||
|
|
||||||
|
def map_file_to_sha256(file_path):
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
with open(file_path, 'rb') as file:
|
||||||
|
content = file.read()
|
||||||
|
|
||||||
|
# Calculate the SHA-256 hash of the file contents
|
||||||
|
sha_hash = hashlib.sha256(content).hexdigest()
|
||||||
|
|
||||||
|
return sha_hash
|
||||||
|
|
||||||
|
|
||||||
|
def check_repeat_upload(new_pdf_path, pdf_hash):
|
||||||
|
'''
|
||||||
|
检查历史上传的文件是否与新上传的文件相同,如果相同则返回(True, 重复文件路径),否则返回(False,None)
|
||||||
|
'''
|
||||||
|
from toolbox import get_conf
|
||||||
|
import PyPDF2
|
||||||
|
|
||||||
|
user_upload_dir = os.path.dirname(os.path.dirname(new_pdf_path))
|
||||||
|
file_name = os.path.basename(new_pdf_path)
|
||||||
|
|
||||||
|
file_manifest = [f for f in glob.glob(f'{user_upload_dir}/**/{file_name}', recursive=True)]
|
||||||
|
|
||||||
|
for saved_file in file_manifest:
|
||||||
|
with open(new_pdf_path, 'rb') as file1, open(saved_file, 'rb') as file2:
|
||||||
|
reader1 = PyPDF2.PdfFileReader(file1)
|
||||||
|
reader2 = PyPDF2.PdfFileReader(file2)
|
||||||
|
|
||||||
|
# 比较页数是否相同
|
||||||
|
if reader1.getNumPages() != reader2.getNumPages():
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 比较每一页的内容是否相同
|
||||||
|
for page_num in range(reader1.getNumPages()):
|
||||||
|
page1 = reader1.getPage(page_num).extractText()
|
||||||
|
page2 = reader2.getPage(page_num).extractText()
|
||||||
|
if page1 != page2:
|
||||||
|
continue
|
||||||
|
|
||||||
|
maybe_project_dir = glob.glob('{}/**/{}'.format(get_log_folder(), pdf_hash + ".tag"), recursive=True)
|
||||||
|
|
||||||
|
|
||||||
|
if len(maybe_project_dir) > 0:
|
||||||
|
return True, os.path.dirname(maybe_project_dir[0])
|
||||||
|
|
||||||
|
# 如果所有页的内容都相同,返回 True
|
||||||
|
return False, None
|
4
version
4
version
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": 3.72,
|
"version": 3.73,
|
||||||
"show_feature": true,
|
"show_feature": true,
|
||||||
"new_feature": "支持切换多个智谱ai模型 <-> 用绘图功能增强部分插件 <-> 基础功能区支持自动切换中英提示词 <-> 支持Mermaid绘图库(让大模型绘制脑图) <-> 支持Gemini-pro <-> 支持直接拖拽文件到上传区 <-> 支持将图片粘贴到输入区"
|
"new_feature": "优化oneapi接入方法 <-> 接入月之暗面模型 <-> 支持切换多个智谱ai模型 <-> 用绘图功能增强部分插件 <-> 基础功能区支持自动切换中英提示词 <-> 支持Mermaid绘图库(让大模型绘制脑图)"
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user