python系列&deep_study系列:Gradio中文教程(三)Sharing Your App




Gradio中文教程(三)Sharing Your App

分享你的应用

如何分享你的Gradio应用:

  1. 通过共享参数分享演示

  2. 在HF Spaces上托管

  3. 嵌入托管空间

  4. 使用API页面

  5. 访问网络请求

  6. 在FastAPI中挂载

  7. 认证

  8. 安全和文件访问

分享演示

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

这会生成一个公共的、可分享的链接,你可以将其发送给任何人!当你发送这个链接时,另一端的用户可以在他们的浏览器中尝试使用该模型。因为处理发生在你的设备上(只要你的设备保持开启状态),你不必担心打包任何依赖项。

共享链接通常看起来像这样:No interface is running。尽管链接是通过Gradio Share Servers提供的,但这些服务器只是你本地服务器的代理,不会存储通过你的应用发送的任何数据。共享链接在72小时后过期。(也可以在自己的云服务器上设置自己的Share Server来克服这个限制。)✍️提示:请记住,共享链接是公开可访问的,这意味着任何人都可以使用你的模型进行预测!因此,请确保不要通过你编写的函数暴露任何敏感信息,或者允许在你的设备上发生任何关键更改。或者,你可以像下面讨论的那样为你的Gradio应用添加认证。

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

在HF Spaces上托管

如果你想在互联网上拥有一个永久链接指向你的Gradio演示,请使用Hugging Face SpacesHugging Face Spaces提供了免费永久托管你的机器学习模型的基础设施!

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

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

  2. 从你的浏览器:将包含你的Gradio模型和所有相关文件的文件夹拖放到这里。查看如何在Hugging Face Spaces上托管的指南,或者观看嵌入的视频:

嵌入托管空间

一旦你在Hugging Face Spaces(或你自己的服务器)上托管了你的应用,你可能想将其嵌入到不同的网站上,比如你的博客或你的作品集。嵌入一个交互式演示允许人们尝试你构建的机器学习模型,而无需下载或安装任何东西——就在他们的浏览器中!最好的部分是,你甚至可以在静态网站(如GitHub页面)上嵌入交互式演示。

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

使用Web组件嵌入

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

要使用Web组件嵌入:

gradio JS库导入到你的站点中,通过在你的站点中添加下面的脚本(将{GRADIO_VERSION}替换为你使用的Gradio库版本)。

<script
	type="module"
	src="https://gradio.s3-us-west-2.amazonaws.com/{GRADIO_VERSION}/gradio.js"
></script>

添加

<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组件的示例。

你还可以使用传递给标签的属性自定义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:一旦嵌入的空间完成渲染,触发的事件。

这里是一个如何使用这些属性创建一个不懒加载且初始高度为0pxGradio应用的示例。

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

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

使用IFrames嵌入

如果你不能向你的网站添加javascript(例如),则可以使用IFrames嵌入:

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

再次,你可以在“Embed this Space”按钮中找到src=属性Space嵌入URL

注意:如果你使用IFrames,你可能想要添加一个固定的height属性并设置style="border:0;"来移除边框。此外,如果你的应用需要权限(如访问摄像头或麦克风),你还需要使用allow属性提供这些权限。

API页面

你可以将几乎任何Gradio应用用作API!在像这样的Gradio应用的页脚中,你会看到一个“Use via API”链接。

这是一个列出了可以用来查询Gradio应用的端点的页面,通过我们支持的客户端:Python客户端JavaScript客户端。对于每个端点,Gradio自动生成参数及其类型,以及示例输入,像这样。

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

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

这将向自动生成的API页面添加并记录端点/api/addition/。否则,你的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(例如,当示例被缓存,或者当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。默认情况下,SafariChrome Incognito模式不启用此功能。

如果用户访问你的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元数据中定义你将使用的范围(请参阅文档了解更多细节)。

这里是一个简短的示例:

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 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://huggingface.co/settings/tokens)生成一个新的令牌。然后,点击gr.LoginButton将登录你的本地Hugging Face个人资料,允许你在部署到Space之前使用你的Hugging Face账户调试你的应用。

OAuth(使用外部提供商)

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

FastAPI依赖函数类似,auth_dependency指定的函数将在你的FastAPI应用中的任何Gradio相关路由之前运行。该函数应该接受一个参数:FastAPIRequest,并返回一个字符串(代表用户的用户名)或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应用。当然,这并没有增加多少安全性,因为任何用户都可以在他们的请求中添加这个头。

这里是一个更完整的示例,展示了如何为Gradio应用添加Google OAuth(假设你已经在Google开发者控制台创建了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://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)

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

安全和文件访问

与他人分享你的Gradio应用(通过在Spaces上托管、在你自己的服务器上托管或通过临时共享链接)会向你的Gradio应用的用户暴露主机机器上的某些文件。

特别是,Gradio应用允许用户访问以下四种类型的文件:

  • Gradio创建的临时文件。这些文件是由Gradio在运行你的预测函数时创建的。例如,如果你的预测函数返回一个视频文件,那么Gradio会将该视频保存到你设备上的一个临时缓存中,然后将文件的路径发送到前端。你可以通过将环境变量GRADIO_TEMP_DIR设置为绝对路径(例如/home/usr/scripts/project/temp/)来自定义由Gradio创建的临时缓存文件的位置。你可以通过gradio.Blocksgradio.Interfacegradio.ChatInterfacedelete_cache参数在应用关闭时删除由你的应用创建的文件。这个参数是一个整数元组,形式为[frequency, age],其中frequency是删除文件的频率,age是自文件最后修改以来的时间(以秒为单位)。

  • Gradio创建的缓存示例。如果你在gr.Interface()gr.ChatInterface()gr.Examples()中设置cache_examples=Truecache_examples="lazy",这些文件是由Gradio在缓存示例以加快运行时间时创建的。默认情况下,这些文件保存在你的应用工作目录内的gradio_cached_examples/子目录中。你可以通过将环境变量GRADIO_EXAMPLES_CACHE设置为绝对路径或相对于你的工作目录的路径来自定义由Gradio创建的缓存示例文件的位置。

  • 通过launch()中的allowed_paths参数显式允许的文件。这个参数允许你传递一个额外的目录或你希望允许用户访问的精确文件路径的列表。(默认情况下,这个参数是一个空列表)。

  • 通过gr.set_static_paths函数显式设置的静态文件。这个参数允许你传递一个目录或文件名的列表,这些将被视为静态文件。这意味着它们不会被复制到缓存中,而是直接从你的计算机提供。这可以帮助节省磁盘空间并减少你的应用启动所需的时间,但要留意可能的安全影响。

Gradio不允许访问:

通过launch()中的blocked_paths参数显式阻止的文件。你可以向launch()中的blocked_paths参数传递一个额外的目录或精确文件路径的列表。这个参数优先于Gradio默认暴露的文件或通过allowed_paths允许的文件。
主机机器上的任何其他路径。用户不应该能够访问主机上的其他任意路径。
分享你的Gradio应用还将允许用户将文件上传到你的计算机或服务器。你可以为上传设置最大文件大小,以防止滥用并节省磁盘空间。你可以通过.launchmax_file_size参数来做到这一点。例如,以下两个代码片段将文件上传限制为每文件5兆字节

import gradio as gr

demo = gr.Interface(lambda x: x, "image", "image")

demo.launch(max_file_size="5mb")
# or
demo.launch(max_file_size=5 * gr.FileSize.MB)

请确保你运行的是最新版本的gradio,以便这些安全设置生效。







老刘

Gradio中文教程(三)Sharing Your App

  • 31
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

坦笑&&life

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值