Gradio Agents & MCP 黑客马拉松

获奖者
Gradio logo
  1. 附加功能
  2. 分享你的应用

分享你的应用

在本指南中,我们将深入探讨与他人分享 Gradio 应用的各个方面。我们将涵盖:

  1. 使用 `share` 参数分享演示
  2. 在 HF Spaces 上托管
  3. 分享深层链接
  4. 嵌入托管 Spaces
  5. 使用 API 页面
  6. 访问网络请求
  7. 在 FastAPI 中挂载
  8. 身份验证
  9. 分析
  10. 渐进式 Web 应用 (PWA)

分享演示

通过在 `launch()` 方法中设置 `share=True`,可以轻松公开分享 Gradio 演示。如下所示:

import gradio as gr

def greet(name):
    return "Hello " + name + "!"

demo = gr.Interface(fn=greet, inputs="textbox", outputs="textbox")

demo.launch(share=True)  # Share your demo with just 1 extra parameter 🚀

这将生成一个可公开分享的链接,你可以发送给任何人!当你发送此链接时,另一端的用户可以在他们的浏览器中尝试该模型。由于处理发生在你的设备上(只要你的设备保持开启),你无需担心任何依赖项的打包问题。

sharing

分享链接通常看起来像这样:**https://07ff8706ab.gradio.live**。尽管链接是通过 Gradio 分享服务器提供的,但这些服务器仅充当你的本地服务器的代理,并且不存储通过你的应用发送的任何数据。分享链接会在 1 周后过期。(也可以在你的云服务器上设置自己的分享服务器来克服此限制。)

提示: 请记住,分享链接是公开可访问的,这意味着任何人都可以使用你的模型进行预测!因此,请确保不要通过你编写的函数暴露任何敏感信息,也不要允许在你的设备上发生任何关键更改。或者,你可以如以下所述,为你的 Gradio 应用添加身份验证

请注意,默认情况下,`share=False`,这意味着你的服务器仅在本地运行。(这是默认设置,但在 Google Colab 笔记本中除外,其中会自动创建分享链接)。作为使用分享链接的替代方案,你可以使用 SSH 端口转发与特定用户分享你的本地服务器。

在 HF Spaces 上托管

如果你希望在互联网上拥有 Gradio 演示的永久链接,请使用 Hugging Face Spaces。Hugging Face Spaces 提供基础设施,可免费永久托管你的机器学习模型!

创建免费的 Hugging Face 帐户后,你有两种方法可以将你的 Gradio 应用部署到 Hugging Face Spaces

  1. 从终端:在你的应用目录中运行 `gradio deploy`。CLI 将收集一些基本元数据,然后启动你的应用。要更新你的 Space,你可以重新运行此命令或启用 GitHub Actions 选项以在 `git push` 时自动更新 Spaces。

  2. 从浏览器:将包含你的 Gradio 模型和所有相关文件的文件夹拖放到此处。有关更多信息,请参阅此关于如何在 Hugging Face Spaces 上托管的指南,或观看嵌入视频

你可以在 Gradio 应用中添加一个按钮,该按钮会创建一个唯一的 URL,你可以使用它与他人分享你的应用以及所有组件的**当前状态**。这对于分享应用中独特有趣的生成结果,或保存应用在特定时间点的快照非常有用。

要在你的应用中添加深层链接按钮,请将 `gr.DeepLinkButton` 组件放置在应用中的任何位置。为了使 URL 对他人可见,你的应用必须通过公共 URL 访问。因此,请确保在启动应用时像 Hugging Face Spaces 那样托管你的应用或使用 `share=True` 参数。

我们来看一个例子,了解它是如何工作的。这是一个使用 `gr.DeepLinkButton` 组件的简单 Gradio 聊天应用。发送几条消息后,点击深层链接按钮并将其粘贴到新的浏览器标签页中,即可查看该应用在当时的状态。

import gradio as gr
import random

def random_response(message, history):
    return random.choice(["Hi!", "Hello!", "Greetings!"])

with gr.Blocks() as demo:
    gr.ChatInterface(
        random_response,
        title="Greeting Bot",
        description="Ask anything and receive a nice greeting!",
    )
    gr.DeepLinkButton()

if __name__ == "__main__":
    demo.launch(share=True)

嵌入托管 Spaces

一旦你将应用托管在 Hugging Face Spaces(或你自己的服务器上),你可能希望将演示嵌入到其他网站,例如你的博客或作品集。嵌入交互式演示允许人们无需下载或安装任何东西,即可在他们的浏览器中直接试用你构建的机器学习模型!最棒的是,你甚至可以将交互式演示嵌入到静态网站中,例如 GitHub Pages。

有两种方法可以嵌入你的 Gradio 演示。你可以在 Hugging Face Space 页面上的“嵌入此 Space”下拉选项中直接找到这两种选项的快速链接

Embed this Space dropdown option

使用 Web Components 嵌入

Web Components 通常比 IFrames 为用户提供更好的体验。Web Components 采用延迟加载,这意味着它们不会减慢你网站的加载时间,并且会根据 Gradio 应用的大小自动调整其高度。

要使用 Web Components 嵌入:

  1. 通过在你的网站中添加以下脚本来导入 Gradio JS 库(将 URL 中的 {GRADIO_VERSION} 替换为你正在使用的 Gradio 库版本)。
<script
	type="module"
	src="https://#/{GRADIO_VERSION}/gradio.js"
></script>
  1. 添加
<gradio-app src="https://$your_space_host.hf.space"></gradio-app>

元素,放置你想要放置应用的位置。将 `src=` 属性设置为你的 Space 的嵌入 URL,你可以在“嵌入此 Space”按钮中找到它。例如:

<gradio-app
	src="https://abidlabs-pytorch-image-classifier.hf.space"
></gradio-app>

你可以在Gradio 登录页面上查看 Web Components 的外观示例。

你还可以通过传递给 `<gradio-app>` 标签的属性来自定义 Web Component 的外观和行为

  • `src`:如我们所见,`src` 属性链接到你想要嵌入的托管 Gradio 演示的 URL
  • `space`:如果你的 Gradio 演示托管在 Hugging Face Space 上,这是一个可选的简写。接受 `username/space_name` 而不是完整的 URL。示例:`gradio/Echocardiogram-Segmentation`。如果提供了此属性,则无需提供 `src`。
  • `control_page_title`:一个布尔值,表示页面 HTML 标题是否应设置为 Gradio 应用的标题(默认为 `"false"`)
  • `initial_height`:Web Component 在加载 Gradio 应用时的初始高度(默认为 `"300px"`)。请注意,最终高度是根据 Gradio 应用的大小设置的。
  • `container`:是否显示边框和有关 Space 托管位置的信息(默认为 `"true"`)
  • `info`:是否仅在嵌入式应用下方显示有关 Space 托管位置的信息(默认为 `"true"`)
  • `autoscroll`:预测完成后是否自动滚动到输出(默认为 `"false"`)
  • `eager`:是否在页面加载后立即加载 Gradio 应用(默认为 `"false"`)
  • `theme_mode`:是否使用 `dark`(深色)、`light`(浅色)或默认的 `system`(系统)主题模式(默认为 `"system"`)
  • `render`:嵌入式 Space 完成渲染后触发的事件。

以下是如何使用这些属性来创建一个不延迟加载且初始高度为 0px 的 Gradio 应用的示例。

<gradio-app
	space="gradio/Echocardiogram-Segmentation"
	eager="true"
	initial_height="0px"
></gradio-app>

以下是另一个使用 `render` 事件的示例。事件监听器用于捕获 `render` 事件,并在渲染完成后调用 `handleLoadComplete()` 函数。

<script>
	function handleLoadComplete() {
		console.log("Embedded space has finished rendering");
	}

	const gradioApp = document.querySelector("gradio-app");
	gradioApp.addEventListener("render", handleLoadComplete);
</script>

注意:Gradio 的 CSS 永远不会影响嵌入页面,但嵌入页面可能会影响嵌入式 Gradio 应用的样式。请确保父页面中的任何 CSS 不会过于通用,以至于它也可能应用于嵌入式 Gradio 应用并导致样式损坏。像 `header { ... }` 和 `footer { ... }` 这样的元素选择器最有可能引起问题。

使用 IFrames 嵌入

如果不能(例如,如果你无法在你的网站中添加 JavaScript),则可以使用 IFrames 嵌入,添加此元素

<iframe src="https://$your_space_host.hf.space"></iframe>

同样,你可以在“嵌入此 Space”按钮中找到你的 Space 的嵌入 URL 的 `src=` 属性。

注意:如果你使用 IFrames,你可能需要添加固定的 `height` 属性并设置 `style="border:0;"` 以去除边框。此外,如果你的应用需要权限,例如访问网络摄像头或麦克风,你也需要使用 `allow` 属性提供这些权限。

API 页面

你几乎可以将任何 Gradio 应用用作 API!在 Gradio 应用(例如此应用)的页脚,你会看到一个“通过 API 使用”链接。

Use via API

此页面列出了可用于通过我们支持的客户端查询 Gradio 应用的端点:无论是Python 客户端还是JavaScript 客户端。对于每个端点,Gradio 都会自动生成参数及其类型,以及示例输入,如下所示。

端点在你启动 Gradio 应用时自动创建。如果你正在使用 Gradio `Blocks`,你还可以为每个事件监听器命名,例如:

btn.click(add, [num1, num2], output, api_name="addition")

这将把 `/addition/` 端点添加到自动生成的 API 页面并进行文档化。在此处阅读更多关于API 页面的信息。

直接访问网络请求

当用户向你的应用发出预测请求时,你可能需要底层网络请求,以便获取请求头(例如用于高级身份验证)、记录客户端 IP 地址、获取查询参数或其他原因。Gradio 以类似于 FastAPI 的方式支持此功能:只需添加一个类型提示为 `gr.Request` 的函数参数,Gradio 就会将网络请求作为该参数传递。以下是一个示例:

import gradio as gr

def echo(text, request: gr.Request):
    if request:
        print("Request headers dictionary:", request.headers)
        print("IP address:", request.client.host)
        print("Query parameters:", dict(request.query_params))
    return text

io = gr.Interface(echo, "textbox", "textbox").launch()

注意:如果你的函数是直接调用而不是通过 UI 调用(例如,当示例被缓存时,或通过 API 调用 Gradio 应用时),则 `request` 将为 `None`。你应该明确处理这种情况,以确保你的应用不会抛出任何错误。这就是我们进行显式检查 `if request` 的原因。

在另一个 FastAPI 应用中挂载

在某些情况下,你可能已经有一个现有的 FastAPI 应用,并且希望为 Gradio 演示添加一个路径。你可以使用 `gradio.mount_gradio_app()` 轻松实现此操作。

以下是一个完整示例:

from fastapi import FastAPI
import gradio as gr

CUSTOM_PATH = "/gradio"

app = FastAPI()

@app.get("/")
def read_main():
    return {"message": "This is your main app"}

io = gr.Interface(lambda x: "Hello, " + x + "!", "textbox", "textbox")
app = gr.mount_gradio_app(app, io, path=CUSTOM_PATH)

# Run this from the terminal as you would normally start a FastAPI app: `uvicorn run:app`
# and navigate to https://:8000/gradio in your browser.

请注意,这种方法还允许你在自定义路径上运行 Gradio 应用(在上面的示例中为 `https://:8000/gradio`)。

身份验证

密码保护应用

你可能希望在你的应用前面设置一个身份验证页面,以限制谁可以打开你的应用。通过 `launch()` 方法中的 `auth=` 关键字参数,你可以提供一个包含用户名和密码的元组,或一个可接受的用户名/密码元组列表;以下是一个为名为“admin”的单个用户提供基于密码的身份验证的示例:

demo.launch(auth=("admin", "pass1234"))

对于更复杂的身份验证处理,你甚至可以传递一个函数,该函数接受用户名和密码作为参数,并返回 `True` 允许访问,否则返回 `False`。

以下是一个接受用户名和密码相同即可登录的函数的示例:

def same_auth(username, password):
    return username == password
demo.launch(auth=same_auth)

如果你有多个用户,你可能希望根据登录用户自定义显示的内容。你可以通过如上所述直接访问网络请求来检索已登录用户,然后读取请求的 `.username` 属性。以下是一个示例:

import gradio as gr

def update_message(request: gr.Request):
    return f"Welcome, {request.username}"

with gr.Blocks() as demo:
    m = gr.Markdown()
    demo.load(update_message, None, m)

demo.launch(auth=[("Abubakar", "Abubakar"), ("Ali", "Ali")])

注意:为了使身份验证正常工作,你的浏览器中必须启用第三方 Cookie。Safari 或 Chrome 无痕模式默认情况下不启用此功能。

如果用户访问你的 Gradio 应用的 `/logout` 页面,他们将自动退出登录并删除会话 Cookie。这使得你也可以在 Gradio 应用中添加退出登录功能。让我们更新之前的示例以包含一个退出登录按钮:

import gradio as gr

def update_message(request: gr.Request):
    return f"Welcome, {request.username}"

with gr.Blocks() as demo:
    m = gr.Markdown()
    logout_button = gr.Button("Logout", link="/logout")
    demo.load(update_message, None, m)

demo.launch(auth=[("Pete", "Pete"), ("Dawood", "Dawood")])

注意:Gradio 的内置身份验证提供了一个简单基本的访问控制层,但并未为需要严格访问控制(例如多因素身份验证、速率限制或自动锁定策略)的应用提供强大的安全功能。

OAuth(通过 Hugging Face 登录)

Gradio 原生支持通过 Hugging Face 进行 OAuth 登录。换句话说,你可以轻松地在你的演示中添加一个“*使用 Hugging Face 登录*”按钮,这允许你获取用户的 HF 用户名以及他们 HF 个人资料中的其他信息。请查看此 Space 以获取实时演示。

要启用 OAuth,你必须在 README.md 文件中将 `hf_oauth: true` 设置为 Space 元数据。这将把你的 Space 注册为 Hugging Face 上的 OAuth 应用。接下来,你可以使用 `gr.LoginButton` 将登录按钮添加到你的 Gradio 应用。一旦用户使用他们的 HF 帐户登录,你可以通过向任何 Gradio 函数添加 `gr.OAuthProfile` 类型的参数来检索他们的个人资料。用户个人资料将自动作为参数值注入。如果你想代表用户执行操作(例如列出用户的私有仓库、创建仓库等),你可以通过添加 `gr.OAuthToken` 类型的参数来检索用户令牌。你必须在你的 Space 元数据中定义将使用的范围(有关更多详细信息,请参阅文档)。

以下是一个简短示例:

from __future__ import annotations

import gradio as gr
from huggingface_hub import whoami

def hello(profile: gr.OAuthProfile | None) -> str:
    if profile is None:
        return "I don't know you."
    return f"Hello {profile.name}"

def list_organizations(oauth_token: gr.OAuthToken | None) -> str:
    if oauth_token is None:
        return "Please deploy this on Spaces and log in to list organizations."
    org_names = [org["name"] for org in whoami(oauth_token.token)["orgs"]]
    return f"You belong to {', '.join(org_names)}."

with gr.Blocks() as demo:
    gr.LoginButton()
    m1 = gr.Markdown()
    m2 = gr.Markdown()
    demo.load(hello, inputs=None, outputs=m1)
    demo.load(list_organizations, inputs=None, outputs=m2)

demo.launch()

当用户点击登录按钮时,他们将被重定向到一个新页面以授权你的 Space。

用户可以随时在他们的设置中撤销对其个人资料的访问权限。

如上所述,OAuth 功能仅在你的应用在 Space 中运行时可用。但是,你通常需要在部署之前在本地测试你的应用。要在本地测试 OAuth 功能,你的机器必须登录 Hugging Face。请运行 `huggingface-cli login` 或将 `HF_TOKEN` 设置为环境变量,其中包含你的访问令牌之一。你可以在设置页面(https://hugging-face.cn/settings/tokens)中生成新令牌。然后,点击 `gr.LoginButton` 将登录你的本地 Hugging Face 个人资料,允许你在将应用部署到 Space 之前使用你的 Hugging Face 帐户调试你的应用。

安全提示:请务必注意,添加 `gr.LoginButton` 不会像添加用户名-密码身份验证那样限制用户使用你的应用。这意味着即使未通过 Hugging Face 登录的用户仍然可以访问并运行你的 Gradio 应用中的事件——区别在于 `gr.OAuthProfile` 或 `gr.OAuthToken` 在相应的函数中将为 `None`。

OAuth(与外部提供商)

在 Gradio 应用中,也可以使用外部 OAuth 提供商(例如 Google OAuth)进行身份验证。为此,首先将你的 Gradio 应用挂载到 FastAPI 应用中(如上所述)。然后,你必须编写一个身份验证函数,该函数从 OAuth 提供商获取用户的用户名并返回。此函数应传递给 `gr.mount_gradio_app` 中的 `auth_dependency` 参数。

FastAPI 依赖函数类似,`auth_dependency` 指定的函数将在你的 FastAPI 应用中的任何 Gradio 相关路由之前运行。该函数应接受一个参数:FastAPI `Request`,并返回一个字符串(表示用户的用户名)或 `None`。如果返回一个字符串,用户将能够访问你的 FastAPI 应用中的 Gradio 相关路由。

首先,我们展示一个简化示例来说明 `auth_dependency` 参数:

from fastapi import FastAPI, Request
import gradio as gr

app = FastAPI()

def get_user(request: Request):
    return request.headers.get("user")

demo = gr.Interface(lambda s: f"Hello {s}!", "textbox", "textbox")

app = gr.mount_gradio_app(app, demo, path="/demo", auth_dependency=get_user)

if __name__ == '__main__':
    uvicorn.run(app)

在此示例中,只有包含“user”头的请求才被允许访问 Gradio 应用。当然,这并不能增加多少安全性,因为任何用户都可以在其请求中添加此头。

以下是一个更完整的示例,展示如何将 Google OAuth 添加到 Gradio 应用(假设你已经在 Google Developer Console 上创建了 OAuth 凭据):

import os
from authlib.integrations.starlette_client import OAuth, OAuthError
from fastapi import FastAPI, Depends, Request
from starlette.config import Config
from starlette.responses import RedirectResponse
from starlette.middleware.sessions import SessionMiddleware
import uvicorn
import gradio as gr

app = FastAPI()

# Replace these with your own OAuth settings
GOOGLE_CLIENT_ID = "..."
GOOGLE_CLIENT_SECRET = "..."
SECRET_KEY = "..."

config_data = {'GOOGLE_CLIENT_ID': GOOGLE_CLIENT_ID, 'GOOGLE_CLIENT_SECRET': GOOGLE_CLIENT_SECRET}
starlette_config = Config(environ=config_data)
oauth = OAuth(starlette_config)
oauth.register(
    name='google',
    server_metadata_url='https://#/.well-known/openid-configuration',
    client_kwargs={'scope': 'openid email profile'},
)

SECRET_KEY = os.environ.get('SECRET_KEY') or "a_very_secret_key"
app.add_middleware(SessionMiddleware, secret_key=SECRET_KEY)

# Dependency to get the current user
def get_user(request: Request):
    user = request.session.get('user')
    if user:
        return user['name']
    return None

@app.get('/')
def public(user: dict = Depends(get_user)):
    if user:
        return RedirectResponse(url='/gradio')
    else:
        return RedirectResponse(url='/login-demo')

@app.route('/logout')
async def logout(request: Request):
    request.session.pop('user', None)
    return RedirectResponse(url='/')

@app.route('/login')
async def login(request: Request):
    redirect_uri = request.url_for('auth')
    # If your app is running on https, you should ensure that the
    # `redirect_uri` is https, e.g. uncomment the following lines:
    #
    # from urllib.parse import urlparse, urlunparse
    # redirect_uri = urlunparse(urlparse(str(redirect_uri))._replace(scheme='https'))
    return await oauth.google.authorize_redirect(request, redirect_uri)

@app.route('/auth')
async def auth(request: Request):
    try:
        access_token = await oauth.google.authorize_access_token(request)
    except OAuthError:
        return RedirectResponse(url='/')
    request.session['user'] = dict(access_token)["userinfo"]
    return RedirectResponse(url='/')

with gr.Blocks() as login_demo:
    gr.Button("Login", link="/login")

app = gr.mount_gradio_app(app, login_demo, path="/login-demo")

def greet(request: gr.Request):
    return f"Welcome to Gradio, {request.username}"

with gr.Blocks() as main_demo:
    m = gr.Markdown("Welcome to Gradio!")
    gr.Button("Logout", link="/logout")
    main_demo.load(greet, None, m)

app = gr.mount_gradio_app(app, main_demo, path="/gradio", auth_dependency=get_user)

if __name__ == '__main__':
    uvicorn.run(app)

这个示例中实际上有两个独立的 Gradio 应用!一个只是简单地显示一个登录按钮(这个演示对任何用户都可访问),而另一个主演示只对已登录的用户可访问。你可以在这个 Space 上尝试这个示例。

分析

默认情况下,Gradio 会收集某些分析数据,以帮助我们更好地了解 `gradio` 库的使用情况。这包括以下信息:

  • Gradio 应用运行的环境(例如 Colab Notebook、Hugging Face Spaces)
  • Gradio 应用中使用的输入/输出组件
  • Gradio 应用是否使用了某些高级功能,例如 `auth` 或 `show_error`
  • 仅用于衡量使用 Gradio 的独立开发者数量的 IP 地址
  • 正在运行的 Gradio 版本

不会从你的 Gradio 应用的*用户*那里收集任何信息。如果你想完全禁用分析功能,可以通过在 `gr.Blocks`、`gr.Interface` 或 `gr.ChatInterface` 中将 `analytics_enabled` 参数设置为 `False` 来实现。或者,你可以将 GRADIO_ANALYTICS_ENABLED 环境变量设置为 `"False"`,以便将其应用于系统上创建的所有 Gradio 应用。

注意:这反映了 `gradio>=4.32.0` 版本起的分析策略。

渐进式 Web 应用 (PWA)

渐进式 Web 应用 (PWA) 是常规网页或网站,但可以像可安装的平台特定应用一样向用户呈现。

通过在 `launch()` 方法中设置 `pwa=True` 参数,Gradio 应用可以轻松地作为 PWA 提供服务。以下是一个示例:

import gradio as gr

def greet(name):
    return "Hello " + name + "!"

demo = gr.Interface(fn=greet, inputs="textbox", outputs="textbox")

demo.launch(pwa=True)  # Launch your app as a PWA

这将生成一个可以安装在你设备上的 PWA。它看起来是这样的:

Installing PWA

当你在 `launch()` 方法中指定 `favicon_path` 时,该图标将用作应用的图标。以下是一个示例:

demo.launch(pwa=True, favicon_path="./hf-logo.svg")  # Use a custom icon for your PWA

Custom PWA Icon