From 8046900b89d2238713be80889a0f4359225ae070 Mon Sep 17 00:00:00 2001 From: w_xiaolizu Date: Tue, 27 Jun 2023 15:54:20 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E4=B8=80=E4=BA=9B=E5=90=88?= =?UTF-8?q?=E5=B9=B6=E5=86=B2=E7=AA=81=E9=81=97=E6=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __main__.py | 88 ++++++++++++++++++++++++++++----------- core_functional.py | 4 ++ docs/assets/custom.css | 90 ++++++++++++++++++++++++++++++++++++---- docs/imgs/pic_desc.png | Bin 0 -> 18124 bytes func_box.py | 91 ++++++++++++++++++++++++++++++++++++----- toolbox.py | 13 ++++-- 6 files changed, 243 insertions(+), 43 deletions(-) create mode 100644 docs/imgs/pic_desc.png diff --git a/__main__.py b/__main__.py index ec33f1c..8570c48 100644 --- a/__main__.py +++ b/__main__.py @@ -75,16 +75,52 @@ class ChatBot(ChatBotFrame): self.chatbot = gr.Chatbot(elem_id='main_chatbot', label=f"当前模型:{LLM_MODEL}") self.chatbot.style() self.history = gr.State([]) - temp_draw = [gr.HTML() for i in range(4)] + temp_draw = [gr.HTML() for i in range(2)] with gr.Row(): self.txt = gr.Textbox(show_label=False, placeholder="Input question here.", elem_id='chat_txt').style(container=False) self.input_copy = gr.State('') - self.submitBtn = gr.Button("提交", variant="primary", visible=False).style(full_width=False) - with gr.Row(elem_id='debug_mes'): - self.status = gr.Markdown(f"Tip: 按Enter提交, 按Shift+Enter换行。当前模型: {LLM_MODEL} \n {proxy_info}") + self.submitBtn = gr.Button("", variant="primary", elem_classes='submit_btn').style(full_width=False) + with gr.Row(): + self.status = gr.Markdown(f"Tip: 按Enter提交, 按Shift+Enter换行。当前模型: {LLM_MODEL} \n {proxy_info}", elem_id='debug_mes') + + + def draw_examples(self): + with gr.Column(elem_id='examples_col') as self.examples_column: + gr.Markdown('# Get Started Quickly') + with gr.Row(): + hide_components = gr.Textbox(visible=False) + gr.Button.update = func_box.update_btn + self.example = [['今天伦敦天气怎么样?', '对2021年以后的世界和事件了解有限', self.submitBtn.update(elem_id='highlight_update')], + ['今夕何夕,明月何月?', '偶尔会产生不正确的信息', self.submitBtn.update(elem_id='highlight_update')], + ['怎么才能把学校给炸了?', '经过训练,会拒绝不适当的请求', self.submitBtn.update(elem_id='highlight_update')]] + self.example_inputs = [self.txt, hide_components, self.submitBtn] + self.guidance_example = gr.Examples(examples=self.example, inputs=self.example_inputs, label='基础对话') + self.guidance_plugins = gr.Dataset(components=[gr.HTML(visible=False)], samples=[['...'] for i in range(4)], label='高级功能', type='index') + self.guidance_plugins_state = gr.State() + self.guidance_news = gr.Examples(examples=func_box.git_log_list(), inputs=[hide_components, hide_components], label='News') + + def plug_update(index, date_set): + variant = crazy_fns[date_set[index]]["Color"] if "Color" in crazy_fns[date_set[index]] else "secondary" + ret = {self.switchy_bt: self.switchy_bt.update(value=date_set[index], variant=variant, elem_id='highlight_update'), + self.tabs_inputs: gr.Tabs.update(selected='plug_tab'), + self.area_crazy_fn: self.area_crazy_fn.update(open=True)} + fns_value = func_box.txt_converter_json(str(crazy_fns[date_set[index]].get('Parameters', ''))) + fns_lable = f"插件[{date_set[index]}]的高级参数说明:\n" + crazy_fns[date_set[index]].get("ArgsReminder", f"没有提供高级参数功能说明") + temp_dict = dict(visible=True, interactive=True, value=str(fns_value), label=fns_lable) + # 是否唤起高级插件参数区 + if crazy_fns[date_set[index]].get("AdvancedArgs", False): + ret.update({self.plugin_advanced_arg: gr.update(**temp_dict)}) + ret.update({self.area_crazy_fn: self.area_crazy_fn.update(open=False)}) + else: + ret.update({self.plugin_advanced_arg: gr.update(visible=False, label=f"插件[{date_set[index]}]不需要高级参数。")}) + return ret + + self.guidance_plugins.select(fn=plug_update, inputs=[self.guidance_plugins, self.guidance_plugins_state], + outputs=[self.switchy_bt, self.plugin_advanced_arg, self.tabs_inputs, + self.area_crazy_fn]) def __clear_input(self, inputs): - return '', inputs + return '', inputs, self.examples_column.update(visible=False) def draw_prompt(self): with gr.Row(): @@ -102,7 +138,7 @@ class ChatBot(ChatBotFrame): with gr.Row(): with gr.Column(scale=100): self.pro_results = gr.Chatbot(label='Prompt and result', elem_id='prompt_result').style() - with gr.Column(scale=11): + with gr.Column(scale=16): Tips = "用 BORF 分析法设计chat GPT prompt:\n" \ "1、阐述背景 B(Background): 说明背景,为chatGPT提供充足的信息\n" \ "2、定义目标 O(Objectives):“我们希望实现什么”\n" \ @@ -147,16 +183,12 @@ class ChatBot(ChatBotFrame): self.pro_reuse_btn.click( fn=func_box.reuse_chat, inputs=[self.pro_results, self.chatbot, self.history, self.pro_name_txt], - outputs=[self.chatbot, self.history, self.txt, self.tabs_chatbot, self.pro_name_txt] + outputs=[self.chatbot, self.history, self.txt, self.tabs_chatbot, self.pro_name_txt, self.examples_column] ) def draw_function_chat(self): prompt_list, devs_document = get_conf('prompt_list', 'devs_document') - with gr.Row(): - # self.cpopyBtn = gr.Button("复制回答", variant="secondary").style(size="sm") - self.resetBtn = gr.Button("新建对话", variant="secondary", elem_id='empty_btn').style(size="sm") - self.stopBtn = gr.Button("中止对话", variant="stop").style(size="sm") - with gr.Tab('Function'): + with gr.TabItem('Function', id='func_tab'): with gr.Accordion("基础功能区", open=True) as self.area_basic_fn: with gr.Row(): for k in functional: @@ -189,7 +221,7 @@ class ChatBot(ChatBotFrame): self.prompt_tab.select(fn=lambda: 1, inputs=None, outputs=self.tabs_code) def draw_public_chat(self): - with gr.Tab('Plugins'): + with gr.TabItem('Plugins', id='plug_tab'): with gr.Accordion("上传本地文件可供高亮函数插件调用", open=False) as self.area_file_up: self.file_upload = gr.Files(label="任何文件, 但推荐上传压缩文件(zip, tar)", file_count="multiple") @@ -220,7 +252,7 @@ class ChatBot(ChatBotFrame): def draw_setting_chat(self): switch_model = get_conf('switch_model')[0] - with gr.Tab('Settings'): + with gr.TabItem('Settings', id='sett_tab'): self.top_p = gr.Slider(minimum=-0, maximum=1.0, value=1.0, step=0.01, interactive=True, label="Top-p (nucleus sampling)", ).style(container=False) self.temperature = gr.Slider(minimum=-0, maximum=2.0, value=1.0, step=0.01, interactive=True, @@ -270,7 +302,8 @@ class ChatBot(ChatBotFrame): self.system_prompt, self.models_box, self.plugin_advanced_arg] self.output_combo = [self.cookies, self.chatbot, self.history, self.status] self.predict_args = dict(fn=ArgsGeneralWrapper(predict), inputs=self.input_combo, outputs=self.output_combo) - self.clear_agrs = dict(fn=self.__clear_input, inputs=[self.txt], outputs=[self.txt, self.input_copy]) + self.clear_agrs = dict(fn=self.__clear_input, inputs=[self.txt], outputs=[self.txt, self.input_copy, + self.examples_column]) # 提交按钮、重置按钮 self.cancel_handles.append(self.txt.submit(**self.clear_agrs).then(**self.predict_args)) self.cancel_handles.append(self.submitBtn.click(**self.clear_agrs).then(**self.predict_args)) @@ -305,7 +338,7 @@ class ChatBot(ChatBotFrame): def on_dropdown_changed(k): # 按钮颜色随变 variant = crazy_fns[k]["Color"] if "Color" in crazy_fns[k] else "secondary" - ret = {self.switchy_bt: gr.update(value=k, variant=variant)} + ret = {self.switchy_bt: self.switchy_bt.update(value=k, variant=variant)} # 参数取随变 fns_value = func_box.txt_converter_json(str(crazy_fns[k].get('Parameters', ''))) fns_lable = f"插件[{k}]的高级参数说明:\n" + crazy_fns[k].get("ArgsReminder", f"没有提供高级参数功能说明") @@ -336,13 +369,12 @@ class ChatBot(ChatBotFrame): self.md_dropdown.select(on_md_dropdown_changed, [self.md_dropdown], [self.chatbot]) def signals_auto_input(self): - from autogpt.cli import agent_main self.auto_input_combo = [self.ai_name, self.ai_role, self.ai_goal_list, self.ai_budget, self.cookies, self.chatbot, self.history, self.agent_obj] self.auto_output_combo = [self.cookies, self.chatbot, self.history, self.status, self.agent_obj, self.submit_start, self.submit_next, self.text_continue] - self.submit_start.click(fn=agent_main, inputs=self.auto_input_combo, outputs=self.auto_output_combo) + # gradio的inbrowser触发不太稳定,回滚代码到原始的浏览器打开函数 def auto_opentab_delay(self, is_open=False): @@ -369,13 +401,19 @@ class ChatBot(ChatBotFrame): # 绘制一个ROW,row会让底下的元素自动排成一行 with gr.Row().style(justify='between'): # 绘制列1 - with gr.Column(scale=46): + with gr.Column(scale=44): with gr.Tabs() as self.tabs_copilot: # 绘制对话模组 with gr.TabItem('Chat-Copilot'): - self.draw_function_chat() - self.draw_public_chat() - self.draw_setting_chat() + with gr.Row(): + # self.cpopyBtn = gr.Button("复制回答", variant="secondary").style(size="sm") + self.resetBtn = gr.Button("新建对话", variant="secondary", elem_id='empty_btn').style( + size="sm") + self.stopBtn = gr.Button("中止对话", variant="stop").style(size="sm") + with gr.Tabs() as self.tabs_inputs: + self.draw_function_chat() + self.draw_public_chat() + self.draw_setting_chat() # 绘制autogpt模组 with gr.TabItem('Auto-GPT'): @@ -392,6 +430,7 @@ class ChatBot(ChatBotFrame): with self.chat_tab: # 使用 gr.State()对组件进行拷贝时,如果之前绘制了Markdown格式,会导致启动崩溃,所以将 markdown相关绘制放在最后 self.draw_chatbot() + self.draw_examples() with self.prompt_tab: self.draw_temp_edit() # 函数注册,需要在Blocks下进行 @@ -401,7 +440,10 @@ class ChatBot(ChatBotFrame): self.signals_public() self.signals_prompt_edit() # self.signals_auto_input() - self.demo.load(fn=func_box.refresh_load_data, postprocess=False, inputs=[self.chatbot, self.history, self.pro_fp_state], outputs=[self.pro_func_prompt, self.pro_fp_state, self.chatbot, self.history, ]) + adv_plugins = gr.State([i for i in crazy_fns]) + self.demo.load(fn=func_box.refresh_load_data, postprocess=False, + inputs=[self.chatbot, self.history, self.pro_fp_state, adv_plugins], + outputs=[self.pro_func_prompt, self.pro_fp_state, self.chatbot, self.history, self.guidance_plugins, self.guidance_plugins_state]) # Start self.auto_opentab_delay() diff --git a/core_functional.py b/core_functional.py index a86cb43..ab1600d 100644 --- a/core_functional.py +++ b/core_functional.py @@ -78,5 +78,9 @@ def get_core_functions(): } +def get_guidance(): + pass + + def get_guidance(): pass \ No newline at end of file diff --git a/docs/assets/custom.css b/docs/assets/custom.css index 29377e0..89480a4 100644 --- a/docs/assets/custom.css +++ b/docs/assets/custom.css @@ -11,6 +11,38 @@ mspace { display: block; } + +@keyframes highlight { + 0%, 100% { + border: 2px solid transparent; + } + 50% { + border-color: yellow; + } +} + +#highlight_update { + animation-name: highlight; + animation-duration: 0.75s; + animation-iteration-count: 3; +} + +.table-wrap.svelte-13hsdno.svelte-13hsdno.svelte-13hsdno { + border: 0px solid var(--border-color-primary) !important; +} + +#examples_col { + z-index: 3; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + margin-bottom: 30% !important; +} +.gradio-container-3-32-2 h6 { + font-weight: 200 !important; + font-size: 12px !important; +} .gradio-container-3-32-2 h1 { font-weight: 700 !important; font-size: 28px !important; @@ -31,17 +63,18 @@ mspace { font-weight: 300 !important; font-size: 14px !important; } -.gradio-container-3-32-2 h6 { - font-weight: 200 !important; - font-size: 12px !important; +#hide_examples { + z-index: 0; } + #debug_mes { position: absolute; + display: flex; bottom: 0; left: 0; width: 100%; z-index: 1; /* 设置更高的 z-index 值 */ - margin-bottom: 10px !important; + margin-bottom: -4px !important; } #chat_txt { display: flex; @@ -53,8 +86,24 @@ mspace { bottom: 0; left: 0; width: 100%; - margin-bottom: 35px !important; + margin-bottom: 20px !important; } + +.submit_btn { + display: flex; + flex-direction: column-reverse; + overflow-y: auto !important; + z-index: 3; + flex-grow: 1; /* 自动填充剩余空间 */ + position: absolute; + bottom: 0; + right: 0; + width: 100%; + margin-bottom: 20px !important; + min-width: min(50px,100%) !important; +} + + #sm_btn { display: flex; flex-wrap: unset !important; @@ -182,6 +231,33 @@ span.svelte-1gfkn6j { height: 100%; } +.gradio-container-3-32-2 h1 { + font-weight: 700 !important; + font-size: 28px !important; +} + + +.gradio-container-3-32-2 h2 { + font-weight: 600 !important; + font-size: 24px !important; +} +.gradio-container-3-32-2 h3 { + font-weight: 500 !important; + font-size: 20px !important; +} +.gradio-container-3-32-2 h4 { + font-weight: 400 !important; + font-size: 16px !important; +} +.gradio-container-3-32-2 h5 { + font-weight: 300 !important; + font-size: 14px !important; +} +.gradio-container-3-32-2 h6 { + font-weight: 200 !important; + font-size: 12px !important; +} + /* usage_display */ .insert_block { position: relative; @@ -296,10 +372,10 @@ input[type=range]::-webkit-slider-runnable-track { background: transparent; } -#submit_btn, #cancel_btn { +.submit_btn, #cancel_btn { height: 42px !important; } -#submit_btn::before { +.submit_btn::before { content: url("data:image/svg+xml, %3Csvg width='21px' height='20px' viewBox='0 0 21 20' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E %3Cg id='page' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E %3Cg id='send' transform='translate(0.435849, 0.088463)' fill='%23FFFFFF' fill-rule='nonzero'%3E %3Cpath d='M0.579148261,0.0428666046 C0.301105539,-0.0961547561 -0.036517765,0.122307382 0.0032026237,0.420210298 L1.4927172,18.1553639 C1.5125774,18.4334066 1.79062012,18.5922882 2.04880264,18.4929872 L8.24518329,15.8913017 L11.6412765,19.7441794 C11.8597387,19.9825018 12.2370824,19.8832008 12.3165231,19.5852979 L13.9450591,13.4882182 L19.7839562,11.0255541 C20.0619989,10.8865327 20.0818591,10.4694687 19.7839562,10.3105871 L0.579148261,0.0428666046 Z M11.6138902,17.0883151 L9.85385903,14.7195502 L0.718169621,0.618812241 L12.69945,12.9346347 L11.6138902,17.0883151 Z' id='shape'%3E%3C/path%3E %3C/g%3E %3C/g%3E %3C/svg%3E"); height: 21px; } diff --git a/docs/imgs/pic_desc.png b/docs/imgs/pic_desc.png new file mode 100644 index 0000000000000000000000000000000000000000..6b6d434f389ef1d42d216ef0acf92eab947a0c62 GIT binary patch literal 18124 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%0DcWph%B4N53862o+x`BlT;a4NHe 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 literal 0 HcmV?d00001 diff --git a/func_box.py b/func_box.py index e38b59f..f1150a4 100644 --- a/func_box.py +++ b/func_box.py @@ -133,7 +133,7 @@ def html_tag_color(tag, color=None, font='black'): def html_a_blank(__href, name=''): if not name: - dir_name = __href + name = __href a = f'{name}' return a @@ -145,6 +145,9 @@ def html_download_blank(__href, file_name='temp', dir_name=''): a = f'{file_name}' return a +def html_local_img(__file): + a = f'
' + return a def ipaddr(): # 获取本地ipx @@ -301,8 +304,9 @@ def diff_list(txt='', percent=0.70, switch: list = None, lst: dict = None, sp=15 for key in sorted_dict: # 开始匹配关键字 index = str(key[0]).lower().find(txt.lower()) - - if index != -1: + index_ = str(key[1]).lower().find(txt.lower()) + if index != -1 or index_ != -1: + if index == -1: index = index_ # 增加搜索prompt 名称 # sp=split 用于判断在哪里启动、在哪里断开 if index - sp > 0: start = index - sp @@ -505,7 +509,10 @@ def thread_write_chat(chatbot, history): private_key = toolbox.get_conf('private_key')[0] chat_title = chatbot[0][1].split() i_say = pattern_markdown.sub('', chatbot[-1][0]) - gpt_result = history + if history: + gpt_result = history + else: # 如果历史对话不存在,那么读取对话框 + gpt_result = [pattern_markdown.sub('', v) for i in chatbot for v in i] if private_key in chat_title: SqliteHandle(f'ai_private_{chat_title[-2]}').inset_prompt({i_say: gpt_result}) else: @@ -515,11 +522,10 @@ def thread_write_chat(chatbot, history): base_path = os.path.dirname(__file__) prompt_path = os.path.join(base_path, 'prompt_users') - def reuse_chat(result, chatbot, history, pro_numb): """复用对话记录""" if result is None or result == []: - return chatbot, history, gr.update(), gr.update(), '' + return chatbot, history, gr.update(), gr.update(), '', gr.Column.update() else: if pro_numb: chatbot += result @@ -529,7 +535,7 @@ def reuse_chat(result, chatbot, history, pro_numb): history += [pattern_markdown.sub('', _) for i in result[-2:] for _ in i] print(chatbot[-1][0]) i_say = pattern_markdown.sub('', chatbot[-1][0]) - return chatbot, history, i_say, gr.Tabs.update(selected='chatbot'), '' + return chatbot, history, i_say, gr.Tabs.update(selected='chatbot'), '', gr.Column.update(visible=False) def num_tokens_from_string(listing: list, encoding_name: str = 'cl100k_base') -> int: @@ -553,7 +559,7 @@ def spinner_chatbot_loading(chatbot): loading_msg[-1] = tuple(temp_list) return loading_msg -def refresh_load_data(chat, history, prompt): +def refresh_load_data(chat, history, prompt, crazy_list): """ Args: chat: 聊天组件 @@ -566,7 +572,8 @@ def refresh_load_data(chat, history, prompt): is_all = toolbox.get_conf('prompt_list')[0]['key'][0] data = prompt_retrieval(is_all=[is_all]) prompt.samples = data - return prompt.update(samples=data, visible=True), prompt, chat, history + selected = random.sample(crazy_list, 4) + return prompt.update(samples=data, visible=True), prompt, chat, history, gr.Dataset.update(samples=[[i] for i in selected]), selected @@ -588,6 +595,70 @@ def clean_br_string(s): s = re.sub('<\s*br\s*/?>', '\n', s) # 使用正则表达式同时匹配


、< br>和< br/> return s + +def update_btn(self, + value: str = None, + variant: str = None, + visible: bool = None, + interactive: bool = None, + elem_id: str = None, + label: str = None +): + if not variant: variant = self.variant + if not visible: visible = self.visible + if not value: value = self.value + if not interactive: interactive = self.interactive + if not elem_id: elem_id = self.elem_id + if not elem_id: label = self.label + return { + "variant": variant, + "visible": visible, + "value": value, + "interactive": interactive, + 'elem_id': elem_id, + 'label': label, + "__type__": "update", + } + +def update_txt(self, + value: str = None, + lines: int = None, + max_lines: int = None, + placeholder: str = None, + label: str = None, + show_label: bool = None, + visible: bool = None, + interactive: bool = None, + type: str = None, + elem_id: str = None + ): + + return { + "lines": self.lines, + "max_lines": self.max_lines, + "placeholder": self.placeholder, + "label": self.label, + "show_label": self.show_label, + "visible": self.visible, + "value": self.value, + "type": self.type, + "interactive": self.interactive, + "elem_id": elem_id, + "__type__": "update", + + } + + +def txtx(f, q): + return f + + +def git_log_list(): + ll = Shell("git log --pretty=format:'%s | %h' -n 10").read()[1].splitlines() + + return [i.split('|') for i in ll if 'branch' not in i][:5] + + class YamlHandle: def __init__(self, file=os.path.join(prompt_path, 'ai_common.yaml')): @@ -633,4 +704,4 @@ class JsonHandle: if __name__ == '__main__': - pass \ No newline at end of file + html_local_img("docs/imgs/openai-api-key-billing-paid-account.png") \ No newline at end of file diff --git a/toolbox.py b/toolbox.py index bfcaf84..47b1990 100644 --- a/toolbox.py +++ b/toolbox.py @@ -595,7 +595,7 @@ def is_api2d_key(key): return False def is_proxy_key(key): - if 'proxy' in key: + if key.startswith('proxy-') and len(key) == 37: return True else: return False @@ -621,7 +621,14 @@ def what_keys(keys): if is_api2d_key(k): avail_key_list['API2D Key'] += 1 - return f"检测到: OpenAI Key {avail_key_list['OpenAI Key']} 个,API2D Key {avail_key_list['API2D Key']} 个" + for k in key_list: + if is_proxy_key(k): + avail_key_list['Proxy Key'] += 1 + + return f"检测到: \n" \ + f"OpenAI Key {avail_key_list['OpenAI Key']} 个\n" \ + f"API2D Key {avail_key_list['API2D Key']} 个\n" \ + f"Proxy Key {avail_key_list['API2D Key']} 个\n" def select_api_key(keys, llm_model): import random @@ -636,7 +643,7 @@ def select_api_key(keys, llm_model): for k in key_list: if is_api2d_key(k): avail_key_list.append(k) - if llm_model.startswith('proxy'): + if llm_model.startswith('proxy-'): for k in key_list: if is_proxy_key(k): avail_key_list.append(k.replace('proxy-', ''))