镜像自地址
https://github.com/binary-husky/gpt_academic.git
已同步 2025-12-08 07:26:48 +00:00
比较提交
29 次代码提交
version3.6
...
production
| 作者 | SHA1 | 提交日期 | |
|---|---|---|---|
|
|
ffb5655a23 | ||
|
|
cb92ccb409 | ||
|
|
cc4df91900 | ||
|
|
89707a1c58 | ||
|
|
d539ad809e | ||
|
|
02b18ff67a | ||
|
|
6896b10be9 | ||
|
|
0ec5a8e5f8 | ||
|
|
79a0b687b8 | ||
|
|
70766cdd44 | ||
|
|
97f33b8bea | ||
|
|
7280ea17fd | ||
|
|
535a901991 | ||
|
|
56f42397b1 | ||
|
|
aa7c47e821 | ||
|
|
62fb2794ec | ||
|
|
3121dee04a | ||
|
|
cad541d8d7 | ||
|
|
9023aa6732 | ||
|
|
2d37b74a0c | ||
|
|
fdc350cfe8 | ||
|
|
58c6d45d84 | ||
|
|
4cc6ff65ac | ||
|
|
8632413011 | ||
|
|
46e279b5dd | ||
|
|
25cf86dae6 | ||
|
|
19e202ddfd | ||
|
|
65dab46a28 | ||
|
|
ecb473bc8b |
@@ -1,44 +0,0 @@
|
|||||||
# https://docs.github.com/en/actions/publishing-packages/publishing-docker-images#publishing-images-to-github-packages
|
|
||||||
name: build-with-all-capacity-beta
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- 'master'
|
|
||||||
|
|
||||||
env:
|
|
||||||
REGISTRY: ghcr.io
|
|
||||||
IMAGE_NAME: ${{ github.repository }}_with_all_capacity_beta
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-and-push-image:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Log in to the Container registry
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Extract metadata (tags, labels) for Docker
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v4
|
|
||||||
with:
|
|
||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
||||||
|
|
||||||
- name: Build and push Docker image
|
|
||||||
uses: docker/build-push-action@v4
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
push: true
|
|
||||||
file: docs/GithubAction+AllCapacityBeta
|
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
@@ -590,19 +590,19 @@ def get_crazy_functions():
|
|||||||
print(trimmed_format_exc())
|
print(trimmed_format_exc())
|
||||||
print('Load function plugin failed')
|
print('Load function plugin failed')
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
from crazy_functions.互动小游戏 import 随机小游戏
|
# from crazy_functions.互动小游戏 import 随机小游戏
|
||||||
function_plugins.update({
|
# function_plugins.update({
|
||||||
"随机互动小游戏(仅供测试)": {
|
# "随机小游戏": {
|
||||||
"Group": "智能体",
|
# "Group": "智能体",
|
||||||
"Color": "stop",
|
# "Color": "stop",
|
||||||
"AsButton": False,
|
# "AsButton": True,
|
||||||
"Function": HotReload(随机小游戏)
|
# "Function": HotReload(随机小游戏)
|
||||||
}
|
# }
|
||||||
})
|
# })
|
||||||
except:
|
# except:
|
||||||
print(trimmed_format_exc())
|
# print(trimmed_format_exc())
|
||||||
print('Load function plugin failed')
|
# print('Load function plugin failed')
|
||||||
|
|
||||||
# try:
|
# try:
|
||||||
# from crazy_functions.chatglm微调工具 import 微调数据集生成
|
# from crazy_functions.chatglm微调工具 import 微调数据集生成
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ class PaperFileGroup():
|
|||||||
self.sp_file_index.append(index)
|
self.sp_file_index.append(index)
|
||||||
self.sp_file_tag.append(self.file_paths[index])
|
self.sp_file_tag.append(self.file_paths[index])
|
||||||
else:
|
else:
|
||||||
from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit
|
from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf
|
||||||
segments = breakdown_text_to_satisfy_token_limit(file_content, max_token_limit)
|
segments = breakdown_txt_to_satisfy_token_limit_for_pdf(file_content, self.get_token_num, max_token_limit)
|
||||||
for j, segment in enumerate(segments):
|
for j, segment in enumerate(segments):
|
||||||
self.sp_file_contents.append(segment)
|
self.sp_file_contents.append(segment)
|
||||||
self.sp_file_index.append(index)
|
self.sp_file_index.append(index)
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ class PaperFileGroup():
|
|||||||
self.sp_file_index.append(index)
|
self.sp_file_index.append(index)
|
||||||
self.sp_file_tag.append(self.file_paths[index])
|
self.sp_file_tag.append(self.file_paths[index])
|
||||||
else:
|
else:
|
||||||
from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit
|
from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf
|
||||||
segments = breakdown_text_to_satisfy_token_limit(file_content, max_token_limit)
|
segments = breakdown_txt_to_satisfy_token_limit_for_pdf(file_content, self.get_token_num, max_token_limit)
|
||||||
for j, segment in enumerate(segments):
|
for j, segment in enumerate(segments):
|
||||||
self.sp_file_contents.append(segment)
|
self.sp_file_contents.append(segment)
|
||||||
self.sp_file_index.append(index)
|
self.sp_file_index.append(index)
|
||||||
|
|||||||
@@ -312,6 +312,95 @@ def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
|
|||||||
return gpt_response_collection
|
return gpt_response_collection
|
||||||
|
|
||||||
|
|
||||||
|
def breakdown_txt_to_satisfy_token_limit(txt, get_token_fn, limit):
|
||||||
|
def cut(txt_tocut, must_break_at_empty_line): # 递归
|
||||||
|
if get_token_fn(txt_tocut) <= limit:
|
||||||
|
return [txt_tocut]
|
||||||
|
else:
|
||||||
|
lines = txt_tocut.split('\n')
|
||||||
|
estimated_line_cut = limit / get_token_fn(txt_tocut) * len(lines)
|
||||||
|
estimated_line_cut = int(estimated_line_cut)
|
||||||
|
for cnt in reversed(range(estimated_line_cut)):
|
||||||
|
if must_break_at_empty_line:
|
||||||
|
if lines[cnt] != "":
|
||||||
|
continue
|
||||||
|
print(cnt)
|
||||||
|
prev = "\n".join(lines[:cnt])
|
||||||
|
post = "\n".join(lines[cnt:])
|
||||||
|
if get_token_fn(prev) < limit:
|
||||||
|
break
|
||||||
|
if cnt == 0:
|
||||||
|
raise RuntimeError("存在一行极长的文本!")
|
||||||
|
# print(len(post))
|
||||||
|
# 列表递归接龙
|
||||||
|
result = [prev]
|
||||||
|
result.extend(cut(post, must_break_at_empty_line))
|
||||||
|
return result
|
||||||
|
try:
|
||||||
|
return cut(txt, must_break_at_empty_line=True)
|
||||||
|
except RuntimeError:
|
||||||
|
return cut(txt, must_break_at_empty_line=False)
|
||||||
|
|
||||||
|
|
||||||
|
def force_breakdown(txt, limit, get_token_fn):
|
||||||
|
"""
|
||||||
|
当无法用标点、空行分割时,我们用最暴力的方法切割
|
||||||
|
"""
|
||||||
|
for i in reversed(range(len(txt))):
|
||||||
|
if get_token_fn(txt[:i]) < limit:
|
||||||
|
return txt[:i], txt[i:]
|
||||||
|
return "Tiktoken未知错误", "Tiktoken未知错误"
|
||||||
|
|
||||||
|
def breakdown_txt_to_satisfy_token_limit_for_pdf(txt, get_token_fn, limit):
|
||||||
|
# 递归
|
||||||
|
def cut(txt_tocut, must_break_at_empty_line, break_anyway=False):
|
||||||
|
if get_token_fn(txt_tocut) <= limit:
|
||||||
|
return [txt_tocut]
|
||||||
|
else:
|
||||||
|
lines = txt_tocut.split('\n')
|
||||||
|
estimated_line_cut = limit / get_token_fn(txt_tocut) * len(lines)
|
||||||
|
estimated_line_cut = int(estimated_line_cut)
|
||||||
|
cnt = 0
|
||||||
|
for cnt in reversed(range(estimated_line_cut)):
|
||||||
|
if must_break_at_empty_line:
|
||||||
|
if lines[cnt] != "":
|
||||||
|
continue
|
||||||
|
prev = "\n".join(lines[:cnt])
|
||||||
|
post = "\n".join(lines[cnt:])
|
||||||
|
if get_token_fn(prev) < limit:
|
||||||
|
break
|
||||||
|
if cnt == 0:
|
||||||
|
if break_anyway:
|
||||||
|
prev, post = force_breakdown(txt_tocut, limit, get_token_fn)
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"存在一行极长的文本!{txt_tocut}")
|
||||||
|
# print(len(post))
|
||||||
|
# 列表递归接龙
|
||||||
|
result = [prev]
|
||||||
|
result.extend(cut(post, must_break_at_empty_line, break_anyway=break_anyway))
|
||||||
|
return result
|
||||||
|
try:
|
||||||
|
# 第1次尝试,将双空行(\n\n)作为切分点
|
||||||
|
return cut(txt, must_break_at_empty_line=True)
|
||||||
|
except RuntimeError:
|
||||||
|
try:
|
||||||
|
# 第2次尝试,将单空行(\n)作为切分点
|
||||||
|
return cut(txt, must_break_at_empty_line=False)
|
||||||
|
except RuntimeError:
|
||||||
|
try:
|
||||||
|
# 第3次尝试,将英文句号(.)作为切分点
|
||||||
|
res = cut(txt.replace('.', '。\n'), must_break_at_empty_line=False) # 这个中文的句号是故意的,作为一个标识而存在
|
||||||
|
return [r.replace('。\n', '.') for r in res]
|
||||||
|
except RuntimeError as e:
|
||||||
|
try:
|
||||||
|
# 第4次尝试,将中文句号(。)作为切分点
|
||||||
|
res = cut(txt.replace('。', '。。\n'), must_break_at_empty_line=False)
|
||||||
|
return [r.replace('。。\n', '。') for r in res]
|
||||||
|
except RuntimeError as e:
|
||||||
|
# 第5次尝试,没办法了,随便切一下敷衍吧
|
||||||
|
return cut(txt, must_break_at_empty_line=False, break_anyway=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def read_and_clean_pdf_text(fp):
|
def read_and_clean_pdf_text(fp):
|
||||||
"""
|
"""
|
||||||
@@ -542,6 +631,7 @@ def get_files_from_everything(txt, type): # type='.md'
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class nougat_interface():
|
class nougat_interface():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
from toolbox import CatchException, update_ui, update_ui_lastest_msg
|
|
||||||
from crazy_functions.multi_stage.multi_stage_utils import GptAcademicGameBaseState
|
|
||||||
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
|
||||||
from request_llms.bridge_all import predict_no_ui_long_connection
|
|
||||||
from crazy_functions.game_fns.game_utils import get_code_block, is_same_thing
|
|
||||||
import random
|
|
||||||
|
|
||||||
|
|
||||||
class MiniGame_ASCII_Art(GptAcademicGameBaseState):
|
|
||||||
def step(self, prompt, chatbot, history):
|
|
||||||
if self.step_cnt == 0:
|
|
||||||
chatbot.append(["我画你猜(动物)", "请稍等..."])
|
|
||||||
else:
|
|
||||||
if prompt.strip() == 'exit':
|
|
||||||
self.delete_game = True
|
|
||||||
yield from update_ui_lastest_msg(lastmsg=f"谜底是{self.obj},游戏结束。", chatbot=chatbot, history=history, delay=0.)
|
|
||||||
return
|
|
||||||
chatbot.append([prompt, ""])
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
|
||||||
|
|
||||||
if self.step_cnt == 0:
|
|
||||||
self.lock_plugin(chatbot)
|
|
||||||
self.cur_task = 'draw'
|
|
||||||
|
|
||||||
if self.cur_task == 'draw':
|
|
||||||
avail_obj = ["狗","猫","鸟","鱼","老鼠","蛇"]
|
|
||||||
self.obj = random.choice(avail_obj)
|
|
||||||
inputs = "I want to play a game called Guess the ASCII art. You can draw the ASCII art and I will try to guess it. " + \
|
|
||||||
f"This time you draw a {self.obj}. Note that you must not indicate what you have draw in the text, and you should only produce the ASCII art wrapped by ```. "
|
|
||||||
raw_res = predict_no_ui_long_connection(inputs=inputs, llm_kwargs=self.llm_kwargs, history=[], sys_prompt="")
|
|
||||||
self.cur_task = 'identify user guess'
|
|
||||||
res = get_code_block(raw_res)
|
|
||||||
history += ['', f'the answer is {self.obj}', inputs, res]
|
|
||||||
yield from update_ui_lastest_msg(lastmsg=res, chatbot=chatbot, history=history, delay=0.)
|
|
||||||
|
|
||||||
elif self.cur_task == 'identify user guess':
|
|
||||||
if is_same_thing(self.obj, prompt, self.llm_kwargs):
|
|
||||||
self.delete_game = True
|
|
||||||
yield from update_ui_lastest_msg(lastmsg="你猜对了!", chatbot=chatbot, history=history, delay=0.)
|
|
||||||
else:
|
|
||||||
self.cur_task = 'identify user guess'
|
|
||||||
yield from update_ui_lastest_msg(lastmsg="猜错了,再试试,输入“exit”获取答案。", chatbot=chatbot, history=history, delay=0.)
|
|
||||||
@@ -1,212 +0,0 @@
|
|||||||
prompts_hs = """ 请以“{headstart}”为开头,编写一个小说的第一幕。
|
|
||||||
|
|
||||||
- 尽量短,不要包含太多情节,因为你接下来将会与用户互动续写下面的情节,要留出足够的互动空间。
|
|
||||||
- 出现人物时,给出人物的名字。
|
|
||||||
- 积极地运用环境描写、人物描写等手法,让读者能够感受到你的故事世界。
|
|
||||||
- 积极地运用修辞手法,比如比喻、拟人、排比、对偶、夸张等等。
|
|
||||||
- 字数要求:第一幕的字数少于300字,且少于2个段落。
|
|
||||||
"""
|
|
||||||
|
|
||||||
prompts_interact = """ 小说的前文回顾:
|
|
||||||
「
|
|
||||||
{previously_on_story}
|
|
||||||
」
|
|
||||||
|
|
||||||
你是一个作家,根据以上的情节,给出4种不同的后续剧情发展方向,每个发展方向都精明扼要地用一句话说明。稍后,我将在这4个选择中,挑选一种剧情发展。
|
|
||||||
|
|
||||||
输出格式例如:
|
|
||||||
1. 后续剧情发展1
|
|
||||||
2. 后续剧情发展2
|
|
||||||
3. 后续剧情发展3
|
|
||||||
4. 后续剧情发展4
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
prompts_resume = """小说的前文回顾:
|
|
||||||
「
|
|
||||||
{previously_on_story}
|
|
||||||
」
|
|
||||||
|
|
||||||
你是一个作家,我们正在互相讨论,确定后续剧情的发展。
|
|
||||||
在以下的剧情发展中,
|
|
||||||
「
|
|
||||||
{choice}
|
|
||||||
」
|
|
||||||
我认为更合理的是:{user_choice}。
|
|
||||||
请在前文的基础上(不要重复前文),围绕我选定的剧情情节,编写小说的下一幕。
|
|
||||||
|
|
||||||
- 禁止杜撰不符合我选择的剧情。
|
|
||||||
- 尽量短,不要包含太多情节,因为你接下来将会与用户互动续写下面的情节,要留出足够的互动空间。
|
|
||||||
- 不要重复前文。
|
|
||||||
- 出现人物时,给出人物的名字。
|
|
||||||
- 积极地运用环境描写、人物描写等手法,让读者能够感受到你的故事世界。
|
|
||||||
- 积极地运用修辞手法,比如比喻、拟人、排比、对偶、夸张等等。
|
|
||||||
- 小说的下一幕字数少于300字,且少于2个段落。
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
prompts_terminate = """小说的前文回顾:
|
|
||||||
「
|
|
||||||
{previously_on_story}
|
|
||||||
」
|
|
||||||
|
|
||||||
你是一个作家,我们正在互相讨论,确定后续剧情的发展。
|
|
||||||
现在,故事该结束了,我认为最合理的故事结局是:{user_choice}。
|
|
||||||
|
|
||||||
请在前文的基础上(不要重复前文),编写小说的最后一幕。
|
|
||||||
|
|
||||||
- 不要重复前文。
|
|
||||||
- 出现人物时,给出人物的名字。
|
|
||||||
- 积极地运用环境描写、人物描写等手法,让读者能够感受到你的故事世界。
|
|
||||||
- 积极地运用修辞手法,比如比喻、拟人、排比、对偶、夸张等等。
|
|
||||||
- 字数要求:最后一幕的字数少于1000字。
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
from toolbox import CatchException, update_ui, update_ui_lastest_msg
|
|
||||||
from crazy_functions.multi_stage.multi_stage_utils import GptAcademicGameBaseState
|
|
||||||
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
|
||||||
from request_llms.bridge_all import predict_no_ui_long_connection
|
|
||||||
from crazy_functions.game_fns.game_utils import get_code_block, is_same_thing
|
|
||||||
import random
|
|
||||||
|
|
||||||
|
|
||||||
class MiniGame_ResumeStory(GptAcademicGameBaseState):
|
|
||||||
story_headstart = [
|
|
||||||
'先行者知道,他现在是全宇宙中唯一的一个人了。',
|
|
||||||
'深夜,一个年轻人穿过天安门广场向纪念堂走去。在二十二世纪编年史中,计算机把他的代号定为M102。',
|
|
||||||
'他知道,这最后一课要提前讲了。又一阵剧痛从肝部袭来,几乎使他晕厥过去。',
|
|
||||||
'在距地球五万光年的远方,在银河系的中心,一场延续了两万年的星际战争已接近尾声。那里的太空中渐渐隐现出一个方形区域,仿佛灿烂的群星的背景被剪出一个方口。',
|
|
||||||
'伊依一行三人乘坐一艘游艇在南太平洋上做吟诗航行,他们的目的地是南极,如果几天后能顺利到达那里,他们将钻出地壳去看诗云。',
|
|
||||||
'很多人生来就会莫名其妙地迷上一样东西,仿佛他的出生就是要和这东西约会似的,正是这样,圆圆迷上了肥皂泡。'
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def begin_game_step_0(self, prompt, chatbot, history):
|
|
||||||
# init game at step 0
|
|
||||||
self.headstart = random.choice(self.story_headstart)
|
|
||||||
self.story = []
|
|
||||||
chatbot.append(["互动写故事", f"这次的故事开头是:{self.headstart}"])
|
|
||||||
self.sys_prompt_ = '你是一个想象力丰富的杰出作家。正在与你的朋友互动,一起写故事,因此你每次写的故事段落应少于300字(结局除外)。'
|
|
||||||
|
|
||||||
|
|
||||||
def generate_story_image(self, story_paragraph):
|
|
||||||
try:
|
|
||||||
from crazy_functions.图片生成 import gen_image
|
|
||||||
prompt_ = predict_no_ui_long_connection(inputs=story_paragraph, llm_kwargs=self.llm_kwargs, history=[], sys_prompt='你需要根据用户给出的小说段落,进行简短的环境描写。要求:80字以内。')
|
|
||||||
image_url, image_path = gen_image(self.llm_kwargs, prompt_, '512x512', model="dall-e-2", quality='standard', style='natural')
|
|
||||||
return f'<br/><div align="center"><img src="file={image_path}"></div>'
|
|
||||||
except:
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def step(self, prompt, chatbot, history):
|
|
||||||
|
|
||||||
"""
|
|
||||||
首先,处理游戏初始化等特殊情况
|
|
||||||
"""
|
|
||||||
if self.step_cnt == 0:
|
|
||||||
self.begin_game_step_0(prompt, chatbot, history)
|
|
||||||
self.lock_plugin(chatbot)
|
|
||||||
self.cur_task = 'head_start'
|
|
||||||
else:
|
|
||||||
if prompt.strip() == 'exit' or prompt.strip() == '结束剧情':
|
|
||||||
# should we terminate game here?
|
|
||||||
self.delete_game = True
|
|
||||||
yield from update_ui_lastest_msg(lastmsg=f"游戏结束。", chatbot=chatbot, history=history, delay=0.)
|
|
||||||
return
|
|
||||||
if '剧情收尾' in prompt:
|
|
||||||
self.cur_task = 'story_terminate'
|
|
||||||
# # well, game resumes
|
|
||||||
# chatbot.append([prompt, ""])
|
|
||||||
# update ui, don't keep the user waiting
|
|
||||||
yield from update_ui(chatbot=chatbot, history=history)
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
处理游戏的主体逻辑
|
|
||||||
"""
|
|
||||||
if self.cur_task == 'head_start':
|
|
||||||
"""
|
|
||||||
这是游戏的第一步
|
|
||||||
"""
|
|
||||||
inputs_ = prompts_hs.format(headstart=self.headstart)
|
|
||||||
history_ = []
|
|
||||||
story_paragraph = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
|
||||||
inputs_, '故事开头', self.llm_kwargs,
|
|
||||||
chatbot, history_, self.sys_prompt_
|
|
||||||
)
|
|
||||||
self.story.append(story_paragraph)
|
|
||||||
# # 配图
|
|
||||||
yield from update_ui_lastest_msg(lastmsg=story_paragraph + '<br/>正在生成插图中 ...', chatbot=chatbot, history=history, delay=0.)
|
|
||||||
yield from update_ui_lastest_msg(lastmsg=story_paragraph + '<br/>'+ self.generate_story_image(story_paragraph), chatbot=chatbot, history=history, delay=0.)
|
|
||||||
|
|
||||||
# # 构建后续剧情引导
|
|
||||||
previously_on_story = ""
|
|
||||||
for s in self.story:
|
|
||||||
previously_on_story += s + '\n'
|
|
||||||
inputs_ = prompts_interact.format(previously_on_story=previously_on_story)
|
|
||||||
history_ = []
|
|
||||||
self.next_choices = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
|
||||||
inputs_, '请在以下几种故事走向中,选择一种(当然,您也可以选择给出其他故事走向):', self.llm_kwargs,
|
|
||||||
chatbot,
|
|
||||||
history_,
|
|
||||||
self.sys_prompt_
|
|
||||||
)
|
|
||||||
self.cur_task = 'user_choice'
|
|
||||||
|
|
||||||
|
|
||||||
elif self.cur_task == 'user_choice':
|
|
||||||
"""
|
|
||||||
根据用户的提示,确定故事的下一步
|
|
||||||
"""
|
|
||||||
if '请在以下几种故事走向中,选择一种' in chatbot[-1][0]: chatbot.pop(-1)
|
|
||||||
previously_on_story = ""
|
|
||||||
for s in self.story:
|
|
||||||
previously_on_story += s + '\n'
|
|
||||||
inputs_ = prompts_resume.format(previously_on_story=previously_on_story, choice=self.next_choices, user_choice=prompt)
|
|
||||||
history_ = []
|
|
||||||
story_paragraph = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
|
||||||
inputs_, f'下一段故事(您的选择是:{prompt})。', self.llm_kwargs,
|
|
||||||
chatbot, history_, self.sys_prompt_
|
|
||||||
)
|
|
||||||
self.story.append(story_paragraph)
|
|
||||||
# # 配图
|
|
||||||
yield from update_ui_lastest_msg(lastmsg=story_paragraph + '<br/>正在生成插图中 ...', chatbot=chatbot, history=history, delay=0.)
|
|
||||||
yield from update_ui_lastest_msg(lastmsg=story_paragraph + '<br/>'+ self.generate_story_image(story_paragraph), chatbot=chatbot, history=history, delay=0.)
|
|
||||||
|
|
||||||
# # 构建后续剧情引导
|
|
||||||
previously_on_story = ""
|
|
||||||
for s in self.story:
|
|
||||||
previously_on_story += s + '\n'
|
|
||||||
inputs_ = prompts_interact.format(previously_on_story=previously_on_story)
|
|
||||||
history_ = []
|
|
||||||
self.next_choices = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
|
||||||
inputs_,
|
|
||||||
'请在以下几种故事走向中,选择一种。当然,您也可以给出您心中的其他故事走向。另外,如果您希望剧情立即收尾,请输入剧情走向,并以“剧情收尾”四个字提示程序。', self.llm_kwargs,
|
|
||||||
chatbot,
|
|
||||||
history_,
|
|
||||||
self.sys_prompt_
|
|
||||||
)
|
|
||||||
self.cur_task = 'user_choice'
|
|
||||||
|
|
||||||
|
|
||||||
elif self.cur_task == 'story_terminate':
|
|
||||||
"""
|
|
||||||
根据用户的提示,确定故事的结局
|
|
||||||
"""
|
|
||||||
previously_on_story = ""
|
|
||||||
for s in self.story:
|
|
||||||
previously_on_story += s + '\n'
|
|
||||||
inputs_ = prompts_terminate.format(previously_on_story=previously_on_story, user_choice=prompt)
|
|
||||||
history_ = []
|
|
||||||
story_paragraph = yield from request_gpt_model_in_new_thread_with_ui_alive(
|
|
||||||
inputs_, f'故事收尾(您的选择是:{prompt})。', self.llm_kwargs,
|
|
||||||
chatbot, history_, self.sys_prompt_
|
|
||||||
)
|
|
||||||
# # 配图
|
|
||||||
yield from update_ui_lastest_msg(lastmsg=story_paragraph + '<br/>正在生成插图中 ...', chatbot=chatbot, history=history, delay=0.)
|
|
||||||
yield from update_ui_lastest_msg(lastmsg=story_paragraph + '<br/>'+ self.generate_story_image(story_paragraph), chatbot=chatbot, history=history, delay=0.)
|
|
||||||
|
|
||||||
# terminate game
|
|
||||||
self.delete_game = True
|
|
||||||
return
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import platform
|
|
||||||
import pickle
|
|
||||||
import multiprocessing
|
|
||||||
|
|
||||||
def run_in_subprocess_wrapper_func(v_args):
|
|
||||||
func, args, kwargs, return_dict, exception_dict = pickle.loads(v_args)
|
|
||||||
import sys
|
|
||||||
try:
|
|
||||||
result = func(*args, **kwargs)
|
|
||||||
return_dict['result'] = result
|
|
||||||
except Exception as e:
|
|
||||||
exc_info = sys.exc_info()
|
|
||||||
exception_dict['exception'] = exc_info
|
|
||||||
|
|
||||||
def run_in_subprocess_with_timeout(func, timeout=60):
|
|
||||||
if platform.system() == 'Linux':
|
|
||||||
def wrapper(*args, **kwargs):
|
|
||||||
return_dict = multiprocessing.Manager().dict()
|
|
||||||
exception_dict = multiprocessing.Manager().dict()
|
|
||||||
v_args = pickle.dumps((func, args, kwargs, return_dict, exception_dict))
|
|
||||||
process = multiprocessing.Process(target=run_in_subprocess_wrapper_func, args=(v_args,))
|
|
||||||
process.start()
|
|
||||||
process.join(timeout)
|
|
||||||
if process.is_alive():
|
|
||||||
process.terminate()
|
|
||||||
raise TimeoutError(f'功能单元{str(func)}未能在规定时间内完成任务')
|
|
||||||
process.close()
|
|
||||||
if 'exception' in exception_dict:
|
|
||||||
# ooops, the subprocess ran into an exception
|
|
||||||
exc_info = exception_dict['exception']
|
|
||||||
raise exc_info[1].with_traceback(exc_info[2])
|
|
||||||
if 'result' in return_dict.keys():
|
|
||||||
# If the subprocess ran successfully, return the result
|
|
||||||
return return_dict['result']
|
|
||||||
return wrapper
|
|
||||||
else:
|
|
||||||
return func
|
|
||||||
@@ -175,6 +175,7 @@ class LatexPaperFileGroup():
|
|||||||
self.sp_file_contents = []
|
self.sp_file_contents = []
|
||||||
self.sp_file_index = []
|
self.sp_file_index = []
|
||||||
self.sp_file_tag = []
|
self.sp_file_tag = []
|
||||||
|
|
||||||
# count_token
|
# count_token
|
||||||
from request_llms.bridge_all import model_info
|
from request_llms.bridge_all import model_info
|
||||||
enc = model_info["gpt-3.5-turbo"]['tokenizer']
|
enc = model_info["gpt-3.5-turbo"]['tokenizer']
|
||||||
@@ -191,12 +192,13 @@ class LatexPaperFileGroup():
|
|||||||
self.sp_file_index.append(index)
|
self.sp_file_index.append(index)
|
||||||
self.sp_file_tag.append(self.file_paths[index])
|
self.sp_file_tag.append(self.file_paths[index])
|
||||||
else:
|
else:
|
||||||
from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit
|
from ..crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf
|
||||||
segments = breakdown_text_to_satisfy_token_limit(file_content, max_token_limit)
|
segments = breakdown_txt_to_satisfy_token_limit_for_pdf(file_content, self.get_token_num, max_token_limit)
|
||||||
for j, segment in enumerate(segments):
|
for j, segment in enumerate(segments):
|
||||||
self.sp_file_contents.append(segment)
|
self.sp_file_contents.append(segment)
|
||||||
self.sp_file_index.append(index)
|
self.sp_file_index.append(index)
|
||||||
self.sp_file_tag.append(self.file_paths[index] + f".part-{j}.tex")
|
self.sp_file_tag.append(self.file_paths[index] + f".part-{j}.tex")
|
||||||
|
print('Segmentation: done')
|
||||||
|
|
||||||
def merge_result(self):
|
def merge_result(self):
|
||||||
self.file_result = ["" for _ in range(len(self.file_paths))]
|
self.file_result = ["" for _ in range(len(self.file_paths))]
|
||||||
@@ -402,7 +404,7 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f
|
|||||||
result_pdf = pj(work_folder_modified, f'merge_diff.pdf') # get pdf path
|
result_pdf = pj(work_folder_modified, f'merge_diff.pdf') # get pdf path
|
||||||
promote_file_to_downloadzone(result_pdf, rename_file=None, chatbot=chatbot) # promote file to web UI
|
promote_file_to_downloadzone(result_pdf, rename_file=None, chatbot=chatbot) # promote file to web UI
|
||||||
if modified_pdf_success:
|
if modified_pdf_success:
|
||||||
yield from update_ui_lastest_msg(f'转化PDF编译已经成功, 正在尝试生成对比PDF, 请稍候 ...', chatbot, history) # 刷新Gradio前端界面
|
yield from update_ui_lastest_msg(f'转化PDF编译已经成功, 即将退出 ...', chatbot, history) # 刷新Gradio前端界面
|
||||||
result_pdf = pj(work_folder_modified, f'{main_file_modified}.pdf') # get pdf path
|
result_pdf = pj(work_folder_modified, f'{main_file_modified}.pdf') # get pdf path
|
||||||
origin_pdf = pj(work_folder_original, f'{main_file_original}.pdf') # get pdf path
|
origin_pdf = pj(work_folder_original, f'{main_file_original}.pdf') # get pdf path
|
||||||
if os.path.exists(pj(work_folder, '..', 'translation')):
|
if os.path.exists(pj(work_folder, '..', 'translation')):
|
||||||
|
|||||||
@@ -1,125 +0,0 @@
|
|||||||
from crazy_functions.ipc_fns.mp import run_in_subprocess_with_timeout
|
|
||||||
|
|
||||||
def force_breakdown(txt, limit, get_token_fn):
|
|
||||||
""" 当无法用标点、空行分割时,我们用最暴力的方法切割
|
|
||||||
"""
|
|
||||||
for i in reversed(range(len(txt))):
|
|
||||||
if get_token_fn(txt[:i]) < limit:
|
|
||||||
return txt[:i], txt[i:]
|
|
||||||
return "Tiktoken未知错误", "Tiktoken未知错误"
|
|
||||||
|
|
||||||
|
|
||||||
def maintain_storage(remain_txt_to_cut, remain_txt_to_cut_storage):
|
|
||||||
""" 为了加速计算,我们采样一个特殊的手段。当 remain_txt_to_cut > `_max` 时, 我们把 _max 后的文字转存至 remain_txt_to_cut_storage
|
|
||||||
当 remain_txt_to_cut < `_min` 时,我们再把 remain_txt_to_cut_storage 中的部分文字取出
|
|
||||||
"""
|
|
||||||
_min = int(5e4)
|
|
||||||
_max = int(1e5)
|
|
||||||
# print(len(remain_txt_to_cut), len(remain_txt_to_cut_storage))
|
|
||||||
if len(remain_txt_to_cut) < _min and len(remain_txt_to_cut_storage) > 0:
|
|
||||||
remain_txt_to_cut = remain_txt_to_cut + remain_txt_to_cut_storage
|
|
||||||
remain_txt_to_cut_storage = ""
|
|
||||||
if len(remain_txt_to_cut) > _max:
|
|
||||||
remain_txt_to_cut_storage = remain_txt_to_cut[_max:] + remain_txt_to_cut_storage
|
|
||||||
remain_txt_to_cut = remain_txt_to_cut[:_max]
|
|
||||||
return remain_txt_to_cut, remain_txt_to_cut_storage
|
|
||||||
|
|
||||||
|
|
||||||
def cut(limit, get_token_fn, txt_tocut, must_break_at_empty_line, break_anyway=False):
|
|
||||||
""" 文本切分
|
|
||||||
"""
|
|
||||||
res = []
|
|
||||||
total_len = len(txt_tocut)
|
|
||||||
fin_len = 0
|
|
||||||
remain_txt_to_cut = txt_tocut
|
|
||||||
remain_txt_to_cut_storage = ""
|
|
||||||
# 为了加速计算,我们采样一个特殊的手段。当 remain_txt_to_cut > `_max` 时, 我们把 _max 后的文字转存至 remain_txt_to_cut_storage
|
|
||||||
remain_txt_to_cut, remain_txt_to_cut_storage = maintain_storage(remain_txt_to_cut, remain_txt_to_cut_storage)
|
|
||||||
|
|
||||||
while True:
|
|
||||||
if get_token_fn(remain_txt_to_cut) <= limit:
|
|
||||||
# 如果剩余文本的token数小于限制,那么就不用切了
|
|
||||||
res.append(remain_txt_to_cut); fin_len+=len(remain_txt_to_cut)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# 如果剩余文本的token数大于限制,那么就切
|
|
||||||
lines = remain_txt_to_cut.split('\n')
|
|
||||||
|
|
||||||
# 估计一个切分点
|
|
||||||
estimated_line_cut = limit / get_token_fn(remain_txt_to_cut) * len(lines)
|
|
||||||
estimated_line_cut = int(estimated_line_cut)
|
|
||||||
|
|
||||||
# 开始查找合适切分点的偏移(cnt)
|
|
||||||
cnt = 0
|
|
||||||
for cnt in reversed(range(estimated_line_cut)):
|
|
||||||
if must_break_at_empty_line:
|
|
||||||
# 首先尝试用双空行(\n\n)作为切分点
|
|
||||||
if lines[cnt] != "":
|
|
||||||
continue
|
|
||||||
prev = "\n".join(lines[:cnt])
|
|
||||||
post = "\n".join(lines[cnt:])
|
|
||||||
if get_token_fn(prev) < limit:
|
|
||||||
break
|
|
||||||
|
|
||||||
if cnt == 0:
|
|
||||||
# 如果没有找到合适的切分点
|
|
||||||
if break_anyway:
|
|
||||||
# 是否允许暴力切分
|
|
||||||
prev, post = force_breakdown(txt_tocut, limit, get_token_fn)
|
|
||||||
else:
|
|
||||||
# 不允许直接报错
|
|
||||||
raise RuntimeError(f"存在一行极长的文本!{txt_tocut}")
|
|
||||||
|
|
||||||
# 追加列表
|
|
||||||
res.append(prev); fin_len+=len(prev)
|
|
||||||
# 准备下一次迭代
|
|
||||||
remain_txt_to_cut = post
|
|
||||||
remain_txt_to_cut, remain_txt_to_cut_storage = maintain_storage(remain_txt_to_cut, remain_txt_to_cut_storage)
|
|
||||||
process = fin_len/total_len
|
|
||||||
print(f'正在文本切分 {int(process*100)}%')
|
|
||||||
if len(remain_txt_to_cut.strip()) == 0:
|
|
||||||
break
|
|
||||||
return res
|
|
||||||
|
|
||||||
|
|
||||||
def breakdown_text_to_satisfy_token_limit_(txt, limit, llm_model="gpt-3.5-turbo"):
|
|
||||||
""" 使用多种方式尝试切分文本,以满足 token 限制
|
|
||||||
"""
|
|
||||||
from request_llms.bridge_all import model_info
|
|
||||||
enc = model_info[llm_model]['tokenizer']
|
|
||||||
def get_token_fn(txt): return len(enc.encode(txt, disallowed_special=()))
|
|
||||||
try:
|
|
||||||
# 第1次尝试,将双空行(\n\n)作为切分点
|
|
||||||
return cut(limit, get_token_fn, txt, must_break_at_empty_line=True)
|
|
||||||
except RuntimeError:
|
|
||||||
try:
|
|
||||||
# 第2次尝试,将单空行(\n)作为切分点
|
|
||||||
return cut(limit, get_token_fn, txt, must_break_at_empty_line=False)
|
|
||||||
except RuntimeError:
|
|
||||||
try:
|
|
||||||
# 第3次尝试,将英文句号(.)作为切分点
|
|
||||||
res = cut(limit, get_token_fn, txt.replace('.', '。\n'), must_break_at_empty_line=False) # 这个中文的句号是故意的,作为一个标识而存在
|
|
||||||
return [r.replace('。\n', '.') for r in res]
|
|
||||||
except RuntimeError as e:
|
|
||||||
try:
|
|
||||||
# 第4次尝试,将中文句号(。)作为切分点
|
|
||||||
res = cut(limit, get_token_fn, txt.replace('。', '。。\n'), must_break_at_empty_line=False)
|
|
||||||
return [r.replace('。。\n', '。') for r in res]
|
|
||||||
except RuntimeError as e:
|
|
||||||
# 第5次尝试,没办法了,随便切一下吧
|
|
||||||
return cut(limit, get_token_fn, txt, must_break_at_empty_line=False, break_anyway=True)
|
|
||||||
|
|
||||||
breakdown_text_to_satisfy_token_limit = run_in_subprocess_with_timeout(breakdown_text_to_satisfy_token_limit_, timeout=60)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
from crazy_functions.crazy_utils import read_and_clean_pdf_text
|
|
||||||
file_content, page_one = read_and_clean_pdf_text("build/assets/at.pdf")
|
|
||||||
|
|
||||||
from request_llms.bridge_all import model_info
|
|
||||||
for i in range(5):
|
|
||||||
file_content += file_content
|
|
||||||
|
|
||||||
print(len(file_content))
|
|
||||||
TOKEN_LIMIT_PER_FRAGMENT = 2500
|
|
||||||
res = breakdown_text_to_satisfy_token_limit(file_content, TOKEN_LIMIT_PER_FRAGMENT)
|
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ def produce_report_markdown(gpt_response_collection, meta, paper_meta_info, chat
|
|||||||
|
|
||||||
def translate_pdf(article_dict, llm_kwargs, chatbot, fp, generated_conclusion_files, TOKEN_LIMIT_PER_FRAGMENT, DST_LANG):
|
def translate_pdf(article_dict, llm_kwargs, chatbot, fp, generated_conclusion_files, TOKEN_LIMIT_PER_FRAGMENT, DST_LANG):
|
||||||
from crazy_functions.pdf_fns.report_gen_html import construct_html
|
from crazy_functions.pdf_fns.report_gen_html import construct_html
|
||||||
from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit
|
from crazy_functions.crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf
|
||||||
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
from crazy_functions.crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
from crazy_functions.crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ def translate_pdf(article_dict, llm_kwargs, chatbot, fp, generated_conclusion_fi
|
|||||||
# find a smooth token limit to achieve even seperation
|
# find a smooth token limit to achieve even seperation
|
||||||
count = int(math.ceil(raw_token_num / TOKEN_LIMIT_PER_FRAGMENT))
|
count = int(math.ceil(raw_token_num / TOKEN_LIMIT_PER_FRAGMENT))
|
||||||
token_limit_smooth = raw_token_num // count + count
|
token_limit_smooth = raw_token_num // count + count
|
||||||
return breakdown_text_to_satisfy_token_limit(txt, limit=token_limit_smooth, llm_model=llm_kwargs['llm_model'])
|
return breakdown_txt_to_satisfy_token_limit_for_pdf(txt, get_token_fn=get_token_num, limit=token_limit_smooth)
|
||||||
|
|
||||||
for section in article_dict.get('sections'):
|
for section in article_dict.get('sections'):
|
||||||
if len(section['text']) == 0: continue
|
if len(section['text']) == 0: continue
|
||||||
|
|||||||
@@ -3,28 +3,47 @@ from crazy_functions.multi_stage.multi_stage_utils import GptAcademicGameBaseSta
|
|||||||
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
|
||||||
from request_llms.bridge_all import predict_no_ui_long_connection
|
from request_llms.bridge_all import predict_no_ui_long_connection
|
||||||
from crazy_functions.game_fns.game_utils import get_code_block, is_same_thing
|
from crazy_functions.game_fns.game_utils import get_code_block, is_same_thing
|
||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
class MiniGame_ASCII_Art(GptAcademicGameBaseState):
|
||||||
|
|
||||||
|
def step(self, prompt, chatbot, history):
|
||||||
|
if self.step_cnt == 0:
|
||||||
|
chatbot.append(["我画你猜(动物)", "请稍等..."])
|
||||||
|
else:
|
||||||
|
if prompt.strip() == 'exit':
|
||||||
|
self.delete_game = True
|
||||||
|
yield from update_ui_lastest_msg(lastmsg=f"谜底是{self.obj},游戏结束。", chatbot=chatbot, history=history, delay=0.)
|
||||||
|
return
|
||||||
|
chatbot.append([prompt, ""])
|
||||||
|
yield from update_ui(chatbot=chatbot, history=history)
|
||||||
|
|
||||||
|
if self.step_cnt == 0:
|
||||||
|
self.lock_plugin(chatbot)
|
||||||
|
self.cur_task = 'draw'
|
||||||
|
|
||||||
|
if self.cur_task == 'draw':
|
||||||
|
avail_obj = ["狗","猫","鸟","鱼","老鼠","蛇"]
|
||||||
|
self.obj = random.choice(avail_obj)
|
||||||
|
inputs = "I want to play a game called Guess the ASCII art. You can draw the ASCII art and I will try to guess it. " + f"This time you draw a {self.obj}. Note that you must not indicate what you have draw in the text, and you should only produce the ASCII art wrapped by ```. "
|
||||||
|
raw_res = predict_no_ui_long_connection(inputs=inputs, llm_kwargs=self.llm_kwargs, history=[], sys_prompt="")
|
||||||
|
self.cur_task = 'identify user guess'
|
||||||
|
res = get_code_block(raw_res)
|
||||||
|
history += ['', f'the answer is {self.obj}', inputs, res]
|
||||||
|
yield from update_ui_lastest_msg(lastmsg=res, chatbot=chatbot, history=history, delay=0.)
|
||||||
|
|
||||||
|
elif self.cur_task == 'identify user guess':
|
||||||
|
if is_same_thing(self.obj, prompt, self.llm_kwargs):
|
||||||
|
self.delete_game = True
|
||||||
|
yield from update_ui_lastest_msg(lastmsg="你猜对了!", chatbot=chatbot, history=history, delay=0.)
|
||||||
|
else:
|
||||||
|
self.cur_task = 'identify user guess'
|
||||||
|
yield from update_ui_lastest_msg(lastmsg="猜错了,再试试,输入“exit”获取答案。", chatbot=chatbot, history=history, delay=0.)
|
||||||
|
|
||||||
|
|
||||||
@CatchException
|
@CatchException
|
||||||
def 随机小游戏(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
def 随机小游戏(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
||||||
from crazy_functions.game_fns.game_interactive_story import MiniGame_ResumeStory
|
|
||||||
# 清空历史
|
|
||||||
history = []
|
|
||||||
# 选择游戏
|
|
||||||
cls = MiniGame_ResumeStory
|
|
||||||
# 如果之前已经初始化了游戏实例,则继续该实例;否则重新初始化
|
|
||||||
state = cls.sync_state(chatbot,
|
|
||||||
llm_kwargs,
|
|
||||||
cls,
|
|
||||||
plugin_name='MiniGame_ResumeStory',
|
|
||||||
callback_fn='crazy_functions.互动小游戏->随机小游戏',
|
|
||||||
lock_plugin=True
|
|
||||||
)
|
|
||||||
yield from state.continue_game(prompt, chatbot, history)
|
|
||||||
|
|
||||||
|
|
||||||
@CatchException
|
|
||||||
def 随机小游戏1(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
|
|
||||||
from crazy_functions.game_fns.game_ascii_art import MiniGame_ASCII_Art
|
|
||||||
# 清空历史
|
# 清空历史
|
||||||
history = []
|
history = []
|
||||||
# 选择游戏
|
# 选择游戏
|
||||||
@@ -34,7 +53,7 @@ def 随机小游戏1(prompt, llm_kwargs, plugin_kwargs, chatbot, history, system
|
|||||||
llm_kwargs,
|
llm_kwargs,
|
||||||
cls,
|
cls,
|
||||||
plugin_name='MiniGame_ASCII_Art',
|
plugin_name='MiniGame_ASCII_Art',
|
||||||
callback_fn='crazy_functions.互动小游戏->随机小游戏1',
|
callback_fn='crazy_functions.互动小游戏->随机小游戏',
|
||||||
lock_plugin=True
|
lock_plugin=True
|
||||||
)
|
)
|
||||||
yield from state.continue_game(prompt, chatbot, history)
|
yield from state.continue_game(prompt, chatbot, history)
|
||||||
|
|||||||
@@ -29,12 +29,17 @@ def 解析docx(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot
|
|||||||
except:
|
except:
|
||||||
raise RuntimeError('请先将.doc文档转换为.docx文档。')
|
raise RuntimeError('请先将.doc文档转换为.docx文档。')
|
||||||
|
|
||||||
|
print(file_content)
|
||||||
# private_upload里面的文件名在解压zip后容易出现乱码(rar和7z格式正常),故可以只分析文章内容,不输入文件名
|
# private_upload里面的文件名在解压zip后容易出现乱码(rar和7z格式正常),故可以只分析文章内容,不输入文件名
|
||||||
from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit
|
from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf
|
||||||
from request_llms.bridge_all import model_info
|
from request_llms.bridge_all import model_info
|
||||||
max_token = model_info[llm_kwargs['llm_model']]['max_token']
|
max_token = model_info[llm_kwargs['llm_model']]['max_token']
|
||||||
TOKEN_LIMIT_PER_FRAGMENT = max_token * 3 // 4
|
TOKEN_LIMIT_PER_FRAGMENT = max_token * 3 // 4
|
||||||
paper_fragments = breakdown_text_to_satisfy_token_limit(txt=file_content, limit=TOKEN_LIMIT_PER_FRAGMENT, llm_model=llm_kwargs['llm_model'])
|
paper_fragments = breakdown_txt_to_satisfy_token_limit_for_pdf(
|
||||||
|
txt=file_content,
|
||||||
|
get_token_fn=model_info[llm_kwargs['llm_model']]['token_cnt'],
|
||||||
|
limit=TOKEN_LIMIT_PER_FRAGMENT
|
||||||
|
)
|
||||||
this_paper_history = []
|
this_paper_history = []
|
||||||
for i, paper_frag in enumerate(paper_fragments):
|
for i, paper_frag in enumerate(paper_fragments):
|
||||||
i_say = f'请对下面的文章片段用中文做概述,文件名是{os.path.relpath(fp, project_folder)},文章内容是 ```{paper_frag}```'
|
i_say = f'请对下面的文章片段用中文做概述,文件名是{os.path.relpath(fp, project_folder)},文章内容是 ```{paper_frag}```'
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ class PaperFileGroup():
|
|||||||
self.sp_file_index.append(index)
|
self.sp_file_index.append(index)
|
||||||
self.sp_file_tag.append(self.file_paths[index])
|
self.sp_file_tag.append(self.file_paths[index])
|
||||||
else:
|
else:
|
||||||
from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit
|
from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf
|
||||||
segments = breakdown_text_to_satisfy_token_limit(file_content, max_token_limit)
|
segments = breakdown_txt_to_satisfy_token_limit_for_pdf(file_content, self.get_token_num, max_token_limit)
|
||||||
for j, segment in enumerate(segments):
|
for j, segment in enumerate(segments):
|
||||||
self.sp_file_contents.append(segment)
|
self.sp_file_contents.append(segment)
|
||||||
self.sp_file_index.append(index)
|
self.sp_file_index.append(index)
|
||||||
|
|||||||
@@ -20,9 +20,14 @@ def 解析PDF(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot,
|
|||||||
|
|
||||||
TOKEN_LIMIT_PER_FRAGMENT = 2500
|
TOKEN_LIMIT_PER_FRAGMENT = 2500
|
||||||
|
|
||||||
from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit
|
from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf
|
||||||
paper_fragments = breakdown_text_to_satisfy_token_limit(txt=file_content, limit=TOKEN_LIMIT_PER_FRAGMENT, llm_model=llm_kwargs['llm_model'])
|
from request_llms.bridge_all import model_info
|
||||||
page_one_fragments = breakdown_text_to_satisfy_token_limit(txt=str(page_one), limit=TOKEN_LIMIT_PER_FRAGMENT//4, llm_model=llm_kwargs['llm_model'])
|
enc = model_info["gpt-3.5-turbo"]['tokenizer']
|
||||||
|
def get_token_num(txt): return len(enc.encode(txt, disallowed_special=()))
|
||||||
|
paper_fragments = breakdown_txt_to_satisfy_token_limit_for_pdf(
|
||||||
|
txt=file_content, get_token_fn=get_token_num, limit=TOKEN_LIMIT_PER_FRAGMENT)
|
||||||
|
page_one_fragments = breakdown_txt_to_satisfy_token_limit_for_pdf(
|
||||||
|
txt=str(page_one), get_token_fn=get_token_num, limit=TOKEN_LIMIT_PER_FRAGMENT//4)
|
||||||
# 为了更好的效果,我们剥离Introduction之后的部分(如果有)
|
# 为了更好的效果,我们剥离Introduction之后的部分(如果有)
|
||||||
paper_meta = page_one_fragments[0].split('introduction')[0].split('Introduction')[0].split('INTRODUCTION')[0]
|
paper_meta = page_one_fragments[0].split('introduction')[0].split('Introduction')[0].split('INTRODUCTION')[0]
|
||||||
|
|
||||||
|
|||||||
@@ -91,9 +91,14 @@ def 解析PDF(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot,
|
|||||||
page_one = str(page_one).encode('utf-8', 'ignore').decode() # avoid reading non-utf8 chars
|
page_one = str(page_one).encode('utf-8', 'ignore').decode() # avoid reading non-utf8 chars
|
||||||
|
|
||||||
# 递归地切割PDF文件
|
# 递归地切割PDF文件
|
||||||
from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit
|
from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf
|
||||||
paper_fragments = breakdown_text_to_satisfy_token_limit(txt=file_content, limit=TOKEN_LIMIT_PER_FRAGMENT, llm_model=llm_kwargs['llm_model'])
|
from request_llms.bridge_all import model_info
|
||||||
page_one_fragments = breakdown_text_to_satisfy_token_limit(txt=page_one, limit=TOKEN_LIMIT_PER_FRAGMENT//4, llm_model=llm_kwargs['llm_model'])
|
enc = model_info["gpt-3.5-turbo"]['tokenizer']
|
||||||
|
def get_token_num(txt): return len(enc.encode(txt, disallowed_special=()))
|
||||||
|
paper_fragments = breakdown_txt_to_satisfy_token_limit_for_pdf(
|
||||||
|
txt=file_content, get_token_fn=get_token_num, limit=TOKEN_LIMIT_PER_FRAGMENT)
|
||||||
|
page_one_fragments = breakdown_txt_to_satisfy_token_limit_for_pdf(
|
||||||
|
txt=page_one, get_token_fn=get_token_num, limit=TOKEN_LIMIT_PER_FRAGMENT//4)
|
||||||
|
|
||||||
# 为了更好的效果,我们剥离Introduction之后的部分(如果有)
|
# 为了更好的效果,我们剥离Introduction之后的部分(如果有)
|
||||||
paper_meta = page_one_fragments[0].split('introduction')[0].split('Introduction')[0].split('INTRODUCTION')[0]
|
paper_meta = page_one_fragments[0].split('introduction')[0].split('Introduction')[0].split('INTRODUCTION')[0]
|
||||||
|
|||||||
@@ -18,9 +18,14 @@ def 解析PDF(file_name, llm_kwargs, plugin_kwargs, chatbot, history, system_pro
|
|||||||
|
|
||||||
TOKEN_LIMIT_PER_FRAGMENT = 2500
|
TOKEN_LIMIT_PER_FRAGMENT = 2500
|
||||||
|
|
||||||
from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit
|
from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf
|
||||||
paper_fragments = breakdown_text_to_satisfy_token_limit(txt=file_content, limit=TOKEN_LIMIT_PER_FRAGMENT, llm_model=llm_kwargs['llm_model'])
|
from request_llms.bridge_all import model_info
|
||||||
page_one_fragments = breakdown_text_to_satisfy_token_limit(txt=str(page_one), limit=TOKEN_LIMIT_PER_FRAGMENT//4, llm_model=llm_kwargs['llm_model'])
|
enc = model_info["gpt-3.5-turbo"]['tokenizer']
|
||||||
|
def get_token_num(txt): return len(enc.encode(txt, disallowed_special=()))
|
||||||
|
paper_fragments = breakdown_txt_to_satisfy_token_limit_for_pdf(
|
||||||
|
txt=file_content, get_token_fn=get_token_num, limit=TOKEN_LIMIT_PER_FRAGMENT)
|
||||||
|
page_one_fragments = breakdown_txt_to_satisfy_token_limit_for_pdf(
|
||||||
|
txt=str(page_one), get_token_fn=get_token_num, limit=TOKEN_LIMIT_PER_FRAGMENT//4)
|
||||||
# 为了更好的效果,我们剥离Introduction之后的部分(如果有)
|
# 为了更好的效果,我们剥离Introduction之后的部分(如果有)
|
||||||
paper_meta = page_one_fragments[0].split('introduction')[0].split('Introduction')[0].split('INTRODUCTION')[0]
|
paper_meta = page_one_fragments[0].split('introduction')[0].split('Introduction')[0].split('INTRODUCTION')[0]
|
||||||
|
|
||||||
@@ -40,7 +45,7 @@ def 解析PDF(file_name, llm_kwargs, plugin_kwargs, chatbot, history, system_pro
|
|||||||
for i in range(n_fragment):
|
for i in range(n_fragment):
|
||||||
NUM_OF_WORD = MAX_WORD_TOTAL // n_fragment
|
NUM_OF_WORD = MAX_WORD_TOTAL // n_fragment
|
||||||
i_say = f"Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} words: {paper_fragments[i]}"
|
i_say = f"Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} words: {paper_fragments[i]}"
|
||||||
i_say_show_user = f"[{i+1}/{n_fragment}] Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} words: {paper_fragments[i][:200]} ...."
|
i_say_show_user = f"[{i+1}/{n_fragment}] Read this section, recapitulate the content of this section with less than {NUM_OF_WORD} words: {paper_fragments[i][:200]}"
|
||||||
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(i_say, i_say_show_user, # i_say=真正给chatgpt的提问, i_say_show_user=给用户看的提问
|
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(i_say, i_say_show_user, # i_say=真正给chatgpt的提问, i_say_show_user=给用户看的提问
|
||||||
llm_kwargs, chatbot,
|
llm_kwargs, chatbot,
|
||||||
history=["The main idea of the previous section is?", last_iteration_result], # 迭代上一次的结果
|
history=["The main idea of the previous section is?", last_iteration_result], # 迭代上一次的结果
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ class PaperFileGroup():
|
|||||||
self.sp_file_index = []
|
self.sp_file_index = []
|
||||||
self.sp_file_tag = []
|
self.sp_file_tag = []
|
||||||
|
|
||||||
|
# count_token
|
||||||
|
from request_llms.bridge_all import model_info
|
||||||
|
enc = model_info["gpt-3.5-turbo"]['tokenizer']
|
||||||
|
def get_token_num(txt): return len(
|
||||||
|
enc.encode(txt, disallowed_special=()))
|
||||||
|
self.get_token_num = get_token_num
|
||||||
|
|
||||||
def run_file_split(self, max_token_limit=1900):
|
def run_file_split(self, max_token_limit=1900):
|
||||||
"""
|
"""
|
||||||
将长文本分离开来
|
将长文本分离开来
|
||||||
@@ -22,8 +29,9 @@ class PaperFileGroup():
|
|||||||
self.sp_file_index.append(index)
|
self.sp_file_index.append(index)
|
||||||
self.sp_file_tag.append(self.file_paths[index])
|
self.sp_file_tag.append(self.file_paths[index])
|
||||||
else:
|
else:
|
||||||
from crazy_functions.pdf_fns.breakdown_txt import breakdown_text_to_satisfy_token_limit
|
from .crazy_utils import breakdown_txt_to_satisfy_token_limit_for_pdf
|
||||||
segments = breakdown_text_to_satisfy_token_limit(file_content, max_token_limit)
|
segments = breakdown_txt_to_satisfy_token_limit_for_pdf(
|
||||||
|
file_content, self.get_token_num, max_token_limit)
|
||||||
for j, segment in enumerate(segments):
|
for j, segment in enumerate(segments):
|
||||||
self.sp_file_contents.append(segment)
|
self.sp_file_contents.append(segment)
|
||||||
self.sp_file_index.append(index)
|
self.sp_file_index.append(index)
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
# docker build -t gpt-academic-all-capacity -f docs/GithubAction+AllCapacity --network=host --build-arg http_proxy=http://localhost:10881 --build-arg https_proxy=http://localhost:10881 .
|
|
||||||
# docker build -t gpt-academic-all-capacity -f docs/GithubAction+AllCapacityBeta --network=host .
|
|
||||||
# docker run -it --net=host gpt-academic-all-capacity bash
|
|
||||||
|
|
||||||
# 从NVIDIA源,从而支持显卡(检查宿主的nvidia-smi中的cuda版本必须>=11.3)
|
|
||||||
FROM fuqingxu/11.3.1-runtime-ubuntu20.04-with-texlive:latest
|
|
||||||
|
|
||||||
# use python3 as the system default python
|
|
||||||
WORKDIR /gpt
|
|
||||||
RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.8
|
|
||||||
|
|
||||||
# # 非必要步骤,更换pip源 (以下三行,可以删除)
|
|
||||||
# RUN echo '[global]' > /etc/pip.conf && \
|
|
||||||
# echo 'index-url = https://mirrors.aliyun.com/pypi/simple/' >> /etc/pip.conf && \
|
|
||||||
# echo 'trusted-host = mirrors.aliyun.com' >> /etc/pip.conf
|
|
||||||
|
|
||||||
# 下载pytorch
|
|
||||||
RUN python3 -m pip install torch torchvision --extra-index-url https://download.pytorch.org/whl/cu113
|
|
||||||
# 准备pip依赖
|
|
||||||
RUN python3 -m pip install openai numpy arxiv rich
|
|
||||||
RUN python3 -m pip install colorama Markdown pygments pymupdf
|
|
||||||
RUN python3 -m pip install python-docx moviepy pdfminer
|
|
||||||
RUN python3 -m pip install zh_langchain==0.2.1 pypinyin
|
|
||||||
RUN python3 -m pip install rarfile py7zr
|
|
||||||
RUN python3 -m pip install aliyun-python-sdk-core==2.13.3 pyOpenSSL webrtcvad scipy git+https://github.com/aliyun/alibabacloud-nls-python-sdk.git
|
|
||||||
# 下载分支
|
|
||||||
WORKDIR /gpt
|
|
||||||
RUN git clone --depth=1 https://github.com/binary-husky/gpt_academic.git
|
|
||||||
WORKDIR /gpt/gpt_academic
|
|
||||||
RUN git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llms/moss
|
|
||||||
|
|
||||||
RUN python3 -m pip install -r requirements.txt
|
|
||||||
RUN python3 -m pip install -r request_llms/requirements_moss.txt
|
|
||||||
RUN python3 -m pip install -r request_llms/requirements_qwen.txt
|
|
||||||
RUN python3 -m pip install -r request_llms/requirements_chatglm.txt
|
|
||||||
RUN python3 -m pip install -r request_llms/requirements_newbing.txt
|
|
||||||
RUN python3 -m pip install nougat-ocr
|
|
||||||
|
|
||||||
# 预热Tiktoken模块
|
|
||||||
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
|
||||||
|
|
||||||
# 安装知识库插件的额外依赖
|
|
||||||
RUN apt-get update && apt-get install libgl1 -y
|
|
||||||
RUN pip3 install transformers protobuf langchain sentence-transformers faiss-cpu nltk beautifulsoup4 bitsandbytes tabulate icetk --upgrade
|
|
||||||
RUN pip3 install unstructured[all-docs] --upgrade
|
|
||||||
RUN python3 -c 'from check_proxy import warm_up_vectordb; warm_up_vectordb()'
|
|
||||||
RUN rm -rf /usr/local/lib/python3.8/dist-packages/tests
|
|
||||||
|
|
||||||
|
|
||||||
# COPY .cache /root/.cache
|
|
||||||
# COPY config_private.py config_private.py
|
|
||||||
# 启动
|
|
||||||
CMD ["python3", "-u", "main.py"]
|
|
||||||
@@ -17,10 +17,10 @@ RUN apt-get update && apt-get install libgl1 -y
|
|||||||
RUN pip3 install torch torchvision --index-url https://download.pytorch.org/whl/cpu
|
RUN pip3 install torch torchvision --index-url https://download.pytorch.org/whl/cpu
|
||||||
RUN pip3 install transformers protobuf langchain sentence-transformers faiss-cpu nltk beautifulsoup4 bitsandbytes tabulate icetk --upgrade
|
RUN pip3 install transformers protobuf langchain sentence-transformers faiss-cpu nltk beautifulsoup4 bitsandbytes tabulate icetk --upgrade
|
||||||
RUN pip3 install unstructured[all-docs] --upgrade
|
RUN pip3 install unstructured[all-docs] --upgrade
|
||||||
RUN python3 -c 'from check_proxy import warm_up_vectordb; warm_up_vectordb()'
|
|
||||||
|
|
||||||
# 可选步骤,用于预热模块
|
# 可选步骤,用于预热模块
|
||||||
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
RUN python3 -c 'from check_proxy import warm_up_modules; warm_up_modules()'
|
||||||
|
RUN python3 -c 'from check_proxy import warm_up_vectordb; warm_up_vectordb()'
|
||||||
|
|
||||||
# 启动
|
# 启动
|
||||||
CMD ["python3", "-u", "main.py"]
|
CMD ["python3", "-u", "main.py"]
|
||||||
|
|||||||
@@ -2863,7 +2863,7 @@
|
|||||||
"加载API_KEY": "Loading API_KEY",
|
"加载API_KEY": "Loading API_KEY",
|
||||||
"协助您编写代码": "Assist you in writing code",
|
"协助您编写代码": "Assist you in writing code",
|
||||||
"我可以为您提供以下服务": "I can provide you with the following services",
|
"我可以为您提供以下服务": "I can provide you with the following services",
|
||||||
"排队中请稍候 ...": "Please wait in line ...",
|
"排队中请稍后 ...": "Please wait in line ...",
|
||||||
"建议您使用英文提示词": "It is recommended to use English prompts",
|
"建议您使用英文提示词": "It is recommended to use English prompts",
|
||||||
"不能支撑AutoGen运行": "Cannot support AutoGen operation",
|
"不能支撑AutoGen运行": "Cannot support AutoGen operation",
|
||||||
"帮助您解决编程问题": "Help you solve programming problems",
|
"帮助您解决编程问题": "Help you solve programming problems",
|
||||||
|
|||||||
108
main.py
108
main.py
@@ -1,17 +1,6 @@
|
|||||||
import os; os.environ['no_proxy'] = '*' # 避免代理网络产生意外污染
|
import os; os.environ['no_proxy'] = '*' # 避免代理网络产生意外污染
|
||||||
|
import pickle
|
||||||
help_menu_description = \
|
import base64
|
||||||
"""Github源代码开源和更新[地址🚀](https://github.com/binary-husky/gpt_academic),
|
|
||||||
感谢热情的[开发者们❤️](https://github.com/binary-husky/gpt_academic/graphs/contributors).
|
|
||||||
</br></br>常见问题请查阅[项目Wiki](https://github.com/binary-husky/gpt_academic/wiki),
|
|
||||||
如遇到Bug请前往[Bug反馈](https://github.com/binary-husky/gpt_academic/issues).
|
|
||||||
</br></br>普通对话使用说明: 1. 输入问题; 2. 点击提交
|
|
||||||
</br></br>基础功能区使用说明: 1. 输入文本; 2. 点击任意基础功能区按钮
|
|
||||||
</br></br>函数插件区使用说明: 1. 输入路径/问题, 或者上传文件; 2. 点击任意函数插件区按钮
|
|
||||||
</br></br>虚空终端使用说明: 点击虚空终端, 然后根据提示输入指令, 再次点击虚空终端
|
|
||||||
</br></br>如何保存对话: 点击保存当前的对话按钮
|
|
||||||
</br></br>如何语音对话: 请阅读Wiki
|
|
||||||
</br></br>如何临时更换API_KEY: 在输入区输入临时API_KEY后提交(网页刷新后失效)"""
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
import gradio as gr
|
import gradio as gr
|
||||||
@@ -19,7 +8,7 @@ def main():
|
|||||||
raise ModuleNotFoundError("使用项目内置Gradio获取最优体验! 请运行 `pip install -r requirements.txt` 指令安装内置Gradio及其他依赖, 详情信息见requirements.txt.")
|
raise ModuleNotFoundError("使用项目内置Gradio获取最优体验! 请运行 `pip install -r requirements.txt` 指令安装内置Gradio及其他依赖, 详情信息见requirements.txt.")
|
||||||
from request_llms.bridge_all import predict
|
from request_llms.bridge_all import predict
|
||||||
from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf, ArgsGeneralWrapper, load_chat_cookies, DummyWith
|
from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf, ArgsGeneralWrapper, load_chat_cookies, DummyWith
|
||||||
# 建议您复制一个config_private.py放自己的秘密, 如API和代理网址
|
# 建议您复制一个config_private.py放自己的秘密, 如API和代理网址, 避免不小心传github被别人看到
|
||||||
proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION = get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION')
|
proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION = get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION')
|
||||||
CHATBOT_HEIGHT, LAYOUT, AVAIL_LLM_MODELS, AUTO_CLEAR_TXT = get_conf('CHATBOT_HEIGHT', 'LAYOUT', 'AVAIL_LLM_MODELS', 'AUTO_CLEAR_TXT')
|
CHATBOT_HEIGHT, LAYOUT, AVAIL_LLM_MODELS, AUTO_CLEAR_TXT = get_conf('CHATBOT_HEIGHT', 'LAYOUT', 'AVAIL_LLM_MODELS', 'AUTO_CLEAR_TXT')
|
||||||
ENABLE_AUDIO, AUTO_CLEAR_TXT, PATH_LOGGING, AVAIL_THEMES, THEME = get_conf('ENABLE_AUDIO', 'AUTO_CLEAR_TXT', 'PATH_LOGGING', 'AVAIL_THEMES', 'THEME')
|
ENABLE_AUDIO, AUTO_CLEAR_TXT, PATH_LOGGING, AVAIL_THEMES, THEME = get_conf('ENABLE_AUDIO', 'AUTO_CLEAR_TXT', 'PATH_LOGGING', 'AVAIL_THEMES', 'THEME')
|
||||||
@@ -29,10 +18,20 @@ def main():
|
|||||||
# 如果WEB_PORT是-1, 则随机选取WEB端口
|
# 如果WEB_PORT是-1, 则随机选取WEB端口
|
||||||
PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
|
PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
|
||||||
from check_proxy import get_current_version
|
from check_proxy import get_current_version
|
||||||
from themes.theme import adjust_theme, advanced_css, theme_declaration
|
from themes.theme import adjust_theme, advanced_css, theme_declaration, load_dynamic_theme
|
||||||
from themes.theme import js_code_for_css_changing, js_code_for_darkmode_init, js_code_for_toggle_darkmode, js_code_for_persistent_cookie_init
|
|
||||||
from themes.theme import load_dynamic_theme, to_cookie_str, from_cookie_str, init_cookie
|
|
||||||
title_html = f"<h1 align=\"center\">GPT 学术优化 {get_current_version()}</h1>{theme_declaration}"
|
title_html = f"<h1 align=\"center\">GPT 学术优化 {get_current_version()}</h1>{theme_declaration}"
|
||||||
|
description = "Github源代码开源和更新[地址🚀](https://github.com/binary-husky/gpt_academic), "
|
||||||
|
description += "感谢热情的[开发者们❤️](https://github.com/binary-husky/gpt_academic/graphs/contributors)."
|
||||||
|
description += "</br></br>常见问题请查阅[项目Wiki](https://github.com/binary-husky/gpt_academic/wiki), "
|
||||||
|
description += "如遇到Bug请前往[Bug反馈](https://github.com/binary-husky/gpt_academic/issues)."
|
||||||
|
description += "</br></br>普通对话使用说明: 1. 输入问题; 2. 点击提交"
|
||||||
|
description += "</br></br>基础功能区使用说明: 1. 输入文本; 2. 点击任意基础功能区按钮"
|
||||||
|
description += "</br></br>函数插件区使用说明: 1. 输入路径/问题, 或者上传文件; 2. 点击任意函数插件区按钮"
|
||||||
|
description += "</br></br>虚空终端使用说明: 点击虚空终端, 然后根据提示输入指令, 再次点击虚空终端"
|
||||||
|
description += "</br></br>如何保存对话: 点击保存当前的对话按钮"
|
||||||
|
description += "</br></br>如何语音对话: 请阅读Wiki"
|
||||||
|
description += "</br></br>如何临时更换API_KEY: 在输入区输入临时API_KEY后提交(网页刷新后失效)"
|
||||||
|
|
||||||
# 问询记录, python 版本建议3.9+(越新越好)
|
# 问询记录, python 版本建议3.9+(越新越好)
|
||||||
import logging, uuid
|
import logging, uuid
|
||||||
@@ -163,10 +162,16 @@ def main():
|
|||||||
checkboxes_2 = gr.CheckboxGroup(["自定义菜单"],
|
checkboxes_2 = gr.CheckboxGroup(["自定义菜单"],
|
||||||
value=[], label="显示/隐藏自定义菜单", elem_id='cbs').style(container=False)
|
value=[], label="显示/隐藏自定义菜单", elem_id='cbs').style(container=False)
|
||||||
dark_mode_btn = gr.Button("切换界面明暗 ☀", variant="secondary").style(size="sm")
|
dark_mode_btn = gr.Button("切换界面明暗 ☀", variant="secondary").style(size="sm")
|
||||||
dark_mode_btn.click(None, None, None, _js=js_code_for_toggle_darkmode,
|
dark_mode_btn.click(None, None, None, _js="""() => {
|
||||||
|
if (document.querySelectorAll('.dark').length) {
|
||||||
|
document.querySelectorAll('.dark').forEach(el => el.classList.remove('dark'));
|
||||||
|
} else {
|
||||||
|
document.querySelector('body').classList.add('dark');
|
||||||
|
}
|
||||||
|
}""",
|
||||||
)
|
)
|
||||||
with gr.Tab("帮助", elem_id="interact-panel"):
|
with gr.Tab("帮助", elem_id="interact-panel"):
|
||||||
gr.Markdown(help_menu_description)
|
gr.Markdown(description)
|
||||||
|
|
||||||
with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top") as area_input_secondary:
|
with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top") as area_input_secondary:
|
||||||
with gr.Accordion("浮动输入区", open=True, elem_id="input-panel2"):
|
with gr.Accordion("浮动输入区", open=True, elem_id="input-panel2"):
|
||||||
@@ -181,6 +186,16 @@ def main():
|
|||||||
stopBtn2 = gr.Button("停止", variant="secondary"); stopBtn2.style(size="sm")
|
stopBtn2 = gr.Button("停止", variant="secondary"); stopBtn2.style(size="sm")
|
||||||
clearBtn2 = gr.Button("清除", variant="secondary", visible=False); clearBtn2.style(size="sm")
|
clearBtn2 = gr.Button("清除", variant="secondary", visible=False); clearBtn2.style(size="sm")
|
||||||
|
|
||||||
|
def to_cookie_str(d):
|
||||||
|
# Pickle the dictionary and encode it as a string
|
||||||
|
pickled_dict = pickle.dumps(d)
|
||||||
|
cookie_value = base64.b64encode(pickled_dict).decode('utf-8')
|
||||||
|
return cookie_value
|
||||||
|
|
||||||
|
def from_cookie_str(c):
|
||||||
|
# Decode the base64-encoded string and unpickle it into a dictionary
|
||||||
|
pickled_dict = base64.b64decode(c.encode('utf-8'))
|
||||||
|
return pickle.loads(pickled_dict)
|
||||||
|
|
||||||
with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top") as area_customize:
|
with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top") as area_customize:
|
||||||
with gr.Accordion("自定义菜单", open=True, elem_id="edit-panel"):
|
with gr.Accordion("自定义菜单", open=True, elem_id="edit-panel"):
|
||||||
@@ -212,11 +227,11 @@ def main():
|
|||||||
else:
|
else:
|
||||||
ret.update({predefined_btns[basic_btn_dropdown_]: gr.update(visible=True, value=basic_fn_title)})
|
ret.update({predefined_btns[basic_btn_dropdown_]: gr.update(visible=True, value=basic_fn_title)})
|
||||||
ret.update({cookies: cookies_})
|
ret.update({cookies: cookies_})
|
||||||
try: persistent_cookie_ = from_cookie_str(persistent_cookie_) # persistent cookie to dict
|
try: persistent_cookie_ = from_cookie_str(persistent_cookie_) # persistent cookie to dict
|
||||||
except: persistent_cookie_ = {}
|
except: persistent_cookie_ = {}
|
||||||
persistent_cookie_["custom_bnt"] = customize_fn_overwrite_ # dict update new value
|
persistent_cookie_["custom_bnt"] = customize_fn_overwrite_ # dict update new value
|
||||||
persistent_cookie_ = to_cookie_str(persistent_cookie_) # persistent cookie to dict
|
persistent_cookie_ = to_cookie_str(persistent_cookie_) # persistent cookie to dict
|
||||||
ret.update({persistent_cookie: persistent_cookie_}) # write persistent cookie
|
ret.update({persistent_cookie: persistent_cookie_}) # write persistent cookie
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def reflesh_btn(persistent_cookie_, cookies_):
|
def reflesh_btn(persistent_cookie_, cookies_):
|
||||||
@@ -237,11 +252,10 @@ def main():
|
|||||||
else: ret.update({predefined_btns[k]: gr.update(visible=True, value=v['Title'])})
|
else: ret.update({predefined_btns[k]: gr.update(visible=True, value=v['Title'])})
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
basic_fn_load.click(reflesh_btn, [persistent_cookie, cookies], [cookies, *customize_btns.values(), *predefined_btns.values()])
|
basic_fn_load.click(reflesh_btn, [persistent_cookie, cookies],[cookies, *customize_btns.values(), *predefined_btns.values()])
|
||||||
h = basic_fn_confirm.click(assign_btn, [persistent_cookie, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix],
|
h = basic_fn_confirm.click(assign_btn, [persistent_cookie, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix],
|
||||||
[persistent_cookie, cookies, *customize_btns.values(), *predefined_btns.values()])
|
[persistent_cookie, cookies, *customize_btns.values(), *predefined_btns.values()])
|
||||||
# save persistent cookie
|
h.then(None, [persistent_cookie], None, _js="""(persistent_cookie)=>{setCookie("persistent_cookie", persistent_cookie, 5);}""") # save persistent cookie
|
||||||
h.then(None, [persistent_cookie], None, _js="""(persistent_cookie)=>{setCookie("persistent_cookie", persistent_cookie, 5);}""")
|
|
||||||
|
|
||||||
# 功能区显示开关与功能区的互动
|
# 功能区显示开关与功能区的互动
|
||||||
def fn_area_visibility(a):
|
def fn_area_visibility(a):
|
||||||
@@ -291,8 +305,8 @@ def main():
|
|||||||
click_handle = btn.click(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True), gr.State(btn.value)], outputs=output_combo)
|
click_handle = btn.click(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True), gr.State(btn.value)], outputs=output_combo)
|
||||||
cancel_handles.append(click_handle)
|
cancel_handles.append(click_handle)
|
||||||
# 文件上传区,接收文件后与chatbot的互动
|
# 文件上传区,接收文件后与chatbot的互动
|
||||||
file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt, txt2, checkboxes, cookies], [chatbot, txt, txt2, cookies]).then(None, None, None, _js=r"()=>{toast_push('上传完毕 ...'); cancel_loading_status();}")
|
file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt, txt2, checkboxes, cookies], [chatbot, txt, txt2, cookies])
|
||||||
file_upload_2.upload(on_file_uploaded, [file_upload_2, chatbot, txt, txt2, checkboxes, cookies], [chatbot, txt, txt2, cookies]).then(None, None, None, _js=r"()=>{toast_push('上传完毕 ...'); cancel_loading_status();}")
|
file_upload_2.upload(on_file_uploaded, [file_upload_2, chatbot, txt, txt2, checkboxes, cookies], [chatbot, txt, txt2, cookies])
|
||||||
# 函数插件-固定按钮区
|
# 函数插件-固定按钮区
|
||||||
for k in plugins:
|
for k in plugins:
|
||||||
if not plugins[k].get("AsButton", True): continue
|
if not plugins[k].get("AsButton", True): continue
|
||||||
@@ -328,7 +342,18 @@ def main():
|
|||||||
None,
|
None,
|
||||||
[secret_css],
|
[secret_css],
|
||||||
None,
|
None,
|
||||||
_js=js_code_for_css_changing
|
_js="""(css) => {
|
||||||
|
var existingStyles = document.querySelectorAll("style[data-loaded-css]");
|
||||||
|
for (var i = 0; i < existingStyles.length; i++) {
|
||||||
|
var style = existingStyles[i];
|
||||||
|
style.parentNode.removeChild(style);
|
||||||
|
}
|
||||||
|
var styleElement = document.createElement('style');
|
||||||
|
styleElement.setAttribute('data-loaded-css', css);
|
||||||
|
styleElement.innerHTML = css;
|
||||||
|
document.head.appendChild(styleElement);
|
||||||
|
}
|
||||||
|
"""
|
||||||
)
|
)
|
||||||
# 随变按钮的回调函数注册
|
# 随变按钮的回调函数注册
|
||||||
def route(request: gr.Request, k, *args, **kwargs):
|
def route(request: gr.Request, k, *args, **kwargs):
|
||||||
@@ -360,10 +385,27 @@ def main():
|
|||||||
rad.feed(cookies['uuid'].hex, audio)
|
rad.feed(cookies['uuid'].hex, audio)
|
||||||
audio_mic.stream(deal_audio, inputs=[audio_mic, cookies])
|
audio_mic.stream(deal_audio, inputs=[audio_mic, cookies])
|
||||||
|
|
||||||
|
def init_cookie(cookies, chatbot):
|
||||||
|
# 为每一位访问的用户赋予一个独一无二的uuid编码
|
||||||
|
cookies.update({'uuid': uuid.uuid4()})
|
||||||
|
return cookies
|
||||||
demo.load(init_cookie, inputs=[cookies, chatbot], outputs=[cookies])
|
demo.load(init_cookie, inputs=[cookies, chatbot], outputs=[cookies])
|
||||||
darkmode_js = js_code_for_darkmode_init
|
darkmode_js = """(dark) => {
|
||||||
demo.load(None, inputs=None, outputs=[persistent_cookie], _js=js_code_for_persistent_cookie_init)
|
dark = dark == "True";
|
||||||
|
if (document.querySelectorAll('.dark').length) {
|
||||||
|
if (!dark){
|
||||||
|
document.querySelectorAll('.dark').forEach(el => el.classList.remove('dark'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (dark){
|
||||||
|
document.querySelector('body').classList.add('dark');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
load_cookie_js = """(persistent_cookie) => {
|
||||||
|
return getCookie("persistent_cookie");
|
||||||
|
}"""
|
||||||
|
demo.load(None, inputs=None, outputs=[persistent_cookie], _js=load_cookie_js)
|
||||||
demo.load(None, inputs=[dark_mode], outputs=None, _js=darkmode_js) # 配置暗色主题或亮色主题
|
demo.load(None, inputs=[dark_mode], outputs=None, _js=darkmode_js) # 配置暗色主题或亮色主题
|
||||||
demo.load(None, inputs=[gr.Textbox(LAYOUT, visible=False)], outputs=None, _js='(LAYOUT)=>{GptAcademicJavaScriptInit(LAYOUT);}')
|
demo.load(None, inputs=[gr.Textbox(LAYOUT, visible=False)], outputs=None, _js='(LAYOUT)=>{GptAcademicJavaScriptInit(LAYOUT);}')
|
||||||
|
|
||||||
@@ -376,7 +418,7 @@ def main():
|
|||||||
|
|
||||||
def auto_updates(): time.sleep(0); auto_update()
|
def auto_updates(): time.sleep(0); auto_update()
|
||||||
def open_browser(): time.sleep(2); webbrowser.open_new_tab(f"http://localhost:{PORT}")
|
def open_browser(): time.sleep(2); webbrowser.open_new_tab(f"http://localhost:{PORT}")
|
||||||
def warm_up_mods(): time.sleep(6); warm_up_modules()
|
def warm_up_mods(): time.sleep(4); warm_up_modules()
|
||||||
|
|
||||||
threading.Thread(target=auto_updates, name="self-upgrade", daemon=True).start() # 查看自动更新
|
threading.Thread(target=auto_updates, name="self-upgrade", daemon=True).start() # 查看自动更新
|
||||||
threading.Thread(target=open_browser, name="open-browser", daemon=True).start() # 打开浏览器页面
|
threading.Thread(target=open_browser, name="open-browser", daemon=True).start() # 打开浏览器页面
|
||||||
|
|||||||
@@ -28,6 +28,12 @@ proxies, TIMEOUT_SECONDS, MAX_RETRY, API_ORG, AZURE_CFG_ARRAY = \
|
|||||||
timeout_bot_msg = '[Local Message] Request timeout. Network error. Please check proxy settings in config.py.' + \
|
timeout_bot_msg = '[Local Message] Request timeout. Network error. Please check proxy settings in config.py.' + \
|
||||||
'网络错误,检查代理服务器是否可用,以及代理设置的格式是否正确,格式须是[协议]://[地址]:[端口],缺一不可。'
|
'网络错误,检查代理服务器是否可用,以及代理设置的格式是否正确,格式须是[协议]://[地址]:[端口],缺一不可。'
|
||||||
|
|
||||||
|
def report_invalid_key(key):
|
||||||
|
if get_conf("BLOCK_INVALID_APIKEY"):
|
||||||
|
# 实验性功能,自动检测并屏蔽失效的KEY,请勿使用
|
||||||
|
from request_llms.key_manager import ApiKeyManager
|
||||||
|
api_key = ApiKeyManager().add_key_to_blacklist(key)
|
||||||
|
|
||||||
def get_full_error(chunk, stream_response):
|
def get_full_error(chunk, stream_response):
|
||||||
"""
|
"""
|
||||||
获取完整的从Openai返回的报错
|
获取完整的从Openai返回的报错
|
||||||
@@ -51,8 +57,7 @@ def decode_chunk(chunk):
|
|||||||
chunkjson = json.loads(chunk_decoded[6:])
|
chunkjson = json.loads(chunk_decoded[6:])
|
||||||
has_choices = 'choices' in chunkjson
|
has_choices = 'choices' in chunkjson
|
||||||
if has_choices: choice_valid = (len(chunkjson['choices']) > 0)
|
if has_choices: choice_valid = (len(chunkjson['choices']) > 0)
|
||||||
if has_choices and choice_valid: has_content = ("content" in chunkjson['choices'][0]["delta"])
|
if has_choices and choice_valid: has_content = "content" in chunkjson['choices'][0]["delta"]
|
||||||
if has_content: has_content = (chunkjson['choices'][0]["delta"]["content"] is not None)
|
|
||||||
if has_choices and choice_valid: has_role = "role" in chunkjson['choices'][0]["delta"]
|
if has_choices and choice_valid: has_role = "role" in chunkjson['choices'][0]["delta"]
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
@@ -83,7 +88,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
|
|||||||
用于负责跨越线程传递已经输出的部分,大部分时候仅仅为了fancy的视觉效果,留空即可。observe_window[0]:观测窗。observe_window[1]:看门狗
|
用于负责跨越线程传递已经输出的部分,大部分时候仅仅为了fancy的视觉效果,留空即可。observe_window[0]:观测窗。observe_window[1]:看门狗
|
||||||
"""
|
"""
|
||||||
watch_dog_patience = 5 # 看门狗的耐心, 设置5秒即可
|
watch_dog_patience = 5 # 看门狗的耐心, 设置5秒即可
|
||||||
headers, payload = generate_payload(inputs, llm_kwargs, history, system_prompt=sys_prompt, stream=True)
|
headers, payload, api_key = generate_payload(inputs, llm_kwargs, history, system_prompt=sys_prompt, stream=True)
|
||||||
retry = 0
|
retry = 0
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
@@ -113,6 +118,8 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
|
|||||||
if "reduce the length" in error_msg:
|
if "reduce the length" in error_msg:
|
||||||
raise ConnectionAbortedError("OpenAI拒绝了请求:" + error_msg)
|
raise ConnectionAbortedError("OpenAI拒绝了请求:" + error_msg)
|
||||||
else:
|
else:
|
||||||
|
if "API key has been deactivated" in error_msg: report_invalid_key(api_key)
|
||||||
|
elif "exceeded your current quota" in error_msg: report_invalid_key(api_key)
|
||||||
raise RuntimeError("OpenAI拒绝了请求:" + error_msg)
|
raise RuntimeError("OpenAI拒绝了请求:" + error_msg)
|
||||||
if ('data: [DONE]' in chunk): break # api2d 正常完成
|
if ('data: [DONE]' in chunk): break # api2d 正常完成
|
||||||
json_data = json.loads(chunk.lstrip('data:'))['choices'][0]
|
json_data = json.loads(chunk.lstrip('data:'))['choices'][0]
|
||||||
@@ -175,7 +182,7 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
headers, payload = generate_payload(inputs, llm_kwargs, history, system_prompt, stream)
|
headers, payload, api_key = generate_payload(inputs, llm_kwargs, history, system_prompt, stream)
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
chatbot[-1] = (inputs, f"您提供的api-key不满足要求,不包含任何可用于{llm_kwargs['llm_model']}的api-key。您可能选择了错误的模型或请求源。")
|
chatbot[-1] = (inputs, f"您提供的api-key不满足要求,不包含任何可用于{llm_kwargs['llm_model']}的api-key。您可能选择了错误的模型或请求源。")
|
||||||
yield from update_ui(chatbot=chatbot, history=history, msg="api-key不满足要求") # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history, msg="api-key不满足要求") # 刷新界面
|
||||||
@@ -223,7 +230,7 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
yield from update_ui(chatbot=chatbot, history=history, msg="检测到有缺陷的非OpenAI官方接口,建议选择更稳定的接口。")
|
yield from update_ui(chatbot=chatbot, history=history, msg="检测到有缺陷的非OpenAI官方接口,建议选择更稳定的接口。")
|
||||||
break
|
break
|
||||||
# 其他情况,直接返回报错
|
# 其他情况,直接返回报错
|
||||||
chatbot, history = handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg)
|
chatbot, history = handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg, api_key)
|
||||||
yield from update_ui(chatbot=chatbot, history=history, msg="非OpenAI官方接口返回了错误:" + chunk.decode()) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history, msg="非OpenAI官方接口返回了错误:" + chunk.decode()) # 刷新界面
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -265,12 +272,12 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
|
|||||||
chunk = get_full_error(chunk, stream_response)
|
chunk = get_full_error(chunk, stream_response)
|
||||||
chunk_decoded = chunk.decode()
|
chunk_decoded = chunk.decode()
|
||||||
error_msg = chunk_decoded
|
error_msg = chunk_decoded
|
||||||
chatbot, history = handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg)
|
chatbot, history = handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg, api_key)
|
||||||
yield from update_ui(chatbot=chatbot, history=history, msg="Json异常" + error_msg) # 刷新界面
|
yield from update_ui(chatbot=chatbot, history=history, msg="Json异常" + error_msg) # 刷新界面
|
||||||
print(error_msg)
|
print(error_msg)
|
||||||
return
|
return
|
||||||
|
|
||||||
def handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg):
|
def handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg, api_key=""):
|
||||||
from .bridge_all import model_info
|
from .bridge_all import model_info
|
||||||
openai_website = ' 请登录OpenAI查看详情 https://platform.openai.com/signup'
|
openai_website = ' 请登录OpenAI查看详情 https://platform.openai.com/signup'
|
||||||
if "reduce the length" in error_msg:
|
if "reduce the length" in error_msg:
|
||||||
@@ -281,15 +288,15 @@ def handle_error(inputs, llm_kwargs, chatbot, history, chunk_decoded, error_msg)
|
|||||||
elif "does not exist" in error_msg:
|
elif "does not exist" in error_msg:
|
||||||
chatbot[-1] = (chatbot[-1][0], f"[Local Message] Model {llm_kwargs['llm_model']} does not exist. 模型不存在, 或者您没有获得体验资格.")
|
chatbot[-1] = (chatbot[-1][0], f"[Local Message] Model {llm_kwargs['llm_model']} does not exist. 模型不存在, 或者您没有获得体验资格.")
|
||||||
elif "Incorrect API key" in error_msg:
|
elif "Incorrect API key" in error_msg:
|
||||||
chatbot[-1] = (chatbot[-1][0], "[Local Message] Incorrect API key. OpenAI以提供了不正确的API_KEY为由, 拒绝服务. " + openai_website)
|
chatbot[-1] = (chatbot[-1][0], "[Local Message] Incorrect API key. OpenAI以提供了不正确的API_KEY为由, 拒绝服务. " + openai_website); report_invalid_key(api_key)
|
||||||
elif "exceeded your current quota" in error_msg:
|
elif "exceeded your current quota" in error_msg:
|
||||||
chatbot[-1] = (chatbot[-1][0], "[Local Message] You exceeded your current quota. OpenAI以账户额度不足为由, 拒绝服务." + openai_website)
|
chatbot[-1] = (chatbot[-1][0], "[Local Message] You exceeded your current quota. OpenAI以账户额度不足为由, 拒绝服务." + openai_website); report_invalid_key(api_key)
|
||||||
elif "account is not active" in error_msg:
|
elif "account is not active" in error_msg:
|
||||||
chatbot[-1] = (chatbot[-1][0], "[Local Message] Your account is not active. OpenAI以账户失效为由, 拒绝服务." + openai_website)
|
chatbot[-1] = (chatbot[-1][0], "[Local Message] Your account is not active. OpenAI以账户失效为由, 拒绝服务." + openai_website); report_invalid_key(api_key)
|
||||||
elif "associated with a deactivated account" in error_msg:
|
elif "associated with a deactivated account" in error_msg:
|
||||||
chatbot[-1] = (chatbot[-1][0], "[Local Message] You are associated with a deactivated account. OpenAI以账户失效为由, 拒绝服务." + openai_website)
|
chatbot[-1] = (chatbot[-1][0], "[Local Message] You are associated with a deactivated account. OpenAI以账户失效为由, 拒绝服务." + openai_website); report_invalid_key(api_key)
|
||||||
elif "API key has been deactivated" in error_msg:
|
elif "API key has been deactivated" in error_msg:
|
||||||
chatbot[-1] = (chatbot[-1][0], "[Local Message] API key has been deactivated. OpenAI以账户失效为由, 拒绝服务." + openai_website)
|
chatbot[-1] = (chatbot[-1][0], "[Local Message] API key has been deactivated. OpenAI以账户失效为由, 拒绝服务." + openai_website); report_invalid_key(api_key)
|
||||||
elif "bad forward key" in error_msg:
|
elif "bad forward key" in error_msg:
|
||||||
chatbot[-1] = (chatbot[-1][0], "[Local Message] Bad forward key. API2D账户额度不足.")
|
chatbot[-1] = (chatbot[-1][0], "[Local Message] Bad forward key. API2D账户额度不足.")
|
||||||
elif "Not enough point" in error_msg:
|
elif "Not enough point" in error_msg:
|
||||||
@@ -372,6 +379,6 @@ def generate_payload(inputs, llm_kwargs, history, system_prompt, stream):
|
|||||||
print(f" {llm_kwargs['llm_model']} : {conversation_cnt} : {inputs[:100]} ..........")
|
print(f" {llm_kwargs['llm_model']} : {conversation_cnt} : {inputs[:100]} ..........")
|
||||||
except:
|
except:
|
||||||
print('输入中可能存在乱码。')
|
print('输入中可能存在乱码。')
|
||||||
return headers,payload
|
return headers, payload, api_key
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import random
|
import random
|
||||||
|
import os
|
||||||
|
from toolbox import get_log_folder
|
||||||
|
|
||||||
def Singleton(cls):
|
def Singleton(cls):
|
||||||
_instance = {}
|
_instance = {}
|
||||||
@@ -12,18 +14,41 @@ def Singleton(cls):
|
|||||||
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class OpenAI_ApiKeyManager():
|
class ApiKeyManager():
|
||||||
|
"""
|
||||||
|
只把失效的key保存在内存中
|
||||||
|
"""
|
||||||
def __init__(self, mode='blacklist') -> None:
|
def __init__(self, mode='blacklist') -> None:
|
||||||
# self.key_avail_list = []
|
# self.key_avail_list = []
|
||||||
self.key_black_list = []
|
self.key_black_list = []
|
||||||
|
self.debug = False
|
||||||
|
self.log = True
|
||||||
|
self.remain_keys = []
|
||||||
|
|
||||||
def add_key_to_blacklist(self, key):
|
def add_key_to_blacklist(self, key):
|
||||||
self.key_black_list.append(key)
|
self.key_black_list.append(key)
|
||||||
|
if self.debug: print('black list key added', key)
|
||||||
|
if self.log:
|
||||||
|
with open(
|
||||||
|
os.path.join(get_log_folder(user='admin', plugin_name='api_key_manager'), 'invalid_key.log'), 'a+', encoding='utf8') as f:
|
||||||
|
summary = 'num blacklist keys:' + str(len(self.key_black_list)) + '\tnum valid keys:' + str(len(self.remain_keys))
|
||||||
|
f.write('\n\n' + summary + '\n')
|
||||||
|
f.write('---- <add blacklist key> ----\n')
|
||||||
|
f.write(key)
|
||||||
|
f.write('\n')
|
||||||
|
f.write('---- <all blacklist keys> ----\n')
|
||||||
|
f.write(str(self.key_black_list))
|
||||||
|
f.write('\n')
|
||||||
|
f.write('---- <remain keys> ----\n')
|
||||||
|
f.write(str(self.remain_keys))
|
||||||
|
f.write('\n')
|
||||||
|
|
||||||
def select_avail_key(self, key_list):
|
def select_avail_key(self, key_list):
|
||||||
# select key from key_list, but avoid keys also in self.key_black_list, raise error if no key can be found
|
# select key from key_list, but avoid keys also in self.key_black_list, raise error if no key can be found
|
||||||
available_keys = [key for key in key_list if key not in self.key_black_list]
|
available_keys = [key for key in key_list if key not in self.key_black_list]
|
||||||
if not available_keys:
|
if not available_keys:
|
||||||
raise KeyError("No available key found.")
|
raise KeyError("所有API KEY都被OPENAI拒绝了")
|
||||||
selected_key = random.choice(available_keys)
|
selected_key = random.choice(available_keys)
|
||||||
|
if self.debug: print('total keys', len(key_list), 'valid keys', len(available_keys))
|
||||||
|
if self.log: self.remain_keys = available_keys
|
||||||
return selected_key
|
return selected_key
|
||||||
@@ -183,11 +183,11 @@ class LocalLLMHandle(Process):
|
|||||||
def stream_chat(self, **kwargs):
|
def stream_chat(self, **kwargs):
|
||||||
# ⭐run in main process
|
# ⭐run in main process
|
||||||
if self.get_state() == "`准备就绪`":
|
if self.get_state() == "`准备就绪`":
|
||||||
yield "`正在等待线程锁,排队中请稍候 ...`"
|
yield "`正在等待线程锁,排队中请稍后 ...`"
|
||||||
|
|
||||||
with self.threadLock:
|
with self.threadLock:
|
||||||
if self.parent.poll():
|
if self.parent.poll():
|
||||||
yield "`排队中请稍候 ...`"
|
yield "`排队中请稍后 ...`"
|
||||||
self.clear_pending_messages()
|
self.clear_pending_messages()
|
||||||
self.parent.send(kwargs)
|
self.parent.send(kwargs)
|
||||||
std_out = ""
|
std_out = ""
|
||||||
|
|||||||
@@ -6,3 +6,5 @@ sentencepiece
|
|||||||
numpy
|
numpy
|
||||||
onnxruntime
|
onnxruntime
|
||||||
sentencepiece
|
sentencepiece
|
||||||
|
streamlit
|
||||||
|
streamlit-chat
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ accelerate
|
|||||||
matplotlib
|
matplotlib
|
||||||
huggingface_hub
|
huggingface_hub
|
||||||
triton
|
triton
|
||||||
|
streamlit
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ pypdf2==2.12.1
|
|||||||
tiktoken>=0.3.3
|
tiktoken>=0.3.3
|
||||||
requests[socks]
|
requests[socks]
|
||||||
pydantic==1.10.11
|
pydantic==1.10.11
|
||||||
protobuf==3.18
|
|
||||||
transformers>=4.27.1
|
transformers>=4.27.1
|
||||||
scipdf_parser>=0.52
|
scipdf_parser>=0.52
|
||||||
python-markdown-math
|
python-markdown-math
|
||||||
|
|||||||
314
themes/common.js
314
themes/common.js
@@ -1,13 +1,9 @@
|
|||||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
||||||
// 第 1 部分: 工具函数
|
|
||||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
||||||
|
|
||||||
function gradioApp() {
|
function gradioApp() {
|
||||||
// https://github.com/GaiZhenbiao/ChuanhuChatGPT/tree/main/web_assets/javascript
|
// https://github.com/GaiZhenbiao/ChuanhuChatGPT/tree/main/web_assets/javascript
|
||||||
const elems = document.getElementsByTagName('gradio-app');
|
const elems = document.getElementsByTagName('gradio-app');
|
||||||
const elem = elems.length == 0 ? document : elems[0];
|
const elem = elems.length == 0 ? document : elems[0];
|
||||||
if (elem !== document) {
|
if (elem !== document) {
|
||||||
elem.getElementById = function (id) {
|
elem.getElementById = function(id) {
|
||||||
return document.getElementById(id);
|
return document.getElementById(id);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -18,9 +14,9 @@ function setCookie(name, value, days) {
|
|||||||
var expires = "";
|
var expires = "";
|
||||||
|
|
||||||
if (days) {
|
if (days) {
|
||||||
var date = new Date();
|
var date = new Date();
|
||||||
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||||
expires = "; expires=" + date.toUTCString();
|
expires = "; expires=" + date.toUTCString();
|
||||||
}
|
}
|
||||||
|
|
||||||
document.cookie = name + "=" + value + expires + "; path=/";
|
document.cookie = name + "=" + value + expires + "; path=/";
|
||||||
@@ -31,60 +27,15 @@ function getCookie(name) {
|
|||||||
var cookies = decodedCookie.split(';');
|
var cookies = decodedCookie.split(';');
|
||||||
|
|
||||||
for (var i = 0; i < cookies.length; i++) {
|
for (var i = 0; i < cookies.length; i++) {
|
||||||
var cookie = cookies[i].trim();
|
var cookie = cookies[i].trim();
|
||||||
|
|
||||||
if (cookie.indexOf(name + "=") === 0) {
|
if (cookie.indexOf(name + "=") === 0) {
|
||||||
return cookie.substring(name.length + 1, cookie.length);
|
return cookie.substring(name.length + 1, cookie.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let toastCount = 0;
|
|
||||||
function toast_push(msg, duration) {
|
|
||||||
duration = isNaN(duration) ? 3000 : duration;
|
|
||||||
const existingToasts = document.querySelectorAll('.toast');
|
|
||||||
existingToasts.forEach(toast => {
|
|
||||||
toast.style.top = `${parseInt(toast.style.top, 10) - 70}px`;
|
|
||||||
});
|
|
||||||
const m = document.createElement('div');
|
|
||||||
m.innerHTML = msg;
|
|
||||||
m.classList.add('toast');
|
|
||||||
m.style.cssText = `font-size: var(--text-md) !important; color: rgb(255, 255, 255); background-color: rgba(0, 0, 0, 0.6); padding: 10px 15px; border-radius: 4px; position: fixed; top: ${50 + toastCount * 70}%; left: 50%; transform: translateX(-50%); width: auto; text-align: center; transition: top 0.3s;`;
|
|
||||||
document.body.appendChild(m);
|
|
||||||
setTimeout(function () {
|
|
||||||
m.style.opacity = '0';
|
|
||||||
setTimeout(function () {
|
|
||||||
document.body.removeChild(m);
|
|
||||||
toastCount--;
|
|
||||||
}, 500);
|
|
||||||
}, duration);
|
|
||||||
toastCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
function toast_up(msg) {
|
|
||||||
var m = document.getElementById('toast_up');
|
|
||||||
if (m) {
|
|
||||||
document.body.removeChild(m); // remove the loader from the body
|
|
||||||
}
|
|
||||||
m = document.createElement('div');
|
|
||||||
m.id = 'toast_up';
|
|
||||||
m.innerHTML = msg;
|
|
||||||
m.style.cssText = "font-size: var(--text-md) !important; color: rgb(255, 255, 255); background-color: rgba(0, 0, 100, 0.6); padding: 10px 15px; margin: 0 0 0 -60px; border-radius: 4px; position: fixed; top: 50%; left: 50%; width: auto; text-align: center;";
|
|
||||||
document.body.appendChild(m);
|
|
||||||
}
|
|
||||||
function toast_down() {
|
|
||||||
var m = document.getElementById('toast_up');
|
|
||||||
if (m) {
|
|
||||||
document.body.removeChild(m); // remove the loader from the body
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
||||||
// 第 2 部分: 复制按钮
|
|
||||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
||||||
|
|
||||||
function addCopyButton(botElement) {
|
function addCopyButton(botElement) {
|
||||||
// https://github.com/GaiZhenbiao/ChuanhuChatGPT/tree/main/web_assets/javascript
|
// https://github.com/GaiZhenbiao/ChuanhuChatGPT/tree/main/web_assets/javascript
|
||||||
@@ -147,27 +98,23 @@ function chatbotContentChanged(attempt = 1, force = false) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function chatbotAutoHeight(){
|
||||||
|
|
||||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
||||||
// 第 3 部分: chatbot动态高度调整
|
|
||||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
||||||
|
|
||||||
function chatbotAutoHeight() {
|
|
||||||
// 自动调整高度
|
// 自动调整高度
|
||||||
function update_height() {
|
function update_height(){
|
||||||
var { panel_height_target, chatbot_height, chatbot } = get_elements(true);
|
var { panel_height_target, chatbot_height, chatbot } = get_elements(true);
|
||||||
if (panel_height_target != chatbot_height) {
|
if (panel_height_target!=chatbot_height)
|
||||||
|
{
|
||||||
var pixelString = panel_height_target.toString() + 'px';
|
var pixelString = panel_height_target.toString() + 'px';
|
||||||
chatbot.style.maxHeight = pixelString; chatbot.style.height = pixelString;
|
chatbot.style.maxHeight = pixelString; chatbot.style.height = pixelString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function update_height_slow() {
|
function update_height_slow(){
|
||||||
var { panel_height_target, chatbot_height, chatbot } = get_elements();
|
var { panel_height_target, chatbot_height, chatbot } = get_elements();
|
||||||
if (panel_height_target != chatbot_height) {
|
if (panel_height_target!=chatbot_height)
|
||||||
new_panel_height = (panel_height_target - chatbot_height) * 0.5 + chatbot_height;
|
{
|
||||||
if (Math.abs(new_panel_height - panel_height_target) < 10) {
|
new_panel_height = (panel_height_target - chatbot_height)*0.5 + chatbot_height;
|
||||||
|
if (Math.abs(new_panel_height - panel_height_target) < 10){
|
||||||
new_panel_height = panel_height_target;
|
new_panel_height = panel_height_target;
|
||||||
}
|
}
|
||||||
// console.log(chatbot_height, panel_height_target, new_panel_height);
|
// console.log(chatbot_height, panel_height_target, new_panel_height);
|
||||||
@@ -177,12 +124,21 @@ function chatbotAutoHeight() {
|
|||||||
}
|
}
|
||||||
monitoring_input_box()
|
monitoring_input_box()
|
||||||
update_height();
|
update_height();
|
||||||
setInterval(function () {
|
setInterval(function() {
|
||||||
update_height_slow()
|
update_height_slow()
|
||||||
}, 50); // 每100毫秒执行一次
|
}, 50); // 每100毫秒执行一次
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_elements(consider_state_panel = false) {
|
function GptAcademicJavaScriptInit(LAYOUT = "LEFT-RIGHT") {
|
||||||
|
chatbotIndicator = gradioApp().querySelector('#gpt-chatbot > div.wrap');
|
||||||
|
var chatbotObserver = new MutationObserver(() => {
|
||||||
|
chatbotContentChanged(1);
|
||||||
|
});
|
||||||
|
chatbotObserver.observe(chatbotIndicator, { attributes: true, childList: true, subtree: true });
|
||||||
|
if (LAYOUT === "LEFT-RIGHT") {chatbotAutoHeight();}
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_elements(consider_state_panel=false) {
|
||||||
var chatbot = document.querySelector('#gpt-chatbot > div.wrap.svelte-18telvq');
|
var chatbot = document.querySelector('#gpt-chatbot > div.wrap.svelte-18telvq');
|
||||||
if (!chatbot) {
|
if (!chatbot) {
|
||||||
chatbot = document.querySelector('#gpt-chatbot');
|
chatbot = document.querySelector('#gpt-chatbot');
|
||||||
@@ -193,13 +149,13 @@ function get_elements(consider_state_panel = false) {
|
|||||||
// const panel4 = document.querySelector('#interact-panel').getBoundingClientRect();
|
// const panel4 = document.querySelector('#interact-panel').getBoundingClientRect();
|
||||||
const panel5 = document.querySelector('#input-panel2').getBoundingClientRect();
|
const panel5 = document.querySelector('#input-panel2').getBoundingClientRect();
|
||||||
const panel_active = document.querySelector('#state-panel').getBoundingClientRect();
|
const panel_active = document.querySelector('#state-panel').getBoundingClientRect();
|
||||||
if (consider_state_panel || panel_active.height < 25) {
|
if (consider_state_panel || panel_active.height < 25){
|
||||||
document.state_panel_height = panel_active.height;
|
document.state_panel_height = panel_active.height;
|
||||||
}
|
}
|
||||||
// 25 是chatbot的label高度, 16 是右侧的gap
|
// 25 是chatbot的label高度, 16 是右侧的gap
|
||||||
var panel_height_target = panel1.height + panel2.height + panel3.height + 0 + 0 - 25 + 16 * 2;
|
var panel_height_target = panel1.height + panel2.height + panel3.height + 0 + 0 - 25 + 16*2;
|
||||||
// 禁止动态的state-panel高度影响
|
// 禁止动态的state-panel高度影响
|
||||||
panel_height_target = panel_height_target + (document.state_panel_height - panel_active.height)
|
panel_height_target = panel_height_target + (document.state_panel_height-panel_active.height)
|
||||||
var panel_height_target = parseInt(panel_height_target);
|
var panel_height_target = parseInt(panel_height_target);
|
||||||
var chatbot_height = chatbot.style.height;
|
var chatbot_height = chatbot.style.height;
|
||||||
var chatbot_height = parseInt(chatbot_height);
|
var chatbot_height = parseInt(chatbot_height);
|
||||||
@@ -207,18 +163,6 @@ function get_elements(consider_state_panel = false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
||||||
// 第 4 部分: 粘贴、拖拽文件上传
|
|
||||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
||||||
|
|
||||||
var elem_upload = null;
|
|
||||||
var elem_upload_float = null;
|
|
||||||
var elem_input_main = null;
|
|
||||||
var elem_input_float = null;
|
|
||||||
var elem_chatbot = null;
|
|
||||||
var exist_file_msg = '⚠️请先删除上传区(左上方)中的历史文件,再尝试上传。'
|
|
||||||
|
|
||||||
function add_func_paste(input) {
|
function add_func_paste(input) {
|
||||||
let paste_files = [];
|
let paste_files = [];
|
||||||
if (input) {
|
if (input) {
|
||||||
@@ -236,7 +180,7 @@ function add_func_paste(input) {
|
|||||||
}
|
}
|
||||||
if (paste_files.length > 0) {
|
if (paste_files.length > 0) {
|
||||||
// 按照文件列表执行批量上传逻辑
|
// 按照文件列表执行批量上传逻辑
|
||||||
await upload_files(paste_files);
|
await paste_upload_files(paste_files);
|
||||||
paste_files = []
|
paste_files = []
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -245,43 +189,8 @@ function add_func_paste(input) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function add_func_drag(elem) {
|
|
||||||
if (elem) {
|
|
||||||
const dragEvents = ["dragover"];
|
|
||||||
const leaveEvents = ["dragleave", "dragend", "drop"];
|
|
||||||
|
|
||||||
const onDrag = function (e) {
|
async function paste_upload_files(files) {
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
if (elem_upload_float.querySelector("input[type=file]")) {
|
|
||||||
toast_up('⚠️释放以上传文件')
|
|
||||||
} else {
|
|
||||||
toast_up(exist_file_msg)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onLeave = function (e) {
|
|
||||||
toast_down();
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
};
|
|
||||||
|
|
||||||
dragEvents.forEach(event => {
|
|
||||||
elem.addEventListener(event, onDrag);
|
|
||||||
});
|
|
||||||
|
|
||||||
leaveEvents.forEach(event => {
|
|
||||||
elem.addEventListener(event, onLeave);
|
|
||||||
});
|
|
||||||
|
|
||||||
elem.addEventListener("drop", async function (e) {
|
|
||||||
const files = e.dataTransfer.files;
|
|
||||||
await upload_files(files);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function upload_files(files) {
|
|
||||||
const uploadInputElement = elem_upload_float.querySelector("input[type=file]");
|
const uploadInputElement = elem_upload_float.querySelector("input[type=file]");
|
||||||
let totalSizeMb = 0
|
let totalSizeMb = 0
|
||||||
if (files && files.length > 0) {
|
if (files && files.length > 0) {
|
||||||
@@ -293,101 +202,59 @@ async function upload_files(files) {
|
|||||||
}
|
}
|
||||||
// 检查文件总大小是否超过20MB
|
// 检查文件总大小是否超过20MB
|
||||||
if (totalSizeMb > 20) {
|
if (totalSizeMb > 20) {
|
||||||
toast_push('⚠️文件夹大于 20MB 🚀上传文件中', 3000)
|
toast_push('⚠️文件夹大于20MB 🚀上传文件中', 2000)
|
||||||
// return; // 如果超过了指定大小, 可以不进行后续上传操作
|
// return; // 如果超过了指定大小, 可以不进行后续上传操作
|
||||||
}
|
}
|
||||||
// 监听change事件, 原生Gradio可以实现
|
// 监听change事件, 原生Gradio可以实现
|
||||||
// uploadInputElement.addEventListener('change', function(){replace_input_string()});
|
// uploadInputElement.addEventListener('change', function(){replace_input_string()});
|
||||||
let event = new Event("change");
|
let event = new Event("change");
|
||||||
Object.defineProperty(event, "target", { value: uploadInputElement, enumerable: true });
|
Object.defineProperty(event, "target", {value: uploadInputElement, enumerable: true});
|
||||||
Object.defineProperty(event, "currentTarget", { value: uploadInputElement, enumerable: true });
|
Object.defineProperty(event, "currentTarget", {value: uploadInputElement, enumerable: true});
|
||||||
Object.defineProperty(uploadInputElement, "files", { value: files, enumerable: true });
|
Object.defineProperty(uploadInputElement, "files", {value: files, enumerable: true});
|
||||||
uploadInputElement.dispatchEvent(event);
|
uploadInputElement.dispatchEvent(event);
|
||||||
|
// toast_push('🎉上传文件成功', 2000)
|
||||||
} else {
|
} else {
|
||||||
toast_push(exist_file_msg, 3000)
|
toast_push('⚠️请先删除上传区中的历史文件,再尝试粘贴。', 2000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//提示信息 封装
|
||||||
function begin_loading_status() {
|
function toast_push(msg, duration) {
|
||||||
// Create the loader div and add styling
|
duration = isNaN(duration) ? 3000 : duration;
|
||||||
var loader = document.createElement('div');
|
const m = document.createElement('div');
|
||||||
loader.id = 'Js_File_Loading';
|
m.innerHTML = msg;
|
||||||
loader.style.position = "absolute";
|
m.style.cssText = "font-size: var(--text-md) !important; color: rgb(255, 255, 255);background-color: rgba(0, 0, 0, 0.6);padding: 10px 15px;margin: 0 0 0 -60px;border-radius: 4px;position: fixed; top: 50%;left: 50%;width: auto; text-align: center;";
|
||||||
loader.style.top = "50%";
|
document.body.appendChild(m);
|
||||||
loader.style.left = "50%";
|
setTimeout(function () {
|
||||||
loader.style.width = "60px";
|
var d = 0.5;
|
||||||
loader.style.height = "60px";
|
m.style.opacity = '0';
|
||||||
loader.style.border = "16px solid #f3f3f3";
|
setTimeout(function () {
|
||||||
loader.style.borderTop = "16px solid #3498db";
|
document.body.removeChild(m)
|
||||||
loader.style.borderRadius = "50%";
|
}, d * 1000);
|
||||||
loader.style.animation = "spin 2s linear infinite";
|
}, duration);
|
||||||
loader.style.transform = "translate(-50%, -50%)";
|
|
||||||
document.body.appendChild(loader); // Add the loader to the body
|
|
||||||
// Set the CSS animation keyframes
|
|
||||||
var styleSheet = document.createElement('style');
|
|
||||||
// styleSheet.type = 'text/css';
|
|
||||||
styleSheet.id = 'Js_File_Loading_Style'
|
|
||||||
styleSheet.innerText = `
|
|
||||||
@keyframes spin {
|
|
||||||
0% { transform: rotate(0deg); }
|
|
||||||
100% { transform: rotate(360deg); }
|
|
||||||
}`;
|
|
||||||
document.head.appendChild(styleSheet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancel_loading_status() {
|
var elem_upload = null;
|
||||||
var loadingElement = document.getElementById('Js_File_Loading');
|
var elem_upload_float = null;
|
||||||
if (loadingElement) {
|
var elem_input_main = null;
|
||||||
document.body.removeChild(loadingElement); // remove the loader from the body
|
var elem_input_float = null;
|
||||||
}
|
|
||||||
var loadingStyle = document.getElementById('Js_File_Loading_Style');
|
|
||||||
if (loadingStyle) {
|
|
||||||
document.head.removeChild(loadingStyle);
|
|
||||||
}
|
|
||||||
let clearButton = document.querySelectorAll('div[id*="elem_upload"] button[aria-label="Clear"]');
|
|
||||||
for (let button of clearButton) {
|
|
||||||
button.addEventListener('click', function () {
|
|
||||||
setTimeout(function () {
|
|
||||||
register_upload_event();
|
|
||||||
}, 50);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function register_upload_event() {
|
|
||||||
elem_upload_float = document.getElementById('elem_upload_float')
|
|
||||||
const upload_component = elem_upload_float.querySelector("input[type=file]");
|
|
||||||
if (upload_component) {
|
|
||||||
upload_component.addEventListener('change', function (event) {
|
|
||||||
toast_push('正在上传中,请稍等。', 2000);
|
|
||||||
begin_loading_status();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function monitoring_input_box() {
|
function monitoring_input_box() {
|
||||||
register_upload_event();
|
|
||||||
|
|
||||||
elem_upload = document.getElementById('elem_upload')
|
elem_upload = document.getElementById('elem_upload')
|
||||||
elem_upload_float = document.getElementById('elem_upload_float')
|
elem_upload_float = document.getElementById('elem_upload_float')
|
||||||
elem_input_main = document.getElementById('user_input_main')
|
elem_input_main = document.getElementById('user_input_main')
|
||||||
elem_input_float = document.getElementById('user_input_float')
|
elem_input_float = document.getElementById('user_input_float')
|
||||||
elem_chatbot = document.getElementById('gpt-chatbot')
|
|
||||||
|
|
||||||
if (elem_input_main) {
|
if (elem_input_main) {
|
||||||
if (elem_input_main.querySelector("textarea")) {
|
if (elem_input_main.querySelector("textarea")) {
|
||||||
add_func_paste(elem_input_main.querySelector("textarea"))
|
add_func_paste(elem_input_main.querySelector("textarea"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (elem_input_float) {
|
if (elem_input_float) {
|
||||||
if (elem_input_float.querySelector("textarea")) {
|
if (elem_input_float.querySelector("textarea")){
|
||||||
add_func_paste(elem_input_float.querySelector("textarea"))
|
add_func_paste(elem_input_float.querySelector("textarea"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (elem_chatbot) {
|
|
||||||
add_func_drag(elem_chatbot)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -396,64 +263,3 @@ window.addEventListener("DOMContentLoaded", function () {
|
|||||||
// const ga = document.getElementsByTagName("gradio-app");
|
// const ga = document.getElementsByTagName("gradio-app");
|
||||||
gradioApp().addEventListener("render", monitoring_input_box);
|
gradioApp().addEventListener("render", monitoring_input_box);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
||||||
// 第 5 部分: 音频按钮样式变化
|
|
||||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
||||||
|
|
||||||
function audio_fn_init() {
|
|
||||||
let audio_component = document.getElementById('elem_audio');
|
|
||||||
if (audio_component) {
|
|
||||||
let buttonElement = audio_component.querySelector('button');
|
|
||||||
let specificElement = audio_component.querySelector('.hide.sr-only');
|
|
||||||
specificElement.remove();
|
|
||||||
|
|
||||||
buttonElement.childNodes[1].nodeValue = '启动麦克风';
|
|
||||||
buttonElement.addEventListener('click', function (event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
toast_push('您启动了麦克风!下一步请点击“实时语音对话”启动语音对话。');
|
|
||||||
});
|
|
||||||
|
|
||||||
// 查找语音插件按钮
|
|
||||||
let buttons = document.querySelectorAll('button');
|
|
||||||
let audio_button = null;
|
|
||||||
for (let button of buttons) {
|
|
||||||
if (button.textContent.includes('语音')) {
|
|
||||||
audio_button = button;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (audio_button) {
|
|
||||||
audio_button.addEventListener('click', function () {
|
|
||||||
toast_push('您点击了“实时语音对话”启动语音对话。');
|
|
||||||
});
|
|
||||||
let parent_element = audio_component.parentElement; // 将buttonElement移动到audio_button的内部
|
|
||||||
audio_button.appendChild(audio_component);
|
|
||||||
buttonElement.style.cssText = 'border-color: #00ffe0;border-width: 2px; height: 25px;'
|
|
||||||
parent_element.remove();
|
|
||||||
audio_component.style.cssText = 'width: 250px;right: 0px;display: inline-flex;flex-flow: row-reverse wrap;place-content: stretch space-between;align-items: center;background-color: #ffffff00;';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
||||||
// 第 6 部分: JS初始化函数
|
|
||||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
||||||
|
|
||||||
function GptAcademicJavaScriptInit(LAYOUT = "LEFT-RIGHT") {
|
|
||||||
audio_fn_init();
|
|
||||||
chatbotIndicator = gradioApp().querySelector('#gpt-chatbot > div.wrap');
|
|
||||||
var chatbotObserver = new MutationObserver(() => {
|
|
||||||
chatbotContentChanged(1);
|
|
||||||
});
|
|
||||||
chatbotObserver.observe(chatbotIndicator, { attributes: true, childList: true, subtree: true });
|
|
||||||
if (LAYOUT === "LEFT-RIGHT") { chatbotAutoHeight(); }
|
|
||||||
}
|
|
||||||
101
themes/theme.py
101
themes/theme.py
@@ -1,14 +1,6 @@
|
|||||||
import pickle
|
import gradio as gr
|
||||||
import base64
|
|
||||||
import uuid
|
|
||||||
from toolbox import get_conf
|
from toolbox import get_conf
|
||||||
|
THEME = get_conf('THEME')
|
||||||
"""
|
|
||||||
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
||||||
第 1 部分
|
|
||||||
加载主题相关的工具函数
|
|
||||||
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
||||||
"""
|
|
||||||
|
|
||||||
def load_dynamic_theme(THEME):
|
def load_dynamic_theme(THEME):
|
||||||
adjust_dynamic_theme = None
|
adjust_dynamic_theme = None
|
||||||
@@ -28,91 +20,4 @@ def load_dynamic_theme(THEME):
|
|||||||
theme_declaration = ""
|
theme_declaration = ""
|
||||||
return adjust_theme, advanced_css, theme_declaration, adjust_dynamic_theme
|
return adjust_theme, advanced_css, theme_declaration, adjust_dynamic_theme
|
||||||
|
|
||||||
adjust_theme, advanced_css, theme_declaration, _ = load_dynamic_theme(get_conf('THEME'))
|
adjust_theme, advanced_css, theme_declaration, _ = load_dynamic_theme(THEME)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
||||||
第 2 部分
|
|
||||||
cookie相关工具函数
|
|
||||||
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
||||||
"""
|
|
||||||
|
|
||||||
def init_cookie(cookies, chatbot):
|
|
||||||
# 为每一位访问的用户赋予一个独一无二的uuid编码
|
|
||||||
cookies.update({'uuid': uuid.uuid4()})
|
|
||||||
return cookies
|
|
||||||
|
|
||||||
def to_cookie_str(d):
|
|
||||||
# Pickle the dictionary and encode it as a string
|
|
||||||
pickled_dict = pickle.dumps(d)
|
|
||||||
cookie_value = base64.b64encode(pickled_dict).decode('utf-8')
|
|
||||||
return cookie_value
|
|
||||||
|
|
||||||
def from_cookie_str(c):
|
|
||||||
# Decode the base64-encoded string and unpickle it into a dictionary
|
|
||||||
pickled_dict = base64.b64decode(c.encode('utf-8'))
|
|
||||||
return pickle.loads(pickled_dict)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
||||||
第 3 部分
|
|
||||||
内嵌的javascript代码
|
|
||||||
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
||||||
"""
|
|
||||||
|
|
||||||
js_code_for_css_changing = """(css) => {
|
|
||||||
var existingStyles = document.querySelectorAll("body > gradio-app > div > style")
|
|
||||||
for (var i = 0; i < existingStyles.length; i++) {
|
|
||||||
var style = existingStyles[i];
|
|
||||||
style.parentNode.removeChild(style);
|
|
||||||
}
|
|
||||||
var existingStyles = document.querySelectorAll("style[data-loaded-css]");
|
|
||||||
for (var i = 0; i < existingStyles.length; i++) {
|
|
||||||
var style = existingStyles[i];
|
|
||||||
style.parentNode.removeChild(style);
|
|
||||||
}
|
|
||||||
var styleElement = document.createElement('style');
|
|
||||||
styleElement.setAttribute('data-loaded-css', 'placeholder');
|
|
||||||
styleElement.innerHTML = css;
|
|
||||||
document.body.appendChild(styleElement);
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
js_code_for_darkmode_init = """(dark) => {
|
|
||||||
dark = dark == "True";
|
|
||||||
if (document.querySelectorAll('.dark').length) {
|
|
||||||
if (!dark){
|
|
||||||
document.querySelectorAll('.dark').forEach(el => el.classList.remove('dark'));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (dark){
|
|
||||||
document.querySelector('body').classList.add('dark');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
js_code_for_toggle_darkmode = """() => {
|
|
||||||
if (document.querySelectorAll('.dark').length) {
|
|
||||||
document.querySelectorAll('.dark').forEach(el => el.classList.remove('dark'));
|
|
||||||
} else {
|
|
||||||
document.querySelector('body').classList.add('dark');
|
|
||||||
}
|
|
||||||
}"""
|
|
||||||
|
|
||||||
|
|
||||||
js_code_for_persistent_cookie_init = """(persistent_cookie) => {
|
|
||||||
return getCookie("persistent_cookie");
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
19
toolbox.py
19
toolbox.py
@@ -87,7 +87,7 @@ def ArgsGeneralWrapper(f):
|
|||||||
}
|
}
|
||||||
chatbot_with_cookie = ChatBotWithCookies(cookies)
|
chatbot_with_cookie = ChatBotWithCookies(cookies)
|
||||||
chatbot_with_cookie.write_list(chatbot)
|
chatbot_with_cookie.write_list(chatbot)
|
||||||
|
print('[plugin is called]:', f)
|
||||||
if cookies.get('lock_plugin', None) is None:
|
if cookies.get('lock_plugin', None) is None:
|
||||||
# 正常状态
|
# 正常状态
|
||||||
if len(args) == 0: # 插件通道
|
if len(args) == 0: # 插件通道
|
||||||
@@ -583,8 +583,7 @@ def promote_file_to_downloadzone(file, rename_file=None, chatbot=None):
|
|||||||
if chatbot is not None:
|
if chatbot is not None:
|
||||||
if 'files_to_promote' in chatbot._cookies: current = chatbot._cookies['files_to_promote']
|
if 'files_to_promote' in chatbot._cookies: current = chatbot._cookies['files_to_promote']
|
||||||
else: current = []
|
else: current = []
|
||||||
if new_path not in current: # 避免把同一个文件添加多次
|
chatbot._cookies.update({'files_to_promote': [new_path] + current})
|
||||||
chatbot._cookies.update({'files_to_promote': [new_path] + current})
|
|
||||||
return new_path
|
return new_path
|
||||||
|
|
||||||
|
|
||||||
@@ -824,6 +823,11 @@ def select_api_key(keys, llm_model):
|
|||||||
raise RuntimeError(f"您提供的api-key不满足要求,不包含任何可用于{llm_model}的api-key。您可能选择了错误的模型或请求源(右下角更换模型菜单中可切换openai,azure,claude,api2d等请求源)。")
|
raise RuntimeError(f"您提供的api-key不满足要求,不包含任何可用于{llm_model}的api-key。您可能选择了错误的模型或请求源(右下角更换模型菜单中可切换openai,azure,claude,api2d等请求源)。")
|
||||||
|
|
||||||
api_key = random.choice(avail_key_list) # 随机负载均衡
|
api_key = random.choice(avail_key_list) # 随机负载均衡
|
||||||
|
|
||||||
|
if get_conf("BLOCK_INVALID_APIKEY"):
|
||||||
|
# 实验性功能,自动检测并屏蔽失效的KEY,请勿使用
|
||||||
|
from request_llms.key_manager import ApiKeyManager
|
||||||
|
api_key = ApiKeyManager().select_avail_key(avail_key_list)
|
||||||
return api_key
|
return api_key
|
||||||
|
|
||||||
def read_env_variable(arg, default_value):
|
def read_env_variable(arg, default_value):
|
||||||
@@ -1008,19 +1012,14 @@ def clip_history(inputs, history, tokenizer, max_token_limit):
|
|||||||
def get_token_num(txt):
|
def get_token_num(txt):
|
||||||
return len(tokenizer.encode(txt, disallowed_special=()))
|
return len(tokenizer.encode(txt, disallowed_special=()))
|
||||||
input_token_num = get_token_num(inputs)
|
input_token_num = get_token_num(inputs)
|
||||||
|
|
||||||
if max_token_limit < 5000: output_token_expect = 256 # 4k & 2k models
|
|
||||||
elif max_token_limit < 9000: output_token_expect = 512 # 8k models
|
|
||||||
else: output_token_expect = 1024 # 16k & 32k models
|
|
||||||
|
|
||||||
if input_token_num < max_token_limit * 3 / 4:
|
if input_token_num < max_token_limit * 3 / 4:
|
||||||
# 当输入部分的token占比小于限制的3/4时,裁剪时
|
# 当输入部分的token占比小于限制的3/4时,裁剪时
|
||||||
# 1. 把input的余量留出来
|
# 1. 把input的余量留出来
|
||||||
max_token_limit = max_token_limit - input_token_num
|
max_token_limit = max_token_limit - input_token_num
|
||||||
# 2. 把输出用的余量留出来
|
# 2. 把输出用的余量留出来
|
||||||
max_token_limit = max_token_limit - output_token_expect
|
max_token_limit = max_token_limit - 128
|
||||||
# 3. 如果余量太小了,直接清除历史
|
# 3. 如果余量太小了,直接清除历史
|
||||||
if max_token_limit < output_token_expect:
|
if max_token_limit < 128:
|
||||||
history = []
|
history = []
|
||||||
return history
|
return history
|
||||||
else:
|
else:
|
||||||
|
|||||||
4
version
4
version
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": 3.64,
|
"version": 3.62,
|
||||||
"show_feature": true,
|
"show_feature": true,
|
||||||
"new_feature": "支持直接拖拽文件到上传区 <-> 支持将图片粘贴到输入区 <-> 修复若干隐蔽的内存BUG <-> 修复多用户冲突问题 <-> 接入Deepseek Coder <-> AutoGen多智能体插件测试版"
|
"new_feature": "修复若干隐蔽的内存BUG <-> 修复多用户冲突问题 <-> 接入Deepseek Coder <-> AutoGen多智能体插件测试版 <-> 修复本地模型在Windows下的加载BUG <-> 支持文心一言v4和星火v3 <-> 支持GLM3和智谱的API <-> 解决本地模型并发BUG <-> 支持动态追加基础功能按钮"
|
||||||
}
|
}
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户