Gradio 月活用户突破 100 万!

阅读更多
Gradio logo
  1. 自定义组件
  2. 前端

前端 🌐⭐️

本指南将涵盖您实现自定义组件前端所需了解的一切。

提示: Gradio 组件使用 Svelte。编写 Svelte 很有趣!如果您不熟悉它,我们建议您查看他们的交互式[指南](https://learn.svelte.dev/tutorial/welcome-to-svelte)。

目录结构

前端代码应至少包含三个文件

  • Index.svelte:这是主要导出,也是组件的布局和逻辑所在。
  • Example.svelte:这是定义组件示例视图的位置。

随意添加其他文件和子目录。如果您想导出任何其他模块,请记住修改 package.json 文件

"exports": {
    ".": "./Index.svelte",
    "./example": "./Example.svelte",
    "./package.json": "./package.json"
},

Index.svelte 文件

您的组件应公开以下属性,这些属性将从父 Gradio 应用程序向下传递。

import type { LoadingStatus } from "@gradio/statustracker";
import type { Gradio } from "@gradio/utils";

export let gradio: Gradio<{
    event_1: never;
    event_2: never;
}>;

export let elem_id = "";
export let elem_classes: string[] = [];
export let scale: number | null = null;
export let min_width: number | undefined = undefined;
export let loading_status: LoadingStatus | undefined = undefined;
export let mode: "static" | "interactive";
  • elem_idelem_classes 允许 Gradio 应用开发者使用来自 Python Blocks 类的自定义 CSS 和 JavaScript 定位您的组件。

  • scalemin_width 允许 Gradio 应用开发者控制您的组件在 UI 中占据多少空间。

  • loading_status 用于在组件作为事件的输出时显示加载状态。

  • mode 是父 Gradio 应用告知您的组件应显示 interactive 版本还是 static 版本的方式。

  • gradiogradio 对象由父 Gradio 应用创建。它存储一些应用程序级别的配置,这些配置在您的组件中很有用,例如国际化。您必须使用它从您的组件调度事件。

一个最小的 Index.svelte 文件可能如下所示

<script lang="ts">
	import type { LoadingStatus } from "@gradio/statustracker";
    import { Block } from "@gradio/atoms";
	import { StatusTracker } from "@gradio/statustracker";
	import type { Gradio } from "@gradio/utils";

	export let gradio: Gradio<{
		event_1: never;
		event_2: never;
	}>;

    export let value = "";
	export let elem_id = "";
	export let elem_classes: string[] = [];
	export let scale: number | null = null;
	export let min_width: number | undefined = undefined;
	export let loading_status: LoadingStatus | undefined = undefined;
    export let mode: "static" | "interactive";
</script>

<Block
	visible={true}
	{elem_id}
	{elem_classes}
	{scale}
	{min_width}
	allow_overflow={false}
	padding={true}
>
	{#if loading_status}
		<StatusTracker
			autoscroll={gradio.autoscroll}
			i18n={gradio.i18n}
			{...loading_status}
		/>
	{/if}
    <p>{value}</p>
</Block>

Example.svelte 文件

Example.svelte 文件应公开以下属性

    export let value: string;
    export let type: "gallery" | "table";
    export let selected = false;
    export let index: number;
  • value:应显示的示例值。

  • type:这是一个变量,可以是 "gallery""table",具体取决于示例的显示方式。当示例对应于单个输入组件时,使用 "gallery" 形式,而当用户有多个输入组件,并且示例需要填充所有组件时,使用 "table" 形式。

  • selected:如果用户通过使用 selected 变量“选择”了特定示例,您还可以调整示例的显示方式。

  • index:所选值的当前索引。

  • 您的“非示例”组件所需的任何其他属性!

这是 Radio 代码组件的 Example.svelte 文件

<script lang="ts">
	export let value: string;
	export let type: "gallery" | "table";
	export let selected = false;
</script>

<div
	class:table={type === "table"}
	class:gallery={type === "gallery"}
	class:selected
>
	{value}
</div>

<style>
	.gallery {
		padding: var(--size-1) var(--size-2);
	}
</style>

处理文件

如果您的组件处理文件,则这些文件应该上传到后端服务器。@gradio/client npm 包提供了 uploadprepare_files 实用程序函数来帮助您完成此操作。

prepare_files 函数会将浏览器的 File 数据类型转换为 gradio 的内部 FileData 类型。您应该在组件中使用 FileData 数据来跟踪上传的文件。

upload 函数会将 FileData 值的数组上传到服务器。

这是一个从 <input> 元素加载文件的示例,当其值更改时。

<script lang="ts">
    import { upload, prepare_files, type FileData } from "@gradio/client";
    export let root;
    export let value;
    let uploaded_files;

    async function handle_upload(file_data: FileData[]): Promise<void> {
        await tick();
        uploaded_files = await upload(file_data, root);
    }

    async function loadFiles(files: FileList): Promise<void> {
        let _files: File[] = Array.from(files);
        if (!files.length) {
            return;
        }
        if (file_count === "single") {
            _files = [files[0]];
        }
        let file_data = await prepare_files(_files);
        await handle_upload(file_data);
    }

    async function loadFilesFromUpload(e: Event): Promise<void> {
		const target = e.target;

		if (!target.files) return;
		await loadFiles(target.files);
	}
</script>

<input
    type="file"
    on:change={loadFilesFromUpload}
    multiple={true}
/>

该组件公开了一个名为 root 的属性。这是由父 gradio 应用向下传递的,它表示文件将上传到和从中获取的基本 URL。

对于 WASM 支持,您应该从 Context 获取 upload 函数,并将其作为 upload 函数的第三个参数传递。

<script lang="ts">
    import { getContext } from "svelte";
    const upload_fn = getContext<typeof upload_files>("upload_files");

    async function handle_upload(file_data: FileData[]): Promise<void> {
        await tick();
        await upload(file_data, root, upload_fn);
    }
</script>

利用现有的 Gradio 组件

Gradio 的大多数前端组件都发布在 npm,即 javascript 包存储库上。这意味着您可以使用它们来节省时间,同时在组件中融入常见模式,例如上传文件。例如,@gradio/upload 包具有 UploadModifyUpload 组件,用于正确地将文件上传到 Gradio 服务器。以下是如何使用它们来创建用户界面以上传和显示 PDF 文件。

<script>
	import { type FileData, Upload, ModifyUpload } from "@gradio/upload";
	import { Empty, UploadText, BlockLabel } from "@gradio/atoms";
</script>

<BlockLabel Icon={File} label={label || "PDF"} />
{#if value === null && interactive}
    <Upload
        filetype="application/pdf"
        on:load={handle_load}
        {root}
        >
        <UploadText type="file" i18n={gradio.i18n} />
    </Upload>
{:else if value !== null}
    {#if interactive}
        <ModifyUpload i18n={gradio.i18n} on:clear={handle_clear}/>
    {/if}
    <iframe title={value.orig_name || "PDF"} src={value.data} height="{height}px" width="100%"></iframe>
{:else}
    <Empty size="large"> <File/> </Empty>	
{/if}

您还可以组合现有的 Gradio 组件来创建完全独特的体验。例如,渲染聊天机器人对话的画廊。可能性是无限的,请阅读我们 javascript 包的文档此处。我们将在未来几周内添加更多包和文档!

匹配 Gradio Core 的设计系统

您可以通过 Storybook 探索我们的组件库。您将能够与我们的组件进行交互,并查看它们的不同状态。

对于那些对设计定制感兴趣的人,我们提供了 CSS 变量,其中包括我们的调色板、半径、间距以及我们使用的图标 - 因此您可以轻松地将您的自定义组件与我们核心组件的样式相匹配。此 Storybook 将定期更新任何新增内容或更改。

Storybook 链接

自定义配置

如果您想利用庞大的 vite 生态系统,可以使用 gradio.config.js 文件来配置组件的构建过程。这允许您使用 tailwindcss、mdsvex 等工具。

目前,可以配置以下内容

Vite 选项

  • plugins:要使用的 vite 插件列表。

Svelte 选项

  • preprocess:要使用的 svelte 预处理器列表。
  • extensions:要编译为 .svelte 文件的文件扩展名列表。
  • build.target:要构建的目标,这可能是支持较新的 javascript 功能所必需的。有关更多信息,请参阅 esbuild 文档

gradio.config.js 文件应放置在组件 frontend 目录的根目录下。当您创建一个新组件时,将为您创建一个默认的配置文件。但是,如果不存在配置文件,您也可以创建自己的配置文件,并使用它来自定义组件的构建过程。

Vite 插件示例

自定义组件可以使用 Vite 插件来自定义构建过程。请查看 Vite 文档 以获取更多信息。

这里我们配置了 TailwindCSS,一个实用至上的 CSS 框架。使用版本 4 预发布版可以最轻松地进行设置。

npm install tailwindcss@next @tailwindcss/vite@next

gradio.config.js

import tailwindcss from "@tailwindcss/vite";
export default {
    plugins: [tailwindcss()]
};

然后创建一个包含以下内容的 style.css 文件

@import "tailwindcss";

将此文件导入到 Index.svelte 中。请注意,您需要导入包含 @import 的 css 文件,而不能仅仅使用 <style> 标签并在其中使用 @import

<script lang="ts">
[...]
import "./style.css";
[...]
</script>

Svelte 选项示例

gradio.config.js 中,您还可以指定一些 Svelte 选项,以应用于 Svelte 编译。在此示例中,我们将添加对 mdsvex 的支持,这是一个用于 Svelte 的 Markdown 预处理器。

为了做到这一点,我们需要在 gradio.config.js 中的 svelte 对象中添加一个 Svelte 预处理器,并配置 extensions 字段。目前不支持其他选项。

首先,安装 mdsvex 插件

npm install mdsvex

然后将以下内容添加到 gradio.config.js

import { mdsvex } from "mdsvex";

export default {
    svelte: {
        preprocess: [
            mdsvex()
        ],
        extensions: [".svelte", ".svx"]
    }
};

现在我们可以在组件的 frontend 目录中创建 mdsvex 文档,它们将被编译为 .svelte 文件。

<!-- HelloWorld.svx -->

<script lang="ts">
    import { Block } from "@gradio/atoms";

    export let title = "Hello World";
</script>

<Block label="Hello World">

# {title}

This is a markdown file.

</Block>

然后我们可以在组件中使用 HelloWorld.svx 文件

<script lang="ts">
    import HelloWorld from "./HelloWorld.svx";
</script>

<HelloWorld />

结论

您现在知道如何为您的组件创建令人愉快的前端了!