当前位置: 首页 > news >正文

大模型WebUI:Gradio全解系列9——Additional Features:补充特性(下)

大模型WebUI:Gradio全解系列9——Additional Features:补充特性(下)

  • 前言
  • 本篇摘要
  • 8. Additional Features:补充特性
    • 8.5 分享demo
      • 8.5.1 嵌入托管 Spaces
      • 8.5.2 使用 Web Components 嵌入
      • 8.5.3 Embedding with IFrames
    • 8.6 访问网络请求和网络分析
      • 8.6.1 直接访问网络请求
      • 8.6.1 网络分析
    • 8.7 授权
      • 8.7.1 OAuth(通过 Hugging Face 登录)
      • 8.7.2 OAuth (with external providers)
    • 8.8 安全访问文件
      • 8.8.1 Gradio文件访问限制
        • 1. Gradio 允许用户访问的文件
        • 2. Gradio 不允许他人访问的文件
      • 8.8.2 Gradio缓存
        • 1. 缓存作用
        • 2. Gradio移动到缓存的文件
      • 8.8.3 文件上传
        • 1. 设置上传限制
        • 2. 最佳实践
    • 8.9 资源清理
      • 8.9.1 清理方法
        • 1. 自动删除 gr.State
        • 2. 通过 delete_cache 自动清理缓存
        • 3. unload 事件
      • 8.9.2 综合清理演示
    • 参考文献

前言

本系列文章主要介绍WEB界面工具Gradio。Gradio是Hugging Face发布的简易webui开发框架,它基于FastAPI和svelte,便于部署人工智能模型,是当前热门的非常易于开发和展示机器学习大语言模型LLM及扩散模型DM的UI框架。本系列文章分为前置概念和实战演练两部分。前置概念先介绍Gradio的详细技术架构、历史、应用场景、与其他框架Gradio/NiceGui/StreamLit/Dash/PyWebIO的区别,然后详细介绍了大模型及数据的资源网站Hugging Face,包括三类工具models/datasets/spaces、六类开源库transformers/diffusers/datasets/PEFT/accelerate/optimum实战。实战演练部分先讲解了多种不同的安装、运行和部署方式,安装包括Linux/Win/Mac三类系统安装,运行包括普通方式和热重载方式,部署包括本地部署、HuggingFace托管、FastAPI挂载和Gradio-Lite浏览器集成;然后按照先整体再细节的逻辑,讲解Gradio的多种高级特性:三种Gradio Clients(python/javascript/curl)、Gradio Tools、Gradio的模块架构和环境变量等,方便读者对Gradio整体把握;最后深入细节,也是本系列文章的核心,先实践基础功能Interface、Blocks和Additional Features,再详解高级功能Chatbots、Data Science And Plots和Streaming。本系列文章讲解详细,涵盖Gradio大部分组件和功能,代码均可运行并附有大量运行截图,方便读者理解,Gradio一定会成为每个技术人员实现奇思妙想的最称手工具。

本系列文章目录如下:

  1. 《Gradio全解1——Gradio简介》
  2. 《Gradio全解1——Gradio的安装与运行》
  3. 《Gradio全解2——Gradio的3+1种部署方式实践》
  4. 《Gradio全解2——浏览器集成Gradio-Lite》
  5. 《Gradio全解3——Gradio Client:python客户端》
  6. 《Gradio全解3——Gradio Client:javascript客户端》
  7. 《Gradio全解3——Gradio Client:curl客户端》
  8. 《Gradio全解4——Gradio Tools:将Gradio用于LLM Agents》
  9. 《Gradio全解5——Gradio库的模块架构和环境变量》
  10. 《Gradio全解6——Interface:高级抽象界面类(上)》
  11. 《Gradio全解6——Interface:高级抽象界面类(下)》
  12. 《Gradio全解7——Blocks:底层区块类(上)》
  13. 《Gradio全解7——Blocks:底层区块类(下)》
  14. 《Gradio全解8——Additional Features:补充特性(上)》
  15. 《Gradio全解8——Additional Features:补充特性(下)》
  16. 《Gradio全解9——Chatbots:聊天机器人(上)》
  17. 《Gradio全解9——Chatbots:聊天机器人(下)》
  18. 《Gradio全解系列10——Data Science And Plots:数据科学与绘图》
  19. 《Gradio全解11——Streaming:数据流(上)》
  20. 《Gradio全解11——Streaming:数据流(下)》

本篇摘要

本篇介绍Gradio的其它特性功能,这些功能辅助Interface/Blocks实现更绚丽效果和更多功能。本章补充特性功能主要包括队列、输入输出流、提示及进度条、批处理函数、安全访问文件和资源清理,下面逐一讲述。

8. Additional Features:补充特性

本篇介绍Gradio的其它附加功能,这些功能辅助Interface/Blocks实现更绚丽效果和更多功能。本章附加功能主要包括队列、输入输出流、提示及进度条、批处理函数、安全访问文件和资源清理,下面逐一讲述。

8.5 分享demo

8.5.1 嵌入托管 Spaces

一旦您在 Hugging Face Spaces(或您自己的服务器)上托管了您的应用程序,您可能希望将演示嵌入到不同的网站上,例如您的博客或作品集。嵌入交互式演示可以让人们直接在浏览器中尝试您构建的机器学习模型,而无需下载或安装任何内容!最棒的是,您甚至可以在静态网站(如 GitHub 页面)中嵌入交互式演示。

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

Embedding Hosted Spaces
Once you have hosted your app on Hugging Face Spaces (or on your own server), you may want to embed the demo on a different website, such as your blog or your portfolio. Embedding an interactive demo allows people to try out the machine learning model that you have built, without needing to download or install anything — right in their browser! The best part is that you can embed interactive demos even in static websites, such as GitHub pages.

There are two ways to embed your Gradio demos. You can find quick links to both options directly on the Hugging Face Space page, in the “Embed this Space” dropdown option:

Embed this Space dropdown option

在这里插入图片描述点击后出现如下页面:
在这里插入图片描述

8.5.2 使用 Web Components 嵌入

Web components typically offer a better experience to users than IFrames. Web components load lazily, meaning that they won’t slow down the loading time of your website, and they automatically adjust their height based on the size of the Gradio app.

To embed with Web Components:

Import the gradio JS library into into your site by adding the script below in your site (replace {GRADIO_VERSION} in the URL with the library version of Gradio you are using).
Add

element where you want to place the app. Set the src= attribute to your Space’s embed URL, which you can find in the “Embed this Space” button. For example:

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

You can see examples of how web components look on the Gradio landing page.
Web Components 通常能为用户提供比 IFrames 更好的体验。Web Components 是延迟加载的,这意味着它们不会减慢您网站的加载速度,并且它们会根据 Gradio 应用程序的大小自动调整高度。

要使用 Web Components 嵌入:

通过将以下脚本添加到您的网站中,将 Gradio JS 库导入到您的网站中(将 URL 中的 {GRADIO_VERSION} 替换为您使用的 Gradio 库版本)。
在您希望放置应用程序的位置添加 <gradio-app> 元素。将 src= 属性设置为您 Space 的嵌入 URL,您可以在“嵌入此 Space”按钮中找到该 URL。例如:

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

您可以在 Gradio 主页上查看 Web Components 的示例。
You can also customize the appearance and behavior of your web component with attributes that you pass into the tag:

src: as we've seen, the src attributes links to the URL of the hosted Gradio demo that you would like to embed
space: an optional shorthand if your Gradio demo is hosted on Hugging Face Space. Accepts a username/space_name instead of a full URL. Example: gradio/Echocardiogram-Segmentation. If this attribute attribute is provided, then src does not need to be provided.
control_page_title: a boolean designating whether the html title of the page should be set to the title of the Gradio app (by default "false")
initial_height: the initial height of the web component while it is loading the Gradio app, (by default "300px"). Note that the final height is set based on the size of the Gradio app.
container: whether to show the border frame and information about where the Space is hosted (by default "true")
info: whether to show just the information about where the Space is hosted underneath the embedded app (by default "true")
autoscroll: whether to autoscroll to the output when prediction has finished (by default "false")
eager: whether to load the Gradio app as soon as the page loads (by default "false")
theme_mode: whether to use the dark, light, or default system theme mode (by default "system")
render: an event that is triggered once the embedded space has finished rendering.

您还可以通过传递给 标签的属性来自定义 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:是否使用深色、浅色或默认的系统主题模式(默认为 system)。
render:一个事件,在嵌入的 Space 完成渲染时触发。

Here’s an example of how to use these attributes to create a Gradio app that does not lazy load and has an initial height of 0px.

<gradio-app
space=“gradio/Echocardiogram-Segmentation”
eager=“true”
initial_height=“0px”

Here’s another example of how to use the render event. An event listener is used to capture the render event and will call the handleLoadComplete() function once rendering is complete.

Note: While Gradio’s CSS will never impact the embedding page, the embedding page can affect the style of the embedded Gradio app. Make sure that any CSS in the parent page isn’t so general that it could also apply to the embedded Gradio app and cause the styling to break. Element selectors such as header { … } and footer { … } will be the most likely to cause issues.
以下是一个如何使用这些属性创建不延迟加载且初始高度为 0px 的 Gradio 应用的示例:

<gradio-app
space=“gradio/Echocardiogram-Segmentation”
eager=“true”
initial_height=“0px”

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

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

8.5.3 Embedding with IFrames

To embed with IFrames instead (if you cannot add javascript to your website, for example), add this element:

Again, you can find the src= attribute to your Space’s embed URL, which you can find in the “Embed this Space” button.

Note: if you use IFrames, you’ll probably want to add a fixed height attribute and set style=“border:0;” to remove the boreder. In addition, if your app requires permissions such as access to the webcam or the microphone, you’ll need to provide that as well using the allow attribute.

使用 IFrame 嵌入

如果你无法在网站中添加 JavaScript(例如),可以使用 IFrame 来嵌入你的应用。添加以下元素:

同样,你可以在 “Embed this Space” 按钮中找到 Space 的嵌入 URL,并将其作为 src 属性。

注意:如果你使用 IFrame,可能需要添加一个固定的高度属性,并设置 style=“border:0;” 以去除边框。此外,如果你的应用需要访问摄像头或麦克风等权限,你还需要使用 allow 属性来提供这些权限。

8.6 访问网络请求和网络分析

8.6.1 直接访问网络请求

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

import gradio as grdef 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 request.headers, request.client.host, dict(request.query_params)io = gr.Interface(echo, "textbox", ["textbox", "textbox", "textbox"]).launch()

在这里插入图片描述

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

Analytics

By default, Gradio collects certain analytics to help us better understand the usage of the gradio library. This includes the following information:

What environment the Gradio app is running on (e.g. Colab Notebook, Hugging Face Spaces)
What input/output components are being used in the Gradio app
Whether the Gradio app is utilizing certain advanced features, such as auth or show_error
The IP address which is used solely to measure the number of unique developers using Gradio
The version of Gradio that is running

No information is collected from users of your Gradio app. If you’d like to diable analytics altogether, you can do so by setting the analytics_enabled parameter to False in gr.Blocks, gr.Interface, or gr.ChatInterface. Or, you can set the GRADIO_ANALYTICS_ENABLED environment variable to “False” to apply this to all Gradio apps created across your system.

Note: this reflects the analytics policy as of gradio>=4.32.0.

8.6.1 网络分析

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

Gradio 应用程序运行的环境(例如 Colab Notebook、Hugging Face Spaces)。Gradio 应用程序中使用的输入/输出组件。Gradio 应用程序是否使用了某些高级功能,例如身份验证或显示错误。仅用于衡量使用 Gradio 的独立开发者数量的 IP 地址。正在运行的 Gradio 版本。

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

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

Accessing the Network Request Directly

When a user makes a prediction to your app, you may need the underlying network request, in order to get the request headers (e.g. for advanced authentication), log the client’s IP address, getting the query parameters, or for other reasons. Gradio supports this in a similar manner to FastAPI: simply add a function parameter whose type hint is gr.Request and Gradio will pass in the network request as that parameter. Here is an example:

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()

Note: if your function is called directly instead of through the UI (this happens, for example, when examples are cached, or when the Gradio app is called via API), then request will be None. You should handle this case explicitly to ensure that your app does not throw any errors. That is why we have the explicit check if request.

8.7 授权

8.7.1 OAuth(通过 Hugging Face 登录)

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

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

以下是一个简短的示例:OAuth (Login via Hugging Face)

Gradio natively supports OAuth login via Hugging Face. In other words, you can easily add a “Sign in with Hugging Face” button to your demo, which allows you to get a user’s HF username as well as other information from their HF profile. Check out this Space for a live demo.

To enable OAuth, you must set hf_oauth: true as a Space metadata in your README.md file. This will register your Space as an OAuth application on Hugging Face. Next, you can use gr.LoginButton to add a login button to your Gradio app. Once a user is logged in with their HF account, you can retrieve their profile by adding a parameter of type gr.OAuthProfile to any Gradio function. The user profile will be automatically injected as a parameter value. If you want to perform actions on behalf of the user (e.g. list user’s private repos, create repo, etc.), you can retrieve the user token by adding a parameter of type gr.OAuthToken. You must define which scopes you will use in your Space metadata (see documentation for more details).

Here is a short example:

from __future__ import annotationsimport gradio as gr
from huggingface_hub import whoamidef 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()

在这里插入图片描述
在这里插入图片描述When the user clicks on the login button, they get redirected in a new page to authorize your Space.

在这里插入图片描述
Users can revoke access to their profile at any time in their settings.

As seen above, OAuth features are available only when your app runs in a Space. However, you often need to test your app locally before deploying it. To test OAuth features locally, your machine must be logged in to Hugging Face. Please run huggingface-cli login or set HF_TOKEN as environment variable with one of your access token. You can generate a new token in your settings page (https://huggingface.co/settings/tokens). Then, clicking on the gr.LoginButton will login your local Hugging Face profile, allowing you to debug your app with your Hugging Face account before deploying it to a Space.

Security Note: It is important to note that adding a gr.LoginButton does not restrict users from using your app, in the same way that adding username-password authentication does. This means that users of your app who have not logged in with Hugging Face can still access and run events in your Gradio app – the difference is that the gr.OAuthProfile or gr.OAuthToken will be None in the corresponding functions.
用户可以随时在他们的设置中撤销对其个人资料的访问权限。

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

安全注意事项:需要注意的是,添加 gr.LoginButton 并不会像添加用户名-密码认证那样限制用户使用您的应用。这意味着未使用 Hugging Face 登录的用户仍然可以访问并运行您的 Gradio 应用中的事件——区别在于,在相应的函数中,gr.OAuthProfile 或 gr.OAuthToken 将为 None。

8.7.2 OAuth (with external providers)

It is also possible to authenticate with external OAuth providers (e.g. Google OAuth) in your Gradio apps. To do this, first mount your Gradio app within a FastAPI app (as discussed above). Then, you must write an authentication function, which gets the user’s username from the OAuth provider and returns it. This function should be passed to the auth_dependency parameter in gr.mount_gradio_app.

Similar to FastAPI dependency functions, the function specified by auth_dependency will run before any Gradio-related route in your FastAPI app. The function should accept a single parameter: the FastAPI Request and return either a string (representing a user’s username) or None. If a string is returned, the user will be able to access the Gradio-related routes in your FastAPI app.

First, let’s show a simplistic example to illustrate the auth_dependency parameter:

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 grapp = 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凭据):
In this example, only requests that include a “user” header will be allowed to access the Gradio app. Of course, this does not add much security, since any user can add this header in their request.
Here’s a more complete example showing how to add Google OAuth to a Gradio app (assuming you’ve already created OAuth Credentials on the Google Developer Console):

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 grapp = 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://accounts.google.com/.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)

There are actually two separate Gradio apps in this example! One that simply displays a log in button (this demo is accessible to any user), while the other main demo is only accessible to users that are logged in. You can try this example out on this Space.
在这个例子中,实际上有两个单独的Gradio应用程序!一个简单地显示登录按钮(任何用户都可以访问此演示),而另一个主演示仅对已登录的用户可用。您可以在此空间上尝试此示例。

8.8 安全访问文件

当我们通过托管在Spaces、自己的服务器或临时共享链接共享Gradio 应用程序时,会将机器上的某些文件暴露在互联网上。本节解释了哪些文件会被暴露,以及确保机器上文件安全的一些最佳实践。

8.8.1 Gradio文件访问限制

Gradio文件访问分为允许用户访问的文件和不允许他人访问的文件。

1. Gradio 允许用户访问的文件

Gradio 允许用户访问的文件有以下三种:

  1. 通过 gr.set_static_paths 函数显式设置的静态文件。默认情况下,此参数为空列表,它可以传入一个目录或文件列表,这些文件将被视为静态文件。这意味着它们不会被复制到缓存中,而是直接从计算机读取。这有助于节省磁盘空间并减少应用程序启动时间,但请注意可能的安全隐患;
  2. launch() 函数中参数 allowed_paths 中的文件。默认情况下,此参数为空列表,它可传入一个额外的目录或确切文件路径列表,表示允许用户访问这些文件;
  3. Gradio 缓存中的文件。在启动 Gradio 应用程序后,Gradio 会将某些文件复制到临时缓存中,并使这些文件可供用户访问。我们将在下面更详细地解释这一点。
2. Gradio 不允许他人访问的文件

在运行时,Gradio 应用程序不会允许用户访问以下文件:

  1. 通过 launch() 函数中的参数 blocked_paths 显式阻止的文件。您可以向 launch() 函数中的 blocked_paths 参数传入一个额外的目录或确切文件路径列表。此参数优先于 Gradio 默认暴露的文件,或通过 allowed_paths 参数或 gr.set_static_paths 函数暴露的文件。
  2. 主机上的任何其他路径。用户不应能够访问主机上的任何其他路径。

8.8.2 Gradio缓存

1. 缓存作用

首先,了解 Gradio 为什么会有缓存是很重要的。Gradio 在将文件返回给前端之前,会将它们复制到缓存目录中。这可以防止文件被某个用户覆盖,因为应用程序的其他用户仍然需要这些文件。例如,如果预测函数返回一个视频文件,Gradio 会在预测函数运行后将该视频移动到缓存中,并返回一个前端可以用来显示视频的 URL。缓存中的任何文件都可以通过 URL 方式提供给所有正在运行应用程序用户。

提示:我们可以通过将 GRADIO_TEMP_DIR 环境变量设置为绝对路径(例如 /home/usr/scripts/project/temp/)来自定义缓存的位置。

2. Gradio移动到缓存的文件

Gradio 会将三种类型的文件移动到缓存中:

  1. 开发者在运行前指定的文件,例如缓存的示例、组件的默认值或传递给参数的文件(如 gr.Chatbot 的 avatar_images)。
  2. Gradio 应用程序中预测函数返回的文件路径,且满足以下条件之一:(1)它们在 Blocks.launch 方法的 allowed_paths 参数中;(2)它们在 Python 解释器的当前工作目录中;(3)它们在通过 tempfile.gettempdir() 获取的临时目录中。如果这些条件都不满足,返回该文件的预测函数将引发异常,而不是将文件移动到缓存中。Gradio 执行此检查是为了确保机器上的任意文件不会被非法访问。
  3. 用户上传到 Gradio 应用程序的文件(例如通过 File 或 Image 输入组件)。

需要注意的是:

  • 对于第二种类型的文件,当前工作目录中以句点(.)开头的文件不会被移动到缓存中,即使它们是从预测函数返回的,因为它们通常包含敏感信息。
  • 如果 Gradio 拒绝了我们希望它处理的文件,请将其路径添加到参数 allowed_paths 中。

8.8.3 文件上传

1. 设置上传限制

当我们共享 Gradio 应用程序时,通常还会允许用户将文件上传到计算机或服务器。这时可以设置上传文件的最大大小,以防止滥用并节省磁盘空间。我们可以通过函数 .launch 的 max_file_size 参数来实现这一点。例如以下两个代码片段将每个文件的上传限制为 5 兆字节:

import gradio as grdemo = gr.Interface(lambda x: x, "image", "image")demo.launch(max_file_size="5mb")
# or
demo.launch(max_file_size=5 * gr.FileSize.MB)
2. 最佳实践

为了确保安全访问文件,有4种最佳实践方法:

  1. 为Gradio应用程序设置 max_file_size。
  2. 不要从连接到基于文件的输出组件(如 gr.Image、gr.File 等)的函数中返回任何用户输入。例如,以下代码将允许任何人将本地目录中的任意文件移动到缓存中:gr.Interface(lambda s: s, “text”, “file”),这是因为用户输入被视为任意的文件路径。
  3. 尽可能缩小 allowed_paths 的范围。如果 allowed_paths 中的路径是目录,则该目录中的任何文件都可以被访问。确保 allowed_paths 中的条目仅包含与应用程序相关的文件。
  4. 从应用程序文件所在的目录运行 Gradio 应用程序,这将缩小 Gradio 允许移动到缓存中文件的范围。例如启动命令优先使用 python app.py 而不是 python Users/sources/project/app.py。

8.9 资源清理

Gradio 应用程序在其生命周期中可能会创建资源。资源示例包括 gr.State 变量、创建并显式保存在内存中的任何变量或保存到磁盘的文件。随着时间的推移,这些资源可能会耗尽服务器的所有 RAM 或磁盘空间,并导致应用程序崩溃,所以需要定期清理临时资源。

8.9.1 清理方法

Gradio 提供了一些方法来帮助您清理应用程序创建的资源:自动删除 gr.State 变量、使用 delete_cache 参数自动清理缓存和使用Blocks.unload 事件。让我们分别来看一下这些工具。

1. 自动删除 gr.State

当用户关闭浏览器标签页时,Gradio 将在 60 分钟后自动删除与该用户会话关联的所有 gr.State 变量。如果用户在 60 分钟内重新连接,则不会删除任何 gr.State。

我们可以通过下面 gr.State 的两个参数进一步控制删除行为:

  • delete_callback:可以是任意函数,当变量被删除时将调用该函数。此函数必须将状态值作为输入。此函数对于从 GPU 内存中删除变量非常有用。
  • time_to_live:状态在创建或更新后应存储的秒数。这将在会话关闭之前删除变量,因此对于清理可能长时间运行的会话的状态非常有用。
2. 通过 delete_cache 自动清理缓存

Gradio 应用程序会将上传和生成的文件保存到一个名为cache的特殊目录中。Gradio 使用哈希方案来确保不会将重复文件保存到缓存中,但随着时间的推移,尤其是当应用程序变得非常流行时,缓存的大小仍会不断增长。

如果启动时指定了 gr.Blocks()、gr.Interface() 或 gr.ChatInterface() 的 delete_cache 参数,那么Gradio 可以定期为您清理缓存。此参数是一个形式为 [frequency, age] 的元组,两者均以秒为单位表示。此参数表示每过 frequency 秒,如果文件创建时间超过 age 秒,则会删除此 Blocks 实例创建的临时文件。例如,将其设置为 (86400, 86400) 将会每天删除超过一天的文件。此外,缓存将在服务器重启时完全删除。

3. unload 事件

此外,Gradio 现在包含一个 Blocks.unload() 事件,它允许Gradio程序在用户断开连接时运行任意清理函数,此时不会有 60 分钟的延迟。与其他 Gradio 事件不同,此事件不接受输入或输出。我们可以将 unload 事件视为 load 事件的反向操作。

8.9.2 综合清理演示

以下演示使用了上面列举的所有功能。当用户访问页面时,会为该用户创建一个特殊的唯一目录:当用户与应用程序交互时,图像会被保存到该特殊目录中;当用户关闭页面时,该会话中创建的图像将通过 unload 事件删除,状态和缓存中的文件也会立即自动清理。代码如下:

from __future__ import annotations
import gradio as gr
import numpy as np
from PIL import Image
from pathlib import Path
import secrets
import shutilcurrent_dir = Path(__file__).parentdef generate_random_img(history: list[Image.Image], request: gr.Request):"""Generate a random red, green, blue, orange, yellor or purple image."""colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 165, 0), (255, 255, 0), (128, 0, 128)]color = colors[np.random.randint(0, len(colors))]img = Image.new('RGB', (100, 100), color)user_dir: Path = current_dir / str(request.session_hash)user_dir.mkdir(exist_ok=True)path = user_dir / f"{secrets.token_urlsafe(8)}.webp"img.save(path)history.append(img)return img, history, historydef delete_directory(req: gr.Request):if not req.username:returnuser_dir: Path = current_dir / req.usernameshutil.rmtree(str(user_dir))with gr.Blocks(delete_cache=(60, 3600)) as demo:gr.Markdown("""# State Cleanup Demo🖼️ Images are saved in a user-specific directory and deleted when the users closes the page via demo.unload.""")with gr.Row():with gr.Column(scale=1):with gr.Row():img = gr.Image(label="Generated Image", height=300, width=300)with gr.Row():gen = gr.Button(value="Generate")with gr.Row():history = gr.Gallery(label="Previous Generations", height=500, columns=10)state = gr.State(value=[], delete_callback=lambda v: print("STATE DELETED"))demo.load(generate_random_img, [state], [img, state, history])gen.click(generate_random_img, [state], [img, state, history])demo.unload(delete_directory)demo.launch()

运行截图如下:
在这里插入图片描述

参考文献

  1. Gradio - guides - Additional Features

http://www.mrgr.cn/news/82071.html

相关文章:

  • JavaScript的diff库详解(示例:vue项目实现两段字符串比对标黄功能)
  • OpenCV-Python实战(9)——滤波降噪
  • Spring-AI讲解
  • Python的列表
  • Oracle Dataguard(主库为 Oracle 11g 单节点)配置详解(3):配置备用数据库
  • SWM221系列芯片之电机应用及控制
  • NFS V4网络文件共享新认识——筑梦之路
  • SpringCloudAlibaba实战入门之路由网关Gateway过滤器(十三)
  • 云效流水线自动化部署前端纯静态web网站
  • 四大自平衡树对比:AVL树、红黑树、B树与B+树
  • 2024/12/29 黄冈师范学院计算机学院网络工程《路由期末复习作业一》
  • 从0到机器视觉工程师(一):机器视觉工业相机总结
  • 【Leetcode 每日一题 - 扩展】面试题 04.10. 检查子树
  • 初始nginx
  • 因数据库表被锁死导致服务假死的排查和解决过程
  • 混合合并两个pdf文件
  • vue实现下拉多选、可搜索、全选功能
  • Vue多页面路由与模版解析
  • 自动驾驶新纪元:城区NOA功能如何成为智能驾驶技术的分水岭
  • SpringAI从入门到熟练
  • FreeRTOS Lwip Socket APi TCP Server 1对多
  • 大模型WebUI:Gradio全解系列8——Additional Features:补充特性(上)
  • 小米路由器开启SSH,配置阿里云ddns,开启外网访问SSH和WEB管理界面
  • Isaac Sim Docker 中使用 Python 脚本
  • 一份关于 Ubuntu 系统下代理配置的故障排查笔记
  • Linux高并发服务器开发 第七天(静态库 动态库)