Gradio Agents & MCP 黑客马拉松
获奖者Gradio Agents & MCP 黑客马拉松
获奖者在本指南中,我们将深入探讨与他人分享 Gradio 应用的各个方面。我们将涵盖:
通过在 `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 🚀
这将生成一个可公开分享的链接,你可以发送给任何人!当你发送此链接时,另一端的用户可以在他们的浏览器中尝试该模型。由于处理发生在你的设备上(只要你的设备保持开启),你无需担心任何依赖项的打包问题。
分享链接通常看起来像这样:**https://07ff8706ab.gradio.live**。尽管链接是通过 Gradio 分享服务器提供的,但这些服务器仅充当你的本地服务器的代理,并且不存储通过你的应用发送的任何数据。分享链接会在 1 周后过期。(也可以在你的云服务器上设置自己的分享服务器来克服此限制。)
提示: 请记住,分享链接是公开可访问的,这意味着任何人都可以使用你的模型进行预测!因此,请确保不要通过你编写的函数暴露任何敏感信息,也不要允许在你的设备上发生任何关键更改。或者,你可以如以下所述,为你的 Gradio 应用添加身份验证。
请注意,默认情况下,`share=False`,这意味着你的服务器仅在本地运行。(这是默认设置,但在 Google Colab 笔记本中除外,其中会自动创建分享链接)。作为使用分享链接的替代方案,你可以使用 SSH 端口转发与特定用户分享你的本地服务器。
如果你希望在互联网上拥有 Gradio 演示的永久链接,请使用 Hugging Face Spaces。Hugging Face Spaces 提供基础设施,可免费永久托管你的机器学习模型!
在创建免费的 Hugging Face 帐户后,你有两种方法可以将你的 Gradio 应用部署到 Hugging Face Spaces
从终端:在你的应用目录中运行 `gradio deploy`。CLI 将收集一些基本元数据,然后启动你的应用。要更新你的 Space,你可以重新运行此命令或启用 GitHub Actions 选项以在 `git push` 时自动更新 Spaces。
从浏览器:将包含你的 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)
一旦你将应用托管在 Hugging Face Spaces(或你自己的服务器上),你可能希望将演示嵌入到其他网站,例如你的博客或作品集。嵌入交互式演示允许人们无需下载或安装任何东西,即可在他们的浏览器中直接试用你构建的机器学习模型!最棒的是,你甚至可以将交互式演示嵌入到静态网站中,例如 GitHub Pages。
有两种方法可以嵌入你的 Gradio 演示。你可以在 Hugging Face Space 页面上的“嵌入此 Space”下拉选项中直接找到这两种选项的快速链接
Web Components 通常比 IFrames 为用户提供更好的体验。Web Components 采用延迟加载,这意味着它们不会减慢你网站的加载时间,并且会根据 Gradio 应用的大小自动调整其高度。
要使用 Web Components 嵌入:
<script
type="module"
src="https://#/{GRADIO_VERSION}/gradio.js"
></script>
<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 的外观和行为
以下是如何使用这些属性来创建一个不延迟加载且初始高度为 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 { ... }` 这样的元素选择器最有可能引起问题。
如果不能(例如,如果你无法在你的网站中添加 JavaScript),则可以使用 IFrames 嵌入,添加此元素
<iframe src="https://$your_space_host.hf.space"></iframe>
同样,你可以在“嵌入此 Space”按钮中找到你的 Space 的嵌入 URL 的 `src=` 属性。
注意:如果你使用 IFrames,你可能需要添加固定的 `height` 属性并设置 `style="border:0;"` 以去除边框。此外,如果你的应用需要权限,例如访问网络摄像头或麦克风,你也需要使用 `allow` 属性提供这些权限。
你几乎可以将任何 Gradio 应用用作 API!在 Gradio 应用(例如此应用)的页脚,你会看到一个“通过 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 应用,并且希望为 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 的内置身份验证提供了一个简单基本的访问控制层,但并未为需要严格访问控制(例如多因素身份验证、速率限制或自动锁定策略)的应用提供强大的安全功能。
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`。
在 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 应用的*用户*那里收集任何信息。如果你想完全禁用分析功能,可以通过在 `gr.Blocks`、`gr.Interface` 或 `gr.ChatInterface` 中将 `analytics_enabled` 参数设置为 `False` 来实现。或者,你可以将 GRADIO_ANALYTICS_ENABLED 环境变量设置为 `"False"`,以便将其应用于系统上创建的所有 Gradio 应用。
注意:这反映了 `gradio>=4.32.0` 版本起的分析策略。
渐进式 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。它看起来是这样的:
当你在 `launch()` 方法中指定 `favicon_path` 时,该图标将用作应用的图标。以下是一个示例:
demo.launch(pwa=True, favicon_path="./hf-logo.svg") # Use a custom icon for your PWA