本指南将涵盖实现自定义组件后端处理所需了解的一切内容。
所有组件都继承自三个类之一:Component、FormComponent 或 BlockContext。您需要继承其中一个,以便您的组件表现得像所有其他 Gradio 组件一样。当您使用 gradio cc create --template 从模板开始时,您无需担心选择哪个类,因为模板会使用正确的类。为了完整起见,如果您需要从头开始创建自己的组件,我们将解释每个类的用途。
FormComponent:当您希望您的组件与其他 FormComponents 一起分组在同一个 Form 布局中时使用。Slider、Textbox 和 Number 组件都是 FormComponents。BlockContext:当您希望将其他组件放置在您的组件“内部”时使用。这使得 with MyComponent() as component: 语法成为可能。Component:用于所有其他情况。如果您的组件支持流式输出,请继承自 StreamingOutput 类。
如果您继承自 BlockContext,您还需要将元类设置为 ComponentMeta。请参阅下面的示例。
from gradio.blocks import BlockContext
from gradio.component_meta import ComponentMeta
@document()
class Row(BlockContext, metaclass=ComponentMeta):
pass当您继承这些类中的任何一个时,必须实现以下方法。否则,当您实例化组件时,Python 解释器会引发错误!
preprocess 和 postprocess如关键概念指南中所述。它们处理从前端发送的数据到 Python 函数所需格式的转换。
def preprocess(self, x: Any) -> Any:
"""
Convert from the web-friendly (typically JSON) value in the frontend to the format expected by the python function.
"""
return x
def postprocess(self, y):
"""
Convert from the data returned by the python function to the web-friendly (typically JSON) value expected by the frontend.
"""
return yprocess_example接受原始 Python 值并返回应在应用程序中的示例预览中显示修改后的值。如果未提供,则使用 .postprocess() 方法。让我们看一下 SimpleDropdown 组件中的以下示例。
def process_example(self, input_data):
return next((c[0] for c in self.choices if c[1] == input_data), None)由于 self.choices 是一个对应于 (display_name, value) 的元组列表,因此这会将用户提供的值转换为显示值(如果该值不在 self.choices 中,则将其转换为 None)。
api_infopreprocess 期望的值的 JSON 模式表示。这通过 gradio 客户端启用 API 使用。如果您的组件指定了 data_model,则您不需要自己实现此功能。data_model 在下一节中。
def api_info(self) -> dict[str, list[str]]:
"""
A JSON-schema representation of the value that the `preprocess` expects and the `postprocess` returns.
"""
passexample_payload您的组件的示例负载,例如可以传递到组件的 .preprocess() 方法中的内容。示例输入显示在使用您的自定义组件的 Gradio 应用程序的 View API 页面中。必须是 JSON 可序列化的。如果您的组件需要上传文件,最好使用可公开访问的 URL。
def example_payload(self) -> Any:
"""
The example inputs for this component for API usage. Must be JSON-serializable.
"""
passexample_value您的组件的示例值,例如可以传递到组件的 .postprocess() 方法中的内容。这在自定义组件开发中创建的默认应用程序中用作示例值。
def example_payload(self) -> Any:
"""
The example inputs for this component for API usage. Must be JSON-serializable.
"""
passflag将组件的值写入可存储在用于标记的 csv 或 json 文件中的格式。如果您的组件指定了 data_model,则您不需要自己实现此功能。data_model 在下一节中。
def flag(self, x: Any | GradioDataModel, flag_dir: str | Path = "") -> str:
passread_from_flag将用于标记的 csv 或 json 文件中存储的格式转换为组件的 python value。如果您的组件指定了 data_model,则您不需要自己实现此功能。data_model 在下一节中。
def read_from_flag(
self,
x: Any,
) -> GradioDataModel | Any:
"""
Convert the data from the csv or jsonl file into the component state.
"""
return xdata_modeldata_model 是您定义组件值将存储在前端中的预期数据格式的方式。它指定了您的 preprocess 方法期望的数据格式和 postprocess 方法返回的格式。为组件定义 data_model 不是必需的,但它极大地简化了创建自定义组件的过程。如果您定义了自定义组件,您只需要实现四个方法——preprocess、postprocess、example_payload 和 example_value!
您通过定义继承自 GradioModel 或 GradioRootModel 的 pydantic 模型来定义 data_model。
这最好通过一个示例来解释。让我们看一下核心 Video 组件,它将视频数据存储为一个 JSON 对象,其中包含两个键 video 和 subtitles,它们指向单独的文件。
from gradio.data_classes import FileData, GradioModel
class VideoData(GradioModel):
video: FileData
subtitles: Optional[FileData] = None
class Video(Component):
data_model = VideoData通过添加这四行代码,您的组件会自动实现 API 使用所需的方法、标记方法和示例缓存方法!它还具有自我记录代码的额外好处。任何阅读您的组件代码的人都会确切地知道它期望的数据。
如果您的组件期望从前端上传文件,则必须使用 FileData 模型!这将在下一节中解释。
在此处阅读 pydantic 文档 here。
GradioModel 和 GradioRootModel 之间的区别在于,RootModel 不会将数据序列化为字典。例如,Names 模型会将数据序列化为 {'names': ['freddy', 'pete']},而 NamesRoot 模型会将其序列化为 ['freddy', 'pete']。
from typing import List
class Names(GradioModel):
names: List[str]
class NamesRoot(GradioRootModel):
root: List[str]即使您的组件不期望“复杂”的 JSON 数据结构,定义 GradioRootModel 也是有益的,这样您就不必担心实现 API 和标记方法。
使用 Python 类型库中的类来对模型进行类型化。例如,使用 List 而不是 list。
如果您的组件需要上传文件作为输入,或者向前端返回保存的文件,则必须使用 FileData 在 data_model 中对文件进行类型化。
当您使用 FileData 时
Gradio 知道它应该允许将此文件提供给前端。Gradio 会自动阻止向运行服务器的计算机上的任意文件提供服务的请求。
Gradio 会自动将文件放置在缓存中,这样就不会保存重复的文件副本。
客户端库会自动知道它们应该在发送请求之前上传输入文件。它们还会自动下载文件。
如果您不使用 FileData,您的组件将无法按预期工作!
您的组件的事件触发器在 EVENTS 类属性中定义。这是一个包含事件字符串名称的列表。将事件添加到此列表会自动向您的组件添加同名方法!
您可以从 gradio.events 导入 Events 枚举以访问核心 gradio 组件中常用的事件。
例如,以下代码将在 MyComponent 类中定义 text_submit、file_upload 和 change 方法。
from gradio.events import Events
from gradio.components import FormComponent
class MyComponent(FormComponent):
EVENTS = [
"text_submit",
"file_upload",
Events.change
]不要忘记也在 JavaScript 代码中处理这些事件!