Gradio 月活跃用户达到 100 万!

阅读更多
Gradio logo
  1. Gradio 客户端和 Lite
  2. 使用 Gradio 客户端的 FastAPI 应用

使用 Gradio Python 客户端构建 Web 应用

在这篇博文中,我们将演示如何使用 gradio_client Python 库,该库使开发者能够以编程方式向 Gradio 应用发出请求,方法是使用 FastAPI 创建一个端到端的示例 Web 应用。我们将构建的 Web 应用名为“Acapellify”,它将允许用户上传视频文件作为输入,并返回一个去除背景音乐的视频版本。它还将显示一个生成的视频库。

前提条件

在开始之前,请确保您运行的是 Python 3.9 或更高版本,并已安装以下库

  • gradio_client
  • fastapi
  • uvicorn

您可以使用 pip 安装这些库

$ pip install gradio_client fastapi uvicorn

您还需要安装 ffmpeg。您可以在终端中运行以下命令来检查是否已安装 ffmpeg

$ ffmpeg version

否则,请按照这些说明安装 ffmpeg。

步骤 1:编写视频处理函数

让我们从看似最复杂的部分开始——使用机器学习从视频中移除音乐。

幸运的是,我们有一个现有的 Space 可以简化此过程:https://hugging-face.cn/spaces/abidlabs/music-separation。这个 Space 接受一个音频文件,并生成两个单独的音频文件:一个包含背景音乐,另一个包含原始剪辑中的所有其他声音。非常适合与我们的客户端一起使用!

打开一个新的 Python 文件,例如 main.py,首先从 gradio_client 导入 Client 类并将其连接到此 Space

from gradio_client import Client, handle_file

client = Client("abidlabs/music-separation")

def acapellify(audio_path):
    result = client.predict(handle_file(audio_path), api_name="/predict")
    return result[0]

这就是所需的全部代码——请注意,API 端点在一个列表中返回两个音频文件(一个没有音乐,一个只有音乐),因此我们只需返回列表的第一个元素。


注意:由于这是一个公共 Space,可能还有其他用户也在使用此 Space,这可能会导致体验缓慢。您可以使用自己的 Hugging Face token 复制此 Space,并创建一个只有您有权访问并绕过队列的私有 Space。为此,只需将上面的前两行替换为

from gradio_client import Client

client = Client.duplicate("abidlabs/music-separation", hf_token=YOUR_HF_TOKEN)

其他所有内容保持不变!


现在,当然,我们正在处理视频文件,所以我们首先需要从视频文件中提取音频。为此,我们将使用 ffmpeg 库,该库在处理音频和视频文件方面做了大量繁重的工作。使用 ffmpeg 最常见的方式是通过命令行,我们将通过 Python 的 subprocess 模块调用它

我们的视频处理工作流程将包含三个步骤

  1. 首先,我们从获取视频文件路径并使用 ffmpeg 提取音频开始。
  2. 然后,我们将音频文件传递到上面的 acapellify() 函数中。
  3. 最后,我们将新的音频与原始视频结合起来,生成最终的 acapellified 视频。

这是完整的 Python 代码,您可以将其添加到您的 main.py 文件中

import subprocess

def process_video(video_path):
    old_audio = os.path.basename(video_path).split(".")[0] + ".m4a"
    subprocess.run(['ffmpeg', '-y', '-i', video_path, '-vn', '-acodec', 'copy', old_audio])

    new_audio = acapellify(old_audio)

    new_video = f"acap_{video_path}"
    subprocess.call(['ffmpeg', '-y', '-i', video_path, '-i', new_audio, '-map', '0:v', '-map', '1:a', '-c:v', 'copy', '-c:a', 'aac', '-strict', 'experimental', f"static/{new_video}"])
    return new_video

如果您想了解所有命令行参数,可以阅读 ffmpeg 文档,因为它们超出了本教程的范围。

步骤 2:创建 FastAPI 应用(后端路由)

接下来,我们将创建一个简单的 FastAPI 应用。如果您之前没有使用过 FastAPI,请查看 优秀的 FastAPI 文档。否则,我们将添加到 main.py 中的这个基本模板看起来会非常熟悉

import os
from fastapi import FastAPI, File, UploadFile, Request
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates

app = FastAPI()
os.makedirs("static", exist_ok=True)
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")

videos = []

@app.get("/", response_class=HTMLResponse)
async def home(request: Request):
    return templates.TemplateResponse(
        "home.html", {"request": request, "videos": videos})

@app.post("/uploadvideo/")
async def upload_video(video: UploadFile = File(...)):
    video_path = video.filename
    with open(video_path, "wb+") as fp:
        fp.write(video.file.read())

    new_video = process_video(video.filename)
    videos.append(new_video)
    return RedirectResponse(url='/', status_code=303)

在此示例中,FastAPI 应用有两个路由://uploadvideo/

/ 路由返回一个 HTML 模板,该模板显示所有上传视频的库。

/uploadvideo/ 路由接受带有 UploadFile 对象的 POST 请求,该对象表示上传的视频文件。视频文件通过 process_video() 方法进行“acapellified”处理,输出视频存储在一个列表中,该列表在内存中存储所有上传的视频。

请注意,这是一个非常基本的示例,如果这是一个生产应用,您将需要添加更多逻辑来处理文件存储、用户身份验证和安全考虑。

步骤 3:创建 FastAPI 应用(前端模板)

最后,我们创建 Web 应用程序的前端。首先,我们在与 main.py 相同的目录中创建一个名为 templates 的文件夹。然后,我们在 templates 文件夹内创建一个模板 home.html。 这是生成的文件结构

├── main.py
├── templates
│   └── home.html

将以下内容写入 home.html

<!DOCTYPE html> <html> <head> <title>Video Gallery</title>
<style> body { font-family: sans-serif; margin: 0; padding: 0;
background-color: #f5f5f5; } h1 { text-align: center; margin-top: 30px;
margin-bottom: 20px; } .gallery { display: flex; flex-wrap: wrap;
justify-content: center; gap: 20px; padding: 20px; } .video { border: 2px solid
#ccc; box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2); border-radius: 5px; overflow:
hidden; width: 300px; margin-bottom: 20px; } .video video { width: 100%; height:
200px; } .video p { text-align: center; margin: 10px 0; } form { margin-top:
20px; text-align: center; } input[type="file"] { display: none; } .upload-btn {
display: inline-block; background-color: #3498db; color: #fff; padding: 10px
20px; font-size: 16px; border: none; border-radius: 5px; cursor: pointer; }
.upload-btn:hover { background-color: #2980b9; } .file-name { margin-left: 10px;
} </style> </head> <body> <h1>Video Gallery</h1> {% if videos %}
<div class="gallery"> {% for video in videos %} <div class="video">
<video controls> <source src="{{ url_for('static', path=video) }}"
type="video/mp4"> Your browser does not support the video tag. </video>
<p>{{ video }}</p> </div> {% endfor %} </div> {% else %} <p>No
videos uploaded yet.</p> {% endif %} <form action="/uploadvideo/"
method="post" enctype="multipart/form-data"> <label for="video-upload"
class="upload-btn">Choose video file</label> <input type="file"
name="video" id="video-upload"> <span class="file-name"></span> <button
type="submit" class="upload-btn">Upload</button> </form> <script> //
Display selected file name in the form const fileUpload =
document.getElementById("video-upload"); const fileName =
document.querySelector(".file-name"); fileUpload.addEventListener("change", (e)
=> { fileName.textContent = e.target.files[0].name; }); </script> </body>
</html>

步骤 4:运行 FastAPI 应用

最后,我们准备好运行由 Gradio Python 客户端驱动的 FastAPI 应用了!

打开终端并导航到包含 main.py 的目录。然后在终端中运行以下命令

$ uvicorn main:app

您应该看到如下所示的输出

Loaded as API: https://abidlabs-music-separation.hf.space ✔
INFO:     Started server process [1360]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

就是这样!开始上传视频,您将收到一些“acapellified”的视频作为响应(处理时间可能需要几秒到几分钟,具体取决于视频的长度)。 这是上传两个视频后 UI 的外观

如果您想了解更多关于如何在项目中使用 Gradio Python 客户端的信息,请阅读专门的指南