Gradio 自定义组件三大核心概念:interactive 模式、value 与 preprocess/postprocess、Example 示例视图 Gradio 自定义组件三大核心概念interactive 模式、value 与 preprocess/postprocess、Example 示例视图【免费下载链接】gradioBuild and share delightful machine learning apps, all in Python. Star to support our work!项目地址: https://gitcode.com/GitHub_Trending/gr/gradio导读开发自定义组件与使用现成组件的最大区别在于你必须真正理解 Gradio 组件在前端展示与后端函数之间如何协调数据。本指南以官方《Key Component Concepts》为核心逐一拆解三个决定组件行为的关键概念——静态版 / 交互版组件、value 的preprocess/postprocess双向转换、以及Example.svelte示例视图。阅读并对照仓库源码后你将掌握设计自定义组件时不容违背的约定避免做出行为与其它 Gradio 组件格格不入的组件。本指南对应的官方配套章节位于 guides/08_custom-components五分钟上手见 01_custom-components-in-five-minutes.md后端与前端深入指南见 04_backend.md 与 05_frontend.md。若你已熟悉每个组件的preprocess/postprocess内部细节可以略过本篇直接阅读上述深入指南。一、Interactive vs Static组件的两种形态Gradio 中每个组件都提供静态static形态而大多数组件还额外提供交互interactive形态static 版本用于展示一个值的场景用户无法通过操作界面改变该值。interactive 版本用于用户可以操作界面改变该值的场景。在渲染层面这两个概念与interactive参数直接对应。例如两个gr.Textbox仅差一个布尔值import gradio as gr with gr.Blocks() as demo: gr.Textbox(valueHello, interactiveTrue) gr.Textbox(valueHello, interactiveFalse) demo.launch()运行后页面会出现两个文本框唯一的区别是上方的可以编辑内容下方的处于禁用状态、不可编辑。对于媒体类组件两者的差异往往更大。以Image为例import gradio as gr with gr.Blocks() as demo: gr.Image(interactiveTrue) gr.Image(interactiveFalse) demo.launch()gr.Image(interactiveTrue)的交互版组件要复杂得多——它允许上传图片、从剪贴板粘贴甚至调用摄像头拍照sources[upload, webcam, clipboard]而gr.Image(interactiveFalse)的静态版只能用于展示已有图片。值得注意的是并非所有组件都有独立的交互版。例如gr.AnnotatedImage只有静态形态因为注解和底图本身不存在通过界面交互地修改值的方式。对照源码可以看到annotated_image.py 的构造函数确实没有接收interactive关键字——它天生只作为输出/展示组件使用。模式选择的判定规则事件输入 → 交互版只要组件被用作某个事件的输入例如出现在fn的入参中Gradio 就会使用它的交互版本如果存在否则使用静态版本。输出方向上的默认非交互在Interface中若组件的interactive显式为None未指定且该组件是输出组件Gradio 会强制把它设为False。这一逻辑可直接在源码 interface.py 中看到if o.interactive is None: o.interactive False注释明确写着除非显式指定否则强制输出组件为非交互。对自定义组件作者的硬性要求Python 侧你必须在 Python 类的构造函数中接受布尔型interactive关键字。前端侧你可以接受interactive属性——一个表示静态还是交互的布尔值。警告如果你在前端不使用这个属性你的组件在交互/静态两种模式下外观将完全一样。在 Python 侧接受interactive关键字不是口头约定而是Component基类构造函数的正式签名之一。查看 base.py 可以看到Component.__init__定义了interactive: bool | None None形参并保存为self.interactive。所有内置组件如 image.py 中super().__init__(..., interactiveinteractive, ...)都会把它层层透传给基类自定义组件也应遵循同一套透传模式保证与Interface/Blocks的默认逻辑协同工作。二、value 以及它的 preprocess / postprocess一个组件最重要的属性是它的value。每个组件都有value对交互版组件value通常由用户在前端设置对静态版组件value是被展示给用户的内容当用户触发事件时正是这个value被发送给后端函数当你的函数返回结果时如预测结束时value又承载函数的返回值。value在前端与后端之间被频繁传递但前端格式与后端格式并不总是一致于是组件需要做转换。以经典示例对应仓库 demo sepia_filter为例import numpy as np import gradio as gr def sepia(input_img): sepia_filter np.array([ [0.393, 0.769, 0.189], [0.349, 0.686, 0.168], [0.272, 0.534, 0.131] ]) sepia_img input_img.dot(sepia_filter.T) sepia_img / sepia_img.max() return sepia_img demo gr.Interface(sepia, gr.Image(width200, height200), image) demo.launch()这个应用输入输出都是Image组件但两端数据形态不同前端 → 后端Image组件实际上会把文件上传到服务器并只发送文件路径filepath但该路径在送入你的函数之前会被转换成numpy数组。后端 → 前端当你的函数返回numpy数组时这个数组会被转换回文件以便发送到前端并由Image组件展示。补充说明Image默认给 Python 函数传numpy数组是因为它对机器学习工程师而言是最常见的约定但Image也支持通过type参数选择其它格式如pil、filepath。每个组件必须实现的两个转换每个组件都要做两类转换preprocess把前端发来的value转换成Python 函数期望的格式。通常是从 Web 友好的JSON结构转为Python 原生数据结构如numpy数组或PIL图像。Audio、Image是preprocess的典型代表。postprocess把Python 函数返回的value转换成前端期望的格式。通常是从Python 原生数据结构如PIL图像转为JSON结构。在源码层面这两个方法被定义为Component基类的抽象方法。查看 base.pyabstractmethod def preprocess(self, payload: Any) - Any: ... The preprocessed input data sent to the users function in the backend. abstractmethod def postprocess(self, value): ... The postprocessed output data sent to the frontend.以真实组件印证Image的preprocess调用image_utils.preprocess_image(...)把上传产生的ImageData本质是FileData按type转成numpy数组、PIL.Image或文件路径字符串其postprocess则调用image_utils.postprocess_image(...)把numpy数组 /PIL.Image/ 文件路径转回FileData对象详见 image.py。对自定义组件作者的硬性要求每个组件都必须实现preprocess和postprocess。在极少数无需任何转换的场景下直接原样返回该值即可——Textbox和Number就是这类例子它们前后端数据都是基础 JSON 标量见 textbox.py其preprocess/postprocess只是返回自身。转换格式完全由你把控作为组件作者前端展示的数据格式、以及使用者拿到的数据格式都由你决定。请为 Python 开发者设计一个符合直觉、符合人体工程学的数据结构并用preprocess/postprocess掌控它与Web 友好 JSON结构之间的双向转换。设计建议转换的着陆点应尽量贴近组件使用者的心智模型。机器学习场景常见的做法是前端保持轻量的 JSON / 文件引用后端则提供numpy、PIL等科学计算原生对象从而让用户函数可以拿过来直接用。三、组件的 Example 版本示例视图Gradio 应用支持提供示例输入examples这对帮助用户快速上手你的应用非常有用在gr.Interface中用examples关键字提供示例在gr.Blocks中用特殊的gr.Examples组件提供示例。示例在界面上呈现为可点击的小卡片例如一张缩略猎豹图片用户点击后该示例值就会被填充到对应的输入组件中。启用示例视图的前提两个 Svelte 文件要启用示例视图你的组件前端目录顶部必须包含两个文件命名不可随意更改Example.svelte对应组件的示例版本Index.svelte对应常规版本。这一约定在仓库的前端组件目录中有大量实例例如图像组件就同时具备 Index.svelte 与 Example.svelteGradio 正是依靠这两个入口文件区分正式组件视图与示例缩略视图。后端默认无需额外工作在后端你通常什么都不用做用户提供的示例value会复用前面介绍的同一个.postprocess()方法进行加工。如果你希望用不同的方式处理示例数据例如你的.postprocess()计算开销很大不希望它在渲染示例缩略图时重复执行可以为自定义组件单独编写.process_example()方法Gradio 会优先使用它。这一机制在基类源码中清晰可见。base.py 中Component.process_example的默认实现就是return self.postprocess(value)同时其 docstring 明确解释了为什么可以重写它Audio组件的process_example()只返回文件名而不返回完整处理后的音频Dataframe的process_example()只返回 DataFrame 的表头部分而非完整表格。要点是该方法或其默认走postprocess的结果必须能被 JSON 序列化因为它会写入 config 供前端渲染示例。对自定义组件作者的硬性要求如果你预期组件会被用作输入务必定义一个Example 视图Example.svelte。 如果你不定义Gradio 虽然会使用一个默认视图兜底但它远不如你精心设计的示例视图信息丰富。Example.svelte的写法与process_example()的进阶用法分别会在前端指南 05_frontend.md 与后端指南 04_backend.md 中深入展开。四、总结动手前必须记住的三件事开发自己的 Gradio 组件时请把本文的要点当作组件行为公约双形态Python 构造函数必须接收interactive布尔关键字前端应消费interactive属性以区分可编辑的交互版与纯展示的静态版。请牢记 Gradio 的自动选择规则——组件作为事件输入时倾向交互版而Interface的输出组件在未显式指定时会被强制设为非交互见 interface.py。双向转换每个组件必须实现preprocessJSON → Python 原生结构与postprocessPython 原生结构 → JSON。你完全掌控两端的值的形态请站在 Python 使用者的角度设计直觉化的数据结构。无需转换时可原样返回参考 textbox.py需要复杂转换时可对照Image的实现image.py。示例视图若组件可能作为输入请在frontend目录提供Example.svelte与Index.svelte后端示例数据默认走process_example()其默认实现即调用postprocess()见 base.py开销大可自行重写但务必保证返回结果可 JSON 序列化。理解并遵守这三条约定后你的组件在Interface、Blocks、gr.Examples与事件系统中就会表现得与官方内置组件一致。接下来即可进入动手环节先用 01_custom-components-in-five-minutes.md 五分钟搭建第一个自定义组件再通过 03_configuration.md、04_backend.md 与 05_frontend.md 完善它的配置、后端逻辑与前端界面。【免费下载链接】gradioBuild and share delightful machine learning apps, all in Python. Star to support our work!项目地址: https://gitcode.com/GitHub_Trending/gr/gradio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考