diff --git a/ChuanhuChatbot.py b/ChuanhuChatbot.py
index d498359af5c02037247406830672bcbbdbb7006b..62f199dac91a48595d66fc38edf945588b31ab75 100644
--- a/ChuanhuChatbot.py
+++ b/ChuanhuChatbot.py
@@ -5,18 +5,18 @@ logging.basicConfig(
format="%(asctime)s [%(levelname)s] [%(filename)s:%(lineno)d] %(message)s",
)
-import colorama
+from modules.models.models import get_model
+from modules.train_func import *
+from modules.repo import *
+from modules.webui import *
+from modules.overwrites import *
+from modules.presets import *
+from modules.utils import *
+from modules.config import *
+from modules import config
import gradio as gr
+import colorama
-from modules import config
-from modules.config import *
-from modules.utils import *
-from modules.presets import *
-from modules.overwrites import *
-from modules.webui import *
-from modules.repo import *
-from modules.train_func import *
-from modules.models.models import get_model
logging.getLogger("httpx").setLevel(logging.WARNING)
@@ -26,25 +26,28 @@ gr.Chatbot.postprocess = postprocess
# with open("web_assets/css/ChuanhuChat.css", "r", encoding="utf-8") as f:
# ChuanhuChatCSS = f.read()
+
def create_new_model():
- return get_model(model_name = MODELS[DEFAULT_MODEL], access_key = my_api_key)[0]
+ return get_model(model_name=MODELS[DEFAULT_MODEL], access_key=my_api_key)[0]
+
with gr.Blocks(theme=small_and_beautiful_theme) as demo:
- user_name = gr.State("")
- promptTemplates = gr.State(load_template(get_template_names(plain=True)[0], mode=2))
+ user_name = gr.Textbox("", visible=False)
+ promptTemplates = gr.State(load_template(get_template_names()[0], mode=2))
user_question = gr.State("")
- assert type(my_api_key)==str
+ assert type(my_api_key) == str
user_api_key = gr.State(my_api_key)
- current_model = gr.State(create_new_model)
+ current_model = gr.State()
topic = gr.State(i18n("未命名对话历史记录"))
- with gr.Row():
- gr.HTML(CHUANHU_TITLE, elem_id="app-title")
+ with gr.Row(elem_id="chuanhu-header"):
+ gr.HTML(get_html("header_title.html").format(
+ app_title=CHUANHU_TITLE), elem_id="app-title")
status_display = gr.Markdown(get_geoip(), elem_id="status-display")
with gr.Row(elem_id="float-display"):
- user_info = gr.Markdown(value="getting user info...", elem_id="user-info")
- config_info = gr.HTML(get_html("config_info.html").format(bot_avatar=config.bot_avatar, user_avatar=config.user_avatar), visible=False, elem_id="config-info")
+ user_info = gr.Markdown(
+ value="getting user info...", elem_id="user-info")
update_info = gr.HTML(get_html("update.html").format(
current_version=repo_tag_html(),
version_time=version_time(),
@@ -52,248 +55,339 @@ with gr.Blocks(theme=small_and_beautiful_theme) as demo:
update_btn=i18n("更新"),
seenew_btn=i18n("详情"),
ok_btn=i18n("好"),
- ), visible=check_update)
-
- with gr.Row(equal_height=True):
- with gr.Column(scale=5):
- with gr.Row():
- chatbot = gr.Chatbot(label="Chuanhu Chat", elem_id="chuanhu-chatbot", latex_delimiters=latex_delimiters_set, height=700)
- with gr.Row():
- with gr.Column(min_width=225, scale=12):
- user_input = gr.Textbox(
- elem_id="user-input-tb",
- show_label=False, placeholder=i18n("在这里输入"),
- container=False
- )
- with gr.Column(min_width=42, scale=1):
- submitBtn = gr.Button(value="", variant="primary", elem_id="submit-btn")
- cancelBtn = gr.Button(value="", variant="secondary", visible=False, elem_id="cancel-btn")
- with gr.Row(elem_id="chatbot-buttons"):
- with gr.Column(min_width=120, scale=1):
- emptyBtn = gr.Button(
- i18n("🧹 新的对话"), elem_id="empty-btn"
- )
- with gr.Column(min_width=120, scale=1):
- retryBtn = gr.Button(i18n("🔄 重新生成"))
- with gr.Column(min_width=120, scale=1):
- delFirstBtn = gr.Button(i18n("🗑️ 删除最旧对话"))
- with gr.Column(min_width=120, scale=1):
- delLastBtn = gr.Button(i18n("🗑️ 删除最新对话"))
- with gr.Row(visible=False) as like_dislike_area:
- with gr.Column(min_width=20, scale=1):
- likeBtn = gr.Button(i18n("👍"))
- with gr.Column(min_width=20, scale=1):
- dislikeBtn = gr.Button(i18n("👎"))
-
- with gr.Column():
- with gr.Column(min_width=50, scale=1):
- with gr.Tab(label=i18n("模型")):
- keyTxt = gr.Textbox(
- show_label=True,
- placeholder=f"Your API-key...",
- value=hide_middle_chars(user_api_key.value),
- type="password",
- visible=not HIDE_MY_KEY,
- label="API-Key",
- )
- if multi_api_key:
- usageTxt = gr.Markdown(i18n("多账号模式已开启,无需输入key,可直接开始对话"), elem_id="usage-display", elem_classes="insert-block", visible=show_api_billing)
- else:
- usageTxt = gr.Markdown(i18n("**发送消息** 或 **提交key** 以显示额度"), elem_id="usage-display", elem_classes="insert-block", visible=show_api_billing)
+ ), visible=check_update)
+
+ with gr.Row(equal_height=True, elem_id="chuanhu-body"):
+
+ with gr.Column(elem_id="menu-area"):
+ with gr.Column(elem_id="chuanhu-history"):
+ with gr.Box():
+ with gr.Row(elem_id="chuanhu-history-header"):
+ with gr.Row(elem_id="chuanhu-history-search-row"):
+ with gr.Column(min_width=150, scale=2):
+ historySearchTextbox = gr.Textbox(show_label=False, container=False, placeholder=i18n(
+ "搜索(支持正则)..."), lines=1, elem_id="history-search-tb")
+ with gr.Column(min_width=52, scale=1, elem_id="gr-history-header-btns"):
+ uploadFileBtn = gr.UploadButton(
+ interactive=True, label="", file_types=[".json"], elem_id="gr-history-upload-btn")
+ historyRefreshBtn = gr.Button("", elem_id="gr-history-refresh-btn")
+
+
+ with gr.Row(elem_id="chuanhu-history-body"):
+ with gr.Column(scale=6, elem_id="history-select-wrap"):
+ historySelectList = gr.Radio(
+ label=i18n("从列表中加载对话"),
+ choices=get_history_names(),
+ value=get_first_history_name(),
+ # multiselect=False,
+ container=False,
+ elem_id="history-select-dropdown"
+ )
+ with gr.Row(visible=False):
+ with gr.Column(min_width=42, scale=1):
+ historyDeleteBtn = gr.Button(
+ "🗑️", elem_id="gr-history-delete-btn")
+ with gr.Column(min_width=42, scale=1):
+ historyDownloadBtn = gr.Button(
+ "⏬", elem_id="gr-history-download-btn")
+ with gr.Column(min_width=42, scale=1):
+ historyMarkdownDownloadBtn = gr.Button(
+ "⤵️", elem_id="gr-history-mardown-download-btn")
+ with gr.Row(visible=False):
+ with gr.Column(scale=6):
+ saveFileName = gr.Textbox(
+ show_label=True,
+ placeholder=i18n("设置文件名: 默认为.json,可选为.md"),
+ label=i18n("设置保存文件名"),
+ value=i18n("对话历史记录"),
+ elem_classes="no-container"
+ # container=False,
+ )
+ with gr.Column(scale=1):
+ renameHistoryBtn = gr.Button(
+ i18n("💾 保存对话"), elem_id="gr-history-save-btn")
+ exportMarkdownBtn = gr.Button(
+ i18n("📝 导出为 Markdown"), elem_id="gr-markdown-export-btn")
+
+ with gr.Column(elem_id="chuanhu-menu-footer"):
+ with gr.Row(elem_id="chuanhu-func-nav"):
+ gr.HTML(get_html("func_nav.html"))
+ # gr.HTML(get_html("footer.html").format(versions=versions_html()), elem_id="footer")
+ # gr.Markdown(CHUANHU_DESCRIPTION, elem_id="chuanhu-author")
+
+ with gr.Column(elem_id="chuanhu-area", scale=5):
+ with gr.Column(elem_id="chatbot-area"):
+ with gr.Row(elem_id="chatbot-header"):
model_select_dropdown = gr.Dropdown(
- label=i18n("选择模型"), choices=MODELS, multiselect=False, value=MODELS[DEFAULT_MODEL], interactive=True
+ label=i18n("选择模型"), choices=MODELS, multiselect=False, value=MODELS[DEFAULT_MODEL], interactive=True,
+ show_label=False, container=False, elem_id="model-select-dropdown"
)
lora_select_dropdown = gr.Dropdown(
- label=i18n("选择LoRA模型"), choices=[], multiselect=False, interactive=True, visible=False
+ label=i18n("选择LoRA模型"), choices=[], multiselect=False, interactive=True, visible=False,
+ container=False,
)
- with gr.Row():
- single_turn_checkbox = gr.Checkbox(label=i18n("单轮对话"), value=False, elem_classes="switch-checkbox")
- use_websearch_checkbox = gr.Checkbox(label=i18n("使用在线搜索"), value=False, elem_classes="switch-checkbox")
- language_select_dropdown = gr.Dropdown(
- label=i18n("选择回复语言(针对搜索&索引功能)"),
- choices=REPLY_LANGUAGES,
- multiselect=False,
- value=REPLY_LANGUAGES[0],
+ gr.HTML(get_html("chatbot_header_btn.html").format(
+ json_label=i18n("历史记录(JSON)"),
+ md_label=i18n("导出为 Markdown")
+ ), elem_id="chatbot-header-btn-bar")
+ with gr.Row():
+ chatbot = gr.Chatbot(
+ label="Chuanhu Chat",
+ elem_id="chuanhu-chatbot",
+ latex_delimiters=latex_delimiters_set,
+ # height=700,
+ show_label=False,
+ avatar_images=[config.user_avatar, config.bot_avatar],
+ show_share_button=False,
)
- index_files = gr.Files(label=i18n("上传"), type="file", elem_id="upload-index-file")
- two_column = gr.Checkbox(label=i18n("双栏pdf"), value=advance_docs["pdf"].get("two_column", False))
- summarize_btn = gr.Button(i18n("总结"))
- # TODO: 公式ocr
- # formula_ocr = gr.Checkbox(label=i18n("识别公式"), value=advance_docs["pdf"].get("formula_ocr", False))
-
- with gr.Tab(label="Prompt"):
- systemPromptTxt = gr.Textbox(
- show_label=True,
- placeholder=i18n("在这里输入System Prompt..."),
- label="System prompt",
- value=INITIAL_SYSTEM_PROMPT,
- lines=10
- )
- with gr.Accordion(label=i18n("加载Prompt模板"), open=True):
- with gr.Column():
- with gr.Row():
- with gr.Column(scale=6):
- templateFileSelectDropdown = gr.Dropdown(
- label=i18n("选择Prompt模板集合文件"),
- choices=get_template_names(plain=True),
- multiselect=False,
- value=get_template_names(plain=True)[0],
- container=False,
- )
- with gr.Column(scale=1):
- templateRefreshBtn = gr.Button(i18n("🔄 刷新"))
- with gr.Row():
- with gr.Column():
- templateSelectDropdown = gr.Dropdown(
- label=i18n("从Prompt模板中加载"),
- choices=load_template(
- get_template_names(plain=True)[0], mode=1
- ),
- multiselect=False,
- container=False,
- )
-
- with gr.Tab(label=i18n("保存/加载")):
- with gr.Accordion(label=i18n("保存/加载对话历史记录"), open=True):
- with gr.Column():
- with gr.Row():
- with gr.Column(scale=6):
- historyFileSelectDropdown = gr.Dropdown(
- label=i18n("从列表中加载对话"),
- choices=get_history_names(plain=True),
- multiselect=False,
- container=False,
+ with gr.Row(elem_id="chatbot-footer"):
+ with gr.Box(elem_id="chatbot-input-box"):
+ with gr.Row(elem_id="chatbot-input-row"):
+ gr.HTML(get_html("chatbot_more.html").format(
+ single_turn_label=i18n("单轮对话"),
+ websearch_label=i18n("在线搜索"),
+ upload_file_label=i18n("上传文件"),
+ uploaded_files_label=i18n("知识库文件"),
+ uploaded_files_tip=i18n("在工具箱中管理知识库文件")
+ ))
+ with gr.Row(elem_id="chatbot-input-tb-row"):
+ with gr.Column(min_width=225, scale=12):
+ user_input = gr.Textbox(
+ elem_id="user-input-tb",
+ show_label=False,
+ placeholder=i18n("在这里输入"),
+ elem_classes="no-container",
+ max_lines=5,
+ # container=False
)
- with gr.Row():
- with gr.Column(min_width=42, scale=1):
- historyRefreshBtn = gr.Button(i18n("🔄 刷新"))
- with gr.Column(min_width=42, scale=1):
- historyDeleteBtn = gr.Button(i18n("🗑️ 删除"))
- with gr.Row():
- with gr.Column(scale=6):
- saveFileName = gr.Textbox(
- show_label=True,
- placeholder=i18n("设置文件名: 默认为.json,可选为.md"),
- label=i18n("设置保存文件名"),
- value=i18n("对话历史记录"),
- elem_classes="no-container"
- # container=False,
- )
- with gr.Column(scale=1):
- saveHistoryBtn = gr.Button(i18n("💾 保存对话"))
- exportMarkdownBtn = gr.Button(i18n("📝 导出为Markdown"))
- gr.Markdown(i18n("默认保存于history文件夹"))
- with gr.Row():
+ with gr.Column(min_width=42, scale=1, elem_id="chatbot-ctrl-btns"):
+ submitBtn = gr.Button(
+ value="", variant="primary", elem_id="submit-btn")
+ cancelBtn = gr.Button(
+ value="", variant="secondary", visible=False, elem_id="cancel-btn")
+ # Note: Buttons below are set invisible in UI. But they are used in JS.
+ with gr.Row(elem_id="chatbot-buttons", visible=False):
+ with gr.Column(min_width=120, scale=1):
+ emptyBtn = gr.Button(
+ i18n("🧹 新的对话"), elem_id="empty-btn"
+ )
+ with gr.Column(min_width=120, scale=1):
+ retryBtn = gr.Button(
+ i18n("🔄 重新生成"), elem_id="gr-retry-btn")
+ with gr.Column(min_width=120, scale=1):
+ delFirstBtn = gr.Button(i18n("🗑️ 删除最旧对话"))
+ with gr.Column(min_width=120, scale=1):
+ delLastBtn = gr.Button(
+ i18n("🗑️ 删除最新对话"), elem_id="gr-dellast-btn")
+ with gr.Row(visible=False) as like_dislike_area:
+ with gr.Column(min_width=20, scale=1):
+ likeBtn = gr.Button(
+ "👍", elem_id="gr-like-btn")
+ with gr.Column(min_width=20, scale=1):
+ dislikeBtn = gr.Button(
+ "👎", elem_id="gr-dislike-btn")
+
+ with gr.Column(elem_id="toolbox-area", scale=1):
+ # For CSS setting, there is an extra box. Don't remove it.
+ with gr.Box(elem_id="chuanhu-toolbox"):
+ with gr.Row():
+ gr.Markdown("## "+i18n("工具箱"))
+ gr.HTML(get_html("close_btn.html").format(
+ obj="toolbox"), elem_classes="close-btn")
+ with gr.Tabs(elem_id="chuanhu-toolbox-tabs"):
+ with gr.Tab(label=i18n("对话")):
+ with gr.Accordion(label="Prompt", open=True):
+ systemPromptTxt = gr.Textbox(
+ show_label=True,
+ placeholder=i18n("在这里输入System Prompt..."),
+ label="System prompt",
+ value=INITIAL_SYSTEM_PROMPT,
+ lines=8
+ )
+ retain_system_prompt_checkbox = gr.Checkbox(
+ label=i18n("新建对话保留Prompt"), value=False, visible=True, elem_classes="switch-checkbox")
+ with gr.Accordion(label=i18n("加载Prompt模板"), open=False):
with gr.Column():
- downloadFile = gr.File(interactive=True)
-
- with gr.Tab(label=i18n("微调")):
- openai_train_status = gr.Markdown(label=i18n("训练状态"), value=i18n("在这里[查看使用介绍](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B#%E5%BE%AE%E8%B0%83-gpt-35)"))
-
- with gr.Tab(label=i18n("准备数据集")):
- dataset_preview_json = gr.JSON(label=i18n("数据集预览"), readonly=True)
- dataset_selection = gr.Files(label = i18n("选择数据集"), file_types=[".xlsx", ".jsonl"], file_count="single")
- upload_to_openai_btn = gr.Button(i18n("上传到OpenAI"), variant="primary", interactive=False)
-
- with gr.Tab(label=i18n("训练")):
- openai_ft_file_id = gr.Textbox(label=i18n("文件ID"), value="", lines=1, placeholder=i18n("上传到 OpenAI 后自动填充"))
- openai_ft_suffix = gr.Textbox(label=i18n("模型名称后缀"), value="", lines=1, placeholder=i18n("可选,用于区分不同的模型"))
- openai_train_epoch_slider = gr.Slider(label=i18n("训练轮数(Epochs)"), minimum=1, maximum=100, value=3, step=1, interactive=True)
- openai_start_train_btn = gr.Button(i18n("开始训练"), variant="primary", interactive=False)
-
- with gr.Tab(label=i18n("状态")):
- openai_status_refresh_btn = gr.Button(i18n("刷新状态"))
- openai_cancel_all_jobs_btn = gr.Button(i18n("取消所有任务"))
- add_to_models_btn = gr.Button(i18n("添加训练好的模型到模型列表"), interactive=False)
-
- with gr.Tab(label=i18n("高级")):
- gr.HTML(get_html("appearance_switcher.html").format(label=i18n("切换亮暗色主题")), elem_classes="insert-block")
- use_streaming_checkbox = gr.Checkbox(
- label=i18n("实时传输回答"), value=True, visible=ENABLE_STREAMING_OPTION, elem_classes="switch-checkbox"
- )
- checkUpdateBtn = gr.Button(i18n("🔄 检查更新..."), visible=check_update)
- gr.Markdown(i18n("# ⚠️ 务必谨慎更改 ⚠️"), elem_id="advanced-warning")
- with gr.Accordion(i18n("参数"), open=False):
- temperature_slider = gr.Slider(
- minimum=-0,
- maximum=2.0,
- value=1.0,
- step=0.1,
- interactive=True,
- label="temperature",
- )
- top_p_slider = gr.Slider(
- minimum=-0,
- maximum=1.0,
- value=1.0,
- step=0.05,
- interactive=True,
- label="top-p",
- )
- n_choices_slider = gr.Slider(
- minimum=1,
- maximum=10,
- value=1,
- step=1,
- interactive=True,
- label="n choices",
- )
- stop_sequence_txt = gr.Textbox(
+ with gr.Row():
+ with gr.Column(scale=6):
+ templateFileSelectDropdown = gr.Dropdown(
+ label=i18n("选择Prompt模板集合文件"),
+ choices=get_template_names(),
+ multiselect=False,
+ value=get_template_names()[0],
+ container=False,
+ )
+ with gr.Column(scale=1):
+ templateRefreshBtn = gr.Button(
+ i18n("🔄 刷新"))
+ with gr.Row():
+ with gr.Column():
+ templateSelectDropdown = gr.Dropdown(
+ label=i18n("从Prompt模板中加载"),
+ choices=load_template(
+ get_template_names()[
+ 0], mode=1
+ ),
+ multiselect=False,
+ container=False,
+ )
+ gr.Markdown("---", elem_classes="hr-line")
+ with gr.Accordion(label=i18n("知识库"), open=True):
+ use_websearch_checkbox = gr.Checkbox(label=i18n(
+ "使用在线搜索"), value=False, elem_classes="switch-checkbox", elem_id="gr-websearch-cb", visible=False)
+ index_files = gr.Files(label=i18n(
+ "上传"), type="file", elem_id="upload-index-file")
+ two_column = gr.Checkbox(label=i18n(
+ "双栏pdf"), value=advance_docs["pdf"].get("two_column", False))
+ summarize_btn = gr.Button(i18n("总结"))
+ # TODO: 公式ocr
+ # formula_ocr = gr.Checkbox(label=i18n("识别公式"), value=advance_docs["pdf"].get("formula_ocr", False))
+
+ with gr.Tab(label=i18n("参数")):
+ gr.Markdown(i18n("# ⚠️ 务必谨慎更改 ⚠️"),
+ elem_id="advanced-warning")
+ with gr.Accordion(i18n("参数"), open=True):
+ temperature_slider = gr.Slider(
+ minimum=-0,
+ maximum=2.0,
+ value=1.0,
+ step=0.1,
+ interactive=True,
+ label="temperature",
+ )
+ top_p_slider = gr.Slider(
+ minimum=-0,
+ maximum=1.0,
+ value=1.0,
+ step=0.05,
+ interactive=True,
+ label="top-p",
+ )
+ n_choices_slider = gr.Slider(
+ minimum=1,
+ maximum=10,
+ value=1,
+ step=1,
+ interactive=True,
+ label="n choices",
+ )
+ stop_sequence_txt = gr.Textbox(
+ show_label=True,
+ placeholder=i18n("停止符,用英文逗号隔开..."),
+ label="stop",
+ value="",
+ lines=1,
+ )
+ max_context_length_slider = gr.Slider(
+ minimum=1,
+ maximum=32768,
+ value=2000,
+ step=1,
+ interactive=True,
+ label="max context",
+ )
+ max_generation_slider = gr.Slider(
+ minimum=1,
+ maximum=32768,
+ value=1000,
+ step=1,
+ interactive=True,
+ label="max generations",
+ )
+ presence_penalty_slider = gr.Slider(
+ minimum=-2.0,
+ maximum=2.0,
+ value=0.0,
+ step=0.01,
+ interactive=True,
+ label="presence penalty",
+ )
+ frequency_penalty_slider = gr.Slider(
+ minimum=-2.0,
+ maximum=2.0,
+ value=0.0,
+ step=0.01,
+ interactive=True,
+ label="frequency penalty",
+ )
+ logit_bias_txt = gr.Textbox(
+ show_label=True,
+ placeholder=f"word:likelihood",
+ label="logit bias",
+ value="",
+ lines=1,
+ )
+ user_identifier_txt = gr.Textbox(
+ show_label=True,
+ placeholder=i18n("用于定位滥用行为"),
+ label=i18n("用户名"),
+ value=user_name.value,
+ lines=1,
+ )
+ with gr.Tab(label=i18n("拓展")):
+ gr.Markdown(
+ "Will be here soon...\n(We hope)\n\nAnd we hope you can help us to make more extensions!")
+
+ # changeAPIURLBtn = gr.Button(i18n("🔄 切换API地址"))
+
+ with gr.Row(elem_id="popup-wrapper"):
+ with gr.Box(elem_id="chuanhu-popup"):
+ with gr.Box(elem_id="chuanhu-setting"):
+ with gr.Row():
+ gr.Markdown("## "+i18n("设置"))
+ gr.HTML(get_html("close_btn.html").format(
+ obj="box"), elem_classes="close-btn")
+ with gr.Tabs(elem_id="chuanhu-setting-tabs"):
+ with gr.Tab(label=i18n("模型")):
+ keyTxt = gr.Textbox(
show_label=True,
- placeholder=i18n("停止符,用英文逗号隔开..."),
- label="stop",
- value="",
- lines=1,
+ placeholder=f"Your API-key...",
+ value=hide_middle_chars(user_api_key.value),
+ type="password",
+ visible=not HIDE_MY_KEY,
+ label="API-Key",
)
- max_context_length_slider = gr.Slider(
- minimum=1,
- maximum=32768,
- value=2000,
- step=1,
- interactive=True,
- label="max context",
+ if multi_api_key:
+ usageTxt = gr.Markdown(i18n(
+ "多账号模式已开启,无需输入key,可直接开始对话"), elem_id="usage-display", elem_classes="insert-block", visible=show_api_billing)
+ else:
+ usageTxt = gr.Markdown(i18n(
+ "**发送消息** 或 **提交key** 以显示额度"), elem_id="usage-display", elem_classes="insert-block", visible=show_api_billing)
+ # model_select_dropdown = gr.Dropdown(
+ # label=i18n("选择模型"), choices=MODELS, multiselect=False, value=MODELS[DEFAULT_MODEL], interactive=True
+ # )
+ # lora_select_dropdown = gr.Dropdown(
+ # label=i18n("选择LoRA模型"), choices=[], multiselect=False, interactive=True, visible=False
+ # )
+ # with gr.Row():
+
+ language_select_dropdown = gr.Dropdown(
+ label=i18n("选择回复语言(针对搜索&索引功能)"),
+ choices=REPLY_LANGUAGES,
+ multiselect=False,
+ value=REPLY_LANGUAGES[0],
)
- max_generation_slider = gr.Slider(
- minimum=1,
- maximum=32768,
- value=1000,
- step=1,
- interactive=True,
- label="max generations",
- )
- presence_penalty_slider = gr.Slider(
- minimum=-2.0,
- maximum=2.0,
- value=0.0,
- step=0.01,
- interactive=True,
- label="presence penalty",
+
+ with gr.Tab(label=i18n("高级")):
+ gr.HTML(get_html("appearance_switcher.html").format(
+ label=i18n("切换亮暗色主题")), elem_classes="insert-block", visible=False)
+ use_streaming_checkbox = gr.Checkbox(
+ label=i18n("实时传输回答"), value=True, visible=ENABLE_STREAMING_OPTION, elem_classes="switch-checkbox"
)
- frequency_penalty_slider = gr.Slider(
- minimum=-2.0,
- maximum=2.0,
- value=0.0,
- step=0.01,
+ name_chat_method = gr.Dropdown(
+ label=i18n("对话命名方式"),
+ choices=HISTORY_NAME_METHODS,
+ multiselect=False,
interactive=True,
- label="frequency penalty",
- )
- logit_bias_txt = gr.Textbox(
- show_label=True,
- placeholder=f"word:likelihood",
- label="logit bias",
- value="",
- lines=1,
- )
- user_identifier_txt = gr.Textbox(
- show_label=True,
- placeholder=i18n("用于定位滥用行为"),
- label=i18n("用户名"),
- value=user_name.value,
- lines=1,
+ value=HISTORY_NAME_METHODS[chat_name_method_index],
)
+ single_turn_checkbox = gr.Checkbox(label=i18n(
+ "单轮对话"), value=False, elem_classes="switch-checkbox", elem_id="gr-single-session-cb", visible=False)
+ # checkUpdateBtn = gr.Button(i18n("🔄 检查更新..."), visible=check_update)
- with gr.Accordion(i18n("网络参数"), open=False):
- gr.Markdown(i18n("---\n⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置"), elem_id="netsetting-warning")
+ with gr.Tab(i18n("网络")):
+ gr.Markdown(
+ i18n("⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置"), elem_id="netsetting-warning")
default_btn = gr.Button(i18n("🔙 恢复默认网络设置"))
# 网络代理
proxyTxt = gr.Textbox(
@@ -319,25 +413,99 @@ with gr.Blocks(theme=small_and_beautiful_theme) as demo:
# container=False,
elem_classes="view-only-textbox no-container",
)
- # changeAPIURLBtn = gr.Button(i18n("🔄 切换API地址"))
- updateChuanhuBtn = gr.Button(visible=False, elem_classes="invisible-btn", elem_id="update-chuanhu-btn")
-
- gr.Markdown(CHUANHU_DESCRIPTION, elem_id="description")
- gr.HTML(get_html("footer.html").format(versions=versions_html()), elem_id="footer")
+ with gr.Tab(label=i18n("关于"), elem_id="about-tab"):
+ gr.Markdown(
+ '')
+ gr.Markdown("# "+i18n("川虎Chat"))
+ gr.HTML(get_html("footer.html").format(
+ versions=versions_html()), elem_id="footer")
+ gr.Markdown(CHUANHU_DESCRIPTION, elem_id="description")
+
+ with gr.Box(elem_id="chuanhu-training"):
+ with gr.Row():
+ gr.Markdown("## "+i18n("训练"))
+ gr.HTML(get_html("close_btn.html").format(
+ obj="box"), elem_classes="close-btn")
+ with gr.Tabs(elem_id="chuanhu-training-tabs"):
+ with gr.Tab(label="OpenAI "+i18n("微调")):
+ openai_train_status = gr.Markdown(label=i18n("训练状态"), value=i18n(
+ "查看[使用介绍](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35)"))
+
+ with gr.Tab(label=i18n("准备数据集")):
+ dataset_preview_json = gr.JSON(
+ label=i18n("数据集预览"))
+ dataset_selection = gr.Files(label=i18n("选择数据集"), file_types=[
+ ".xlsx", ".jsonl"], file_count="single")
+ upload_to_openai_btn = gr.Button(
+ i18n("上传到OpenAI"), variant="primary", interactive=False)
+
+ with gr.Tab(label=i18n("训练")):
+ openai_ft_file_id = gr.Textbox(label=i18n(
+ "文件ID"), value="", lines=1, placeholder=i18n("上传到 OpenAI 后自动填充"))
+ openai_ft_suffix = gr.Textbox(label=i18n(
+ "模型名称后缀"), value="", lines=1, placeholder=i18n("可选,用于区分不同的模型"))
+ openai_train_epoch_slider = gr.Slider(label=i18n(
+ "训练轮数(Epochs)"), minimum=1, maximum=100, value=3, step=1, interactive=True)
+ openai_start_train_btn = gr.Button(
+ i18n("开始训练"), variant="primary", interactive=False)
+
+ with gr.Tab(label=i18n("状态")):
+ openai_status_refresh_btn = gr.Button(i18n("刷新状态"))
+ openai_cancel_all_jobs_btn = gr.Button(
+ i18n("取消所有任务"))
+ add_to_models_btn = gr.Button(
+ i18n("添加训练好的模型到模型列表"), interactive=False)
+
+ with gr.Box(elem_id="web-config", visible=False):
+ gr.HTML(get_html('web_config.html').format(
+ enableCheckUpdate_config=check_update,
+ hideHistoryWhenNotLoggedIn_config=hide_history_when_not_logged_in,
+ forView_i18n=i18n("仅供查看"),
+ deleteConfirm_i18n_pref=i18n("你真的要删除 "),
+ deleteConfirm_i18n_suff=i18n(" 吗?"),
+ usingLatest_i18n=i18n("您使用的就是最新版!"),
+ updatingMsg_i18n=i18n("正在尝试更新..."),
+ updateSuccess_i18n=i18n("更新成功,请重启本程序"),
+ updateFailure_i18n=i18n(
+ "更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)"),
+ regenerate_i18n=i18n("重新生成"),
+ deleteRound_i18n=i18n("删除这轮问答"),
+ renameChat_i18n=i18n("重命名该对话"),
+ validFileName_i18n=i18n("请输入有效的文件名,不要包含以下特殊字符:"),
+ ))
+ with gr.Box(elem_id="fake-gradio-components", visible=False):
+ updateChuanhuBtn = gr.Button(
+ visible=False, elem_classes="invisible-btn", elem_id="update-chuanhu-btn")
+ changeSingleSessionBtn = gr.Button(
+ visible=False, elem_classes="invisible-btn", elem_id="change-single-session-btn")
+ changeOnlineSearchBtn = gr.Button(
+ visible=False, elem_classes="invisible-btn", elem_id="change-online-search-btn")
+ historySelectBtn = gr.Button(
+ visible=False, elem_classes="invisible-btn", elem_id="history-select-btn") # Not used
# https://github.com/gradio-app/gradio/pull/3296
+
def create_greeting(request: gr.Request):
- if hasattr(request, "username") and request.username: # is not None or is not ""
+ if hasattr(request, "username") and request.username: # is not None or is not ""
logging.info(f"Get User Name: {request.username}")
- user_info, user_name = gr.Markdown.update(value=f"User: {request.username}"), request.username
+ user_info, user_name = gr.Markdown.update(
+ value=f"User: {request.username}"), request.username
else:
- user_info, user_name = gr.Markdown.update(value=f"", visible=False), ""
- current_model = get_model(model_name = MODELS[DEFAULT_MODEL], access_key = my_api_key)[0]
+ user_info, user_name = gr.Markdown.update(
+ value=f"", visible=False), ""
+ current_model = get_model(
+ model_name=MODELS[DEFAULT_MODEL], access_key=my_api_key)[0]
current_model.set_user_identifier(user_name)
- chatbot = gr.Chatbot.update(label=MODELS[DEFAULT_MODEL])
- return user_info, user_name, current_model, toggle_like_btn_visibility(DEFAULT_MODEL), *current_model.auto_load(), get_history_names(False, user_name), chatbot
- demo.load(create_greeting, inputs=None, outputs=[user_info, user_name, current_model, like_dislike_area, systemPromptTxt, chatbot, historyFileSelectDropdown, chatbot], api_name="load")
+ if not hide_history_when_not_logged_in or user_name:
+ filename, system_prompt, chatbot = current_model.auto_load()
+ else:
+ system_prompt = gr.update()
+ filename = gr.update()
+ chatbot = gr.Chatbot.update(label=MODELS[DEFAULT_MODEL])
+ return user_info, user_name, current_model, toggle_like_btn_visibility(DEFAULT_MODEL), filename, system_prompt, chatbot, init_history_list(user_name)
+ demo.load(create_greeting, inputs=None, outputs=[
+ user_info, user_name, current_model, like_dislike_area, saveFileName, systemPromptTxt, chatbot, historySelectList], api_name="load")
chatgpt_predict_args = dict(
fn=predict,
inputs=[
@@ -369,42 +537,58 @@ with gr.Blocks(theme=small_and_beautiful_theme) as demo:
)
transfer_input_args = dict(
- fn=transfer_input, inputs=[user_input], outputs=[user_question, user_input, submitBtn, cancelBtn], show_progress=True
+ fn=transfer_input, inputs=[user_input], outputs=[
+ user_question, user_input, submitBtn, cancelBtn], show_progress=True
)
get_usage_args = dict(
- fn=billing_info, inputs=[current_model], outputs=[usageTxt], show_progress=False
+ fn=billing_info, inputs=[current_model], outputs=[
+ usageTxt], show_progress=False
)
load_history_from_file_args = dict(
fn=load_chat_history,
- inputs=[current_model, historyFileSelectDropdown, user_name],
+ inputs=[current_model, historySelectList, user_name],
outputs=[saveFileName, systemPromptTxt, chatbot]
)
refresh_history_args = dict(
- fn=get_history_names, inputs=[gr.State(False), user_name], outputs=[historyFileSelectDropdown]
+ fn=get_history_list, inputs=[user_name], outputs=[historySelectList]
)
+ auto_name_chat_history_args = dict(
+ fn=auto_name_chat_history,
+ inputs=[current_model, name_chat_method, user_question, chatbot, user_name, single_turn_checkbox],
+ outputs=[historySelectList],
+ show_progress=False,
+ )
# Chatbot
cancelBtn.click(interrupt, [current_model], [])
- user_input.submit(**transfer_input_args).then(**chatgpt_predict_args).then(**end_outputing_args)
+ user_input.submit(**transfer_input_args).then(**
+ chatgpt_predict_args).then(**end_outputing_args).then(**auto_name_chat_history_args)
user_input.submit(**get_usage_args)
- submitBtn.click(**transfer_input_args).then(**chatgpt_predict_args, api_name="predict").then(**end_outputing_args)
+ # user_input.submit(auto_name_chat_history, [current_model, user_question, chatbot, user_name], [historySelectList], show_progress=False)
+
+ submitBtn.click(**transfer_input_args).then(**chatgpt_predict_args,
+ api_name="predict").then(**end_outputing_args).then(**auto_name_chat_history_args)
submitBtn.click(**get_usage_args)
- index_files.change(handle_file_upload, [current_model, index_files, chatbot, language_select_dropdown], [index_files, chatbot, status_display])
- summarize_btn.click(handle_summarize_index, [current_model, index_files, chatbot, language_select_dropdown], [chatbot, status_display])
+ # submitBtn.click(auto_name_chat_history, [current_model, user_question, chatbot, user_name], [historySelectList], show_progress=False)
+
+ index_files.upload(handle_file_upload, [current_model, index_files, chatbot, language_select_dropdown], [
+ index_files, chatbot, status_display])
+ summarize_btn.click(handle_summarize_index, [
+ current_model, index_files, chatbot, language_select_dropdown], [chatbot, status_display])
emptyBtn.click(
reset,
- inputs=[current_model],
- outputs=[chatbot, status_display],
+ inputs=[current_model, retain_system_prompt_checkbox],
+ outputs=[chatbot, status_display, historySelectList, systemPromptTxt],
show_progress=True,
- _js='clearChatbot',
+ _js='(a,b)=>{return clearChatbot(a,b);}',
)
retryBtn.click(**start_outputing_args).then(
@@ -452,17 +636,24 @@ with gr.Blocks(theme=small_and_beautiful_theme) as demo:
two_column.change(update_doc_config, [two_column], None)
# LLM Models
- keyTxt.change(set_key, [current_model, keyTxt], [user_api_key, status_display], api_name="set_key").then(**get_usage_args)
+ keyTxt.change(set_key, [current_model, keyTxt], [
+ user_api_key, status_display], api_name="set_key").then(**get_usage_args)
keyTxt.submit(**get_usage_args)
- single_turn_checkbox.change(set_single_turn, [current_model, single_turn_checkbox], None)
- model_select_dropdown.change(get_model, [model_select_dropdown, lora_select_dropdown, user_api_key, temperature_slider, top_p_slider, systemPromptTxt, user_name], [current_model, status_display, chatbot, lora_select_dropdown, user_api_key, keyTxt], show_progress=True, api_name="get_model")
- model_select_dropdown.change(toggle_like_btn_visibility, [model_select_dropdown], [like_dislike_area], show_progress=False)
- lora_select_dropdown.change(get_model, [model_select_dropdown, lora_select_dropdown, user_api_key, temperature_slider, top_p_slider, systemPromptTxt, user_name], [current_model, status_display, chatbot], show_progress=True)
+ single_turn_checkbox.change(
+ set_single_turn, [current_model, single_turn_checkbox], None)
+ model_select_dropdown.change(get_model, [model_select_dropdown, lora_select_dropdown, user_api_key, temperature_slider, top_p_slider, systemPromptTxt, user_name, current_model], [
+ current_model, status_display, chatbot, lora_select_dropdown, user_api_key, keyTxt], show_progress=True, api_name="get_model")
+ model_select_dropdown.change(toggle_like_btn_visibility, [model_select_dropdown], [
+ like_dislike_area], show_progress=False)
+ lora_select_dropdown.change(get_model, [model_select_dropdown, lora_select_dropdown, user_api_key, temperature_slider,
+ top_p_slider, systemPromptTxt, user_name, current_model], [current_model, status_display, chatbot], show_progress=True)
# Template
- systemPromptTxt.change(set_system_prompt, [current_model, systemPromptTxt], None)
- templateRefreshBtn.click(get_template_names, None, [templateFileSelectDropdown])
- templateFileSelectDropdown.change(
+ systemPromptTxt.change(set_system_prompt, [
+ current_model, systemPromptTxt], None)
+ templateRefreshBtn.click(get_template_dropdown, None, [
+ templateFileSelectDropdown])
+ templateFileSelectDropdown.input(
load_template,
[templateFileSelectDropdown],
[promptTemplates, templateSelectDropdown],
@@ -476,47 +667,80 @@ with gr.Blocks(theme=small_and_beautiful_theme) as demo:
)
# S&L
- saveHistoryBtn.click(
- save_chat_history,
+ renameHistoryBtn.click(
+ rename_chat_history,
[current_model, saveFileName, chatbot, user_name],
- downloadFile,
+ [historySelectList],
show_progress=True,
+ _js='(a,b,c,d)=>{return saveChatHistory(a,b,c,d);}'
)
- saveHistoryBtn.click(get_history_names, [gr.State(False), user_name], [historyFileSelectDropdown])
exportMarkdownBtn.click(
export_markdown,
[current_model, saveFileName, chatbot, user_name],
- downloadFile,
+ [],
show_progress=True,
)
historyRefreshBtn.click(**refresh_history_args)
- historyDeleteBtn.click(delete_chat_history, [current_model, historyFileSelectDropdown, user_name], [status_display, historyFileSelectDropdown, chatbot], _js='(a,b,c)=>{return showConfirmationDialog(a, b, c);}')
- historyFileSelectDropdown.change(**load_history_from_file_args)
- downloadFile.change(upload_chat_history, [current_model, downloadFile, user_name], [saveFileName, systemPromptTxt, chatbot])
+ historyDeleteBtn.click(delete_chat_history, [current_model, historySelectList, user_name], [status_display, historySelectList, chatbot], _js='(a,b,c)=>{return showConfirmationDialog(a, b, c);}').then(
+ reset,
+ inputs=[current_model, retain_system_prompt_checkbox],
+ outputs=[chatbot, status_display, historySelectList, systemPromptTxt],
+ show_progress=True,
+ _js='(a,b)=>{return clearChatbot(a,b);}',
+ )
+ historySelectList.input(**load_history_from_file_args)
+ uploadFileBtn.upload(upload_chat_history, [current_model, uploadFileBtn, user_name], [
+ saveFileName, systemPromptTxt, chatbot]).then(**refresh_history_args)
+ historyDownloadBtn.click(None, [
+ user_name, historySelectList], None, _js='(a,b)=>{return downloadHistory(a,b,".json");}')
+ historyMarkdownDownloadBtn.click(None, [
+ user_name, historySelectList], None, _js='(a,b)=>{return downloadHistory(a,b,".md");}')
+ historySearchTextbox.input(
+ filter_history,
+ [user_name, historySearchTextbox],
+ [historySelectList]
+ )
# Train
- dataset_selection.upload(handle_dataset_selection, dataset_selection, [dataset_preview_json, upload_to_openai_btn, openai_train_status])
- dataset_selection.clear(handle_dataset_clear, [], [dataset_preview_json, upload_to_openai_btn])
- upload_to_openai_btn.click(upload_to_openai, [dataset_selection], [openai_ft_file_id, openai_train_status], show_progress=True)
-
- openai_ft_file_id.change(lambda x: gr.update(interactive=True) if len(x) > 0 else gr.update(interactive=False), [openai_ft_file_id], [openai_start_train_btn])
- openai_start_train_btn.click(start_training, [openai_ft_file_id, openai_ft_suffix, openai_train_epoch_slider], [openai_train_status])
-
- openai_status_refresh_btn.click(get_training_status, [], [openai_train_status, add_to_models_btn])
- add_to_models_btn.click(add_to_models, [], [model_select_dropdown, openai_train_status], show_progress=True)
- openai_cancel_all_jobs_btn.click(cancel_all_jobs, [], [openai_train_status], show_progress=True)
+ dataset_selection.upload(handle_dataset_selection, dataset_selection, [
+ dataset_preview_json, upload_to_openai_btn, openai_train_status])
+ dataset_selection.clear(handle_dataset_clear, [], [
+ dataset_preview_json, upload_to_openai_btn])
+ upload_to_openai_btn.click(upload_to_openai, [dataset_selection], [
+ openai_ft_file_id, openai_train_status], show_progress=True)
+
+ openai_ft_file_id.change(lambda x: gr.update(interactive=True) if len(
+ x) > 0 else gr.update(interactive=False), [openai_ft_file_id], [openai_start_train_btn])
+ openai_start_train_btn.click(start_training, [
+ openai_ft_file_id, openai_ft_suffix, openai_train_epoch_slider], [openai_train_status])
+
+ openai_status_refresh_btn.click(get_training_status, [], [
+ openai_train_status, add_to_models_btn])
+ add_to_models_btn.click(add_to_models, [], [
+ model_select_dropdown, openai_train_status], show_progress=True)
+ openai_cancel_all_jobs_btn.click(
+ cancel_all_jobs, [], [openai_train_status], show_progress=True)
# Advanced
- max_context_length_slider.change(set_token_upper_limit, [current_model, max_context_length_slider], None)
- temperature_slider.change(set_temperature, [current_model, temperature_slider], None)
+ max_context_length_slider.change(
+ set_token_upper_limit, [current_model, max_context_length_slider], None)
+ temperature_slider.change(
+ set_temperature, [current_model, temperature_slider], None)
top_p_slider.change(set_top_p, [current_model, top_p_slider], None)
- n_choices_slider.change(set_n_choices, [current_model, n_choices_slider], None)
- stop_sequence_txt.change(set_stop_sequence, [current_model, stop_sequence_txt], None)
- max_generation_slider.change(set_max_tokens, [current_model, max_generation_slider], None)
- presence_penalty_slider.change(set_presence_penalty, [current_model, presence_penalty_slider], None)
- frequency_penalty_slider.change(set_frequency_penalty, [current_model, frequency_penalty_slider], None)
- logit_bias_txt.change(set_logit_bias, [current_model, logit_bias_txt], None)
- user_identifier_txt.change(set_user_identifier, [current_model, user_identifier_txt], None)
+ n_choices_slider.change(
+ set_n_choices, [current_model, n_choices_slider], None)
+ stop_sequence_txt.change(
+ set_stop_sequence, [current_model, stop_sequence_txt], None)
+ max_generation_slider.change(
+ set_max_tokens, [current_model, max_generation_slider], None)
+ presence_penalty_slider.change(
+ set_presence_penalty, [current_model, presence_penalty_slider], None)
+ frequency_penalty_slider.change(
+ set_frequency_penalty, [current_model, frequency_penalty_slider], None)
+ logit_bias_txt.change(
+ set_logit_bias, [current_model, logit_bias_txt], None)
+ user_identifier_txt.change(set_user_identifier, [
+ current_model, user_identifier_txt], None)
default_btn.click(
reset_default, [], [apihostTxt, proxyTxt, status_display], show_progress=True
@@ -533,7 +757,7 @@ with gr.Blocks(theme=small_and_beautiful_theme) as demo:
# [status_display],
# show_progress=True,
# )
- checkUpdateBtn.click(fn=None, _js='manualCheckUpdate')
+ # checkUpdateBtn.click(fn=None, _js='manualCheckUpdate')
# Invisible elements
updateChuanhuBtn.click(
@@ -542,6 +766,25 @@ with gr.Blocks(theme=small_and_beautiful_theme) as demo:
[status_display],
show_progress=True,
)
+ changeSingleSessionBtn.click(
+ fn=lambda value: gr.Checkbox.update(value=value),
+ inputs=[single_turn_checkbox],
+ outputs=[single_turn_checkbox],
+ _js='(a)=>{return bgChangeSingleSession(a);}'
+ )
+ changeOnlineSearchBtn.click(
+ fn=lambda value: gr.Checkbox.update(value=value),
+ inputs=[use_websearch_checkbox],
+ outputs=[use_websearch_checkbox],
+ _js='(a)=>{return bgChangeOnlineSearch(a);}'
+ )
+ historySelectBtn.click( # This is an experimental feature... Not actually used.
+ fn=load_chat_history,
+ inputs=[current_model, historySelectList],
+ outputs=[saveFileName, systemPromptTxt, chatbot],
+ _js='(a,b)=>{return bgSelectHistory(a,b);}'
+ )
+
logging.info(
colorama.Back.GREEN
@@ -554,6 +797,8 @@ demo.title = i18n("川虎Chat 🚀")
if __name__ == "__main__":
reload_javascript()
demo.queue(concurrency_count=CONCURRENT_COUNT).launch(
- blocked_paths=["config.json"],
+ allowed_paths=["history", "web_assets"],
+ auth=auth_from_conf if authflag else None,
favicon_path="./web_assets/favicon.ico",
+ inbrowser=not dockerflag, # 禁止在docker下开启inbrowser
)
diff --git a/README.md b/README.md
index 820a9a57349cfbf6d565c797ed822c398347e682..f22239cee71784ded3c9c459db9b57bda9a92ff3 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,15 @@
+```
---
title: ChuanhuChatGPT
emoji: 🐯
colorFrom: yellow
colorTo: yellow
sdk: gradio
-sdk_version: 3.40.0
+sdk_version: 3.43.2
app_file: ChuanhuChatbot.py
pinned: false
license: gpl-3.0
---
-Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
\ No newline at end of file
+Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
+```
diff --git a/config_example.json b/config_example.json
index 0b77caefbb39ef08d6a53b3b40ee67bb8a3b1576..8558c0229b9ba3ef7194a318bbbd8cfc2fe46cde 100644
--- a/config_example.json
+++ b/config_example.json
@@ -11,6 +11,10 @@
"midjourney_proxy_api_secret": "", // 你的 MidJourney Proxy API Secret,用于鉴权访问 api,可选
"midjourney_discord_proxy_url": "", // 你的 MidJourney Discord Proxy URL,用于对生成对图进行反代,可选
"midjourney_temp_folder": "./tmp", // 你的 MidJourney 临时文件夹,用于存放生成的图片,填空则关闭自动下载切图(直接显示MJ的四宫格图)
+ "spark_appid": "", // 你的 讯飞星火大模型 API AppID,用于讯飞星火大模型对话模型
+ "spark_api_key": "", // 你的 讯飞星火大模型 API Key,用于讯飞星火大模型对话模型
+ "spark_api_secret": "", // 你的 讯飞星火大模型 API Secret,用于讯飞星火大模型对话模型
+ "claude_api_secret":"",// 你的 Claude API Secret,用于 Claude 对话模型
//== Azure ==
@@ -23,14 +27,15 @@
"azure_embedding_model_name": "text-embedding-ada-002", // 你的 Azure OpenAI Embedding 模型名称
//== 基础配置 ==
- "language": "auto", // 界面语言,可选"auto", "zh-CN", "en-US", "ja-JP", "ko-KR", "sv-SE"
+ "language": "auto", // 界面语言,可选"auto", "zh_CN", "en_US", "ja_JP", "ko_KR", "sv_SE", "ru_RU", "vi_VN"
"users": [], // 用户列表,[[用户名1, 密码1], [用户名2, 密码2], ...]
"local_embedding": false, //是否在本地编制索引
"hide_history_when_not_logged_in": false, //未登录情况下是否不展示对话历史
"check_update": true, //是否启用检查更新
"default_model": "gpt-3.5-turbo", // 默认模型
- "bot_avatar": "default", // 机器人头像,可填写图片链接、Data URL (base64),或者"none"(不显示头像)
- "user_avatar": "default", // 用户头像,可填写图片链接、Data URL (base64),或者"none"(不显示头像)
+ "chat_name_method_index": 2, // 选择对话名称的方法。0: 使用日期时间命名;1: 使用第一条提问命名,2: 使用模型自动总结
+ "bot_avatar": "default", // 机器人头像,可填写本地或网络图片链接,或者"none"(不显示头像)
+ "user_avatar": "default", // 用户头像,可填写本地或网络图片链接,或者"none"(不显示头像)
//== API 用量 ==
"show_api_billing": false, //是否显示OpenAI API用量(启用需要填写sensitive_id)
@@ -57,11 +62,13 @@
//== 高级配置 ==
// 是否多个API Key轮换使用
"multi_api_key": false,
- "api_key_list": [
- "sk-xxxxxxxxxxxxxxxxxxxxxxxx1",
- "sk-xxxxxxxxxxxxxxxxxxxxxxxx2",
- "sk-xxxxxxxxxxxxxxxxxxxxxxxx3"
- ],
+ // "available_models": ["GPT3.5 Turbo", "GPT4 Turbo", "GPT4 Vision"], // 可用的模型列表,将覆盖默认的可用模型列表
+ // "extra_models": ["模型名称3", "模型名称4", ...], // 额外的模型,将添加到可用的模型列表之后
+ // "api_key_list": [
+ // "sk-xxxxxxxxxxxxxxxxxxxxxxxx1",
+ // "sk-xxxxxxxxxxxxxxxxxxxxxxxx2",
+ // "sk-xxxxxxxxxxxxxxxxxxxxxxxx3"
+ // ],
// 自定义OpenAI API Base
// "openai_api_base": "https://api.openai.com",
// 自定义使用代理(请替换代理URL)
diff --git a/locale/en_US.json b/locale/en_US.json
index 17a5aa618ee8e1c4425a7ce69e1d86adfbd24b6c..9ceaa244f8d2b468ca02520bc1cbefe477a9fdaa 100644
--- a/locale/en_US.json
+++ b/locale/en_US.json
@@ -1,87 +1,141 @@
{
- "未命名对话历史记录": "Unnamed Dialog History",
- "在这里输入": "Type in here",
- "🧹 新的对话": "🧹 New Dialogue",
- "🔄 重新生成": "🔄 Regeneration",
- "🗑️ 删除最旧对话": "🗑️ Delete oldest dialog",
- "🗑️ 删除最新对话": "🗑️ Delete latest dialog",
- "模型": "Model",
- "多账号模式已开启,无需输入key,可直接开始对话": "Multi-account mode is enabled, no need to enter key, you can start the dialogue directly",
+ " 吗?": " ?",
+ "# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ Caution: Changes require care. ⚠️",
"**发送消息** 或 **提交key** 以显示额度": "**Send message** or **Submit key** to display credit",
- "选择模型": "Select Model",
- "选择LoRA模型": "Select LoRA Model",
- "实时传输回答": "Stream output",
- "单轮对话": "Single-turn dialogue",
- "使用在线搜索": "Use online search",
- "选择回复语言(针对搜索&索引功能)": "Select reply language (for search & index)",
- "上传索引文件": "Upload",
- "双栏pdf": "Two-column pdf",
- "识别公式": "formula OCR",
- "在这里输入System Prompt...": "Type in System Prompt here...",
- "加载Prompt模板": "Load Prompt Template",
- "选择Prompt模板集合文件": "Select Prompt Template Collection File",
- "🔄 刷新": "🔄 Refresh",
+ "**本月使用金额** ": "**Monthly usage** ",
+ "**获取API使用情况失败**": "**Failed to get API usage**",
+ "**获取API使用情况失败**,sensitive_id错误或已过期": "**Failed to get API usage**, wrong or expired sensitive_id",
+ "**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**Failed to get API usage**, correct sensitive_id needed in `config.json`",
+ "API key为空,请检查是否输入正确。": "API key is empty, check whether it is entered correctly.",
+ "API密钥更改为了": "The API key is changed to",
+ "JSON解析错误,收到的内容: ": "JSON parsing error, received content: ",
+ "SSL错误,无法获取对话。": "SSL error, unable to get dialogue.",
+ "Token 计数: ": "Token Count: ",
+ "☹️发生了错误:": "☹️Error: ",
+ "⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "⚠️ To ensure the security of API-Key, please modify the network settings in the configuration file `config.json`.",
+ "。你仍然可以使用聊天功能。": ". You can still use the chat function.",
+ "上传": "Upload",
+ "上传了": "Uploaded",
+ "上传到 OpenAI 后自动填充": "Automatically filled after uploading to OpenAI",
+ "上传到OpenAI": "Upload to OpenAI",
+ "上传文件": "Upload files",
+ "仅供查看": "For viewing only",
"从Prompt模板中加载": "Load from Prompt Template",
- "保存/加载": "Save/Load",
- "保存/加载对话历史记录": "Save/Load Dialog History",
"从列表中加载对话": "Load dialog from list",
- "设置文件名: 默认为.json,可选为.md": "Set file name: default is .json, optional is .md",
- "设置保存文件名": "Set save file name",
- "对话历史记录": "Dialog History",
- "💾 保存对话": "💾 Save Dialog",
- "📝 导出为Markdown": "📝 Export as Markdown",
- "默认保存于history文件夹": "Default save in history folder",
- "高级": "Advanced",
- "# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ Caution: Changes require care. ⚠️",
- "参数": "Parameters",
- "停止符,用英文逗号隔开...": "Type in stop token here, separated by comma...",
- "用于定位滥用行为": "Used to locate abuse",
- "用户名": "Username",
- "在这里输入API-Host...": "Type in API-Host here...",
- "🔄 切换API地址": "🔄 Switch API Address",
- "未设置代理...": "No proxy...",
"代理地址": "Proxy address",
- "🔄 设置代理地址": "🔄 Set Proxy Address",
- "🔙 恢复默认网络设置": "🔙 Reset Network Settings",
- "🔄 检查更新...": "🔄 Check for Update...",
+ "代理错误,无法获取对话。": "Proxy error, unable to get dialogue.",
+ "你没有权限访问 GPT4,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)": "You do not have permission to access GPT-4, [learn more](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)",
+ "你没有选择任何对话历史": "You have not selected any conversation history.",
+ "你真的要删除 ": "Are you sure you want to delete ",
+ "使用在线搜索": "Use online search",
+ "停止符,用英文逗号隔开...": "Type in stop token here, separated by comma...",
+ "关于": "About",
+ "准备数据集": "Prepare Dataset",
+ "切换亮暗色主题": "Switch light/dark theme",
+ "删除对话历史成功": "Successfully deleted conversation history.",
+ "删除这轮问答": "Delete this round of Q&A",
+ "刷新状态": "Refresh Status",
+ "剩余配额不足,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)": "Insufficient remaining quota, [learn more](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)",
+ "加载Prompt模板": "Load Prompt Template",
+ "单轮对话": "Single-turn",
+ "历史记录(JSON)": "History file (JSON)",
+ "参数": "Parameters",
+ "双栏pdf": "Two-column pdf",
"取消": "Cancel",
- "更新": "Update",
- "详情": "Details",
+ "取消所有任务": "Cancel All Tasks",
+ "可选,用于区分不同的模型": "Optional, used to distinguish different models",
+ "启用的工具:": "Enabled tools: ",
+ "在工具箱中管理知识库文件": "Manage knowledge base files in the toolbox",
+ "在线搜索": "Web search",
+ "在这里输入": "Type in here",
+ "在这里输入System Prompt...": "Type in System Prompt here...",
+ "多账号模式已开启,无需输入key,可直接开始对话": "Multi-account mode is enabled, no need to enter key, you can start the dialogue directly",
"好": "OK",
- "更新成功,请重启本程序": "Updated successfully, please restart this program",
- "更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "Update failed, please try [manually updating](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)",
+ "实时传输回答": "Stream output",
+ "对话": "Dialogue",
+ "对话历史": "Conversation history",
+ "对话历史记录": "Dialog History",
+ "对话命名方式": "History naming method",
+ "导出为 Markdown": "Export as Markdown",
+ "川虎Chat": "Chuanhu Chat",
"川虎Chat 🚀": "Chuanhu Chat 🚀",
+ "工具箱": "Toolbox",
+ "已经被删除啦": "It has been deleted.",
"开始实时传输回答……": "Start streaming output...",
- "Token 计数: ": "Token Count: ",
- ",本次对话累计消耗了 ": ", Total cost for this dialogue is ",
- "**获取API使用情况失败**": "**Failed to get API usage**",
- "**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**Failed to get API usage**, correct sensitive_id needed in `config.json`",
- "**获取API使用情况失败**,sensitive_id错误或已过期": "**Failed to get API usage**, wrong or expired sensitive_id",
- "**本月使用金额** ": "**Monthly usage** ",
+ "开始训练": "Start Training",
+ "微调": "Fine-tuning",
+ "总结": "Summarize",
+ "总结完成": "Summary completed.",
+ "您使用的就是最新版!": "You are using the latest version!",
+ "您的IP区域:": "Your IP region: ",
+ "您的IP区域:未知。": "Your IP region: Unknown.",
+ "拓展": "Extensions",
+ "搜索(支持正则)...": "Search (supports regex)...",
+ "数据集预览": "Dataset Preview",
+ "文件ID": "File ID",
+ "新对话 ": "New Chat ",
+ "新建对话保留Prompt": "Retain Prompt For New Chat",
+ "暂时未知": "Unknown",
+ "更新": "Update",
+ "更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "Update failed, please try [manually updating](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)",
+ "更新成功,请重启本程序": "Updated successfully, please restart this program",
+ "未命名对话历史记录": "Unnamed Dialog History",
+ "未设置代理...": "No proxy...",
"本月使用金额": "Monthly usage",
- "获取API使用情况失败:": "Failed to get API usage:",
- "API密钥更改为了": "The API key is changed to",
- "JSON解析错误,收到的内容: ": "JSON parsing error, received content: ",
+ "查看[使用介绍](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35)": "View the [usage guide](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35) for more details",
+ "根据日期时间": "By date and time",
+ "模型": "Model",
+ "模型名称后缀": "Model Name Suffix",
+ "模型自动总结(消耗tokens)": "Auto summary by LLM (Consume tokens)",
"模型设置为了:": "Model is set to: ",
- "☹️发生了错误:": "☹️Error: ",
+ "正在尝试更新...": "Trying to update...",
+ "添加训练好的模型到模型列表": "Add trained model to the model list",
+ "状态": "Status",
+ "生成内容总结中……": "Generating content summary...",
+ "用于定位滥用行为": "Used to locate abuse",
+ "用户名": "Username",
+ "由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536)、[明昭MZhao](https://space.bilibili.com/24807452) 和 [Keldos](https://github.com/Keldos-Li) 开发
访问川虎Chat的 [GitHub项目](https://github.com/GaiZhenbiao/ChuanhuChatGPT) 下载最新版脚本": "Developed by Bilibili [土川虎虎虎](https://space.bilibili.com/29125536), [明昭MZhao](https://space.bilibili.com/24807452) and [Keldos](https://github.com/Keldos-Li)\n\nDownload latest code from [GitHub](https://github.com/GaiZhenbiao/ChuanhuChatGPT)",
+ "知识库": "Knowledge base",
+ "知识库文件": "Knowledge base files",
+ "第一条提问": "By first question",
+ "索引构建完成": "Indexing complete.",
+ "网络": "Network",
+ "获取API使用情况失败:": "Failed to get API usage:",
+ "获取IP地理位置失败。原因:": "Failed to get IP location. Reason: ",
"获取对话时发生错误,请查看后台日志": "Error occurred when getting dialogue, check the background log",
+ "训练": "Training",
+ "训练状态": "Training Status",
+ "训练轮数(Epochs)": "Training Epochs",
+ "设置": "Settings",
+ "设置保存文件名": "Set save file name",
+ "设置文件名: 默认为.json,可选为.md": "Set file name: default is .json, optional is .md",
+ "识别公式": "formula OCR",
+ "详情": "Details",
+ "请查看 config_example.json,配置 Azure OpenAI": "Please review config_example.json to configure Azure OpenAI",
"请检查网络连接,或者API-Key是否有效。": "Check the network connection or whether the API-Key is valid.",
- "连接超时,无法获取对话。": "Connection timed out, unable to get dialogue.",
- "读取超时,无法获取对话。": "Read timed out, unable to get dialogue.",
- "代理错误,无法获取对话。": "Proxy error, unable to get dialogue.",
- "SSL错误,无法获取对话。": "SSL error, unable to get dialogue.",
- "API key为空,请检查是否输入正确。": "API key is empty, check whether it is entered correctly.",
"请输入对话内容。": "Enter the content of the conversation.",
+ "请输入有效的文件名,不要包含以下特殊字符:": "Please enter a valid file name, do not include the following special characters: ",
+ "读取超时,无法获取对话。": "Read timed out, unable to get dialogue.",
"账单信息不适用": "Billing information is not applicable",
- "由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536)、[明昭MZhao](https://space.bilibili.com/24807452) 和 [Keldos](https://github.com/Keldos-Li) 开发
访问川虎Chat的 [GitHub项目](https://github.com/GaiZhenbiao/ChuanhuChatGPT) 下载最新版脚本": "Developed by Bilibili [土川虎虎虎](https://space.bilibili.com/29125536), [明昭MZhao](https://space.bilibili.com/24807452) and [Keldos](https://github.com/Keldos-Li)\n\nDownload latest code from [GitHub](https://github.com/GaiZhenbiao/ChuanhuChatGPT)",
- "切换亮暗色主题": "Switch light/dark theme",
- "您的IP区域:未知。": "Your IP region: Unknown.",
- "获取IP地理位置失败。原因:": "Failed to get IP location. Reason: ",
- "。你仍然可以使用聊天功能。": ". You can still use the chat function.",
- "您的IP区域:": "Your IP region: ",
- "总结": "Summarize",
- "生成内容总结中……": "Generating content summary...",
- "由于下面的原因,Google 拒绝返回 PaLM 的回答:\n\n": "Due to the following reasons, Google refuses to provide an answer to PaLM: \n\n",
- "---\n⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "---\n⚠️ To ensure the security of API-Key, please modify the network settings in the configuration file `config.json`.",
- "网络参数": "Network parameter"
-}
+ "连接超时,无法获取对话。": "Connection timed out, unable to get dialogue.",
+ "选择LoRA模型": "Select LoRA Model",
+ "选择Prompt模板集合文件": "Select Prompt Template Collection File",
+ "选择回复语言(针对搜索&索引功能)": "Select reply language (for search & index)",
+ "选择数据集": "Select Dataset",
+ "选择模型": "Select Model",
+ "重命名该对话": "Rename this chat",
+ "重新生成": "Regenerate",
+ "高级": "Advanced",
+ ",本次对话累计消耗了 ": ", total cost: ",
+ "💾 保存对话": "💾 Save Dialog",
+ "📝 导出为 Markdown": "📝 Export as Markdown",
+ "🔄 切换API地址": "🔄 Switch API Address",
+ "🔄 刷新": "🔄 Refresh",
+ "🔄 检查更新...": "🔄 Check for Update...",
+ "🔄 设置代理地址": "🔄 Set Proxy Address",
+ "🔄 重新生成": "🔄 Regeneration",
+ "🔙 恢复默认网络设置": "🔙 Reset Network Settings",
+ "🗑️ 删除最新对话": "🗑️ Delete latest dialog",
+ "🗑️ 删除最旧对话": "🗑️ Delete oldest dialog",
+ "🧹 新的对话": "🧹 New Dialogue"
+}
\ No newline at end of file
diff --git a/locale/extract_locale.py b/locale/extract_locale.py
index 32b0924bd6dffe150cb3e481ddadef836b91b83c..316d1dafd0f65d86fe152a14909305b4bd6ec2aa 100644
--- a/locale/extract_locale.py
+++ b/locale/extract_locale.py
@@ -1,26 +1,138 @@
-import os
-import json
-import re
+import os, json, re, sys
+import aiohttp, asyncio
+import commentjson
-# Define regular expression patterns
-pattern = r'i18n\((\"{3}.*?\"{3}|\".*?\")\)'
+asyncio.set_event_loop_policy(asyncio.DefaultEventLoopPolicy())
-# Load the .py file
-with open('ChuanhuChatbot.py', 'r', encoding='utf-8') as f:
- contents = f.read()
+with open("config.json", "r", encoding="utf-8") as f:
+ config = commentjson.load(f)
+api_key = config["openai_api_key"]
+url = config["openai_api_base"] + "/v1/chat/completions" if "openai_api_base" in config else "https://api.openai.com/v1/chat/completions"
-# Load the .py files in the modules folder
-for filename in os.listdir("modules"):
- if filename.endswith(".py"):
- with open(os.path.join("modules", filename), "r", encoding="utf-8") as f:
- contents += f.read()
-# Matching with regular expressions
-matches = re.findall(pattern, contents, re.DOTALL)
+def get_current_strings():
+ pattern = r'i18n\s*\(\s*["\']([^"\']*(?:\)[^"\']*)?)["\']\s*\)'
-# Convert to key/value pairs
-data = {match.strip('()"'): '' for match in matches}
+ # Load the .py files
+ contents = ""
+ for dirpath, dirnames, filenames in os.walk("."):
+ for filename in filenames:
+ if filename.endswith(".py"):
+ filepath = os.path.join(dirpath, filename)
+ with open(filepath, 'r', encoding='utf-8') as f:
+ contents += f.read()
+ # Matching with regular expressions
+ matches = re.findall(pattern, contents, re.DOTALL)
+ data = {match.strip('()"'): '' for match in matches}
+ fixed_data = {} # fix some keys
+ for key, value in data.items():
+ if "](" in key and key.count("(") != key.count(")"):
+ fixed_data[key+")"] = value
+ else:
+ fixed_data[key] = value
-# Save as a JSON file
-with open('labels.json', 'w', encoding='utf-8') as f:
- json.dump(data, f, ensure_ascii=False, indent=4)
\ No newline at end of file
+ return fixed_data
+
+
+def get_locale_strings(filename):
+ try:
+ with open(filename, "r", encoding="utf-8") as f:
+ locale_strs = json.load(f)
+ except FileNotFoundError:
+ locale_strs = {}
+ return locale_strs
+
+
+def sort_strings(existing_translations):
+ # Sort the merged data
+ sorted_translations = {}
+ # Add entries with (NOT USED) in their values
+ for key, value in sorted(existing_translations.items(), key=lambda x: x[0]):
+ if "(🔴NOT USED)" in value:
+ sorted_translations[key] = value
+ # Add entries with empty values
+ for key, value in sorted(existing_translations.items(), key=lambda x: x[0]):
+ if value == "":
+ sorted_translations[key] = value
+ # Add the rest of the entries
+ for key, value in sorted(existing_translations.items(), key=lambda x: x[0]):
+ if value != "" and "(NOT USED)" not in value:
+ sorted_translations[key] = value
+
+ return sorted_translations
+
+
+async def auto_translate(str, language):
+ headers = {
+ "Content-Type": "application/json",
+ "Authorization": f"Bearer {api_key}",
+ "temperature": f"{0}",
+ }
+ payload = {
+ "model": "gpt-3.5-turbo",
+ "messages": [
+ {
+ "role": "system",
+ "content": f"You are a translation program;\nYour job is to translate user input into {language};\nThe content you are translating is a string in the App;\nDo not explain emoji;\nIf input is only a emoji, please simply return origin emoji;\nPlease ensure that the translation results are concise and easy to understand."
+ },
+ {"role": "user", "content": f"{str}"}
+ ],
+ }
+
+ async with aiohttp.ClientSession() as session:
+ async with session.post(url, headers=headers, json=payload) as response:
+ data = await response.json()
+ return data["choices"][0]["message"]["content"]
+
+
+async def main(auto=False):
+ current_strs = get_current_strings()
+ locale_files = []
+ # 遍历locale目录下的所有json文件
+ for dirpath, dirnames, filenames in os.walk("locale"):
+ for filename in filenames:
+ if filename.endswith(".json"):
+ locale_files.append(os.path.join(dirpath, filename))
+
+
+ for locale_filename in locale_files:
+ if "zh_CN" in locale_filename:
+ continue
+ locale_strs = get_locale_strings(locale_filename)
+
+ # Add new keys
+ new_keys = []
+ for key in current_strs:
+ if key not in locale_strs:
+ new_keys.append(key)
+ locale_strs[key] = ""
+ print(f"{locale_filename[7:-5]}'s new str: {len(new_keys)}")
+ # Add (NOT USED) to invalid keys
+ for key in locale_strs:
+ if key not in current_strs:
+ locale_strs[key] = "(🔴NOT USED)" + locale_strs[key]
+ print(f"{locale_filename[7:-5]}'s invalid str: {len(locale_strs) - len(current_strs)}")
+
+ locale_strs = sort_strings(locale_strs)
+
+ if auto:
+ tasks = []
+ non_translated_keys = []
+ for key in locale_strs:
+ if locale_strs[key] == "":
+ non_translated_keys.append(key)
+ tasks.append(auto_translate(key, locale_filename[7:-5]))
+ results = await asyncio.gather(*tasks)
+ for key, result in zip(non_translated_keys, results):
+ locale_strs[key] = "(🟡REVIEW NEEDED)" + result
+ print(f"{locale_filename[7:-5]}'s auto translated str: {len(non_translated_keys)}")
+
+ with open(locale_filename, 'w', encoding='utf-8') as f:
+ json.dump(locale_strs, f, ensure_ascii=False, indent=4)
+
+
+if __name__ == "__main__":
+ auto = False
+ if len(sys.argv) > 1 and sys.argv[1] == "--auto":
+ auto = True
+ asyncio.run(main(auto))
diff --git a/locale/ja_JP.json b/locale/ja_JP.json
index db8fb8441bb669848c5eec4644d5b3e8d814060a..3b918489ce37a270a4ce1730a587eaed704086eb 100644
--- a/locale/ja_JP.json
+++ b/locale/ja_JP.json
@@ -1,87 +1,141 @@
{
- "未命名对话历史记录": "名無しの会話履歴",
- "在这里输入": "ここに入力",
- "🧹 新的对话": "🧹 新しい会話",
- "🔄 重新生成": "🔄 再生成",
- "🗑️ 删除最旧对话": "🗑️ 最古の会話削除",
- "🗑️ 删除最新对话": "🗑️ 最新の会話削除",
- "模型": "LLMモデル",
- "多账号模式已开启,无需输入key,可直接开始对话": "複数アカウントモードがオンになっています。キーを入力する必要はありません。会話を開始できます",
+ " 吗?": " を削除してもよろしいですか?",
+ "# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ 変更には慎重に ⚠️",
"**发送消息** 或 **提交key** 以显示额度": "**メッセージを送信** または **キーを送信** して、クレジットを表示します",
- "选择模型": "LLMモデルを選択",
- "选择LoRA模型": "LoRAモデルを選択",
- "实时传输回答": "ストリーム出力",
- "单轮对话": "単発会話",
- "使用在线搜索": "オンライン検索を使用",
- "选择回复语言(针对搜索&索引功能)": "回答言語を選択(検索とインデックス機能に対して)",
- "上传索引文件": "アップロード",
- "双栏pdf": "2カラムpdf",
- "识别公式": "formula OCR",
- "在这里输入System Prompt...": "System Promptを入力してください...",
- "加载Prompt模板": "Promptテンプレートを読込",
- "选择Prompt模板集合文件": "Promptテンプレートコレクションを選択",
- "🔄 刷新": "🔄 更新",
+ "**本月使用金额** ": "**今月の使用料金** ",
+ "**获取API使用情况失败**": "**API使用状況の取得に失敗しました**",
+ "**获取API使用情况失败**,sensitive_id错误或已过期": "**API使用状況の取得に失敗しました**、sensitive_idが間違っているか、期限切れです",
+ "**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**API使用状況の取得に失敗しました**、`config.json`に正しい`sensitive_id`を入力する必要があります",
+ "API key为空,请检查是否输入正确。": "APIキーが入力されていません。正しく入力されているか確認してください。",
+ "API密钥更改为了": "APIキーが変更されました",
+ "JSON解析错误,收到的内容: ": "JSON解析エラー、受信内容: ",
+ "SSL错误,无法获取对话。": "SSLエラー、会話を取得できません。",
+ "Token 计数: ": "Token数: ",
+ "☹️发生了错误:": "エラーが発生しました: ",
+ "⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "⚠️ APIキーの安全性を確保するために、`config.json`ファイルでネットワーク設定を変更してください。",
+ "。你仍然可以使用聊天功能。": "。あなたはまだチャット機能を使用できます。",
+ "上传": "アップロード",
+ "上传了": "アップロードしました。",
+ "上传到 OpenAI 后自动填充": "OpenAIへのアップロード後、自動的に入力されます",
+ "上传到OpenAI": "OpenAIへのアップロード",
+ "上传文件": "ファイルをアップロード",
+ "仅供查看": "閲覧専用",
"从Prompt模板中加载": "Promptテンプレートから読込",
- "保存/加载": "保存/読込",
- "保存/加载对话历史记录": "会話履歴を保存/読込",
"从列表中加载对话": "リストから会話を読込",
- "设置文件名: 默认为.json,可选为.md": "ファイル名を設定: デフォルトは.json、.mdを選択できます",
- "设置保存文件名": "保存ファイル名を設定",
- "对话历史记录": "会話履歴",
- "💾 保存对话": "💾 会話を保存",
- "📝 导出为Markdown": "📝 Markdownでエクスポート",
- "默认保存于history文件夹": "デフォルトでhistoryフォルダに保存されます",
- "高级": "Advanced",
- "# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ 変更には慎重に ⚠️",
- "参数": "パラメータ",
- "停止符,用英文逗号隔开...": "ここにストップ文字を英語のカンマで区切って入力してください...",
- "用于定位滥用行为": "不正行為を特定するために使用されます",
- "用户名": "ユーザー名",
- "在这里输入API-Host...": "API-Hostを入力してください...",
- "🔄 切换API地址": "🔄 APIアドレスを切り替え",
- "未设置代理...": "代理が設定されていません...",
"代理地址": "プロキシアドレス",
- "🔄 设置代理地址": "🔄 プロキシアドレスを設定",
- "🔙 恢复默认网络设置": "🔙 ネットワーク設定のリセット",
- "🔄 检查更新...": "🔄 アップデートをチェック...",
+ "代理错误,无法获取对话。": "プロキシエラー、会話を取得できません。",
+ "你没有权限访问 GPT4,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)": "GPT-4にアクセス権がありません、[詳細はこちら](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)",
+ "你没有选择任何对话历史": "あなたは何の会話履歴も選択していません。",
+ "你真的要删除 ": "本当に ",
+ "使用在线搜索": "オンライン検索を使用",
+ "停止符,用英文逗号隔开...": "ここにストップ文字を英語のカンマで区切って入力してください...",
+ "关于": "について",
+ "准备数据集": "データセットの準備",
+ "切换亮暗色主题": "テーマの明暗切替",
+ "删除对话历史成功": "削除した会話の履歴",
+ "删除这轮问答": "この質疑応答を削除",
+ "刷新状态": "ステータスを更新",
+ "剩余配额不足,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)": "剩余配额不足,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)",
+ "加载Prompt模板": "Promptテンプレートを読込",
+ "单轮对话": "単発会話",
+ "历史记录(JSON)": "履歴ファイル(JSON)",
+ "参数": "パラメータ",
+ "双栏pdf": "2カラムpdf",
"取消": "キャンセル",
- "更新": "アップデート",
- "详情": "詳細",
+ "取消所有任务": "すべてのタスクをキャンセル",
+ "可选,用于区分不同的模型": "オプション、異なるモデルを区別するために使用",
+ "启用的工具:": "有効なツール:",
+ "在工具箱中管理知识库文件": "ツールボックスでナレッジベースファイルの管理を行う",
+ "在线搜索": "オンライン検索",
+ "在这里输入": "ここに入力",
+ "在这里输入System Prompt...": "System Promptを入力してください...",
+ "多账号模式已开启,无需输入key,可直接开始对话": "複数アカウントモードがオンになっています。キーを入力する必要はありません。会話を開始できます",
"好": "はい",
- "更新成功,请重启本程序": "更新が成功しました、このプログラムを再起動してください",
- "更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "更新に失敗しました、[手動での更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)をお試しください。",
+ "实时传输回答": "ストリーム出力",
+ "对话": "会話",
+ "对话历史": "対話履歴",
+ "对话历史记录": "会話履歴",
+ "对话命名方式": "会話の命名方法",
+ "导出为 Markdown": "Markdownでエクスポート",
+ "川虎Chat": "川虎Chat",
"川虎Chat 🚀": "川虎Chat 🚀",
+ "工具箱": "ツールボックス",
+ "已经被删除啦": "削除されました。",
"开始实时传输回答……": "ストリーム出力開始……",
- "Token 计数: ": "Token数: ",
- ",本次对话累计消耗了 ": ", 今の会話で消費合計 ",
- "**获取API使用情况失败**": "**API使用状況の取得に失敗しました**",
- "**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**API使用状況の取得に失敗しました**、`config.json`に正しい`sensitive_id`を入力する必要があります",
- "**获取API使用情况失败**,sensitive_id错误或已过期": "**API使用状況の取得に失敗しました**、sensitive_idが間違っているか、期限切れです",
- "**本月使用金额** ": "**今月の使用料金** ",
+ "开始训练": "トレーニングを開始",
+ "微调": "ファインチューニング",
+ "总结": "要約する",
+ "总结完成": "完了",
+ "您使用的就是最新版!": "最新バージョンを使用しています!",
+ "您的IP区域:": "あなたのIPアドレス地域:",
+ "您的IP区域:未知。": "あなたのIPアドレス地域:不明",
+ "拓展": "拡張",
+ "搜索(支持正则)...": "検索(正規表現をサポート)...",
+ "数据集预览": "データセットのプレビュー",
+ "文件ID": "ファイルID",
+ "新对话 ": "新しい会話 ",
+ "新建对话保留Prompt": "新しい会話を作成してください。プロンプトを保留します。",
+ "暂时未知": "しばらく不明である",
+ "更新": "アップデート",
+ "更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "更新に失敗しました、[手動での更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)をお試しください。",
+ "更新成功,请重启本程序": "更新が成功しました、このプログラムを再起動してください",
+ "未命名对话历史记录": "名無しの会話履歴",
+ "未设置代理...": "代理が設定されていません...",
"本月使用金额": "今月の使用料金",
- "获取API使用情况失败:": "API使用状況の取得に失敗しました:",
- "API密钥更改为了": "APIキーが変更されました",
- "JSON解析错误,收到的内容: ": "JSON解析エラー、受信内容: ",
+ "查看[使用介绍](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35)": "[使用ガイド](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35)を表示",
+ "根据日期时间": "日付と時刻に基づいて",
+ "模型": "LLMモデル",
+ "模型名称后缀": "モデル名のサフィックス",
+ "模型自动总结(消耗tokens)": "モデルによる自動要約(トークン消費)",
"模型设置为了:": "LLMモデルを設定しました: ",
- "☹️发生了错误:": "エラーが発生しました: ",
+ "正在尝试更新...": "更新を試みています...",
+ "添加训练好的模型到模型列表": "トレーニング済みモデルをモデルリストに追加",
+ "状态": "ステータス",
+ "生成内容总结中……": "コンテンツ概要を生成しています...",
+ "用于定位滥用行为": "不正行為を特定するために使用されます",
+ "用户名": "ユーザー名",
+ "由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536)、[明昭MZhao](https://space.bilibili.com/24807452) 和 [Keldos](https://github.com/Keldos-Li) 开发
访问川虎Chat的 [GitHub项目](https://github.com/GaiZhenbiao/ChuanhuChatGPT) 下载最新版脚本": "開発:Bilibili [土川虎虎虎](https://space.bilibili.com/29125536) と [明昭MZhao](https://space.bilibili.com/24807452) と [Keldos](https://github.com/Keldos-Li)\n\n最新コードは川虎Chatのサイトへ [GitHubプロジェクト](https://github.com/GaiZhenbiao/ChuanhuChatGPT)",
+ "知识库": "ナレッジベース",
+ "知识库文件": "ナレッジベースファイル",
+ "第一条提问": "最初の質問",
+ "索引构建完成": "索引の構築が完了しました。",
+ "网络": "ネットワーク",
+ "获取API使用情况失败:": "API使用状況の取得に失敗しました:",
+ "获取IP地理位置失败。原因:": "IPアドレス地域の取得に失敗しました。理由:",
"获取对话时发生错误,请查看后台日志": "会話取得時にエラー発生、あとのログを確認してください",
+ "训练": "トレーニング",
+ "训练状态": "トレーニングステータス",
+ "训练轮数(Epochs)": "トレーニングエポック数",
+ "设置": "設定",
+ "设置保存文件名": "保存ファイル名を設定",
+ "设置文件名: 默认为.json,可选为.md": "ファイル名を設定: デフォルトは.json、.mdを選択できます",
+ "识别公式": "formula OCR",
+ "详情": "詳細",
+ "请查看 config_example.json,配置 Azure OpenAI": "Azure OpenAIの設定については、config_example.jsonをご覧ください",
"请检查网络连接,或者API-Key是否有效。": "ネットワーク接続を確認するか、APIキーが有効かどうかを確認してください。",
- "连接超时,无法获取对话。": "接続タイムアウト、会話を取得できません。",
- "读取超时,无法获取对话。": "読み込みタイムアウト、会話を取得できません。",
- "代理错误,无法获取对话。": "プロキシエラー、会話を取得できません。",
- "SSL错误,无法获取对话。": "SSLエラー、会話を取得できません。",
- "API key为空,请检查是否输入正确。": "APIキーが入力されていません。正しく入力されているか確認してください。",
"请输入对话内容。": "会話内容を入力してください。",
+ "请输入有效的文件名,不要包含以下特殊字符:": "有効なファイル名を入力してください。以下の特殊文字は使用しないでください:",
+ "读取超时,无法获取对话。": "読み込みタイムアウト、会話を取得できません。",
"账单信息不适用": "課金情報は対象外です",
- "由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536)、[明昭MZhao](https://space.bilibili.com/24807452) 和 [Keldos](https://github.com/Keldos-Li) 开发
访问川虎Chat的 [GitHub项目](https://github.com/GaiZhenbiao/ChuanhuChatGPT) 下载最新版脚本": "開発:Bilibili [土川虎虎虎](https://space.bilibili.com/29125536) と [明昭MZhao](https://space.bilibili.com/24807452) と [Keldos](https://github.com/Keldos-Li)\n\n最新コードは川虎Chatのサイトへ [GitHubプロジェクト](https://github.com/GaiZhenbiao/ChuanhuChatGPT)",
- "切换亮暗色主题": "テーマの明暗切替",
- "您的IP区域:未知。": "あなたのIPアドレス地域:不明",
- "获取IP地理位置失败。原因:": "IPアドレス地域の取得に失敗しました。理由:",
- "。你仍然可以使用聊天功能。": "。あなたはまだチャット機能を使用できます。",
- "您的IP区域:": "あなたのIPアドレス地域:",
- "总结": "要約する",
- "生成内容总结中……": "コンテンツ概要を生成しています...",
- "由于下面的原因,Google 拒绝返回 PaLM 的回答:\n\n": "Googleは以下の理由から、PaLMの回答を返すことを拒否しています:\n\n",
- "---\n⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "---\n⚠️ APIキーの安全性を確保するために、`config.json`ファイルでネットワーク設定を変更してください。",
- "网络参数": "ネットワークパラメータ"
-}
+ "连接超时,无法获取对话。": "接続タイムアウト、会話を取得できません。",
+ "选择LoRA模型": "LoRAモデルを選択",
+ "选择Prompt模板集合文件": "Promptテンプレートコレクションを選択",
+ "选择回复语言(针对搜索&索引功能)": "回答言語を選択(検索とインデックス機能に対して)",
+ "选择数据集": "データセットの選択",
+ "选择模型": "LLMモデルを選択",
+ "重命名该对话": "会話の名前を変更",
+ "重新生成": "再生成",
+ "高级": "Advanced",
+ ",本次对话累计消耗了 ": ", 今の会話で消費合計 ",
+ "💾 保存对话": "💾 会話を保存",
+ "📝 导出为 Markdown": "📝 Markdownにエクスポート",
+ "🔄 切换API地址": "🔄 APIアドレスを切り替え",
+ "🔄 刷新": "🔄 更新",
+ "🔄 检查更新...": "🔄 アップデートをチェック...",
+ "🔄 设置代理地址": "🔄 プロキシアドレスを設定",
+ "🔄 重新生成": "🔄 再生成",
+ "🔙 恢复默认网络设置": "🔙 ネットワーク設定のリセット",
+ "🗑️ 删除最新对话": "🗑️ 最新の会話削除",
+ "🗑️ 删除最旧对话": "🗑️ 最古の会話削除",
+ "🧹 新的对话": "🧹 新しい会話"
+}
\ No newline at end of file
diff --git a/locale/ko_KR.json b/locale/ko_KR.json
index a7f45732eeae5b65930a078c0b326c9659abd270..2a460e341b47cace156893a473c6fa9f1593bf53 100644
--- a/locale/ko_KR.json
+++ b/locale/ko_KR.json
@@ -1,89 +1,141 @@
{
- "未命名对话历史记录": "이름없는 대화 기록",
- "在这里输入": "여기에 입력하세요",
- "🧹 新的对话": "🧹 새로운 대화",
- "🔄 重新生成": "🔄 재생성",
- "🗑️ 删除最旧对话": "🗑️ 가장 오래된 대화 삭제",
- "🗑️ 删除最新对话": "🗑️ 최신 대화 삭제",
- "🗑️ 删除": "🗑️ 삭제",
- "模型": "LLM 모델",
- "多账号模式已开启,无需输入key,可直接开始对话": "다중 계정 모드가 활성화되어 있으므로 키를 입력할 필요가 없이 바로 대화를 시작할 수 있습니다",
+ " 吗?": " 을(를) 삭제하시겠습니까?",
+ "# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ 주의: 변경시 주의하세요. ⚠️",
"**发送消息** 或 **提交key** 以显示额度": "**메세지를 전송** 하거나 **Key를 입력**하여 크레딧 표시",
- "选择模型": "모델 선택",
- "选择LoRA模型": "LoRA 모델 선택",
- "实时传输回答": "실시간 전송",
- "单轮对话": "단일 대화",
- "使用在线搜索": "온라인 검색 사용",
- "选择回复语言(针对搜索&索引功能)": "답장 언어 선택 (검색 & 인덱스용)",
- "上传索引文件": "업로드",
- "双栏pdf": "2-column pdf",
- "识别公式": "formula OCR",
- "在这里输入System Prompt...": "여기에 시스템 프롬프트를 입력하세요...",
- "加载Prompt模板": "프롬프트 템플릿 불러오기",
- "选择Prompt模板集合文件": "프롬프트 콜렉션 파일 선택",
- "🔄 刷新": "🔄 새로고침",
+ "**本月使用金额** ": "**이번 달 사용금액** ",
+ "**获取API使用情况失败**": "**API 사용량 가져오기 실패**",
+ "**获取API使用情况失败**,sensitive_id错误或已过期": "**API 사용량 가져오기 실패**. sensitive_id가 잘못되었거나 만료되었습니다",
+ "**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**API 사용량 가져오기 실패**. `config.json`에 올바른 `sensitive_id`를 입력해야 합니다",
+ "API key为空,请检查是否输入正确。": "API 키가 비어 있습니다. 올바르게 입력되었는지 확인하십세요.",
+ "API密钥更改为了": "API 키가 변경되었습니다.",
+ "JSON解析错误,收到的内容: ": "JSON 파싱 에러, 응답: ",
+ "SSL错误,无法获取对话。": "SSL 에러, 대화를 가져올 수 없습니다.",
+ "Token 计数: ": "토큰 수: ",
+ "☹️发生了错误:": "☹️에러: ",
+ "⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "⚠️ API-Key의 안전을 보장하기 위해 네트워크 설정을 `config.json` 구성 파일에서 수정해주세요.",
+ "。你仍然可以使用聊天功能。": ". 채팅 기능을 계속 사용할 수 있습니다.",
+ "上传": "업로드",
+ "上传了": "업로드되었습니다.",
+ "上传到 OpenAI 后自动填充": "OpenAI로 업로드한 후 자동으로 채워집니다",
+ "上传到OpenAI": "OpenAI로 업로드",
+ "上传文件": "파일 업로드",
+ "仅供查看": "읽기 전용",
"从Prompt模板中加载": "프롬프트 템플릿에서 불러오기",
- "保存/加载": "저장/불러오기",
- "保存/加载对话历史记录": "대화 기록 저장/불러오기",
"从列表中加载对话": "리스트에서 대화 불러오기",
- "设置文件名: 默认为.json,可选为.md": "파일 이름 설정: 기본값: .json, 선택: .md",
- "设置保存文件名": "저장 파일명 설정",
- "对话历史记录": "대화 기록",
- "💾 保存对话": "💾 대화 저장",
- "📝 导出为Markdown": "📝 마크다운으로 내보내기",
- "默认保存于history文件夹": "히스토리 폴더에 기본 저장",
- "高级": "고급",
- "# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ 주의: 변경시 주의하세요. ⚠️",
- "参数": "파라미터들",
- "停止符,用英文逗号隔开...": "여기에 정지 토큰 입력, ','로 구분됨...",
- "用于定位滥用行为": "악용 사례 파악에 활용됨",
- "用户名": "사용자 이름",
- "在这里输入API-Host...": "여기에 API host를 입력하세요...",
- "🔄 切换API地址": "🔄 API 주소 변경",
- "未设置代理...": "대리인이 설정되지 않았습니다...",
"代理地址": "프록시 주소",
- "🔄 设置代理地址": "🔄 프록시 주소 설정",
- "🔙 恢复默认网络设置": "🔙 네트워크 설정 초기화",
- "🔄 检查更新...": "🔄 업데이트 확인...",
+ "代理错误,无法获取对话。": "프록시 에러, 대화를 가져올 수 없습니다.",
+ "你没有权限访问 GPT4,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)": "GPT-4에 접근 권한이 없습니다. [자세히 알아보기](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)",
+ "你没有选择任何对话历史": "대화 기록을 선택하지 않았습니다.",
+ "你真的要删除 ": "정말로 ",
+ "使用在线搜索": "온라인 검색 사용",
+ "停止符,用英文逗号隔开...": "여기에 정지 토큰 입력, ','로 구분됨...",
+ "关于": "관련",
+ "准备数据集": "데이터셋 준비",
+ "切换亮暗色主题": "라이트/다크 테마 전환",
+ "删除对话历史成功": "대화 기록이 성공적으로 삭제되었습니다.",
+ "删除这轮问答": "이 라운드의 질문과 답변 삭제",
+ "刷新状态": "상태 새로 고침",
+ "剩余配额不足,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)": "남은 할당량이 부족합니다. [자세한 내용](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)을 확인하세요.",
+ "加载Prompt模板": "프롬프트 템플릿 불러오기",
+ "单轮对话": "단일 대화",
+ "历史记录(JSON)": "기록 파일 (JSON)",
+ "参数": "파라미터들",
+ "双栏pdf": "2-column pdf",
"取消": "취소",
- "更新": "업데이트",
- "详情": "상세",
+ "取消所有任务": "모든 작업 취소",
+ "可选,用于区分不同的模型": "선택 사항, 다른 모델을 구분하는 데 사용",
+ "启用的工具:": "활성화된 도구: ",
+ "在工具箱中管理知识库文件": "지식 라이브러리 파일을 도구 상자에서 관리",
+ "在线搜索": "온라인 검색",
+ "在这里输入": "여기에 입력하세요",
+ "在这里输入System Prompt...": "여기에 시스템 프롬프트를 입력하세요...",
+ "多账号模式已开启,无需输入key,可直接开始对话": "다중 계정 모드가 활성화되어 있으므로 키를 입력할 필요가 없이 바로 대화를 시작할 수 있습니다",
"好": "예",
- "更新成功,请重启本程序": "업데이트 성공, 이 프로그램을 재시작 해주세요",
- "更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "업데이트 실패, [수동 업데이트](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)를 시도하십시오",
+ "实时传输回答": "실시간 전송",
+ "对话": "대화",
+ "对话历史": "대화 내역",
+ "对话历史记录": "대화 기록",
+ "对话命名方式": "대화 이름 설정",
+ "导出为 Markdown": "마크다운으로 내보내기",
+ "川虎Chat": "Chuanhu Chat",
"川虎Chat 🚀": "Chuanhu Chat 🚀",
+ "工具箱": "도구 상자",
+ "已经被删除啦": "이미 삭제되었습니다.",
"开始实时传输回答……": "실시간 응답 출력 시작...",
- "Token 计数: ": "토큰 수: ",
- ",本次对话累计消耗了 ": ",이 대화의 전체 비용은 ",
- "**获取API使用情况失败**": "**API 사용량 가져오기 실패**",
- "**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**API 사용량 가져오기 실패**. `config.json`에 올바른 `sensitive_id`를 입력해야 합니다",
- "**获取API使用情况失败**,sensitive_id错误或已过期": "**API 사용량 가져오기 실패**. sensitive_id가 잘못되었거나 만료되었습니다",
- "**本月使用金额** ": "**이번 달 사용금액** ",
+ "开始训练": "훈련 시작",
+ "微调": "미세 조정",
+ "总结": "요약",
+ "总结完成": "작업 완료",
+ "您使用的就是最新版!": "최신 버전을 사용하고 있습니다!",
+ "您的IP区域:": "당신의 IP 지역: ",
+ "您的IP区域:未知。": "IP 지역: 알 수 없음.",
+ "拓展": "확장",
+ "搜索(支持正则)...": "검색 (정규식 지원)...",
+ "数据集预览": "데이터셋 미리보기",
+ "文件ID": "파일 ID",
+ "新对话 ": "새 대화 ",
+ "新建对话保留Prompt": "새 대화 생성, 프롬프트 유지하기",
+ "暂时未知": "알 수 없음",
+ "更新": "업데이트",
+ "更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "업데이트 실패, [수동 업데이트](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)를 시도하십시오",
+ "更新成功,请重启本程序": "업데이트 성공, 이 프로그램을 재시작 해주세요",
+ "未命名对话历史记录": "이름없는 대화 기록",
+ "未设置代理...": "대리인이 설정되지 않았습니다...",
"本月使用金额": "이번 달 사용금액",
- "获取API使用情况失败:": "API 사용량 가져오기 실패:",
- "API密钥更改为了": "API 키가 변경되었습니다.",
- "JSON解析错误,收到的内容: ": "JSON 파싱 에러, 응답: ",
+ "查看[使用介绍](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35)": "[사용 가이드](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35) 보기",
+ "根据日期时间": "날짜 및 시간 기준",
+ "模型": "LLM 모델",
+ "模型名称后缀": "모델 이름 접미사",
+ "模型自动总结(消耗tokens)": "모델에 의한 자동 요약 (토큰 소비)",
"模型设置为了:": "설정된 모델: ",
- "☹️发生了错误:": "☹️에러: ",
+ "正在尝试更新...": "업데이트를 시도 중...",
+ "添加训练好的模型到模型列表": "훈련된 모델을 모델 목록에 추가",
+ "状态": "상태",
+ "生成内容总结中……": "콘텐츠 요약 생성중...",
+ "用于定位滥用行为": "악용 사례 파악에 활용됨",
+ "用户名": "사용자 이름",
+ "由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536)、[明昭MZhao](https://space.bilibili.com/24807452) 和 [Keldos](https://github.com/Keldos-Li) 开发
访问川虎Chat的 [GitHub项目](https://github.com/GaiZhenbiao/ChuanhuChatGPT) 下载最新版脚本": "제작: Bilibili [土川虎虎虎](https://space.bilibili.com/29125536), [明昭MZhao](https://space.bilibili.com/24807452), [Keldos](https://github.com/Keldos-Li)\n\n최신 코드 다운로드: [GitHub](https://github.com/GaiZhenbiao/ChuanhuChatGPT)",
+ "知识库": "지식 라이브러리",
+ "知识库文件": "지식 라이브러리 파일",
+ "第一条提问": "첫 번째 질문",
+ "索引构建完成": "인덱스 구축이 완료되었습니다.",
+ "网络": "네트워크",
+ "获取API使用情况失败:": "API 사용량 가져오기 실패:",
+ "获取IP地理位置失败。原因:": "다음과 같은 이유로 IP 위치를 가져올 수 없습니다. 이유: ",
"获取对话时发生错误,请查看后台日志": "대화를 가져오는 중 에러가 발생했습니다. 백그라운드 로그를 확인하세요",
+ "训练": "훈련",
+ "训练状态": "훈련 상태",
+ "训练轮数(Epochs)": "훈련 라운드(Epochs)",
+ "设置": "설정",
+ "设置保存文件名": "저장 파일명 설정",
+ "设置文件名: 默认为.json,可选为.md": "파일 이름 설정: 기본값: .json, 선택: .md",
+ "识别公式": "formula OCR",
+ "详情": "상세",
+ "请查看 config_example.json,配置 Azure OpenAI": "Azure OpenAI 설정을 확인하세요",
"请检查网络连接,或者API-Key是否有效。": "네트워크 연결 또는 API키가 유효한지 확인하세요",
- "连接超时,无法获取对话。": "연결 시간 초과, 대화를 가져올 수 없습니다.",
- "读取超时,无法获取对话。": "읽기 시간 초과, 대화를 가져올 수 없습니다.",
- "代理错误,无法获取对话。": "프록시 에러, 대화를 가져올 수 없습니다.",
- "SSL错误,无法获取对话。": "SSL 에러, 대화를 가져올 수 없습니다.",
- "API key为空,请检查是否输入正确。": "API 키가 비어 있습니다. 올바르게 입력되었는지 확인하십세요.",
"请输入对话内容。": "대화 내용을 입력하세요.",
+ "请输入有效的文件名,不要包含以下特殊字符:": "유효한 파일 이름을 입력하세요. 다음 특수 문자는 포함하지 마세요: ",
+ "读取超时,无法获取对话。": "읽기 시간 초과, 대화를 가져올 수 없습니다.",
"账单信息不适用": "청구 정보를 가져올 수 없습니다",
- "由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536)、[明昭MZhao](https://space.bilibili.com/24807452) 和 [Keldos](https://github.com/Keldos-Li) 开发
访问川虎Chat的 [GitHub项目](https://github.com/GaiZhenbiao/ChuanhuChatGPT) 下载最新版脚本": "제작: Bilibili [土川虎虎虎](https://space.bilibili.com/29125536), [明昭MZhao](https://space.bilibili.com/24807452), [Keldos](https://github.com/Keldos-Li)\n\n최신 코드 다운로드: [GitHub](https://github.com/GaiZhenbiao/ChuanhuChatGPT)",
- "切换亮暗色主题": "라이트/다크 테마 전환",
- "您的IP区域:未知。": "IP 지역: 알 수 없음.",
- "获取IP地理位置失败。原因:": "다음과 같은 이유로 IP 위치를 가져올 수 없습니다. 이유: ",
- "。你仍然可以使用聊天功能。": ". 채팅 기능을 계속 사용할 수 있습니다.",
- "您的IP区域:": "당신의 IP 지역: ",
- "总结": "요약",
- "生成内容总结中……": "콘텐츠 요약 생성중...",
- "上传": "업로드",
- "由于下面的原因,Google 拒绝返回 PaLM 的回答:\n\n": "구글은 다음과 같은 이유로 인해 PaLM의 응답을 거부합니다: \n\n",
- "---\n⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "---\n⚠️ API-Key의 안전을 보장하기 위해 네트워크 설정을 `config.json` 구성 파일에서 수정해주세요.",
- "网络参数": "네트워크 매개변수"
-}
+ "连接超时,无法获取对话。": "연결 시간 초과, 대화를 가져올 수 없습니다.",
+ "选择LoRA模型": "LoRA 모델 선택",
+ "选择Prompt模板集合文件": "프롬프트 콜렉션 파일 선택",
+ "选择回复语言(针对搜索&索引功能)": "답장 언어 선택 (검색 & 인덱스용)",
+ "选择数据集": "데이터셋 선택",
+ "选择模型": "모델 선택",
+ "重命名该对话": "대화 이름 변경",
+ "重新生成": "재생성",
+ "高级": "고급",
+ ",本次对话累计消耗了 ": ",이 대화의 전체 비용은 ",
+ "💾 保存对话": "💾 대화 저장",
+ "📝 导出为 Markdown": "📝 마크다운으로 내보내기",
+ "🔄 切换API地址": "🔄 API 주소 변경",
+ "🔄 刷新": "🔄 새로고침",
+ "🔄 检查更新...": "🔄 업데이트 확인...",
+ "🔄 设置代理地址": "🔄 프록시 주소 설정",
+ "🔄 重新生成": "🔄 재생성",
+ "🔙 恢复默认网络设置": "🔙 네트워크 설정 초기화",
+ "🗑️ 删除最新对话": "🗑️ 최신 대화 삭제",
+ "🗑️ 删除最旧对话": "🗑️ 가장 오래된 대화 삭제",
+ "🧹 新的对话": "🧹 새로운 대화"
+}
\ No newline at end of file
diff --git a/locale/ru_RU.json b/locale/ru_RU.json
new file mode 100644
index 0000000000000000000000000000000000000000..402aabaa431147b7ac638c38b819a51b754431a0
--- /dev/null
+++ b/locale/ru_RU.json
@@ -0,0 +1,141 @@
+{
+ " 吗?": " ?",
+ "# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ ВНИМАНИЕ: ИЗМЕНЯЙТЕ ОСТОРОЖНО ⚠️",
+ "**发送消息** 或 **提交key** 以显示额度": "**Отправить сообщение** или **отправить ключ** для отображения лимита",
+ "**本月使用金额** ": "**Использовано средств в этом месяце**",
+ "**获取API使用情况失败**": "**Не удалось получить информацию об использовании API**",
+ "**获取API使用情况失败**,sensitive_id错误或已过期": "**Не удалось получить информацию об использовании API**, ошибка sensitive_id или истек срок действия",
+ "**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**Не удалось получить информацию об использовании API**, необходимо правильно заполнить sensitive_id в `config.json`",
+ "API key为空,请检查是否输入正确。": "Пустой API-Key, пожалуйста, проверьте правильность ввода.",
+ "API密钥更改为了": "Ключ API изменен на",
+ "JSON解析错误,收到的内容: ": "Ошибка анализа JSON, полученный контент:",
+ "SSL错误,无法获取对话。": "Ошибка SSL, не удалось получить диалог.",
+ "Token 计数: ": "Использованно токенов: ",
+ "☹️发生了错误:": "☹️ Произошла ошибка:",
+ "⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "⚠️ Для обеспечения безопасности API-Key, измените настройки сети в файле конфигурации `config.json`",
+ "。你仍然可以使用聊天功能。": ". Вы все равно можете использовать функцию чата.",
+ "上传": "Загрузить",
+ "上传了": "Загрузка завершена.",
+ "上传到 OpenAI 后自动填充": "Автоматическое заполнение после загрузки в OpenAI",
+ "上传到OpenAI": "Загрузить в OpenAI",
+ "上传文件": "Загрузить файл",
+ "仅供查看": "Только для просмотра",
+ "从Prompt模板中加载": "Загрузить из шаблона Prompt",
+ "从列表中加载对话": "Загрузить диалог из списка",
+ "代理地址": "Адрес прокси",
+ "代理错误,无法获取对话。": "Ошибка прокси, не удалось получить диалог.",
+ "你没有权限访问 GPT4,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)": "У вас нет доступа к GPT4, [подробнее](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)",
+ "你没有选择任何对话历史": "Вы не выбрали никакой истории переписки",
+ "你真的要删除 ": "Вы уверены, что хотите удалить ",
+ "使用在线搜索": "Использовать онлайн-поиск",
+ "停止符,用英文逗号隔开...": "Разделительные символы, разделенные запятой...",
+ "关于": "О программе",
+ "准备数据集": "Подготовка набора данных",
+ "切换亮暗色主题": "Переключить светлую/темную тему",
+ "删除对话历史成功": "Успешно удалена история переписки.",
+ "删除这轮问答": "Удалить этот раунд вопросов и ответов",
+ "刷新状态": "Обновить статус",
+ "剩余配额不足,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)": "剩余配额不足,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)",
+ "加载Prompt模板": "Загрузить шаблон Prompt",
+ "单轮对话": "Одиночный диалог",
+ "历史记录(JSON)": "Файл истории (JSON)",
+ "参数": "Параметры",
+ "双栏pdf": "Двухколоночный PDF",
+ "取消": "Отмена",
+ "取消所有任务": "Отменить все задачи",
+ "可选,用于区分不同的模型": "Необязательно, используется для различения разных моделей",
+ "启用的工具:": "Включенные инструменты:",
+ "在工具箱中管理知识库文件": "Управление файлами базы знаний в инструментах",
+ "在线搜索": "Онлайн-поиск",
+ "在这里输入": "Введите здесь",
+ "在这里输入System Prompt...": "Введите здесь системное подсказку...",
+ "多账号模式已开启,无需输入key,可直接开始对话": "Режим множественных аккаунтов включен, не требуется ввод ключа, можно сразу начать диалог",
+ "好": "Хорошо",
+ "实时传输回答": "Передача ответа в реальном времени",
+ "对话": "Диалог",
+ "对话历史": "Диалоговая история",
+ "对话历史记录": "История диалога",
+ "对话命名方式": "Способ названия диалога",
+ "导出为 Markdown": "Экспортировать в Markdown",
+ "川虎Chat": "Chuanhu Чат",
+ "川虎Chat 🚀": "Chuanhu Чат 🚀",
+ "工具箱": "Инструменты",
+ "已经被删除啦": "Уже удалено.",
+ "开始实时传输回答……": "Начните трансляцию ответов в режиме реального времени...",
+ "开始训练": "Начать обучение",
+ "微调": "Своя модель",
+ "总结": "Подведение итога",
+ "总结完成": "Готово",
+ "您使用的就是最新版!": "Вы используете последнюю версию!",
+ "您的IP区域:": "Ваша IP-зона:",
+ "您的IP区域:未知。": "Ваша IP-зона: неизвестно.",
+ "拓展": "Расширенные настройки",
+ "搜索(支持正则)...": "Поиск (поддержка регулярности)...",
+ "数据集预览": "Предпросмотр набора данных",
+ "文件ID": "Идентификатор файла",
+ "新对话 ": "Новый диалог ",
+ "新建对话保留Prompt": "Создать диалог с сохранением подсказки",
+ "暂时未知": "Временно неизвестно",
+ "更新": "Обновить",
+ "更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "Обновление не удалось, пожалуйста, попробуйте обновить вручную",
+ "更新成功,请重启本程序": "Обновление успешно, пожалуйста, перезапустите программу",
+ "未命名对话历史记录": "Безымянная история диалога",
+ "未设置代理...": "Прокси не настроен...",
+ "本月使用金额": "Использовано средств в этом месяце",
+ "查看[使用介绍](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35)": "[Здесь](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35) можно ознакомиться с инструкцией по использованию",
+ "根据日期时间": "По дате и времени",
+ "模型": "Модель",
+ "模型名称后缀": "Суффикс имени модели",
+ "模型自动总结(消耗tokens)": "Автоматическое подведение итогов модели (потребление токенов)",
+ "模型设置为了:": "Модель настроена на:",
+ "正在尝试更新...": "Попытка обновления...",
+ "添加训练好的模型到模型列表": "Добавить обученную модель в список моделей",
+ "状态": "Статус",
+ "生成内容总结中……": "Создание сводки контента...",
+ "用于定位滥用行为": "Используется для выявления злоупотреблений",
+ "用户名": "Имя пользователя",
+ "由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536)、[明昭MZhao](https://space.bilibili.com/24807452) 和 [Keldos](https://github.com/Keldos-Li) 开发
访问川虎Chat的 [GitHub项目](https://github.com/GaiZhenbiao/ChuanhuChatGPT) 下载最新版脚本": "Разработано [土川虎虎虎](https://space.bilibili.com/29125536), [明昭MZhao](https://space.bilibili.com/24807452) и [Keldos](https://github.com/Keldos-Li).
посетите [GitHub Project](https://github.com/GaiZhenbiao/ChuanhuChatGPT) чата Chuanhu, чтобы загрузить последнюю версию скрипта",
+ "知识库": "База знаний",
+ "知识库文件": "Файл базы знаний",
+ "第一条提问": "Первый вопрос",
+ "索引构建完成": "Индексирование завершено.",
+ "网络": "Параметры сети",
+ "获取API使用情况失败:": "Не удалось получитьAPIинформацию об использовании:",
+ "获取IP地理位置失败。原因:": "Не удалось получить географическое положение IP. Причина:",
+ "获取对话时发生错误,请查看后台日志": "Возникла ошибка при получении диалога, пожалуйста, проверьте журналы",
+ "训练": "Обучение",
+ "训练状态": "Статус обучения",
+ "训练轮数(Epochs)": "Количество эпох обучения",
+ "设置": "Настройки",
+ "设置保存文件名": "Установить имя сохраняемого файла",
+ "设置文件名: 默认为.json,可选为.md": "Установить имя файла: по умолчанию .json, можно выбрать .md",
+ "识别公式": "Распознавание формул",
+ "详情": "Подробности",
+ "请查看 config_example.json,配置 Azure OpenAI": "Пожалуйста, просмотрите config_example.json для настройки Azure OpenAI",
+ "请检查网络连接,或者API-Key是否有效。": "Проверьте подключение к сети или действительность API-Key.",
+ "请输入对话内容。": "Пожалуйста, введите содержание диалога.",
+ "请输入有效的文件名,不要包含以下特殊字符:": "Введите действительное имя файла, не содержащее следующих специальных символов: ",
+ "读取超时,无法获取对话。": "Тайм-аут чтения, не удалось получить диалог.",
+ "账单信息不适用": "Информация о счете не применима",
+ "连接超时,无法获取对话。": "Тайм-аут подключения, не удалось получить диалог.",
+ "选择LoRA模型": "Выберите модель LoRA",
+ "选择Prompt模板集合文件": "Выберите файл с набором шаблонов Prompt",
+ "选择回复语言(针对搜索&索引功能)": "Выберите язык ответа (для функций поиска и индексации)",
+ "选择数据集": "Выберите набор данных",
+ "选择模型": "Выберите модель",
+ "重命名该对话": "Переименовать этот диалог",
+ "重新生成": "Пересоздать",
+ "高级": "Расширенные настройки",
+ ",本次对话累计消耗了 ": ", Общая стоимость этого диалога составляет ",
+ "💾 保存对话": "💾 Сохранить диалог",
+ "📝 导出为 Markdown": "📝 Экспортировать в Markdown",
+ "🔄 切换API地址": "🔄 Переключить адрес API",
+ "🔄 刷新": "🔄 Обновить",
+ "🔄 检查更新...": "🔄 Проверить обновления...",
+ "🔄 设置代理地址": "🔄 Установить адрес прокси",
+ "🔄 重新生成": "🔄 Пересоздать",
+ "🔙 恢复默认网络设置": "🔙 Восстановить настройки сети по умолчанию",
+ "🗑️ 删除最新对话": "🗑️ Удалить последний диалог",
+ "🗑️ 删除最旧对话": "🗑️ Удалить старейший диалог",
+ "🧹 新的对话": "🧹 Новый диалог"
+}
\ No newline at end of file
diff --git a/locale/sv_SE.json b/locale/sv_SE.json
new file mode 100644
index 0000000000000000000000000000000000000000..c76510b755a4204cff9540252d22e7acc0749bac
--- /dev/null
+++ b/locale/sv_SE.json
@@ -0,0 +1,141 @@
+{
+ " 吗?": " ?",
+ "# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ Var försiktig med ändringar. ⚠️",
+ "**发送消息** 或 **提交key** 以显示额度": "**Skicka meddelande** eller **Skicka in nyckel** för att visa kredit",
+ "**本月使用金额** ": "**Månadens användning** ",
+ "**获取API使用情况失败**": "**Misslyckades med att hämta API-användning**",
+ "**获取API使用情况失败**,sensitive_id错误或已过期": "**Misslyckades med att hämta API-användning**, felaktig eller utgången sensitive_id",
+ "**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**Misslyckades med att hämta API-användning**, korrekt sensitive_id behövs i `config.json`",
+ "API key为空,请检查是否输入正确。": "API-nyckeln är tom, kontrollera om den är korrekt inmatad.",
+ "API密钥更改为了": "API-nyckeln har ändrats till",
+ "JSON解析错误,收到的内容: ": "JSON-tolkningsfel, mottaget innehåll: ",
+ "SSL错误,无法获取对话。": "SSL-fel, kunde inte hämta dialogen.",
+ "Token 计数: ": "Tokenräkning: ",
+ "☹️发生了错误:": "☹️Fel: ",
+ "⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "⚠️ För att säkerställa säkerheten för API-nyckeln, vänligen ändra nätverksinställningarna i konfigurationsfilen `config.json`.",
+ "。你仍然可以使用聊天功能。": ". Du kan fortfarande använda chattfunktionen.",
+ "上传": "Ladda upp",
+ "上传了": "Uppladdad",
+ "上传到 OpenAI 后自动填充": "Automatiskt ifylld efter uppladdning till OpenAI",
+ "上传到OpenAI": "Ladda upp till OpenAI",
+ "上传文件": "ladda upp fil",
+ "仅供查看": "Endast för visning",
+ "从Prompt模板中加载": "Ladda från Prompt-mall",
+ "从列表中加载对话": "Ladda dialog från lista",
+ "代理地址": "Proxyadress",
+ "代理错误,无法获取对话。": "Proxyfel, kunde inte hämta dialogen.",
+ "你没有权限访问 GPT4,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)": "Du har inte behörighet att komma åt GPT-4, [läs mer](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)",
+ "你没有选择任何对话历史": "Du har inte valt någon konversationshistorik.",
+ "你真的要删除 ": "Är du säker på att du vill ta bort ",
+ "使用在线搜索": "Använd online-sökning",
+ "停止符,用英文逗号隔开...": "Skriv in stopptecken här, separerade med kommatecken...",
+ "关于": "om",
+ "准备数据集": "Förbered dataset",
+ "切换亮暗色主题": "Byt ljus/mörk tema",
+ "删除对话历史成功": "Raderade konversationens historik.",
+ "删除这轮问答": "Ta bort denna omgång av Q&A",
+ "刷新状态": "Uppdatera status",
+ "剩余配额不足,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)": "Återstående kvot är otillräcklig, [läs mer](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%C3%84mnen)",
+ "加载Prompt模板": "Ladda Prompt-mall",
+ "单轮对话": "Enkel dialog",
+ "历史记录(JSON)": "Historikfil (JSON)",
+ "参数": "Parametrar",
+ "双栏pdf": "Två-kolumns pdf",
+ "取消": "Avbryt",
+ "取消所有任务": "Avbryt alla uppgifter",
+ "可选,用于区分不同的模型": "Valfritt, används för att särskilja olika modeller",
+ "启用的工具:": "Aktiverade verktyg: ",
+ "在工具箱中管理知识库文件": "hantera kunskapsbankfiler i verktygslådan",
+ "在线搜索": "onlinesökning",
+ "在这里输入": "Skriv in här",
+ "在这里输入System Prompt...": "Skriv in System Prompt här...",
+ "多账号模式已开启,无需输入key,可直接开始对话": "Flerkontoläge är aktiverat, ingen nyckel behövs, du kan starta dialogen direkt",
+ "好": "OK",
+ "实时传输回答": "Strömmande utdata",
+ "对话": "konversation",
+ "对话历史": "Dialoghistorik",
+ "对话历史记录": "Dialoghistorik",
+ "对话命名方式": "Dialognamn",
+ "导出为 Markdown": "Exportera som Markdown",
+ "川虎Chat": "Chuanhu Chat",
+ "川虎Chat 🚀": "Chuanhu Chat 🚀",
+ "工具箱": "verktygslåda",
+ "已经被删除啦": "Har raderats.",
+ "开始实时传输回答……": "Börjar strömma utdata...",
+ "开始训练": "Börja träning",
+ "微调": "Finjustering",
+ "总结": "Sammanfatta",
+ "总结完成": "Slutfört sammanfattningen.",
+ "您使用的就是最新版!": "Du använder den senaste versionen!",
+ "您的IP区域:": "Din IP-region: ",
+ "您的IP区域:未知。": "Din IP-region: Okänd.",
+ "拓展": "utvidgning",
+ "搜索(支持正则)...": "Sök (stöd för reguljära uttryck)...",
+ "数据集预览": "Datasetförhandsvisning",
+ "文件ID": "Fil-ID",
+ "新对话 ": "Ny dialog ",
+ "新建对话保留Prompt": "Skapa ny konversation med bevarad Prompt",
+ "暂时未知": "Okänd",
+ "更新": "Uppdatera",
+ "更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "Uppdateringen misslyckades, prova att [uppdatera manuellt](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)",
+ "更新成功,请重启本程序": "Uppdaterat framgångsrikt, starta om programmet",
+ "未命名对话历史记录": "Onämnd Dialoghistorik",
+ "未设置代理...": "Inte inställd proxy...",
+ "本月使用金额": "Månadens användning",
+ "查看[使用介绍](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35)": "Se [användarguiden](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35) för mer information",
+ "根据日期时间": "Enligt datum och tid",
+ "模型": "Modell",
+ "模型名称后缀": "Modellnamnstillägg",
+ "模型自动总结(消耗tokens)": "Modellens automatiska sammanfattning (förbrukar tokens)",
+ "模型设置为了:": "Modellen är inställd på: ",
+ "正在尝试更新...": "Försöker uppdatera...",
+ "添加训练好的模型到模型列表": "Lägg till tränad modell i modellistan",
+ "状态": "Status",
+ "生成内容总结中……": "Genererar innehållssammanfattning...",
+ "用于定位滥用行为": "Används för att lokalisera missbruk",
+ "用户名": "Användarnamn",
+ "由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536)、[明昭MZhao](https://space.bilibili.com/24807452) 和 [Keldos](https://github.com/Keldos-Li) 开发
访问川虎Chat的 [GitHub项目](https://github.com/GaiZhenbiao/ChuanhuChatGPT) 下载最新版脚本": "Utvecklad av Bilibili [土川虎虎虎](https://space.bilibili.com/29125536), [明昭MZhao](https://space.bilibili.com/24807452) och [Keldos](https://github.com/Keldos-Li)\n\nLadda ner senaste koden från [GitHub](https://github.com/GaiZhenbiao/ChuanhuChatGPT)",
+ "知识库": "kunskapsbank",
+ "知识库文件": "kunskapsbankfil",
+ "第一条提问": "Första frågan",
+ "索引构建完成": "Indexet har blivit byggt färdigt.",
+ "网络": "nätverksparametrar",
+ "获取API使用情况失败:": "Misslyckades med att hämta API-användning:",
+ "获取IP地理位置失败。原因:": "Misslyckades med att hämta IP-plats. Orsak: ",
+ "获取对话时发生错误,请查看后台日志": "Ett fel uppstod när dialogen hämtades, kontrollera bakgrundsloggen",
+ "训练": "träning",
+ "训练状态": "Träningsstatus",
+ "训练轮数(Epochs)": "Träningsomgångar (Epochs)",
+ "设置": "inställningar",
+ "设置保存文件名": "Ställ in sparfilnamn",
+ "设置文件名: 默认为.json,可选为.md": "Ställ in filnamn: standard är .json, valfritt är .md",
+ "识别公式": "Formel OCR",
+ "详情": "Detaljer",
+ "请查看 config_example.json,配置 Azure OpenAI": "Vänligen granska config_example.json för att konfigurera Azure OpenAI",
+ "请检查网络连接,或者API-Key是否有效。": "Kontrollera nätverksanslutningen eller om API-nyckeln är giltig.",
+ "请输入对话内容。": "Ange dialoginnehåll.",
+ "请输入有效的文件名,不要包含以下特殊字符:": "Ange ett giltigt filnamn, använd inte följande specialtecken: ",
+ "读取超时,无法获取对话。": "Läsningen tog för lång tid, kunde inte hämta dialogen.",
+ "账单信息不适用": "Faktureringsinformation är inte tillämplig",
+ "连接超时,无法获取对话。": "Anslutningen tog för lång tid, kunde inte hämta dialogen.",
+ "选择LoRA模型": "Välj LoRA Modell",
+ "选择Prompt模板集合文件": "Välj Prompt-mall Samlingsfil",
+ "选择回复语言(针对搜索&索引功能)": "Välj svarspråk (för sök- och indexfunktion)",
+ "选择数据集": "Välj dataset",
+ "选择模型": "Välj Modell",
+ "重命名该对话": "Byt namn på dialogen",
+ "重新生成": "Återgenerera",
+ "高级": "Avancerat",
+ ",本次对话累计消耗了 ": ", Total kostnad för denna dialog är ",
+ "💾 保存对话": "💾 Spara Dialog",
+ "📝 导出为 Markdown": "📝 Exportera som Markdown",
+ "🔄 切换API地址": "🔄 Byt API-adress",
+ "🔄 刷新": "🔄 Uppdatera",
+ "🔄 检查更新...": "🔄 Sök efter uppdateringar...",
+ "🔄 设置代理地址": "🔄 Ställ in Proxyadress",
+ "🔄 重新生成": "🔄 Regenerera",
+ "🔙 恢复默认网络设置": "🔙 Återställ standardnätverksinställningar+",
+ "🗑️ 删除最新对话": "🗑️ Ta bort senaste dialogen",
+ "🗑️ 删除最旧对话": "🗑️ Ta bort äldsta dialogen",
+ "🧹 新的对话": "🧹 Ny Dialog"
+}
\ No newline at end of file
diff --git a/locale/vi_VN.json b/locale/vi_VN.json
new file mode 100644
index 0000000000000000000000000000000000000000..d496a59e675c0b36cc35434fdfb5cd472f608f7f
--- /dev/null
+++ b/locale/vi_VN.json
@@ -0,0 +1,141 @@
+{
+ " 吗?": " ?",
+ "# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ Lưu ý: Thay đổi yêu cầu cẩn thận. ⚠️",
+ "**发送消息** 或 **提交key** 以显示额度": "**Gửi tin nhắn** hoặc **Gửi khóa(key)** để hiển thị số dư",
+ "**本月使用金额** ": "**Số tiền sử dụng trong tháng** ",
+ "**获取API使用情况失败**": "**Lỗi khi lấy thông tin sử dụng API**",
+ "**获取API使用情况失败**,sensitive_id错误或已过期": "**Lỗi khi lấy thông tin sử dụng API**, sensitive_id sai hoặc đã hết hạn",
+ "**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**Lỗi khi lấy thông tin sử dụng API**, cần điền đúng sensitive_id trong tệp `config.json`",
+ "API key为空,请检查是否输入正确。": "Khóa API trống, vui lòng kiểm tra xem đã nhập đúng chưa.",
+ "API密钥更改为了": "Khóa API đã được thay đổi thành",
+ "JSON解析错误,收到的内容: ": "Lỗi phân tích JSON, nội dung nhận được: ",
+ "SSL错误,无法获取对话。": "Lỗi SSL, không thể nhận cuộc trò chuyện.",
+ "Token 计数: ": "Số lượng Token: ",
+ "☹️发生了错误:": "☹️Lỗi: ",
+ "⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "⚠️ Để đảm bảo an toàn cho API-Key, vui lòng chỉnh sửa cài đặt mạng trong tệp cấu hình `config.json`.",
+ "。你仍然可以使用聊天功能。": ". Bạn vẫn có thể sử dụng chức năng trò chuyện.",
+ "上传": "Tải lên",
+ "上传了": "Tải lên thành công.",
+ "上传到 OpenAI 后自动填充": "Tự động điền sau khi tải lên OpenAI",
+ "上传到OpenAI": "Tải lên OpenAI",
+ "上传文件": "Tải lên tệp",
+ "仅供查看": "Chỉ xem",
+ "从Prompt模板中加载": "Tải từ mẫu Prompt",
+ "从列表中加载对话": "Tải cuộc trò chuyện từ danh sách",
+ "代理地址": "Địa chỉ proxy",
+ "代理错误,无法获取对话。": "Lỗi proxy, không thể nhận cuộc trò chuyện.",
+ "你没有权限访问 GPT4,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)": "Bạn không có quyền truy cập GPT-4, [tìm hiểu thêm](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)",
+ "你没有选择任何对话历史": "Bạn chưa chọn bất kỳ lịch sử trò chuyện nào.",
+ "你真的要删除 ": "Bạn có chắc chắn muốn xóa ",
+ "使用在线搜索": "Sử dụng tìm kiếm trực tuyến",
+ "停止符,用英文逗号隔开...": "Nhập dấu dừng, cách nhau bằng dấu phẩy...",
+ "关于": "Về",
+ "准备数据集": "Chuẩn bị tập dữ liệu",
+ "切换亮暗色主题": "Chuyển đổi chủ đề sáng/tối",
+ "删除对话历史成功": "Xóa lịch sử cuộc trò chuyện thành công.",
+ "删除这轮问答": "Xóa cuộc trò chuyện này",
+ "刷新状态": "Làm mới tình trạng",
+ "剩余配额不足,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)": "剩余配额 không đủ, [Nhấn vào đây để biết thêm](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)",
+ "加载Prompt模板": "Tải mẫu Prompt",
+ "单轮对话": "Cuộc trò chuyện một lượt",
+ "历史记录(JSON)": "Tệp lịch sử (JSON)",
+ "参数": "Tham số",
+ "双栏pdf": "PDF hai cột",
+ "取消": "Hủy",
+ "取消所有任务": "Hủy tất cả các nhiệm vụ",
+ "可选,用于区分不同的模型": "Tùy chọn, sử dụng để phân biệt các mô hình khác nhau",
+ "启用的工具:": "Công cụ đã bật: ",
+ "在工具箱中管理知识库文件": "Quản lý tệp cơ sở kiến thức trong hộp công cụ",
+ "在线搜索": "Tìm kiếm trực tuyến",
+ "在这里输入": "Nhập vào đây",
+ "在这里输入System Prompt...": "Nhập System Prompt ở đây...",
+ "多账号模式已开启,无需输入key,可直接开始对话": "Chế độ nhiều tài khoản đã được bật, không cần nhập key, bạn có thể bắt đầu cuộc trò chuyện trực tiếp",
+ "好": "OK",
+ "实时传输回答": "Truyền đầu ra trực tiếp",
+ "对话": "Cuộc trò chuyện",
+ "对话历史": "Lịch sử cuộc trò chuyện",
+ "对话历史记录": "Lịch sử Cuộc trò chuyện",
+ "对话命名方式": "Phương thức đặt tên lịch sử trò chuyện",
+ "导出为 Markdown": "Xuất ra Markdown",
+ "川虎Chat": "Chuanhu Chat",
+ "川虎Chat 🚀": "Chuanhu Chat 🚀",
+ "工具箱": "Hộp công cụ",
+ "已经被删除啦": "Đã bị xóa rồi.",
+ "开始实时传输回答……": "Bắt đầu truyền đầu ra trực tiếp...",
+ "开始训练": "Bắt đầu đào tạo",
+ "微调": "Feeling-tuning",
+ "总结": "Tóm tắt",
+ "总结完成": "Hoàn thành tóm tắt",
+ "您使用的就是最新版!": "Bạn đang sử dụng phiên bản mới nhất!",
+ "您的IP区域:": "Khu vực IP của bạn: ",
+ "您的IP区域:未知。": "Khu vực IP của bạn: Không xác định.",
+ "拓展": "Mở rộng",
+ "搜索(支持正则)...": "Tìm kiếm (hỗ trợ regex)...",
+ "数据集预览": "Xem trước tập dữ liệu",
+ "文件ID": "ID Tệp",
+ "新对话 ": "Cuộc trò chuyện mới ",
+ "新建对话保留Prompt": "Tạo Cuộc trò chuyện mới và giữ Prompt nguyên vẹn",
+ "暂时未知": "Tạm thời chưa xác định",
+ "更新": "Cập nhật",
+ "更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "Cập nhật thất bại, vui lòng thử [cập nhật thủ công](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)",
+ "更新成功,请重启本程序": "Cập nhật thành công, vui lòng khởi động lại chương trình này",
+ "未命名对话历史记录": "Lịch sử Cuộc trò chuyện không đặt tên",
+ "未设置代理...": "Không có proxy...",
+ "本月使用金额": "Số tiền sử dụng trong tháng",
+ "查看[使用介绍](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35)": "Xem [hướng dẫn sử dụng](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35) để biết thêm chi tiết",
+ "根据日期时间": "Theo ngày và giờ",
+ "模型": "Mô hình",
+ "模型名称后缀": "Hậu tố Tên Mô hình",
+ "模型自动总结(消耗tokens)": "Tự động tóm tắt bằng LLM (Tiêu thụ token)",
+ "模型设置为了:": "Mô hình đã được đặt thành: ",
+ "正在尝试更新...": "Đang cố gắng cập nhật...",
+ "添加训练好的模型到模型列表": "Thêm mô hình đã đào tạo vào danh sách mô hình",
+ "状态": "Tình trạng",
+ "生成内容总结中……": "Đang tạo tóm tắt nội dung...",
+ "用于定位滥用行为": "Sử dụng để xác định hành vi lạm dụng",
+ "用户名": "Tên người dùng",
+ "由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536)、[明昭MZhao](https://space.bilibili.com/24807452) 和 [Keldos](https://github.com/Keldos-Li) 开发
访问川虎Chat的 [GitHub项目](https://github.com/GaiZhenbiao/ChuanhuChatGPT) 下载最新版脚本": "Phát triển bởi Bilibili [土川虎虎虎](https://space.bilibili.com/29125536), [明昭MZhao](https://space.bilibili.com/24807452) và [Keldos](https://github.com/Keldos-Li)\n\nTải mã nguồn mới nhất từ [GitHub](https://github.com/GaiZhenbiao/ChuanhuChatGPT)",
+ "知识库": "Cơ sở kiến thức",
+ "知识库文件": "Tệp cơ sở kiến thức",
+ "第一条提问": "Theo câu hỏi đầu tiên",
+ "索引构建完成": "Xây dựng chỉ mục hoàn tất",
+ "网络": "Mạng",
+ "获取API使用情况失败:": "Lỗi khi lấy thông tin sử dụng API:",
+ "获取IP地理位置失败。原因:": "Không thể lấy vị trí địa lý của IP. Nguyên nhân: ",
+ "获取对话时发生错误,请查看后台日志": "Xảy ra lỗi khi nhận cuộc trò chuyện, kiểm tra nhật ký nền",
+ "训练": "Đào tạo",
+ "训练状态": "Tình trạng đào tạo",
+ "训练轮数(Epochs)": "Số lượt đào tạo (Epochs)",
+ "设置": "Cài đặt",
+ "设置保存文件名": "Đặt tên tệp lưu",
+ "设置文件名: 默认为.json,可选为.md": "Đặt tên tệp: mặc định là .json, tùy chọn là .md",
+ "识别公式": "Nhận dạng công thức",
+ "详情": "Chi tiết",
+ "请查看 config_example.json,配置 Azure OpenAI": "Vui lòng xem tệp config_example.json để cấu hình Azure OpenAI",
+ "请检查网络连接,或者API-Key是否有效。": "Vui lòng kiểm tra kết nối mạng hoặc xem xét tính hợp lệ của API-Key.",
+ "请输入对话内容。": "Nhập nội dung cuộc trò chuyện.",
+ "请输入有效的文件名,不要包含以下特殊字符:": "Vui lòng nhập tên tệp hợp lệ, không chứa các ký tự đặc biệt sau: ",
+ "读取超时,无法获取对话。": "Hết thời gian đọc, không thể nhận cuộc trò chuyện.",
+ "账单信息不适用": "Thông tin thanh toán không áp dụng",
+ "连接超时,无法获取对话。": "Hết thời gian kết nối, không thể nhận cuộc trò chuyện.",
+ "选择LoRA模型": "Chọn Mô hình LoRA",
+ "选择Prompt模板集合文件": "Chọn Tệp bộ sưu tập mẫu Prompt",
+ "选择回复语言(针对搜索&索引功能)": "Chọn ngôn ngữ phản hồi (đối với chức năng tìm kiếm & chỉ mục)",
+ "选择数据集": "Chọn tập dữ liệu",
+ "选择模型": "Chọn Mô hình",
+ "重命名该对话": "Đổi tên cuộc trò chuyện này",
+ "重新生成": "Tạo lại",
+ "高级": "Nâng cao",
+ ",本次对话累计消耗了 ": ", Tổng cộng chi phí cho cuộc trò chuyện này là ",
+ "💾 保存对话": "💾 Lưu Cuộc trò chuyện",
+ "📝 导出为 Markdown": "📝 Xuất ra dưới dạng Markdown",
+ "🔄 切换API地址": "🔄 Chuyển đổi Địa chỉ API",
+ "🔄 刷新": "🔄 Làm mới",
+ "🔄 检查更新...": "🔄 Kiểm tra cập nhật...",
+ "🔄 设置代理地址": "🔄 Đặt Địa chỉ Proxy",
+ "🔄 重新生成": "🔄 Tạo lại",
+ "🔙 恢复默认网络设置": "🔙 Khôi phục cài đặt mạng mặc định",
+ "🗑️ 删除最新对话": "🗑️ Xóa cuộc trò chuyện mới nhất",
+ "🗑️ 删除最旧对话": "🗑️ Xóa cuộc trò chuyện cũ nhất",
+ "🧹 新的对话": "🧹 Cuộc trò chuyện mới"
+}
\ No newline at end of file
diff --git a/locale/zh_CN.json b/locale/zh_CN.json
new file mode 100644
index 0000000000000000000000000000000000000000..9e26dfeeb6e641a33dae4961196235bdb965b21b
--- /dev/null
+++ b/locale/zh_CN.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/modules/config.py b/modules/config.py
index 8418a36eb7e167c5de1d9f72e1ca9b05669875d0..556aad1a82e3d31f34e8fa9807222549a8ff9102 100644
--- a/modules/config.py
+++ b/modules/config.py
@@ -27,7 +27,8 @@ __all__ = [
"latex_delimiters_set",
"hide_history_when_not_logged_in",
"default_chuanhu_assistant_model",
- "show_api_billing"
+ "show_api_billing",
+ "chat_name_method_index",
]
# 添加一个统一的config文件,避免文件过多造成的疑惑(优先级最低)
@@ -45,15 +46,12 @@ def load_config_to_environ(key_list):
if key in config:
os.environ[key.upper()] = os.environ.get(key.upper(), config[key])
-
-lang_config = config.get("language", "auto")
-language = os.environ.get("LANGUAGE", lang_config)
-
hide_history_when_not_logged_in = config.get(
"hide_history_when_not_logged_in", False)
check_update = config.get("check_update", True)
show_api_billing = config.get("show_api_billing", False)
show_api_billing = bool(os.environ.get("SHOW_API_BILLING", show_api_billing))
+chat_name_method_index = config.get("chat_name_method_index", 2)
if os.path.exists("api_key.txt"):
logging.info("检测到api_key.txt文件,正在进行迁移...")
@@ -87,6 +85,8 @@ if os.environ.get("dockerrun") == "yes":
# 处理 api-key 以及 允许的用户列表
my_api_key = config.get("openai_api_key", "")
my_api_key = os.environ.get("OPENAI_API_KEY", my_api_key)
+os.environ["OPENAI_API_KEY"] = my_api_key
+os.environ["OPENAI_EMBEDDING_API_KEY"] = my_api_key
if config.get("legacy_api_usage", False):
sensitive_id = my_api_key
@@ -94,6 +94,10 @@ else:
sensitive_id = config.get("sensitive_id", "")
sensitive_id = os.environ.get("SENSITIVE_ID", sensitive_id)
+if "available_models" in config:
+ presets.MODELS = config["available_models"]
+ logging.info(f"已设置可用模型:{config['available_models']}")
+
# 模型配置
if "extra_models" in config:
presets.MODELS.extend(config["extra_models"])
@@ -121,6 +125,16 @@ os.environ["MIDJOURNEY_DISCORD_PROXY_URL"] = midjourney_discord_proxy_url
midjourney_temp_folder = config.get("midjourney_temp_folder", "")
os.environ["MIDJOURNEY_TEMP_FOLDER"] = midjourney_temp_folder
+spark_api_key = config.get("spark_api_key", "")
+os.environ["SPARK_API_KEY"] = spark_api_key
+spark_appid = config.get("spark_appid", "")
+os.environ["SPARK_APPID"] = spark_appid
+spark_api_secret = config.get("spark_api_secret", "")
+os.environ["SPARK_API_SECRET"] = spark_api_secret
+
+claude_api_secret = config.get("claude_api_secret", "")
+os.environ["CLAUDE_API_SECRET"] = claude_api_secret
+
load_config_to_environ(["openai_api_type", "azure_openai_api_key", "azure_openai_api_base_url",
"azure_openai_api_version", "azure_deployment_name", "azure_embedding_deployment_name", "azure_embedding_model_name"])
@@ -275,4 +289,12 @@ share = config.get("share", False)
# avatar
bot_avatar = config.get("bot_avatar", "default")
-user_avatar = config.get("user_avatar", "default")
\ No newline at end of file
+user_avatar = config.get("user_avatar", "default")
+if bot_avatar == "" or bot_avatar == "none" or bot_avatar is None:
+ bot_avatar = None
+elif bot_avatar == "default":
+ bot_avatar = "web_assets/chatbot.png"
+if user_avatar == "" or user_avatar == "none" or user_avatar is None:
+ user_avatar = None
+elif user_avatar == "default":
+ user_avatar = "web_assets/user.png"
diff --git a/modules/index_func.py b/modules/index_func.py
index 2e2ea982ccc7c03a62ff3a31db5244e5048c3b31..d19557053728e7946583078d10404943d1a7b32b 100644
--- a/modules/index_func.py
+++ b/modules/index_func.py
@@ -23,6 +23,7 @@ def get_documents(file_src):
filename = os.path.basename(filepath)
file_type = os.path.splitext(filename)[1]
logging.info(f"loading file: {filename}")
+ texts = None
try:
if file_type == ".pdf":
logging.debug("Loading PDF...")
@@ -72,8 +73,9 @@ def get_documents(file_src):
logging.error(f"Error loading file: {filename}")
traceback.print_exc()
- texts = text_splitter.split_documents(texts)
- documents.extend(texts)
+ if texts is not None:
+ texts = text_splitter.split_documents(texts)
+ documents.extend(texts)
logging.debug("Documents loaded.")
return documents
@@ -87,6 +89,7 @@ def construct_index(
chunk_size_limit=600,
embedding_limit=None,
separator=" ",
+ load_from_cache_if_possible=True,
):
from langchain.chat_models import ChatOpenAI
from langchain.vectorstores import FAISS
@@ -114,11 +117,9 @@ def construct_index(
else:
embeddings = OpenAIEmbeddings(deployment=os.environ["AZURE_EMBEDDING_DEPLOYMENT_NAME"], openai_api_key=os.environ["AZURE_OPENAI_API_KEY"],
model=os.environ["AZURE_EMBEDDING_MODEL_NAME"], openai_api_base=os.environ["AZURE_OPENAI_API_BASE_URL"], openai_api_type="azure")
- if os.path.exists(index_path):
+ if os.path.exists(index_path) and load_from_cache_if_possible:
logging.info("找到了缓存的索引文件,加载中……")
- index = FAISS.load_local(index_path, embeddings)
- os.environ["OPENAI_API_KEY"] = ""
- return index
+ return FAISS.load_local(index_path, embeddings)
else:
try:
documents = get_documents(file_src)
@@ -129,12 +130,10 @@ def construct_index(
os.makedirs("./index", exist_ok=True)
index.save_local(index_path)
logging.debug("索引已保存至本地!")
- os.environ["OPENAI_API_KEY"] = ""
return index
except Exception as e:
import traceback
logging.error("索引构建失败!%s", e)
traceback.print_exc()
- os.environ["OPENAI_API_KEY"] = ""
return None
diff --git a/modules/models/Azure.py b/modules/models/Azure.py
new file mode 100644
index 0000000000000000000000000000000000000000..f6c7adaadd57c6860609889d298981ce5f31146c
--- /dev/null
+++ b/modules/models/Azure.py
@@ -0,0 +1,18 @@
+from langchain.chat_models import AzureChatOpenAI, ChatOpenAI
+import os
+
+from .base_model import Base_Chat_Langchain_Client
+
+# load_config_to_environ(["azure_openai_api_key", "azure_api_base_url", "azure_openai_api_version", "azure_deployment_name"])
+
+class Azure_OpenAI_Client(Base_Chat_Langchain_Client):
+ def setup_model(self):
+ # inplement this to setup the model then return it
+ return AzureChatOpenAI(
+ openai_api_base=os.environ["AZURE_OPENAI_API_BASE_URL"],
+ openai_api_version=os.environ["AZURE_OPENAI_API_VERSION"],
+ deployment_name=os.environ["AZURE_DEPLOYMENT_NAME"],
+ openai_api_key=os.environ["AZURE_OPENAI_API_KEY"],
+ openai_api_type="azure",
+ streaming=True
+ )
diff --git a/modules/models/ChatGLM.py b/modules/models/ChatGLM.py
new file mode 100644
index 0000000000000000000000000000000000000000..e90416f40b875476c8d946252e881fbc1979ed29
--- /dev/null
+++ b/modules/models/ChatGLM.py
@@ -0,0 +1,84 @@
+from __future__ import annotations
+
+import logging
+import os
+import platform
+
+import colorama
+
+from ..index_func import *
+from ..presets import *
+from ..utils import *
+from .base_model import BaseLLMModel
+
+
+class ChatGLM_Client(BaseLLMModel):
+ def __init__(self, model_name, user_name="") -> None:
+ super().__init__(model_name=model_name, user=user_name)
+ import torch
+ from transformers import AutoModel, AutoTokenizer
+ global CHATGLM_TOKENIZER, CHATGLM_MODEL
+ if CHATGLM_TOKENIZER is None or CHATGLM_MODEL is None:
+ system_name = platform.system()
+ model_path = None
+ if os.path.exists("models"):
+ model_dirs = os.listdir("models")
+ if model_name in model_dirs:
+ model_path = f"models/{model_name}"
+ if model_path is not None:
+ model_source = model_path
+ else:
+ model_source = f"THUDM/{model_name}"
+ CHATGLM_TOKENIZER = AutoTokenizer.from_pretrained(
+ model_source, trust_remote_code=True
+ )
+ quantified = False
+ if "int4" in model_name:
+ quantified = True
+ model = AutoModel.from_pretrained(
+ model_source, trust_remote_code=True
+ )
+ if torch.cuda.is_available():
+ # run on CUDA
+ logging.info("CUDA is available, using CUDA")
+ model = model.half().cuda()
+ # mps加速还存在一些问题,暂时不使用
+ elif system_name == "Darwin" and model_path is not None and not quantified:
+ logging.info("Running on macOS, using MPS")
+ # running on macOS and model already downloaded
+ model = model.half().to("mps")
+ else:
+ logging.info("GPU is not available, using CPU")
+ model = model.float()
+ model = model.eval()
+ CHATGLM_MODEL = model
+
+ def _get_glm_style_input(self):
+ history = [x["content"] for x in self.history]
+ query = history.pop()
+ logging.debug(colorama.Fore.YELLOW +
+ f"{history}" + colorama.Fore.RESET)
+ assert (
+ len(history) % 2 == 0
+ ), f"History should be even length. current history is: {history}"
+ history = [[history[i], history[i + 1]]
+ for i in range(0, len(history), 2)]
+ return history, query
+
+ def get_answer_at_once(self):
+ history, query = self._get_glm_style_input()
+ response, _ = CHATGLM_MODEL.chat(
+ CHATGLM_TOKENIZER, query, history=history)
+ return response, len(response)
+
+ def get_answer_stream_iter(self):
+ history, query = self._get_glm_style_input()
+ for response, history in CHATGLM_MODEL.stream_chat(
+ CHATGLM_TOKENIZER,
+ query,
+ history,
+ max_length=self.token_upper_limit,
+ top_p=self.top_p,
+ temperature=self.temperature,
+ ):
+ yield response
diff --git a/modules/models/ChuanhuAgent.py b/modules/models/ChuanhuAgent.py
index c3cb944d3d4a5f60f1402445dc52a3501f466916..8e04ee8338231d3990847675bf5951563da9cc83 100644
--- a/modules/models/ChuanhuAgent.py
+++ b/modules/models/ChuanhuAgent.py
@@ -63,7 +63,23 @@ class ChuanhuAgent_Client(BaseLLMModel):
self.index_summary = None
self.index = None
if "Pro" in self.model_name:
- self.tools = load_tools(["serpapi", "google-search-results-json", "llm-math", "arxiv", "wikipedia", "wolfram-alpha"], llm=self.llm)
+ tools_to_enable = ["llm-math", "arxiv", "wikipedia"]
+ # if exists GOOGLE_CSE_ID and GOOGLE_API_KEY, enable google-search-results-json
+ if os.environ.get("GOOGLE_CSE_ID", None) is not None and os.environ.get("GOOGLE_API_KEY", None) is not None:
+ tools_to_enable.append("google-search-results-json")
+ else:
+ logging.warning("GOOGLE_CSE_ID and/or GOOGLE_API_KEY not found, google-search-results-json is disabled.")
+ # if exists WOLFRAM_ALPHA_APPID, enable wolfram-alpha
+ if os.environ.get("WOLFRAM_ALPHA_APPID", None) is not None:
+ tools_to_enable.append("wolfram-alpha")
+ else:
+ logging.warning("WOLFRAM_ALPHA_APPID not found, wolfram-alpha is disabled.")
+ # if exists SERPAPI_API_KEY, enable serpapi
+ if os.environ.get("SERPAPI_API_KEY", None) is not None:
+ tools_to_enable.append("serpapi")
+ else:
+ logging.warning("SERPAPI_API_KEY not found, serpapi is disabled.")
+ self.tools = load_tools(tools_to_enable, llm=self.llm)
else:
self.tools = load_tools(["ddg-search", "llm-math", "arxiv", "wikipedia"], llm=self.llm)
self.tools.append(
@@ -96,7 +112,7 @@ class ChuanhuAgent_Client(BaseLLMModel):
def google_search_simple(self, query):
results = []
with DDGS() as ddgs:
- ddgs_gen = ddgs.text("notes from a dead house", backend="lite")
+ ddgs_gen = ddgs.text(query, backend="lite")
for r in islice(ddgs_gen, 10):
results.append({
"title": r["title"],
diff --git a/modules/models/Claude.py b/modules/models/Claude.py
new file mode 100644
index 0000000000000000000000000000000000000000..719d1af3a0443ab8510971845c62ce961a13933b
--- /dev/null
+++ b/modules/models/Claude.py
@@ -0,0 +1,55 @@
+
+from anthropic import Anthropic, HUMAN_PROMPT, AI_PROMPT
+from ..presets import *
+from ..utils import *
+
+from .base_model import BaseLLMModel
+
+
+class Claude_Client(BaseLLMModel):
+ def __init__(self, model_name, api_secret) -> None:
+ super().__init__(model_name=model_name)
+ self.api_secret = api_secret
+ if None in [self.api_secret]:
+ raise Exception("请在配置文件或者环境变量中设置Claude的API Secret")
+ self.claude_client = Anthropic(api_key=self.api_secret)
+
+
+ def get_answer_stream_iter(self):
+ system_prompt = self.system_prompt
+ history = self.history
+ if system_prompt is not None:
+ history = [construct_system(system_prompt), *history]
+
+ completion = self.claude_client.completions.create(
+ model=self.model_name,
+ max_tokens_to_sample=300,
+ prompt=f"{HUMAN_PROMPT}{history}{AI_PROMPT}",
+ stream=True,
+ )
+ if completion is not None:
+ partial_text = ""
+ for chunk in completion:
+ partial_text += chunk.completion
+ yield partial_text
+ else:
+ yield STANDARD_ERROR_MSG + GENERAL_ERROR_MSG
+
+
+ def get_answer_at_once(self):
+ system_prompt = self.system_prompt
+ history = self.history
+ if system_prompt is not None:
+ history = [construct_system(system_prompt), *history]
+
+ completion = self.claude_client.completions.create(
+ model=self.model_name,
+ max_tokens_to_sample=300,
+ prompt=f"{HUMAN_PROMPT}{history}{AI_PROMPT}",
+ )
+ if completion is not None:
+ return completion.completion, len(completion.completion)
+ else:
+ return "获取资源错误", 0
+
+
diff --git a/modules/models/GooglePaLM.py b/modules/models/GooglePaLM.py
new file mode 100644
index 0000000000000000000000000000000000000000..db38dbc5dbf807009ba8ac9b2ed746cac5e9d264
--- /dev/null
+++ b/modules/models/GooglePaLM.py
@@ -0,0 +1,29 @@
+from .base_model import BaseLLMModel
+import google.generativeai as palm
+
+
+class Google_PaLM_Client(BaseLLMModel):
+ def __init__(self, model_name, api_key, user_name="") -> None:
+ super().__init__(model_name=model_name, user=user_name)
+ self.api_key = api_key
+
+ def _get_palm_style_input(self):
+ new_history = []
+ for item in self.history:
+ if item["role"] == "user":
+ new_history.append({'author': '1', 'content': item["content"]})
+ else:
+ new_history.append({'author': '0', 'content': item["content"]})
+ return new_history
+
+ def get_answer_at_once(self):
+ palm.configure(api_key=self.api_key)
+ messages = self._get_palm_style_input()
+ response = palm.chat(context=self.system_prompt, messages=messages,
+ temperature=self.temperature, top_p=self.top_p)
+ if response.last is not None:
+ return response.last, len(response.last)
+ else:
+ reasons = '\n\n'.join(
+ reason['reason'].name for reason in response.filters)
+ return "由于下面的原因,Google 拒绝返回 PaLM 的回答:\n\n" + reasons, 0
diff --git a/modules/models/LLaMA.py b/modules/models/LLaMA.py
new file mode 100644
index 0000000000000000000000000000000000000000..e7c9a2b42d1d1c5232bc06fea183f346c40b1886
--- /dev/null
+++ b/modules/models/LLaMA.py
@@ -0,0 +1,126 @@
+from __future__ import annotations
+
+import json
+import os
+
+from huggingface_hub import hf_hub_download
+from llama_cpp import Llama
+
+from ..index_func import *
+from ..presets import *
+from ..utils import *
+from .base_model import BaseLLMModel
+
+SYS_PREFIX = "<[INST] "
+INST_POSTFIX = " "
+OUTPUT_PREFIX = "[/INST] "
+OUTPUT_POSTFIX = ""
+
+
+def download(repo_id, filename, retry=10):
+ if os.path.exists("./models/downloaded_models.json"):
+ with open("./models/downloaded_models.json", "r") as f:
+ downloaded_models = json.load(f)
+ if repo_id in downloaded_models:
+ return downloaded_models[repo_id]["path"]
+ else:
+ downloaded_models = {}
+ while retry > 0:
+ try:
+ model_path = hf_hub_download(
+ repo_id=repo_id,
+ filename=filename,
+ cache_dir="models",
+ resume_download=True,
+ )
+ downloaded_models[repo_id] = {"path": model_path}
+ with open("./models/downloaded_models.json", "w") as f:
+ json.dump(downloaded_models, f)
+ break
+ except:
+ print("Error downloading model, retrying...")
+ retry -= 1
+ if retry == 0:
+ raise Exception("Error downloading model, please try again later.")
+ return model_path
+
+
+class LLaMA_Client(BaseLLMModel):
+ def __init__(self, model_name, lora_path=None, user_name="") -> None:
+ super().__init__(model_name=model_name, user=user_name)
+
+ self.max_generation_token = 1000
+ if model_name in MODEL_METADATA:
+ path_to_model = download(
+ MODEL_METADATA[model_name]["repo_id"],
+ MODEL_METADATA[model_name]["filelist"][0],
+ )
+ else:
+ dir_to_model = os.path.join("models", model_name)
+ # look for nay .gguf file in the dir_to_model directory and its subdirectories
+ path_to_model = None
+ for root, dirs, files in os.walk(dir_to_model):
+ for file in files:
+ if file.endswith(".gguf"):
+ path_to_model = os.path.join(root, file)
+ break
+ if path_to_model is not None:
+ break
+ self.system_prompt = ""
+
+ if lora_path is not None:
+ lora_path = os.path.join("lora", lora_path)
+ self.model = Llama(model_path=path_to_model, lora_path=lora_path)
+ else:
+ self.model = Llama(model_path=path_to_model)
+
+ def _get_llama_style_input(self):
+ context = []
+ for conv in self.history:
+ if conv["role"] == "system":
+ context.append(SYS_PREFIX + conv["content"] + SYS_POSTFIX)
+ elif conv["role"] == "user":
+ context.append(
+ INST_PREFIX + conv["content"] + INST_POSTFIX + OUTPUT_PREFIX
+ )
+ else:
+ context.append(conv["content"] + OUTPUT_POSTFIX)
+ return "".join(context)
+ # for conv in self.history:
+ # if conv["role"] == "system":
+ # context.append(conv["content"])
+ # elif conv["role"] == "user":
+ # context.append(
+ # conv["content"]
+ # )
+ # else:
+ # context.append(conv["content"])
+ # return "\n\n".join(context)+"\n\n"
+
+ def get_answer_at_once(self):
+ context = self._get_llama_style_input()
+ response = self.model(
+ context,
+ max_tokens=self.max_generation_token,
+ stop=[],
+ echo=False,
+ stream=False,
+ )
+ return response, len(response)
+
+ def get_answer_stream_iter(self):
+ context = self._get_llama_style_input()
+ iter = self.model(
+ context,
+ max_tokens=self.max_generation_token,
+ stop=[SYS_PREFIX, SYS_POSTFIX, INST_PREFIX, OUTPUT_PREFIX,OUTPUT_POSTFIX],
+ echo=False,
+ stream=True,
+ )
+ partial_text = ""
+ for i in iter:
+ response = i["choices"][0]["text"]
+ partial_text += response
+ yield partial_text
diff --git a/modules/models/OpenAI.py b/modules/models/OpenAI.py
new file mode 100644
index 0000000000000000000000000000000000000000..2a2b1fbd6a652e7a81fe81aafb132539fdd396e3
--- /dev/null
+++ b/modules/models/OpenAI.py
@@ -0,0 +1,279 @@
+from __future__ import annotations
+
+import json
+import logging
+import traceback
+
+import colorama
+import requests
+
+from .. import shared
+from ..config import retrieve_proxy, sensitive_id, usage_limit
+from ..index_func import *
+from ..presets import *
+from ..utils import *
+from .base_model import BaseLLMModel
+
+
+class OpenAIClient(BaseLLMModel):
+ def __init__(
+ self,
+ model_name,
+ api_key,
+ system_prompt=INITIAL_SYSTEM_PROMPT,
+ temperature=1.0,
+ top_p=1.0,
+ user_name=""
+ ) -> None:
+ super().__init__(
+ model_name=MODEL_METADATA[model_name]["model_name"],
+ temperature=temperature,
+ top_p=top_p,
+ system_prompt=system_prompt,
+ user=user_name
+ )
+ self.api_key = api_key
+ self.need_api_key = True
+ self._refresh_header()
+
+ def get_answer_stream_iter(self):
+ response = self._get_response(stream=True)
+ if response is not None:
+ iter = self._decode_chat_response(response)
+ partial_text = ""
+ for i in iter:
+ partial_text += i
+ yield partial_text
+ else:
+ yield STANDARD_ERROR_MSG + GENERAL_ERROR_MSG
+
+ def get_answer_at_once(self):
+ response = self._get_response()
+ response = json.loads(response.text)
+ content = response["choices"][0]["message"]["content"]
+ total_token_count = response["usage"]["total_tokens"]
+ return content, total_token_count
+
+ def count_token(self, user_input):
+ input_token_count = count_token(construct_user(user_input))
+ if self.system_prompt is not None and len(self.all_token_counts) == 0:
+ system_prompt_token_count = count_token(
+ construct_system(self.system_prompt)
+ )
+ return input_token_count + system_prompt_token_count
+ return input_token_count
+
+ def billing_info(self):
+ try:
+ curr_time = datetime.datetime.now()
+ last_day_of_month = get_last_day_of_month(
+ curr_time).strftime("%Y-%m-%d")
+ first_day_of_month = curr_time.replace(day=1).strftime("%Y-%m-%d")
+ usage_url = f"{shared.state.usage_api_url}?start_date={first_day_of_month}&end_date={last_day_of_month}"
+ try:
+ usage_data = self._get_billing_data(usage_url)
+ except Exception as e:
+ # logging.error(f"获取API使用情况失败: " + str(e))
+ if "Invalid authorization header" in str(e):
+ return i18n("**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id")
+ elif "Incorrect API key provided: sess" in str(e):
+ return i18n("**获取API使用情况失败**,sensitive_id错误或已过期")
+ return i18n("**获取API使用情况失败**")
+ # rounded_usage = "{:.5f}".format(usage_data["total_usage"] / 100)
+ rounded_usage = round(usage_data["total_usage"] / 100, 5)
+ usage_percent = round(usage_data["total_usage"] / usage_limit, 2)
+ from ..webui import get_html
+
+ # return i18n("**本月使用金额** ") + f"\u3000 ${rounded_usage}"
+ return get_html("billing_info.html").format(
+ label = i18n("本月使用金额"),
+ usage_percent = usage_percent,
+ rounded_usage = rounded_usage,
+ usage_limit = usage_limit
+ )
+ except requests.exceptions.ConnectTimeout:
+ status_text = (
+ STANDARD_ERROR_MSG + CONNECTION_TIMEOUT_MSG + ERROR_RETRIEVE_MSG
+ )
+ return status_text
+ except requests.exceptions.ReadTimeout:
+ status_text = STANDARD_ERROR_MSG + READ_TIMEOUT_MSG + ERROR_RETRIEVE_MSG
+ return status_text
+ except Exception as e:
+ import traceback
+ traceback.print_exc()
+ logging.error(i18n("获取API使用情况失败:") + str(e))
+ return STANDARD_ERROR_MSG + ERROR_RETRIEVE_MSG
+
+ def set_token_upper_limit(self, new_upper_limit):
+ pass
+
+ @shared.state.switching_api_key # 在不开启多账号模式的时候,这个装饰器不会起作用
+ def _get_response(self, stream=False):
+ openai_api_key = self.api_key
+ system_prompt = self.system_prompt
+ history = self.history
+ logging.debug(colorama.Fore.YELLOW +
+ f"{history}" + colorama.Fore.RESET)
+ headers = {
+ "Content-Type": "application/json",
+ "Authorization": f"Bearer {openai_api_key}",
+ }
+
+ if system_prompt is not None:
+ history = [construct_system(system_prompt), *history]
+
+ payload = {
+ "model": self.model_name,
+ "messages": history,
+ "temperature": self.temperature,
+ "top_p": self.top_p,
+ "n": self.n_choices,
+ "stream": stream,
+ "presence_penalty": self.presence_penalty,
+ "frequency_penalty": self.frequency_penalty,
+ }
+
+ if self.max_generation_token is not None:
+ payload["max_tokens"] = self.max_generation_token
+ if self.stop_sequence is not None:
+ payload["stop"] = self.stop_sequence
+ if self.logit_bias is not None:
+ payload["logit_bias"] = self.logit_bias
+ if self.user_identifier:
+ payload["user"] = self.user_identifier
+
+ if stream:
+ timeout = TIMEOUT_STREAMING
+ else:
+ timeout = TIMEOUT_ALL
+
+ # 如果有自定义的api-host,使用自定义host发送请求,否则使用默认设置发送请求
+ if shared.state.chat_completion_url != CHAT_COMPLETION_URL:
+ logging.debug(f"使用自定义API URL: {shared.state.chat_completion_url}")
+
+ with retrieve_proxy():
+ try:
+ response = requests.post(
+ shared.state.chat_completion_url,
+ headers=headers,
+ json=payload,
+ stream=stream,
+ timeout=timeout,
+ )
+ except:
+ traceback.print_exc()
+ return None
+ return response
+
+ def _refresh_header(self):
+ self.headers = {
+ "Content-Type": "application/json",
+ "Authorization": f"Bearer {sensitive_id}",
+ }
+
+
+ def _get_billing_data(self, billing_url):
+ with retrieve_proxy():
+ response = requests.get(
+ billing_url,
+ headers=self.headers,
+ timeout=TIMEOUT_ALL,
+ )
+
+ if response.status_code == 200:
+ data = response.json()
+ return data
+ else:
+ raise Exception(
+ f"API request failed with status code {response.status_code}: {response.text}"
+ )
+
+ def _decode_chat_response(self, response):
+ error_msg = ""
+ for chunk in response.iter_lines():
+ if chunk:
+ chunk = chunk.decode()
+ chunk_length = len(chunk)
+ try:
+ chunk = json.loads(chunk[6:])
+ except:
+ print(i18n("JSON解析错误,收到的内容: ") + f"{chunk}")
+ error_msg += chunk
+ continue
+ try:
+ if chunk_length > 6 and "delta" in chunk["choices"][0]:
+ if "finish_reason" in chunk["choices"][0]:
+ finish_reason = chunk["choices"][0]["finish_reason"]
+ else:
+ finish_reason = chunk["finish_reason"]
+ if finish_reason == "stop":
+ break
+ try:
+ yield chunk["choices"][0]["delta"]["content"]
+ except Exception as e:
+ # logging.error(f"Error: {e}")
+ continue
+ except:
+ print(f"ERROR: {chunk}")
+ continue
+ if error_msg and not error_msg=="data: [DONE]":
+ raise Exception(error_msg)
+
+ def set_key(self, new_access_key):
+ ret = super().set_key(new_access_key)
+ self._refresh_header()
+ return ret
+
+ def _single_query_at_once(self, history, temperature=1.0):
+ timeout = TIMEOUT_ALL
+ headers = {
+ "Content-Type": "application/json",
+ "Authorization": f"Bearer {self.api_key}",
+ "temperature": f"{temperature}",
+ }
+ payload = {
+ "model": self.model_name,
+ "messages": history,
+ }
+ # 如果有自定义的api-host,使用自定义host发送请求,否则使用默认设置发送请求
+ if shared.state.chat_completion_url != CHAT_COMPLETION_URL:
+ logging.debug(f"使用自定义API URL: {shared.state.chat_completion_url}")
+
+ with retrieve_proxy():
+ response = requests.post(
+ shared.state.chat_completion_url,
+ headers=headers,
+ json=payload,
+ stream=False,
+ timeout=timeout,
+ )
+
+ return response
+
+
+ def auto_name_chat_history(self, name_chat_method, user_question, chatbot, user_name, single_turn_checkbox):
+ if len(self.history) == 2 and not single_turn_checkbox and not hide_history_when_not_logged_in:
+ user_question = self.history[0]["content"]
+ if name_chat_method == i18n("模型自动总结(消耗tokens)"):
+ ai_answer = self.history[1]["content"]
+ try:
+ history = [
+ { "role": "system", "content": SUMMARY_CHAT_SYSTEM_PROMPT},
+ { "role": "user", "content": f"Please write a title based on the following conversation:\n---\nUser: {user_question}\nAssistant: {ai_answer}"}
+ ]
+ response = self._single_query_at_once(history, temperature=0.0)
+ response = json.loads(response.text)
+ content = response["choices"][0]["message"]["content"]
+ filename = replace_special_symbols(content) + ".json"
+ except Exception as e:
+ logging.info(f"自动命名失败。{e}")
+ filename = replace_special_symbols(user_question)[:16] + ".json"
+ return self.rename_chat_history(filename, chatbot, user_name)
+ elif name_chat_method == i18n("第一条提问"):
+ filename = replace_special_symbols(user_question)[:16] + ".json"
+ return self.rename_chat_history(filename, chatbot, user_name)
+ else:
+ return gr.update()
+ else:
+ return gr.update()
diff --git a/modules/models/OpenAIInstruct.py b/modules/models/OpenAIInstruct.py
new file mode 100644
index 0000000000000000000000000000000000000000..12e863f2d3be8abe563f39c9c90b09192ed20547
--- /dev/null
+++ b/modules/models/OpenAIInstruct.py
@@ -0,0 +1,27 @@
+import openai
+from .base_model import BaseLLMModel
+from .. import shared
+from ..config import retrieve_proxy
+
+
+class OpenAI_Instruct_Client(BaseLLMModel):
+ def __init__(self, model_name, api_key, user_name="") -> None:
+ super().__init__(model_name=model_name, user=user_name)
+ self.api_key = api_key
+
+ def _get_instruct_style_input(self):
+ return "\n\n".join([item["content"] for item in self.history])
+
+ @shared.state.switching_api_key
+ def get_answer_at_once(self):
+ prompt = self._get_instruct_style_input()
+ with retrieve_proxy():
+ response = openai.Completion.create(
+ api_key=self.api_key,
+ api_base=shared.state.openai_api_base,
+ model=self.model_name,
+ prompt=prompt,
+ temperature=self.temperature,
+ top_p=self.top_p,
+ )
+ return response.choices[0].text.strip(), response.usage["total_tokens"]
diff --git a/modules/models/OpenAIVision.py b/modules/models/OpenAIVision.py
new file mode 100644
index 0000000000000000000000000000000000000000..1f8ae00d8a517acc3e717642649d6b4b0dd967dc
--- /dev/null
+++ b/modules/models/OpenAIVision.py
@@ -0,0 +1,328 @@
+from __future__ import annotations
+
+import json
+import logging
+import traceback
+import base64
+
+import colorama
+import requests
+from io import BytesIO
+import uuid
+
+import requests
+from PIL import Image
+
+from .. import shared
+from ..config import retrieve_proxy, sensitive_id, usage_limit
+from ..index_func import *
+from ..presets import *
+from ..utils import *
+from .base_model import BaseLLMModel
+
+
+class OpenAIVisionClient(BaseLLMModel):
+ def __init__(
+ self,
+ model_name,
+ api_key,
+ system_prompt=INITIAL_SYSTEM_PROMPT,
+ temperature=1.0,
+ top_p=1.0,
+ user_name=""
+ ) -> None:
+ super().__init__(
+ model_name=MODEL_METADATA[model_name]["model_name"],
+ temperature=temperature,
+ top_p=top_p,
+ system_prompt=system_prompt,
+ user=user_name
+ )
+ self.api_key = api_key
+ self.need_api_key = True
+ self.max_generation_token = 4096
+ self.images = []
+ self._refresh_header()
+
+ def get_answer_stream_iter(self):
+ response = self._get_response(stream=True)
+ if response is not None:
+ iter = self._decode_chat_response(response)
+ partial_text = ""
+ for i in iter:
+ partial_text += i
+ yield partial_text
+ else:
+ yield STANDARD_ERROR_MSG + GENERAL_ERROR_MSG
+
+ def get_answer_at_once(self):
+ response = self._get_response()
+ response = json.loads(response.text)
+ content = response["choices"][0]["message"]["content"]
+ total_token_count = response["usage"]["total_tokens"]
+ return content, total_token_count
+
+ def try_read_image(self, filepath):
+ def is_image_file(filepath):
+ # 判断文件是否为图片
+ valid_image_extensions = [
+ ".jpg", ".jpeg", ".png", ".bmp", ".gif", ".tiff"]
+ file_extension = os.path.splitext(filepath)[1].lower()
+ return file_extension in valid_image_extensions
+ def image_to_base64(image_path):
+ # 打开并加载图片
+ img = Image.open(image_path)
+
+ # 获取图片的宽度和高度
+ width, height = img.size
+
+ # 计算压缩比例,以确保最长边小于4096像素
+ max_dimension = 2048
+ scale_ratio = min(max_dimension / width, max_dimension / height)
+
+ if scale_ratio < 1:
+ # 按压缩比例调整图片大小
+ new_width = int(width * scale_ratio)
+ new_height = int(height * scale_ratio)
+ img = img.resize((new_width, new_height), Image.LANCZOS)
+
+ # 将图片转换为jpg格式的二进制数据
+ buffer = BytesIO()
+ if img.mode == "RGBA":
+ img = img.convert("RGB")
+ img.save(buffer, format='JPEG')
+ binary_image = buffer.getvalue()
+
+ # 对二进制数据进行Base64编码
+ base64_image = base64.b64encode(binary_image).decode('utf-8')
+
+ return base64_image
+
+ if is_image_file(filepath):
+ logging.info(f"读取图片文件: {filepath}")
+ base64_image = image_to_base64(filepath)
+ self.images.append({
+ "path": filepath,
+ "base64": base64_image,
+ })
+
+ def handle_file_upload(self, files, chatbot, language):
+ """if the model accepts multi modal input, implement this function"""
+ if files:
+ for file in files:
+ if file.name:
+ self.try_read_image(file.name)
+ if self.images is not None:
+ chatbot = chatbot + [([image["path"] for image in self.images], None)]
+ return None, chatbot, None
+
+ def prepare_inputs(self, real_inputs, use_websearch, files, reply_language, chatbot):
+ fake_inputs = real_inputs
+ display_append = ""
+ limited_context = False
+ return limited_context, fake_inputs, display_append, real_inputs, chatbot
+
+
+ def count_token(self, user_input):
+ input_token_count = count_token(construct_user(user_input))
+ if self.system_prompt is not None and len(self.all_token_counts) == 0:
+ system_prompt_token_count = count_token(
+ construct_system(self.system_prompt)
+ )
+ return input_token_count + system_prompt_token_count
+ return input_token_count
+
+ def billing_info(self):
+ try:
+ curr_time = datetime.datetime.now()
+ last_day_of_month = get_last_day_of_month(
+ curr_time).strftime("%Y-%m-%d")
+ first_day_of_month = curr_time.replace(day=1).strftime("%Y-%m-%d")
+ usage_url = f"{shared.state.usage_api_url}?start_date={first_day_of_month}&end_date={last_day_of_month}"
+ try:
+ usage_data = self._get_billing_data(usage_url)
+ except Exception as e:
+ # logging.error(f"获取API使用情况失败: " + str(e))
+ if "Invalid authorization header" in str(e):
+ return i18n("**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id")
+ elif "Incorrect API key provided: sess" in str(e):
+ return i18n("**获取API使用情况失败**,sensitive_id错误或已过期")
+ return i18n("**获取API使用情况失败**")
+ # rounded_usage = "{:.5f}".format(usage_data["total_usage"] / 100)
+ rounded_usage = round(usage_data["total_usage"] / 100, 5)
+ usage_percent = round(usage_data["total_usage"] / usage_limit, 2)
+ from ..webui import get_html
+
+ # return i18n("**本月使用金额** ") + f"\u3000 ${rounded_usage}"
+ return get_html("billing_info.html").format(
+ label = i18n("本月使用金额"),
+ usage_percent = usage_percent,
+ rounded_usage = rounded_usage,
+ usage_limit = usage_limit
+ )
+ except requests.exceptions.ConnectTimeout:
+ status_text = (
+ STANDARD_ERROR_MSG + CONNECTION_TIMEOUT_MSG + ERROR_RETRIEVE_MSG
+ )
+ return status_text
+ except requests.exceptions.ReadTimeout:
+ status_text = STANDARD_ERROR_MSG + READ_TIMEOUT_MSG + ERROR_RETRIEVE_MSG
+ return status_text
+ except Exception as e:
+ import traceback
+ traceback.print_exc()
+ logging.error(i18n("获取API使用情况失败:") + str(e))
+ return STANDARD_ERROR_MSG + ERROR_RETRIEVE_MSG
+
+ def set_token_upper_limit(self, new_upper_limit):
+ pass
+
+ @shared.state.switching_api_key # 在不开启多账号模式的时候,这个装饰器不会起作用
+ def _get_response(self, stream=False):
+ openai_api_key = self.api_key
+ system_prompt = self.system_prompt
+ history = self.history
+ if self.images:
+ self.history[-1]["content"] = [
+ {"type": "text", "text": self.history[-1]["content"]},
+ *[{"type": "image_url", "image_url": "data:image/jpeg;base64,"+image["base64"]} for image in self.images]
+ ]
+ self.images = []
+ logging.debug(colorama.Fore.YELLOW +
+ f"{history}" + colorama.Fore.RESET)
+ headers = {
+ "Content-Type": "application/json",
+ "Authorization": f"Bearer {openai_api_key}",
+ }
+
+ if system_prompt is not None:
+ history = [construct_system(system_prompt), *history]
+
+ payload = {
+ "model": self.model_name,
+ "messages": history,
+ "temperature": self.temperature,
+ "top_p": self.top_p,
+ "n": self.n_choices,
+ "stream": stream,
+ "presence_penalty": self.presence_penalty,
+ "frequency_penalty": self.frequency_penalty,
+ }
+
+ if self.max_generation_token is not None:
+ payload["max_tokens"] = self.max_generation_token
+ if self.stop_sequence is not None:
+ payload["stop"] = self.stop_sequence
+ if self.logit_bias is not None:
+ payload["logit_bias"] = self.logit_bias
+ if self.user_identifier:
+ payload["user"] = self.user_identifier
+
+ if stream:
+ timeout = TIMEOUT_STREAMING
+ else:
+ timeout = TIMEOUT_ALL
+
+ # 如果有自定义的api-host,使用自定义host发送请求,否则使用默认设置发送请求
+ if shared.state.chat_completion_url != CHAT_COMPLETION_URL:
+ logging.debug(f"使用自定义API URL: {shared.state.chat_completion_url}")
+
+ with retrieve_proxy():
+ try:
+ response = requests.post(
+ shared.state.chat_completion_url,
+ headers=headers,
+ json=payload,
+ stream=stream,
+ timeout=timeout,
+ )
+ except:
+ traceback.print_exc()
+ return None
+ return response
+
+ def _refresh_header(self):
+ self.headers = {
+ "Content-Type": "application/json",
+ "Authorization": f"Bearer {sensitive_id}",
+ }
+
+
+ def _get_billing_data(self, billing_url):
+ with retrieve_proxy():
+ response = requests.get(
+ billing_url,
+ headers=self.headers,
+ timeout=TIMEOUT_ALL,
+ )
+
+ if response.status_code == 200:
+ data = response.json()
+ return data
+ else:
+ raise Exception(
+ f"API request failed with status code {response.status_code}: {response.text}"
+ )
+
+ def _decode_chat_response(self, response):
+ error_msg = ""
+ for chunk in response.iter_lines():
+ if chunk:
+ chunk = chunk.decode()
+ chunk_length = len(chunk)
+ try:
+ chunk = json.loads(chunk[6:])
+ except:
+ print(i18n("JSON解析错误,收到的内容: ") + f"{chunk}")
+ error_msg += chunk
+ continue
+ try:
+ if chunk_length > 6 and "delta" in chunk["choices"][0]:
+ if "finish_details" in chunk["choices"][0]:
+ finish_reason = chunk["choices"][0]["finish_details"]
+ else:
+ finish_reason = chunk["finish_details"]
+ if finish_reason == "stop":
+ break
+ try:
+ yield chunk["choices"][0]["delta"]["content"]
+ except Exception as e:
+ # logging.error(f"Error: {e}")
+ continue
+ except:
+ traceback.print_exc()
+ print(f"ERROR: {chunk}")
+ continue
+ if error_msg and not error_msg=="data: [DONE]":
+ raise Exception(error_msg)
+
+ def set_key(self, new_access_key):
+ ret = super().set_key(new_access_key)
+ self._refresh_header()
+ return ret
+
+ def _single_query_at_once(self, history, temperature=1.0):
+ timeout = TIMEOUT_ALL
+ headers = {
+ "Content-Type": "application/json",
+ "Authorization": f"Bearer {self.api_key}",
+ "temperature": f"{temperature}",
+ }
+ payload = {
+ "model": self.model_name,
+ "messages": history,
+ }
+ # 如果有自定义的api-host,使用自定义host发送请求,否则使用默认设置发送请求
+ if shared.state.chat_completion_url != CHAT_COMPLETION_URL:
+ logging.debug(f"使用自定义API URL: {shared.state.chat_completion_url}")
+
+ with retrieve_proxy():
+ response = requests.post(
+ shared.state.chat_completion_url,
+ headers=headers,
+ json=payload,
+ stream=False,
+ timeout=timeout,
+ )
+
+ return response
diff --git a/modules/models/Qwen.py b/modules/models/Qwen.py
new file mode 100644
index 0000000000000000000000000000000000000000..f5fc8d1bc2e0a9d357418c209a29197f368377e0
--- /dev/null
+++ b/modules/models/Qwen.py
@@ -0,0 +1,57 @@
+from transformers import AutoModelForCausalLM, AutoTokenizer
+from transformers.generation import GenerationConfig
+import logging
+import colorama
+from .base_model import BaseLLMModel
+from ..presets import MODEL_METADATA
+
+
+class Qwen_Client(BaseLLMModel):
+ def __init__(self, model_name, user_name="") -> None:
+ super().__init__(model_name=model_name, user=user_name)
+ self.tokenizer = AutoTokenizer.from_pretrained(MODEL_METADATA[model_name]["repo_id"], trust_remote_code=True, resume_download=True)
+ self.model = AutoModelForCausalLM.from_pretrained(MODEL_METADATA[model_name]["repo_id"], device_map="auto", trust_remote_code=True, resume_download=True).eval()
+
+ def generation_config(self):
+ return GenerationConfig.from_dict({
+ "chat_format": "chatml",
+ "do_sample": True,
+ "eos_token_id": 151643,
+ "max_length": self.token_upper_limit,
+ "max_new_tokens": 512,
+ "max_window_size": 6144,
+ "pad_token_id": 151643,
+ "top_k": 0,
+ "top_p": self.top_p,
+ "transformers_version": "4.33.2",
+ "trust_remote_code": True,
+ "temperature": self.temperature,
+ })
+
+ def _get_glm_style_input(self):
+ history = [x["content"] for x in self.history]
+ query = history.pop()
+ logging.debug(colorama.Fore.YELLOW +
+ f"{history}" + colorama.Fore.RESET)
+ assert (
+ len(history) % 2 == 0
+ ), f"History should be even length. current history is: {history}"
+ history = [[history[i], history[i + 1]]
+ for i in range(0, len(history), 2)]
+ return history, query
+
+ def get_answer_at_once(self):
+ history, query = self._get_glm_style_input()
+ self.model.generation_config = self.generation_config()
+ response, history = self.model.chat(self.tokenizer, query, history=history)
+ return response, len(response)
+
+ def get_answer_stream_iter(self):
+ history, query = self._get_glm_style_input()
+ self.model.generation_config = self.generation_config()
+ for response in self.model.chat_stream(
+ self.tokenizer,
+ query,
+ history,
+ ):
+ yield response
diff --git a/modules/models/XMChat.py b/modules/models/XMChat.py
new file mode 100644
index 0000000000000000000000000000000000000000..8453a02d5e0ed25a9008fbbf9476f6e042eb9bcb
--- /dev/null
+++ b/modules/models/XMChat.py
@@ -0,0 +1,149 @@
+from __future__ import annotations
+
+import base64
+import json
+import logging
+import os
+import uuid
+from io import BytesIO
+
+import requests
+from PIL import Image
+
+from ..index_func import *
+from ..presets import *
+from ..utils import *
+from .base_model import BaseLLMModel
+
+
+class XMChat(BaseLLMModel):
+ def __init__(self, api_key, user_name=""):
+ super().__init__(model_name="xmchat", user=user_name)
+ self.api_key = api_key
+ self.session_id = None
+ self.reset()
+ self.image_bytes = None
+ self.image_path = None
+ self.xm_history = []
+ self.url = "https://xmbot.net/web"
+ self.last_conv_id = None
+
+ def reset(self, remain_system_prompt=False):
+ self.session_id = str(uuid.uuid4())
+ self.last_conv_id = None
+ return super().reset()
+
+ def image_to_base64(self, image_path):
+ # 打开并加载图片
+ img = Image.open(image_path)
+
+ # 获取图片的宽度和高度
+ width, height = img.size
+
+ # 计算压缩比例,以确保最长边小于4096像素
+ max_dimension = 2048
+ scale_ratio = min(max_dimension / width, max_dimension / height)
+
+ if scale_ratio < 1:
+ # 按压缩比例调整图片大小
+ new_width = int(width * scale_ratio)
+ new_height = int(height * scale_ratio)
+ img = img.resize((new_width, new_height), Image.LANCZOS)
+
+ # 将图片转换为jpg格式的二进制数据
+ buffer = BytesIO()
+ if img.mode == "RGBA":
+ img = img.convert("RGB")
+ img.save(buffer, format='JPEG')
+ binary_image = buffer.getvalue()
+
+ # 对二进制数据进行Base64编码
+ base64_image = base64.b64encode(binary_image).decode('utf-8')
+
+ return base64_image
+
+ def try_read_image(self, filepath):
+ def is_image_file(filepath):
+ # 判断文件是否为图片
+ valid_image_extensions = [
+ ".jpg", ".jpeg", ".png", ".bmp", ".gif", ".tiff"]
+ file_extension = os.path.splitext(filepath)[1].lower()
+ return file_extension in valid_image_extensions
+
+ if is_image_file(filepath):
+ logging.info(f"读取图片文件: {filepath}")
+ self.image_bytes = self.image_to_base64(filepath)
+ self.image_path = filepath
+ else:
+ self.image_bytes = None
+ self.image_path = None
+
+ def like(self):
+ if self.last_conv_id is None:
+ return "点赞失败,你还没发送过消息"
+ data = {
+ "uuid": self.last_conv_id,
+ "appraise": "good"
+ }
+ requests.post(self.url, json=data)
+ return "👍点赞成功,感谢反馈~"
+
+ def dislike(self):
+ if self.last_conv_id is None:
+ return "点踩失败,你还没发送过消息"
+ data = {
+ "uuid": self.last_conv_id,
+ "appraise": "bad"
+ }
+ requests.post(self.url, json=data)
+ return "👎点踩成功,感谢反馈~"
+
+ def prepare_inputs(self, real_inputs, use_websearch, files, reply_language, chatbot):
+ fake_inputs = real_inputs
+ display_append = ""
+ limited_context = False
+ return limited_context, fake_inputs, display_append, real_inputs, chatbot
+
+ def handle_file_upload(self, files, chatbot, language):
+ """if the model accepts multi modal input, implement this function"""
+ if files:
+ for file in files:
+ if file.name:
+ logging.info(f"尝试读取图像: {file.name}")
+ self.try_read_image(file.name)
+ if self.image_path is not None:
+ chatbot = chatbot + [((self.image_path,), None)]
+ if self.image_bytes is not None:
+ logging.info("使用图片作为输入")
+ # XMChat的一轮对话中实际上只能处理一张图片
+ self.reset()
+ conv_id = str(uuid.uuid4())
+ data = {
+ "user_id": self.api_key,
+ "session_id": self.session_id,
+ "uuid": conv_id,
+ "data_type": "imgbase64",
+ "data": self.image_bytes
+ }
+ response = requests.post(self.url, json=data)
+ response = json.loads(response.text)
+ logging.info(f"图片回复: {response['data']}")
+ return None, chatbot, None
+
+ def get_answer_at_once(self):
+ question = self.history[-1]["content"]
+ conv_id = str(uuid.uuid4())
+ self.last_conv_id = conv_id
+ data = {
+ "user_id": self.api_key,
+ "session_id": self.session_id,
+ "uuid": conv_id,
+ "data_type": "text",
+ "data": question
+ }
+ response = requests.post(self.url, json=data)
+ try:
+ response = json.loads(response.text)
+ return response["data"], len(response["data"])
+ except Exception as e:
+ return response.text, len(response.text)
diff --git a/modules/models/base_model.py b/modules/models/base_model.py
index fa94579d725dbf9d739d58fc17b35bc2248c7fcd..ae71d2cecd63d21d479d3c2dffca5ea5fc702435 100644
--- a/modules/models/base_model.py
+++ b/modules/models/base_model.py
@@ -10,6 +10,7 @@ import requests
import urllib3
import traceback
import pathlib
+import shutil
from tqdm import tqdm
import colorama
@@ -142,13 +143,23 @@ class ModelType(Enum):
GooglePaLM = 9
LangchainChat = 10
Midjourney = 11
+ Spark = 12
+ OpenAIInstruct = 13
+ Claude = 14
+ Qwen = 15
+ OpenAIVision = 16
@classmethod
def get_type(cls, model_name: str):
model_type = None
model_name_lower = model_name.lower()
if "gpt" in model_name_lower:
- model_type = ModelType.OpenAI
+ if "instruct" in model_name_lower:
+ model_type = ModelType.OpenAIInstruct
+ elif "vision" in model_name_lower:
+ model_type = ModelType.OpenAIVision
+ else:
+ model_type = ModelType.OpenAI
elif "chatglm" in model_name_lower:
model_type = ModelType.ChatGLM
elif "llama" in model_name_lower or "alpaca" in model_name_lower:
@@ -171,8 +182,14 @@ class ModelType(Enum):
model_type = ModelType.Midjourney
elif "azure" in model_name_lower or "api" in model_name_lower:
model_type = ModelType.LangchainChat
+ elif "星火大模型" in model_name_lower:
+ model_type = ModelType.Spark
+ elif "claude" in model_name_lower:
+ model_type = ModelType.Claude
+ elif "qwen" in model_name_lower:
+ model_type = ModelType.Qwen
else:
- model_type = ModelType.Unknown
+ model_type = ModelType.LLaMA
return model_type
@@ -196,7 +213,7 @@ class BaseLLMModel:
self.model_name = model_name
self.model_type = ModelType.get_type(model_name)
try:
- self.token_upper_limit = MODEL_TOKEN_LIMIT[model_name]
+ self.token_upper_limit = MODEL_METADATA[model_name]["token_limit"]
except KeyError:
self.token_upper_limit = DEFAULT_TOKEN_LIMIT
self.interrupted = False
@@ -204,6 +221,7 @@ class BaseLLMModel:
self.api_key = None
self.need_api_key = False
self.single_turn = False
+ self.history_file_path = get_first_history_name(user)
self.temperature = temperature
self.top_p = top_p
@@ -242,7 +260,7 @@ class BaseLLMModel:
def billing_info(self):
"""get billing infomation, inplement if needed"""
- logging.warning("billing info not implemented, using default")
+ # logging.warning("billing info not implemented, using default")
return BILLING_NOT_APPLICABLE_MSG
def count_token(self, user_input):
@@ -269,9 +287,12 @@ class BaseLLMModel:
if display_append:
display_append = '\n\n