Gradio 月活用户达到 100 万!

阅读更多
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 共享服务器提供的,但这些服务器只是您本地服务器的代理,并且不存储通过您的应用发送的任何数据。共享链接在 72 小时后过期。(也可以在您自己的云服务器上设置您自己的共享服务器,以克服此限制。)

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

请注意,默认情况下,share=False,这意味着您的服务器仅在本地运行。(这是默认设置,但在 Google Colab 笔记本中除外,在 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,您可以使用该 URL 与他人分享您的应用以及所有组件的当前状态。 这对于分享来自您的应用的独特而有趣的生成结果,或用于保存在特定时间点的应用快照非常有用。

要向您的应用添加深度链接按钮,请将 gr.DeepLinkButton 组件放置在应用中的任何位置。 为了使 URL 可供其他人访问,您的应用必须在公共 URL 上可用。 因此,请务必像 Hugging Face Spaces 一样托管您的应用,或在使用启动应用时使用 share=True 参数。

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

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 页面)中,您也可以嵌入交互式演示。

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

Embed this Space dropdown option

使用 Web Components 嵌入

与 IFrames 相比,Web components 通常为用户提供更好的体验。 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,您可以在“Embed this Space”按钮中找到它。 例如

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

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

您还可以通过传递到 <gradio-app> 标签的属性来自定义您的 Web 组件的外观和行为

  • 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 组件在加载 Gradio 应用时的初始高度(默认为 "300px")。请注意,最终高度是根据 Gradio 应用的大小设置的。
  • container: 是否显示边框框架以及有关 Space 托管位置的信息(默认为 "true"
  • info: 是否仅在嵌入式应用下方显示有关 Space 托管位置的信息(默认为 "true"
  • autoscroll: 是否在预测完成后自动滚动到输出(默认为 "false"
  • eager: 是否在页面加载时立即加载 Gradio 应用(默认为 "false"
  • theme_mode: 是否使用 darklight 或默认的 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 嵌入

要使用 IFrames 嵌入(例如,如果您无法将 javascript 添加到您的网站),请添加此元素

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

同样,您可以在 Space 的嵌入 URL 中找到 src= 属性,您可以在“Embed this Space(嵌入此 Space)”按钮中找到它。

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

API 页面

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

Use via API

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

当您启动 Gradio Interface 时,会自动创建端点。如果您使用的是 Gradio Blocks,您也可以设置 Gradio API 页面,但我们建议您显式命名每个事件侦听器,例如

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

这将把端点 /api/addition/ 添加到自动生成的 API 页面并进行文档化。否则,您的 API 端点将显示为“unnamed(未命名)”端点。

直接访问网络请求

当用户对您的应用进行预测时,您可能需要底层的网络请求,以便获取请求头(例如,用于高级身份验证)、记录客户端的 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 调用(例如,当示例被缓存时,或者当 Gradio 应用通过 API 调用时),则 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 http://localhost:8000/gradio in your browser.

请注意,这种方法还允许您在自定义路径上运行 Gradio 应用(在上面的示例中为 http://localhost: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 登录。换句话说,您可以轻松地向您的演示添加一个“Sign in with Hugging Face(使用 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.OAuthProfilegr.OAuthToken 在相应的函数中将为 None

OAuth (使用外部提供商)

在您的 Gradio 应用中,也可以使用外部 OAuth 提供商(例如 Google OAuth)进行身份验证。为此,首先在 FastAPI 应用中挂载您的 Gradio 应用(如上所述)。然后,您必须编写一个身份验证函数,该函数从 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 应用是否正在使用某些高级功能,例如 authshow_error
  • IP 地址,仅用于衡量使用 Gradio 的唯一开发人员的数量
  • 正在运行的 Gradio 版本

不会从您的 Gradio 应用的用户那里收集任何信息。如果您想完全禁用分析,您可以在 gr.Blocksgr.Interfacegr.ChatInterface 中将 analytics_enabled 参数设置为 False。或者,您可以将 GRADIO_ANALYTICS_ENABLED 环境变量设置为 "False",以将其应用于在您的系统上创建的所有 Gradio 应用。

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

渐进式 Web 应用 (PWA)

渐进式 Web 应用 (PWA) 是常规网页或网站的 Web 应用程序,但对用户而言,它们可以像可安装的特定于平台的应用程序一样显示。

通过在 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