diff --git a/config.py b/config.py
index e668ac90..ac8d2fdf 100644
--- a/config.py
+++ b/config.py
@@ -45,6 +45,7 @@ AVAIL_LLM_MODELS = ["qwen-max", "o1-mini", "o1-mini-2024-09-12", "o1", "o1-2024-
"gemini-1.5-pro", "chatglm3", "chatglm4",
"deepseek-chat", "deepseek-coder", "deepseek-reasoner",
"volcengine-deepseek-r1-250120", "volcengine-deepseek-v3-241226",
+ "dashscope-deepseek-r1", "dashscope-deepseek-v3",
]
EMBEDDING_MODEL = "text-embedding-3-small"
diff --git a/main.py b/main.py
index 73a3e2b8..062cba5f 100644
--- a/main.py
+++ b/main.py
@@ -184,7 +184,7 @@ def main():
from themes.gui_floating_menu import define_gui_floating_menu
area_input_secondary, txt2, area_customize, _, resetBtn2, clearBtn2, stopBtn2 = \
define_gui_floating_menu(customize_btns, functional, predefined_btns, cookies, web_cookie_cache)
-
+
# 浮动时间线定义
gr.Spark()
diff --git a/request_llms/bridge_all.py b/request_llms/bridge_all.py
index e911a765..52ed2fa7 100644
--- a/request_llms/bridge_all.py
+++ b/request_llms/bridge_all.py
@@ -530,6 +530,15 @@ model_info = {
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
+ "gemini-2.0-flash": {
+ "fn_with_ui": genai_ui,
+ "fn_without_ui": genai_noui,
+ "endpoint": gemini_endpoint,
+ "has_multimodal_capacity": True,
+ "max_token": 1024 * 204800,
+ "tokenizer": tokenizer_gpt35,
+ "token_cnt": get_token_num_gpt35,
+ },
# cohere
"cohere-command-r-plus": {
@@ -813,8 +822,9 @@ if "qwen-local" in AVAIL_LLM_MODELS:
})
except:
logger.error(trimmed_format_exc())
-# -=-=-=-=-=-=- 通义-在线模型 -=-=-=-=-=-=-
-qwen_models = ["qwen-max-latest", "qwen-max-2025-01-25","qwen-max","qwen-turbo","qwen-plus"]
+
+# -=-=-=-=-=-=- 阿里云百炼(通义)-在线模型 -=-=-=-=-=-=-
+qwen_models = ["qwen-max-latest", "qwen-max-2025-01-25","qwen-max","qwen-turbo","qwen-plus","dashscope-deepseek-r1","dashscope-deepseek-v3"]
if any(item in qwen_models for item in AVAIL_LLM_MODELS):
try:
from .bridge_qwen import predict_no_ui_long_connection as qwen_noui
@@ -864,10 +874,30 @@ if any(item in qwen_models for item in AVAIL_LLM_MODELS):
"max_token": 30720,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
+ },
+ "dashscope-deepseek-r1": {
+ "fn_with_ui": qwen_ui,
+ "fn_without_ui": qwen_noui,
+ "enable_reasoning": True,
+ "can_multi_thread": True,
+ "endpoint": None,
+ "max_token": 57344,
+ "tokenizer": tokenizer_gpt35,
+ "token_cnt": get_token_num_gpt35,
+ },
+ "dashscope-deepseek-v3": {
+ "fn_with_ui": qwen_ui,
+ "fn_without_ui": qwen_noui,
+ "can_multi_thread": True,
+ "endpoint": None,
+ "max_token": 57344,
+ "tokenizer": tokenizer_gpt35,
+ "token_cnt": get_token_num_gpt35,
}
})
except:
logger.error(trimmed_format_exc())
+
# -=-=-=-=-=-=- 零一万物模型 -=-=-=-=-=-=-
yi_models = ["yi-34b-chat-0205","yi-34b-chat-200k","yi-large","yi-medium","yi-spark","yi-large-turbo","yi-large-preview"]
if any(item in yi_models for item in AVAIL_LLM_MODELS):
diff --git a/request_llms/bridge_chatgpt.py b/request_llms/bridge_chatgpt.py
index 7d5cbe64..b1eddb9e 100644
--- a/request_llms/bridge_chatgpt.py
+++ b/request_llms/bridge_chatgpt.py
@@ -368,12 +368,12 @@ def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWith
log_chat(llm_model=llm_kwargs["llm_model"], input_str=inputs, output_str=gpt_replying_buffer)
break # 对于符合规范的接口,这里可以break
else:
- continue # 对于不符合规范的狗屎接口,这里需要继续
+ continue # 对于不符合规范的接口,这里需要继续
# 到这里,我们已经可以假定必须包含choice了
try:
status_text = f"finish_reason: {chunkjson['choices'][0].get('finish_reason', 'null')}"
except:
- logger.error(f"一些垃圾第三方接口出现这样的错误,兼容一下吧: {chunk_decoded}")
+ logger.error(f"一些第三方接口出现这样的错误,兼容一下吧: {chunk_decoded}")
# 处理数据流的主体
if has_content:
# 正常情况
@@ -382,9 +382,9 @@ def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWith
# 一些第三方接口的出现这样的错误,兼容一下吧
continue
else:
- # 至此已经超出了正常接口应该进入的范围,一些垃圾第三方接口会出现这样的错误
+ # 至此已经超出了正常接口应该进入的范围,一些第三方接口会出现这样的错误
if chunkjson['choices'][0]["delta"].get("content", None) is None:
- logger.error(f"一些垃圾第三方接口出现这样的错误,兼容一下吧: {chunk_decoded}")
+ logger.error(f"一些第三方接口出现这样的错误,兼容一下吧: {chunk_decoded}")
continue
gpt_replying_buffer = gpt_replying_buffer + chunkjson['choices'][0]["delta"]["content"]
diff --git a/request_llms/com_qwenapi.py b/request_llms/com_qwenapi.py
index 70872e16..edbf9d7b 100644
--- a/request_llms/com_qwenapi.py
+++ b/request_llms/com_qwenapi.py
@@ -3,6 +3,7 @@ from toolbox import get_conf
import threading
timeout_bot_msg = '[Local Message] Request timeout. Network error.'
+model_prefix_to_remove = 'dashscope-'
class QwenRequestInstance():
def __init__(self):
@@ -20,6 +21,13 @@ class QwenRequestInstance():
raise RuntimeError('请配置 DASHSCOPE_API_KEY')
dashscope.api_key = get_conf("DASHSCOPE_API_KEY")
+ def format_reasoning(self, reasoning_content:str, main_content:str):
+ if reasoning_content:
+ reasoning_content_paragraphs = ''.join([f'
{line}
' for line in reasoning_content.split('\n')])
+ formatted_reasoning_content = f'{reasoning_content_paragraphs}
\n\n---\n\n'
+ return formatted_reasoning_content + main_content
+ else:
+ return main_content
def generate(self, inputs, llm_kwargs, history, system_prompt):
# import _thread as thread
@@ -28,9 +36,13 @@ class QwenRequestInstance():
if top_p == 0: top_p += 1e-5
if top_p == 1: top_p -= 1e-5
+ model_name = llm_kwargs['llm_model']
+ if model_name.startswith(model_prefix_to_remove): model_name = model_name[len(model_prefix_to_remove):]
+
+ self.reasoning_buf = ""
self.result_buf = ""
responses = Generation.call(
- model=llm_kwargs['llm_model'],
+ model=model_name,
messages=generate_message_payload(inputs, llm_kwargs, history, system_prompt),
top_p=top_p,
temperature=llm_kwargs.get('temperature', 1.0),
@@ -46,18 +58,24 @@ class QwenRequestInstance():
self.result_buf += response.output.choices[0].message.content
except:
pass
- yield self.result_buf
+ yield self.format_reasoning(self.reasoning_buf, self.result_buf)
break
elif response.output.choices[0].finish_reason == 'length':
self.result_buf += "[Local Message] 生成长度过长,后续输出被截断"
- yield self.result_buf
+ yield self.format_reasoning(self.reasoning_buf, self.result_buf)
break
else:
+ try:
+ contain_reasoning = hasattr(response.output.choices[0].message, 'reasoning_content')
+ except:
+ contain_reasoning = False
+ if contain_reasoning:
+ self.reasoning_buf += response.output.choices[0].message.reasoning_content
self.result_buf += response.output.choices[0].message.content
- yield self.result_buf
+ yield self.format_reasoning(self.reasoning_buf, self.result_buf)
else:
self.result_buf += f"[Local Message] 请求错误:状态码:{response.status_code},错误码:{response.code},消息:{response.message}"
- yield self.result_buf
+ yield self.format_reasoning(self.reasoning_buf, self.result_buf)
break
# 耗尽generator避免报错
diff --git a/shared_utils/advanced_markdown_format.py b/shared_utils/advanced_markdown_format.py
index 7be1db20..a8a10411 100644
--- a/shared_utils/advanced_markdown_format.py
+++ b/shared_utils/advanced_markdown_format.py
@@ -347,7 +347,7 @@ def markdown_convertion(txt):
# 在文本中插入一个base64编码的原始文本,以便在复制时能够获得原始文本
raw_text_encoded = compress_string(txt)
- raw_text_node = f'{raw_text_encoded}
'
+ raw_text_node = f'{raw_text_encoded}
'
suf = raw_text_node + ""
# 用于查找数学公式的正则表达式
diff --git a/themes/common.css b/themes/common.css
index 2f7dda2f..610d46c2 100644
--- a/themes/common.css
+++ b/themes/common.css
@@ -335,4 +335,74 @@
.raw_text {
display: none;
+}
+
+.message_tail {
+ justify-content: center;
+ align-items: center;
+}
+.message_tail_stop {
+ border: dotted !important;
+ margin-top: 5px !important;
+ padding-left: 8px !important;
+ padding-top: 1px !important;
+ padding-bottom: 1px !important;
+ padding-right: 12px !important;
+}
+
+/* ant 开始 */
+
+/* 通用按钮样式 */
+.ant-btn {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: 8px 16px;
+ font-size: 14px;
+ font-weight: bold;
+ border-radius: 4px;
+ cursor: pointer;
+ transition: background-color 0.3s;
+}
+
+/* 按钮颜色和状态 */
+.ant-btn-primary {
+ background-color: #1890ff;
+ color: white;
+ border: none;
+}
+
+.ant-btn-primary:hover {
+ background-color: #40a9ff;
+}
+
+.ant-btn-loading {
+ pointer-events: none;
+ opacity: 0.7;
+}
+
+/* 图标样式 */
+.ant-btn-icon {
+ display: inline-flex;
+ margin-right: 8px;
+}
+
+.anticon {
+ width: 1em;
+ height: 1em;
+ fill: currentColor;
+}
+
+.anticon-spin {
+ animation: spin 1s linear infinite;
+}
+
+/* 动画效果 */
+@keyframes spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
}
\ No newline at end of file
diff --git a/themes/common.js b/themes/common.js
index f8510624..f05b9b71 100644
--- a/themes/common.js
+++ b/themes/common.js
@@ -289,7 +289,7 @@ function addCopyButton(botElement, index, is_last_in_arr) {
const audioIcon = '';
// const cancelAudioIcon = '';
- // 此功能没准备好
+ // audio functionality
if (allow_auto_read_continously && is_last_in_arr && allow_auto_read_tts_flag) {
process_latest_text_output(botElement.innerText, index);
}
@@ -300,41 +300,6 @@ function addCopyButton(botElement, index, is_last_in_arr) {
return;
}
- // var copyButton = document.createElement('button');
- // copyButton.classList.add('copy-bot-btn');
- // copyButton.setAttribute('aria-label', 'Copy');
- // copyButton.innerHTML = copyIcon;
- // copyButton.addEventListener('click', async () => {
- // const textToCopy = botElement.innerText;
- // try {
- // // push_text_to_audio(textToCopy).catch(console.error);
- // if ("clipboard" in navigator) {
- // await navigator.clipboard.writeText(textToCopy);
- // copyButton.innerHTML = copiedIcon;
- // setTimeout(() => {
- // copyButton.innerHTML = copyIcon;
- // }, 1500);
- // } else {
- // const textArea = document.createElement("textarea");
- // textArea.value = textToCopy;
- // document.body.appendChild(textArea);
- // textArea.select();
- // try {
- // document.execCommand('copy');
- // copyButton.innerHTML = copiedIcon;
- // setTimeout(() => {
- // copyButton.innerHTML = copyIcon;
- // }, 1500);
- // } catch (error) {
- // console.error("Copy failed: ", error);
- // }
- // document.body.removeChild(textArea);
- // }
- // } catch (error) {
- // console.error("Copy failed: ", error);
- // }
- // });
-
// 原始文本拷贝
var copyButtonOrig = document.createElement('button');
copyButtonOrig.classList.add('copy-bot-btn');
@@ -436,7 +401,6 @@ function do_something_but_not_too_frequently(min_interval, func) {
function chatbotContentChanged(attempt = 1, force = false) {
- // https://github.com/GaiZhenbiao/ChuanhuChatGPT/tree/main/web_assets/javascript
for (var i = 0; i < attempt; i++) {
setTimeout(() => {
const messages = gradioApp().querySelectorAll('#gpt-chatbot .message-wrap .message.bot');
@@ -447,6 +411,9 @@ function chatbotContentChanged(attempt = 1, force = false) {
// Now pass both the message element and the is_last_in_arr boolean to addCopyButton
addCopyButton(message, index, is_last_in_arr);
+ // if last message, add stop btn link
+ addStopButton(message, index, is_last_in_arr);
+
// save_conversation_history
save_conversation_history_slow_down();
});
@@ -457,6 +424,79 @@ function chatbotContentChanged(attempt = 1, force = false) {
}
+function addStopButton(botElement, index, is_last_in_arr) {
+ function is_generating() {
+ var statePanelElement = document.getElementById("state-panel");
+ var generatingElement = statePanelElement.querySelector(".generating");
+ if (generatingElement) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ function on_stop_btn_click() {
+ let stopButton = document.getElementById("elem_stop");
+ stopButton.click();
+ }
+ function remove_stop_generate_btn(messageTailElement) {
+ // remove all child elements of messageTailElement
+ while (messageTailElement.firstChild) {
+ messageTailElement.removeChild(messageTailElement.firstChild);
+ }
+ messageTailElement.style.display = 'none';
+ messageTailElement.classList.add('removed');
+ }
+ function add_stop_generate_btn() {
+ // write here: add a beautiful stop btn `bottomElement` as child, when clicked execute on_stop_btn_click
+ console.log("get_gradio_component")
+ const bottomElement = document.createElement('button');
+ bottomElement.className = 'ant-btn ant-btn-primary';
+ bottomElement.innerHTML = `
+
+
+
+ 终止
+ `;
+ bottomElement.classList.add('message_tail_stop');
+ bottomElement.addEventListener('click', on_stop_btn_click);
+ messageTailElement.appendChild(bottomElement);
+ }
+
+ // find a sub element of class `message_tail`
+ const messageTailElement = botElement.querySelector('.message_tail');
+ // if not is_last_in_arr, hide this elem (display none)
+ if (!messageTailElement) {
+ return;
+ }
+ if (messageTailElement.classList.contains('removed')) {
+ return;
+ }
+ if (!is_last_in_arr) {
+ remove_stop_generate_btn(messageTailElement);
+ return;
+ }
+ messageTailElement.style.display = 'flex';
+ const messageTailStopElem = messageTailElement.querySelector('.message_tail_stop');
+ if(!is_generating()) {
+ setTimeout(() => {
+ if(!is_generating()) {
+ remove_stop_generate_btn(messageTailElement);
+ return;
+ } else {
+ if (!messageTailStopElem) {
+ add_stop_generate_btn()
+ }
+ }
+ }, 500);
+ } else {
+ if (!messageTailStopElem) {
+ add_stop_generate_btn()
+ }
+ }
+
+}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=