实战指南:封装Whisper为FastAPI接口并实现高并发处理-附整合包

news2025/4/17 14:02:47

实战指南:封装Whisper为FastAPI接口并实现高并发处理

下面给出一个详细的示例,说明如何使用 FastAPI 封装 OpenAI 的 Whisper 模型,提供一个对外的 REST API 接口,并支持一定的并发请求。

下面是主要步骤和示例代码。


1. 环境准备

  • Python 环境: 建议使用 Python 3.8+。
  • 依赖库:
    • FastAPI:轻量级、高性能的 Python web 框架。
    • Uvicorn:用于运行 FastAPI 的 ASGI 服务器。
    • Whisper:开源的语音识别模型,依赖于 PyTorch,因此需提前安装 torch(根据具体设备配置选择版本)。

可以使用 pip 安装依赖:

pip install fastapi uvicorn
# pip install git+https://github.com/openai/whisper.git 这个网络问题比较大
pip install openai-whisper
pip install torch  # 根据硬件环境选择合适的版本

# torch
# pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126

2. 项目结构

项目目录结构可以如下:

whisper_fastapi/
├── models
├── app.py
└── requirements.txt

其中 requirements.txt 可写入:

fastapi
uvicorn
torch
# git+https://github.com/openai/whisper.git
openai-whisper

3. 编写 FastAPI 应用

app.py 中完成以下主要内容:

  1. 模型加载
    为了避免每次请求都重复加载模型,建议在应用启动时加载一次模型,可以定义为全局变量。

  2. 接口定义
    使用 POST 接口接收音频文件(例如 MP3、WAV 等)通过文件上传方式。注意这里使用 UploadFileFile

  3. 并发执行
    由于 Whisper 的转录过程比较耗时且是 CPU 或 GPU 密集型的计算,我们可以将其放入线程池中执行。FastAPI 中通过 asyncio.get_running_loop().run_in_executor(...) 调用同步的转录方法,让异步接口可以处理并发。

下面给出示例代码:

import sys
import shutil
import tempfile
import asyncio
import warnings
import torch  # 用于检测 CUDA 是否可用
from fastapi import FastAPI, UploadFile, File, HTTPException, Query
from fastapi.responses import JSONResponse
import whisper  # 导入 OpenAI 的 Whisper 模型
from concurrent.futures import ThreadPoolExecutor

# 检查 ffmpeg 是否可用
if shutil.which("ffmpeg") is None:
    sys.exit("错误:未找到 ffmpeg。请下载并安装 ffmpeg,并确保其所在目录已添加到系统 PATH 环境变量中。")

app = FastAPI(title="Whisper FastAPI 接口")

# 指定本地模型文件存储目录,事先要将下载好的模型文件放入该目录
local_model_dir = "./models"

# 用一个全局字典缓存加载过的模型,避免重复加载
loaded_models = {}

# 自动检测设备:如果 CUDA 可用则使用 GPU,否则使用 CPU
device = "cuda" if torch.cuda.is_available() else "cpu"
if device == "cpu":
    warnings.filterwarnings("ignore", message="FP16 is not supported on CPU; using FP32 instead")
print(f"使用的设备:{device}")


def load_model_if_needed(model_name: str):
    """
    检查全局字典中是否已存在指定 model_name 对应的模型,
    如果不存在,则从本地目录加载模型并保存到缓存中,
    并使用 device 参数确保模型加载到正确的设备上。
    """
    if model_name not in loaded_models:
        try:
            model = whisper.load_model(model_name, download_root=local_model_dir, device=device)
            loaded_models[model_name] = model
        except Exception as e:
            raise RuntimeError(
                f"加载 Whisper 模型 {model_name} 失败,请检查本地模型文件是否存在或模型路径配置是否正确"
            ) from e
    return loaded_models[model_name]


# 创建线程池,用于并发处理(模型加载和转录过程可能较为耗时)
executor = ThreadPoolExecutor(max_workers=4)


def transcribe_audio(model, file_path: str) -> dict:
    """
    对给定音频文件进行转录,返回转录结果。
    根据设备自动启用或禁用 fp16 模式:
      - GPU:fp16=True
      - CPU:fp16=False
    """
    try:
        result = model.transcribe(file_path, fp16=(device == "cuda"))
        return result
    except Exception as e:
        return {"error": str(e)}


@app.post("/transcribe")
async def transcribe(
        file: UploadFile = File(...),
        model_name: str = Query("base", description="使用的模型名称(如:tiny, base, small, medium, large)")
):
    """
    接收上传的音频文件及可选参数 model_name,
    通过指定的模型进行转录并返回结果。
    """
    if file.content_type not in [
        "audio/wav",
        "audio/x-wav",
        "audio/wave",
        "audio/x-pn-wav",
        "audio/mpeg",
        "audio/mp3"
    ]:
        raise HTTPException(status_code=400, detail="文件类型不支持,请上传 WAV 或 MP3 格式的音频文件")

    # 保存上传文件到临时文件
    try:
        suffix = "." + file.filename.split(".")[-1]
    except Exception:
        suffix = ".wav"
    try:
        with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as tmp:
            contents = await file.read()
            tmp.write(contents)
            tmp_path = tmp.name
    except Exception as e:
        raise HTTPException(status_code=500, detail="保存临时文件失败")

    # 使用线程池加载指定的模型(如果尚未加载)
    loop = asyncio.get_running_loop()
    try:
        model = await loop.run_in_executor(executor, load_model_if_needed, model_name)
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

    # 异步调用转录任务,放入线程池执行以避免阻塞事件循环
    transcription_result = await loop.run_in_executor(executor, transcribe_audio, model, tmp_path)

    if "error" in transcription_result:
        raise HTTPException(status_code=500, detail=transcription_result["error"])

    return JSONResponse(content=transcription_result)


if __name__ == "__main__":
    import uvicorn

    uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)

4. 运行与部署

  1. 本地测试
    在项目目录下运行:

    uvicorn app:app --host 0.0.0.0 --port 8000 --reload
    

    访问 http://localhost:8000/docs 可查看 FastAPI 自动生成的 API 文档,测试接口。

  2. 并发支持说明

    • 这里我们通过 ThreadPoolExecutor 将转录任务分发到子线程上,利用多线程来处理阻塞的 CPU 密集型任务,支持一定的并发。
    • 在正式生产环境中,建议考虑使用 GPU 加速模型推理,并根据服务器硬件资源配置合理的线程数或进程数。另外,也可使用 Uvicorn 的多进程启动,例如:
      uvicorn app:app --host 0.0.0.0 --port 8000 --workers 4
      
  3. 容错与日志
    根据需要可以增加异常处理、日志记录和监控,这里给出一个简单示例,您可以根据需求扩展。


5. 总结

  1. 环境搭建与依赖安装:确保 Python、FastAPI、Uvicorn、Whisper 及其相关依赖正确安装。
  2. 全局加载模型:避免重复加载模型,提高接口响应效率。
  3. 接口实现:使用 FastAPI 实现 /transcribe 接口,通过上传文件参数进行音频转录。
    http://localhost:8000/transcribe?model_name=base
  4. 并发处理:将耗时的模型转录调用放置在线程池中执行,并结合 uvicorn 部署参数进一步扩展并发。

这样,一个简单的封装了 Whisper 模型的 FastAPI 接口就搭建完成了,可以支持并发调用,对外提供语音转文本的服务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2335949.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Web三漏洞学习(其一:文件上传漏洞)

靶场:云曦历年考核题 一、文件上传 在此之前先准备一个一句话木马 将其命名为muma.txt 23年秋期末考 来给师兄上个马 打开环境以后直接上传muma.txt,出现js弹窗,说明有前端验证 提示只能上传.png .jpg 和 .gif文件,那就把muma.txt的后缀…

Web三漏洞学习(其二:sql注入)

靶场:NSSCTF 、云曦历年考核题 二、sql注入 NSSCTF 【SWPUCTF 2021 新生赛】easy_sql 这题虽然之前做过,但为了学习sql,整理一下就再写一次 打开以后是杰哥的界面 注意到html网页标题的名称是 “参数是wllm” 那就传参数值试一试 首先判…

KrillinAI:视频跨语言传播的一站式AI解决方案

引言 在全球内容创作领域,跨语言传播一直是内容创作者面临的巨大挑战。传统的视频本地化流程繁琐,涉及多个环节和工具,不仅耗时耗力,还常常面临质量不稳定的问题。随着大语言模型(LLM)技术的迅猛发展,一款名为Krillin…

gravity`(控制 View 内部内容的对齐方式)

文章目录 **1. 常用取值****示例** **2. layout_gravity(控制 View 在父容器中的对齐方式)****常用取值****示例** **3. gravity vs layout_gravity 对比****4. 注意事项****5. 总结** 作用对象:当前 View 的内部内容(如 TextView…

gitdiagram源码架构分析

https://github.com/ahmedkhaleel2004/gitdiagram 整体架构分析 前端请求入口: 后端对应接口: 后端调试 后端调试:会提示api_key失败的问题: 有两种方法解决: 1、注释掉下面的行代码; 方法二&#xff1…

蓝光三维扫描:汽车冲压模具与钣金件全尺寸检测的精准解决方案

随着汽车市场竞争日趋激烈,新车型开发周期缩短,安全性能要求提高,车身结构愈加复杂。白车身由多达上百个具有复杂空间型面的钣金件,通过一系列工装装配、焊接而成。 钣金件尺寸精度是白车身装配精度的基础。采用新拓三维XTOM蓝光…

深度学习占用大量内存空间解决办法

应该是缓存的问题,关机重启内存多了10G,暂时没找到别的方法 重启前 关机重启后

Matlab绘制函数方程图形

Matlab绘制函数方程图形: 多项式计算: polyval 函数 Values of Polynomials: polyval ( ) 绘制方程式图形: 代码如下: >> a[9,-5,3,7]; x-2:0.01:5; fpolyval(a,x); plot(x,f,LineWidth,2); xlabel(x); ylabel(f(x))…

电视盒子 刷armbian

参考 中兴电视盒子中兴B860AV3.2-M刷Armbian新手级教程-CSDN博客 1.刷安卓9 带root版本 a. 下载安卓线刷包 链接:https://pan.baidu.com/s/1hz87_ld2lJea0gYjeoHQ8A?pwdd7as 提取码:d7as b.拆机短接 3.安装usbburning工具 使用方法 ,…

AI应用开发之扣子第一课-夸夸机器人

首先,进入官网:点击跳转至扣子。 1.创建智能体 登录进网站后,点击左上角+图标,创建智能体,输入智能体名称、功能介绍 2.输入智能体提示词 在“人设与回复逻辑”输入以下内容: # 角色 你是一…

【计算机网络实践】(十二)大学校园网综合项目设计

本系列包含: (一)以太网帧分析与网际互联协议报文结构分析 (二)地址解析协议分析与传输控制协议特性分析 (三)交换机的基本操作、配置、 虚拟局域网配置和应用 (四)交…

uniapp小程序位置授权弹框与隐私协议耦合(合而为一)(只在真机上有用,模拟器会分开弹 )

注意: 只在真机上有用,模拟器会分开弹 效果图: 模拟器效果图(授权框跟隐私政策会分开弹,先弹隐私政策,同意再弹授权弹框): manifest-template.json配置( "__usePr…

【星闪模组开发板WS8204SLEBLEModule】星闪数据收发测试

目录 开发板简介 串口设置 主从模式设置 AT命令数据发送 透传模式数据发送 结语 本文首发于《电子产品世界》论坛:【星闪模组开发板WS8204SLE&BLEModule】星闪数据收发测试-电子产品世界论坛https://forum.eepw.com.cn/thread/392011/1 感谢eepw论坛和成…

基础知识:Dify 错误排查

Case1:Dify 卡在管理员界面 查看容器状态 docker compose ps 可以看到有个容器异常:docker_db_1 的状态是 Restarting(表示一直在重启) 解决方案 参考:https://github.com/langgenius/dify/issues/5731

spring cloud微服务断路器详解及主流断路器框架对比

微服务断路器详解 1. 核心概念 定义:断路器模式通过快速失败机制防止故障扩散,当服务调用出现异常或超时时,自动切换到降级逻辑,避免级联故障。核心功能: 熔断:在故障阈值(如错误率&#xff09…

(小白0基础) 微调deepseek-8b模型参数详解以及全流程——训练篇

​ 本篇参考bilibili如何在本地微调DeepSeek-R1-8b模型_哔哩哔哩_bilibili 上篇:(小白0基础) 租用AutoDL服务器进行deepseek-8b模型微调全流程(Xshell,XFTP) —— 准备篇 初始变量 max_seq_length 2048 dtype None load_in_4bit True单批次最大处理模型大小dy…

关于汽车辅助驾驶不同等级、技术对比、传感器差异及未来发展方向的详细分析

以下是关于汽车辅助驾驶不同等级、技术对比、传感器差异及未来发展方向的详细分析: 一、汽车辅助驾驶等级详解 根据SAE(国际自动机工程师学会)的标准,自动驾驶分为 L0到L5 六个等级: 1. L0(无自动化&…

mongodb7日志特点介绍:日志分类、级别、关键字段(下)

#作者:任少近 上篇《mongodb7日志特点介绍:日志分类、级别、关键字段(上)》 链接: link 文章目录 4.日志会输出F/E/W/I四种情况5.日志关键字段6.日志量验证情况7.总结 4.日志会输出F/E/W/I四种情况 在MongoDB7中,日志输出按照严重性分为四种…

word中插入图片显示不完整,怎么处理让其显示完整?

在WORD里插入图片后,选择嵌入式发现插入的图片显示不正常,只能显示底部一部分,或者遮住文字。出现此故障的原因有可能是设置为固定值的文档行距小于图形的高度,从而导致插入的图形只显示出了一部分。 1.选中图片,然后点…

SAP S4HANA embedded analytics

SAP S4HANA embedded analytics