1. 自定义组件
  2. 后端

后端 🐍

本指南将涵盖实现自定义组件后端处理所需了解的所有内容。

从哪个类继承

所有组件都继承自三个类之一:ComponentFormComponentBlockContext。 你需要继承其中一个类,以便你的组件像所有其他 gradio 组件一样工作。 当你使用 gradio cc create --template 从模板开始时,你不需要担心选择哪一个,因为模板使用了正确的类。 为了完整性,以及在你需要从头开始创建自己的组件的情况下,我们解释了每个类的用途。

  • FormComponent: 当您希望您的组件与其他FormComponents在同一个Form布局中分组时,请使用此组件。SliderTextboxNumber组件都是FormComponents
  • BlockContext: 当你想将其他组件“放置”在你的组件内部时使用此功能。这启用了 with MyComponent() as component: 语法。
  • Component: Use this for all other cases.

    Tip: If your component supports streaming output, inherit from the `StreamingOutput` class.

    Tip: If you inherit from `BlockContext`, you also need to set the metaclass to be `ComponentMeta`. See example below.

from gradio.blocks import BlockContext
from gradio.component_meta import ComponentMeta




@document()
class Row(BlockContext, metaclass=ComponentMeta):
    pass

你需要实现的方法

当你从这些类中的任何一个继承时,必须实现以下方法。 否则,当你实例化你的组件时,Python解释器将会报错!

preprocesspostprocess

关键概念指南中解释。 它们处理从前端发送的数据到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 y

process_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_info

preprocess 期望的值的 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.
    """
    pass

example_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.
    """
    pass

example_value

组件的一个示例值,例如可以传递给组件的.postprocess()方法的值。这在自定义组件开发中创建的默认应用程序中用作示例值。

def example_payload(self) -> Any:
    """
    The example inputs for this component for API usage. Must be JSON-serializable.
    """
    pass

flag

将组件的值写入可以存储在用于标记的csvjson文件中的格式。 如果您的组件指定了data_model,您不需要自己实现这一点。 data_model在以下部分中。

def flag(self, x: Any | GradioDataModel, flag_dir: str | Path = "") -> str:
    pass

read_from_flag

将从用于标记的csvjson文件中存储的格式转换为组件的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 x

data_model

data_model 是您定义组件值在前端存储的预期数据格式的方式。 它指定了您的 preprocess 方法期望的数据格式以及 postprocess 方法返回的格式。 虽然为您的组件定义 data_model 不是必需的,但它大大简化了创建自定义组件的过程。 如果您定义了一个自定义组件,您只需要实现四个方法 - preprocesspostprocessexample_payloadexample_value

您通过定义一个继承自GradioModelGradioRootModelpydantic模型来定义data_model

这最好通过一个例子来解释。让我们看看核心的Video组件,它将视频数据存储为一个JSON对象,该对象有两个键videosubtitles,分别指向单独的文件。

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](https://docs.pydantic.dev/latest/concepts/models/#basic-model-usage)。

GradioModelGradioRootModel 的区别在于,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 typing库中的类来为你的模型添加类型。例如,使用`List`而不是`list`。

处理文件

如果你的组件期望上传的文件作为输入,或者返回保存的文件到前端,你必须使用FileData来在你的data_model中类型化文件。

当你使用 FileData 时:

  • Gradio 知道它应该允许将这个文件提供给前端。Gradio 会自动阻止在运行服务器的计算机上提供任意文件的请求。

  • Gradio 会自动将文件放入缓存中,这样就不会保存文件的重复副本。

  • 客户端库将自动知道它们应该在发送请求之前上传输入文件。它们也会自动下载文件。

如果不使用FileData,您的组件将无法按预期工作!

为您的组件添加事件触发器

您组件的事件触发器在EVENTS类属性中定义。 这是一个包含事件字符串名称的列表。 将事件添加到此列表将自动向您的组件添加一个具有相同名称的方法!

你可以从gradio.events导入Events枚举,以访问核心gradio组件中常用的事件。

例如,以下代码将在MyComponent类中定义text_submitfile_uploadchange方法。

from gradio.events import Events
from gradio.components import FormComponent

class MyComponent(FormComponent):

    EVENTS = [
        "text_submit",
        "file_upload",
        Events.change
    ]

提示: 别忘了在 JavaScript 代码中也处理这些事件!

结论