1. 自定义组件
  2. 后端

后端 🐍

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

应继承哪个类

所有组件都继承自三个类之一:ComponentFormComponentBlockContext。您需要继承其中一个,以便您的组件表现得像所有其他 Gradio 组件一样。当您使用 gradio cc create --template 从模板开始时,您无需担心选择哪个类,因为模板会使用正确的类。为了完整起见,如果您需要从头开始创建自己的组件,我们将解释每个类的用途。

  • FormComponent:当您希望您的组件与其他 FormComponents 一起分组在同一个 Form 布局中时使用。SliderTextboxNumber 组件都是 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 解释器会引发错误!

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

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 类型库中的类来对模型进行类型化。例如,使用 List 而不是 list

处理文件

如果您的组件需要上传文件作为输入,或者向前端返回保存的文件,则必须使用 FileDatadata_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 代码中处理这些事件!

结论

gradio