镜像自地址
https://github.com/binary-husky/gpt_academic.git
已同步 2025-12-06 14:36:48 +00:00
add document
这个提交包含在:
@@ -13,6 +13,11 @@ class Arxiv_Localize(GptAcademicPluginTemplate):
|
||||
def define_arg_selection_menu(self):
|
||||
"""
|
||||
定义插件的二级选项菜单
|
||||
|
||||
第一个参数,名称`main_input`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
||||
第二个参数,名称`advanced_arg`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
||||
第三个参数,名称`allow_cache`,参数`type`声明这是一个下拉菜单,下拉菜单上方显示`title`+`description`,下拉菜单的选项为`options`,`default_value`为下拉菜单默认值;
|
||||
|
||||
"""
|
||||
gui_definition = {
|
||||
"main_input":
|
||||
|
||||
183
docs/plugin_with_secondary_menu.md
普通文件
183
docs/plugin_with_secondary_menu.md
普通文件
@@ -0,0 +1,183 @@
|
||||
# 实现带二级菜单的插件
|
||||
|
||||
## 一、如何写带有二级菜单的插件
|
||||
|
||||
1. 声明一个 `Class`,继承父类 `GptAcademicPluginTemplate`
|
||||
|
||||
```python
|
||||
from crazy_functions.plugin_template.plugin_class_template import GptAcademicPluginTemplate
|
||||
from crazy_functions.plugin_template.plugin_class_template import ArgProperty
|
||||
|
||||
class Demo_Wrap(GptAcademicPluginTemplate):
|
||||
def __init__(self): ...
|
||||
```
|
||||
|
||||
2. 声明二级菜单中需要的变量,覆盖父类的`define_arg_selection_menu`函数。
|
||||
|
||||
```python
|
||||
class Demo_Wrap(GptAcademicPluginTemplate):
|
||||
...
|
||||
|
||||
def define_arg_selection_menu(self):
|
||||
"""
|
||||
定义插件的二级选项菜单
|
||||
|
||||
第一个参数,名称`main_input`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
||||
第二个参数,名称`advanced_arg`,参数`type`声明这是一个文本框,文本框上方显示`title`,文本框内部显示`description`,`default_value`为默认值;
|
||||
第三个参数,名称`allow_cache`,参数`type`声明这是一个下拉菜单,下拉菜单上方显示`title`+`description`,下拉菜单的选项为`options`,`default_value`为下拉菜单默认值;
|
||||
"""
|
||||
gui_definition = {
|
||||
"main_input":
|
||||
ArgProperty(title="ArxivID", description="输入Arxiv的ID或者网址", default_value="", type="string").model_dump_json(),
|
||||
"advanced_arg":
|
||||
ArgProperty(title="额外的翻译提示词",
|
||||
description=r"如果有必要, 请在此处给出自定义翻译命令",
|
||||
default_value="", type="string").model_dump_json(),
|
||||
"allow_cache":
|
||||
ArgProperty(title="是否允许从缓存中调取结果", options=["允许缓存", "从头执行"], default_value="允许缓存", description="无", type="dropdown").model_dump_json(),
|
||||
}
|
||||
return gui_definition
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
> [!IMPORTANT]
|
||||
>
|
||||
> ArgProperty 中每个条目对应一个参数,`type == "string"`时,使用文本块,`type == dropdown`时,使用下拉菜单。
|
||||
>
|
||||
> 注意:`main_input` 和 `advanced_arg`是两个特殊的参数。`main_input`会自动与界面右上角的`输入区`进行同步,而`advanced_arg`会自动与界面右下角的`高级参数输入区`同步。除此之外,参数名称可以任意选取。其他细节详见`crazy_functions/plugin_template/plugin_class_template.py`。
|
||||
|
||||
|
||||
|
||||
|
||||
3. 编写插件程序,覆盖父类的`execute`函数。
|
||||
|
||||
例如:
|
||||
|
||||
```python
|
||||
class Demo_Wrap(GptAcademicPluginTemplate):
|
||||
...
|
||||
...
|
||||
|
||||
def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
|
||||
"""
|
||||
执行插件
|
||||
|
||||
plugin_kwargs字典中会包含用户的选择,与上述 `define_arg_selection_menu` 一一对应
|
||||
"""
|
||||
allow_cache = plugin_kwargs["allow_cache"]
|
||||
advanced_arg = plugin_kwargs["advanced_arg"]
|
||||
|
||||
if allow_cache == "从头执行": plugin_kwargs["advanced_arg"] = "--no-cache " + plugin_kwargs["advanced_arg"]
|
||||
yield from Latex翻译中文并重新编译PDF(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
4. 注册插件
|
||||
|
||||
将以下条目插入`crazy_functional.py`即可。注意,与旧插件不同的是,`Function`键值应该为None,而`Class`键值为上述插件的类名称(`Demo_Wrap`)。
|
||||
```
|
||||
"新插件": {
|
||||
"Group": "学术",
|
||||
"Color": "stop",
|
||||
"AsButton": True,
|
||||
"Info": "插件说明",
|
||||
"Function": None,
|
||||
"Class": Demo_Wrap,
|
||||
},
|
||||
```
|
||||
|
||||
5. 已经结束了,启动程序测试吧~!
|
||||
|
||||
|
||||
|
||||
## 二、背后的原理
|
||||
|
||||
|
||||
### (I) 首先介绍三个Gradio官方没有的重要前端函数
|
||||
|
||||
主javascript程序`common.js`中有三个Gradio官方没有的重要API
|
||||
|
||||
1. `get_data_from_gradio_component`
|
||||
这个函数可以获取任意gradio组件的当前值,例如textbox中的字符,dropdown中的当前选项,chatbot当前的对话等等。调用方法举例:
|
||||
```javascript
|
||||
// 获取当前的对话
|
||||
let chatbot = await get_data_from_gradio_component('gpt-chatbot');
|
||||
```
|
||||
|
||||
2. `get_gradio_component`
|
||||
有时候我们不仅需要gradio组件的当前值,还需要它的label值、是否隐藏、下拉菜单其他可选选项等等,而通过这个函数可以直接获取这个组件的句柄。举例:
|
||||
```javascript
|
||||
// 获取下拉菜单组件的句柄
|
||||
var model_sel = await get_gradio_component("elem_model_sel");
|
||||
// 获取它的所有属性,包括其所有可选选项
|
||||
console.log(model_sel.props)
|
||||
```
|
||||
|
||||
|
||||
3. `push_data_to_gradio_component`
|
||||
这个函数可以将数据推回gradio组件,例如textbox中的字符,dropdown中的当前选项等等。调用方法举例:
|
||||
|
||||
```javascript
|
||||
// 修改一个按钮上面的文本
|
||||
push_data_to_gradio_component("btnName", "gradio_element_id", "string");
|
||||
|
||||
// 隐藏一个组件
|
||||
push_data_to_gradio_component({ visible: false, __type__: 'update' }, "plugin_arg_menu", "obj");
|
||||
|
||||
// 修改组件label
|
||||
push_data_to_gradio_component({label: '当前模型:' + getCookie("js_md_dropdown_cookie"), __type__: 'update'}, "gpt-chatbot", "obj")
|
||||
```
|
||||
|
||||
|
||||
### (II) 从点击插件到执行插件的逻辑过程
|
||||
|
||||
简述:程序启动时把每个插件的二级菜单编码为BASE64,存储在用户的浏览器前端,用户调用对应功能时,会按照插件的BASE64编码,将平时隐藏的菜单(有选择性地)显示出来。
|
||||
|
||||
1. 启动阶段(主函数 `main.py` 中),遍历每个插件,生成二级菜单的BASE64编码,存入变量`register_advanced_plugin_init_code_arr`。
|
||||
```python
|
||||
def get_js_code_for_generating_menu(self, btnName):
|
||||
define_arg_selection = self.define_arg_selection_menu()
|
||||
DEFINE_ARG_INPUT_INTERFACE = json.dumps(define_arg_selection)
|
||||
return base64.b64encode(DEFINE_ARG_INPUT_INTERFACE.encode('utf-8')).decode('utf-8')
|
||||
```
|
||||
|
||||
|
||||
2. 用户加载阶段(主javascript程序`common.js`中),浏览器加载`register_advanced_plugin_init_code_arr`,存入本地的字典`advanced_plugin_init_code_lib`:
|
||||
|
||||
```javascript
|
||||
advanced_plugin_init_code_lib = {}
|
||||
function register_advanced_plugin_init_code(key, code){
|
||||
advanced_plugin_init_code_lib[key] = code;
|
||||
}
|
||||
```
|
||||
|
||||
3. 用户点击插件按钮(主函数 `main.py` 中)时,仅执行以下javascript代码,唤醒隐藏的二级菜单(生成菜单的代码在`common.js`中的`generate_menu`函数上):
|
||||
|
||||
|
||||
```javascript
|
||||
// 生成高级插件的选择菜单
|
||||
function run_advanced_plugin_launch_code(key){
|
||||
generate_menu(advanced_plugin_init_code_lib[key], key);
|
||||
}
|
||||
function on_flex_button_click(key){
|
||||
run_advanced_plugin_launch_code(key);
|
||||
}
|
||||
```
|
||||
|
||||
```python
|
||||
click_handle = plugins[k]["Button"].click(None, inputs=[], outputs=None, _js=f"""()=>run_advanced_plugin_launch_code("{k}")""")
|
||||
```
|
||||
|
||||
4. 当用户点击二级菜单的执行键时,通过javascript脚本模拟点击一个隐藏按钮,触发后续程序(`common.js`中的`execute_current_pop_up_plugin`,会把二级菜单中的参数缓存到`invisible_current_pop_up_plugin_arg_final`,然后模拟点击`invisible_callback_btn_for_plugin_exe`按钮)。隐藏按钮的定义在(主函数 `main.py` ),该隐藏按钮会最终触发`route_switchy_bt_with_arg`函数(定义于`themes/gui_advanced_plugin_class.py`):
|
||||
|
||||
```python
|
||||
click_handle_ng = new_plugin_callback.click(route_switchy_bt_with_arg, [
|
||||
gr.State(["new_plugin_callback", "usr_confirmed_arg"] + input_combo_order),
|
||||
new_plugin_callback, usr_confirmed_arg, *input_combo
|
||||
], output_combo)
|
||||
```
|
||||
|
||||
5. 最后,`route_switchy_bt_with_arg`中,会搜集所有用户参数,统一集中到`plugin_kwargs`参数中,并执行对应插件的`execute`函数。
|
||||
在新工单中引用
屏蔽一个用户