当前位置:   article > 正文

【Gradio】使用 Gradio Python 客户端构建 FastAPI 应用程序

【Gradio】使用 Gradio Python 客户端构建 FastAPI 应用程序

在这篇博客文章中,我们将展示如何使用 gradio_client Python 库,该库允许开发者以编程方式向 Gradio 应用发出请求,通过创建一个示例 FastAPI 网络应用程序。我们将要构建的网络应用程序称为"Acapellify",它将允许用户上传视频文件作为输入,并返回一个没有伴奏音乐的视频版本。它还将展示一个生成视频的画廊。

 先决条件

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

  • gradio_client

  • fastapi

  • uvicorn

您可以从 pip 安装这些库:

$ pip install gradio_client fastapi uvicorn

您还需要安装 ffmpeg。您可以通过在终端运行来检查是否已经安装了 ffmpeg:

$ ffmpeg version

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

第一步:编写视频处理函数 

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

幸运的是,有一个现成的空间可以让这个过程更简单:https://huggingface.co/spaces/abidlabs/music-separation。这个空间接受一个音频文件,并生成两个独立的音频文件:一个包含原始剪辑中的乐器音乐,另一个包含所有其他声音。非常适合我们的客户使用!

打开一个新的 Python 文件,比如说 main.py ,然后从 gradio_client 中导入 Client 类,并将其连接到这个空间:

  1. from gradio_client import Client
  2. # 创建一个Client实例,指定了要使用的API服务为"abidlabs/music-separation"
  3. client = Client("abidlabs/music-separation")
  4. def acapellify(audio_path):
  5. """
  6. 使用指定的音乐分离服务,从提供的音频路径中分离出人声部分。
  7. :param audio_path: 音频文件的路径。
  8. :return: 分离出的人声音频的路径或结果。
  9. """
  10. # 使用client的predict方法提交预测任务,指定api_name为"/predict"
  11. # 这里预设"/predict"为该服务分离人声的API端点
  12. result = client.predict(audio_path, api_name="/predict")
  13. # 假设服务返回的结果是一个列表,其中第一个元素是我们需要的人声音频的路径或结果
  14. return result[0]

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

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

  1. from gradio_client import Client
  2. client = Client.duplicate("abidlabs/music-separation", hf_token=YOUR_HF_TOKEN)

其他一切保持不变!

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

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

  1. 首先,我们开始通过使用 ffmpeg 提取视频文件路径中的音频。

  2. 然后,我们通过上面的 acapellify() 函数传入音频文件。

  3. 最后,我们将新音频与原始视频结合,制作出最终的无伴奏视频。

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

  1. import subprocess
  2. import os
  3. from gradio_client import Client
  4. # 假设acapellify函数已经定义好,并且可以调用
  5. # def acapellify(audio_path):
  6. # ... # acapellify函数的定义
  7. def process_video(video_path):
  8. """
  9. 处理视频文件,将其音频部分替换为仅包含人声的音频。
  10. :param video_path: 视频文件的路径。
  11. :return: 新视频文件的名称。
  12. """
  13. # 提取原视频文件名,去除扩展名后添加新的音频扩展名.m4a
  14. old_audio = os.path.basename(video_path).split(".")[0] + ".m4a"
  15. # 使用ffmpeg提取原视频的音频部分,保存为old_audio指定的文件
  16. subprocess.run(['ffmpeg', '-y', '-i', video_path, '-vn', '-acodec', 'copy', old_audio])
  17. # 调用acapellify函数处理提取的音频,获取只包含人声的音频文件路径
  18. new_audio = acapellify(old_audio)
  19. # 为新视频文件构造文件名,前面加上"acap_"前缀
  20. new_video = f"acap_{os.path.basename(video_path)}"
  21. # 使用ffmpeg结合原视频和新的人声音频生成新的视频文件
  22. # 新视频文件保存在"static/"目录下
  23. 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}"])
  24. return new_video

ae5fb42b58035dcb106153665cf4531d.png

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

步骤 2:创建一个 FastAPI 应用程序(后端路由) 

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

  1. import os
  2. import subprocess
  3. from fastapi import FastAPI, File, UploadFile, Request
  4. from fastapi.responses import HTMLResponse, RedirectResponse
  5. from fastapi.staticfiles import StaticFiles
  6. from fastapi.templating import Jinja2Templates
  7. # 假设acapellify和process_video函数已经定义好
  8. # def acapellify(audio_path):
  9. # ... # acapellify函数的定义
  10. # def process_video(video_path):
  11. # ... # process_video函数的定义
  12. app = FastAPI()
  13. os.makedirs("static", exist_ok=True) # 确保有一个用来保存静态文件的目录
  14. app.mount("/static", StaticFiles(directory="static"), name="static") # 将静态文件目录挂载至"/static"路径
  15. templates = Jinja2Templates(directory="templates") # 设置Jinja2模板文件的目录
  16. videos = [] # 初始化一个空列表用于存储处理后的视频文件名
  17. @app.get("/", response_class=HTMLResponse)
  18. async def home(request: Request):
  19. """
  20. 根处理函数,返回主页的HTML响应。
  21. :param request: 请求对象,由FastAPI自动提供。
  22. :return: 返回使用Jinja2渲染的home.html模板。
  23. """
  24. return templates.TemplateResponse(
  25. "home.html", {"request": request, "videos": videos}) # 渲染模板,并传入当前已处理的视频列表
  26. @app.post("/uploadvideo/")
  27. async def upload_video(video: UploadFile = File(...)):
  28. """
  29. 处理视频文件上传的路由。
  30. :param video: 上传的视频文件。
  31. :return: 重定向响应,导航回主页。
  32. """
  33. # 将上传的视频文件保存到静态目录中
  34. filepath = os.path.join("static", video.filename)
  35. with open(filepath, "wb") as buffer:
  36. buffer.write(video.file.read())
  37. new_video = process_video(filepath) # 调用process_video函数处理视频文件
  38. videos.append(new_video) # 将处理后的新视频文件名添加到videos列表中
  39. return RedirectResponse(url='/', status_code=303) # 上传完成后重定向回主页

在这个例子中,FastAPI 应用程序有两个路由: / 和 /uploadvideo/ 。

/ 路由返回一个 HTML 模板,用于显示所有已上传视频的画廊。

/uploadvideo/ 路由接受一个带有 UploadFile 对象的 POST 请求,该对象代表上传的视频文件。视频文件通过 process_video() 方法“无伴奏化”,并且输出视频被存储在一个列表中,该列表在内存中存储所有上传的视频。

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

871f41e13fcaf8ca48495db72d5f712f.png

第三步:创建一个 FastAPI 应用程序(前端模板) 

最后,我们创建我们网页应用的前端。首先,在与 main.py 相同的目录中创建一个名为 templates 的文件夹。然后在 templates 文件夹内创建一个模板, home.html 。以下是结果文件结构:

  1. ├── main.py
  2. ├── templates
  3. │ └── home.html

将以下内容写入 home.html :

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

第四步:运行您的 FastAPI 应用程序 

最后,我们准备运行我们的 FastAPI 应用程序,由 Gradio Python 客户端提供支持!

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

$ uvicorn main:app

你应该会看到一个像这样的输出:

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

就是这样!开始上传视频,你会收到一些“acapellified”的视频响应(根据你的视频长度,处理时间可能需要几秒到几分钟)。上传两个视频后,用户界面看起来是这样的:

b999d8635f45f5f9122399e602921cc5.png

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小桥流水78/article/detail/758389
推荐阅读
相关标签
  

闽ICP备14008679号