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

本地WSL ubuntu部署whisper api服务

1. 实现功能

M5-1: Whisper API 服务

本脚本使用 FastAPI 构建一个语音转录微服务。
它提供一个 /transcribe/ 端点,可以接收音频文件上传,
并返回转录后的全文文本和 SRT 格式的字幕。

2.运行效果

(whisper) root@DESKTOP-8IU6393:/home/gpu3090/vscode/M5-应用集成# curl -X POST "http://127.0.0.1:8080/transcribe/" \-F "audio_file=@26.mp3;type=audio/wav" \-F "model_name=large-v3" \-F "language=zh"
{"full_text":"作品二十六号我们家的后园有半亩空地母亲说,让她慌着怪可惜的你们那么爱吃花生,就开辟出来种花生吧我们姐弟几个都很高兴埋种、翻地、播种、浇水没过几个月,居然收获了母亲说,今晚我们过一个收获节请你们父亲也来尝尝我们的新花生,好不好我们都说好母亲把花生做成了好几样食品还吩咐就在后园的茅亭里过这个节晚上天色不太好可是父亲也来了实在很难得父亲说,你们爱吃花生吗我们争着答应,爱谁能把花生的好处说出来姐姐说,花生的味儿美哥哥说,花生可以榨油我说,花生的价钱便宜谁都可以买来吃,都喜欢吃这就是它的好处父亲说,花生的好处很多有一样最可贵它的果实埋在地里不像桃子、石榴、苹果那样把鲜红嫩绿的果实高高地挂在枝头上使人一见就生爱慕之心你们看它矮矮地长在地上等到成熟了就会吃了也不能立刻分辨出来它有没有果实必须挖出来才知道我们都说是母亲也点点头父亲接下去说所以你们要像花生它虽然不好看可是很有用不是外表好看而没有实用的东西我说那么人要做有用的人不是外表好看不要做只讲体面而对别人没有好处的人了父亲说对这是我对你们的希望我们谈到夜深才散花生做的食品都吃完了父亲的话却深深地印在我的心上欢迎光临普通话学习网3w.png.compthxx.com","srt_subtitles":"1\n0:00:00,000 --> 0:00:01,919\n作品二十六号\n\n2\n0:00:01,919 --> 0:00:06,700\n我们家的后园有半亩空地\n\n3\n0:00:06,700 --> 0:00:10,939\n母亲说,让她慌着怪可惜的\n\n4\n0:00:10,939 --> 0:00:15,900\n你们那么爱吃花生,就开辟出来种花生吧\n\n5\n0:00:15,900 --> 0:00:19,699\n我们姐弟几个都很高兴\n\n6\n0:00:19,699 --> 0:00:24,160\n埋种、翻地、播种、浇水\n\n7\n0:00:24,160 --> 0:00:27,660\n没过几个月,居然收获了\n\n8\n0:00:27,660 --> 0:00:32,859\n母亲说,今晚我们过一个收获节\n\n9\n0:00:32,859 --> 0:00:38,060\n请你们父亲也来尝尝我们的新花生,好不好\n\n10\n0:00:38,060 --> 0:00:40,920\n我们都说好\n\n11\n0:00:40,920 --> 0:00:45,439\n母亲把花生做成了好几样食品\n\n12\n0:00:45,439 --> 0:00:49,900\n还吩咐就在后园的茅亭里过这个节\n\n13\n0:00:51,920 --> 0:00:54,120\n晚上天色不太好\n\n14\n0:00:54,120 --> 0:00:56,240\n可是父亲也来了\n\n15\n0:00:56,240 --> 0:00:58,240\n实在很难得\n\n16\n0:00:58,240 --> 0:01:02,820\n父亲说,你们爱吃花生吗\n\n17\n0:01:02,820 --> 0:01:05,960\n我们争着答应,爱\n\n18\n0:01:05,960 --> 0:01:09,599\n谁能把花生的好处说出来\n\n19\n0:01:09,599 --> 0:01:13,840\n姐姐说,花生的味儿美\n\n20\n0:01:13,840 --> 0:01:18,180\n哥哥说,花生可以榨油\n\n21\n0:01:18,180 --> 0:01:22,719\n我说,花生的价钱便宜\n\n22\n0:01:22,719 --> 0:01:25,859\n谁都可以买来吃,都喜欢吃\n\n23\n0:01:26,239 --> 0:01:27,780\n这就是它的好处\n\n24\n0:01:27,780 --> 0:01:33,379\n父亲说,花生的好处很多\n\n25\n0:01:33,379 --> 0:01:35,859\n有一样最可贵\n\n26\n0:01:35,859 --> 0:01:38,919\n它的果实埋在地里\n\n27\n0:01:38,919 --> 0:01:42,639\n不像桃子、石榴、苹果那样\n\n28\n0:01:42,639 --> 0:01:47,579\n把鲜红嫩绿的果实高高地挂在枝头上\n\n29\n0:01:47,579 --> 0:01:50,799\n使人一见就生爱慕之心\n\n30\n0:01:50,799 --> 0:01:54,359\n你们看它矮矮地长在地上\n\n31\n0:01:54,359 --> 0:01:56,119\n等到成熟了\n\n32\n0:01:56,119 --> 0:01:56,219\n就会吃了\n\n33\n0:01:56,239 --> 0:01:58,319\n也不能立刻分辨出来\n\n34\n0:01:58,319 --> 0:02:00,039\n它有没有果实\n\n35\n0:02:00,039 --> 0:02:02,619\n必须挖出来才知道\n\n36\n0:02:02,619 --> 0:02:04,679\n我们都说是\n\n37\n0:02:04,679 --> 0:02:07,060\n母亲也点点头\n\n38\n0:02:07,060 --> 0:02:10,199\n父亲接下去说\n\n39\n0:02:10,199 --> 0:02:13,039\n所以你们要像花生\n\n40\n0:02:13,039 --> 0:02:15,159\n它虽然不好看\n\n41\n0:02:15,159 --> 0:02:16,539\n可是很有用\n\n42\n0:02:16,539 --> 0:02:18,620\n不是外表好看\n\n43\n0:02:18,620 --> 0:02:20,579\n而没有实用的东西\n\n44\n0:02:20,579 --> 0:02:22,620\n我说\n\n45\n0:02:22,620 --> 0:02:25,599\n那么人要做有用的人\n\n46\n0:02:25,599 --> 0:02:26,120\n不是外表好看\n\n47\n0:02:26,120 --> 0:02:28,159\n不要做只讲体面\n\n48\n0:02:28,159 --> 0:02:31,939\n而对别人没有好处的人了\n\n49\n0:02:31,939 --> 0:02:33,280\n父亲说\n\n50\n0:02:33,280 --> 0:02:34,480\n\n\n51\n0:02:34,480 --> 0:02:38,960\n这是我对你们的希望\n\n52\n0:02:38,960 --> 0:02:41,960\n我们谈到夜深才散\n\n53\n0:02:41,960 --> 0:02:45,680\n花生做的食品都吃完了\n\n54\n0:02:45,680 --> 0:02:52,000\n父亲的话却深深地印在我的心上\n\n55\n0:02:52,000 --> 0:02:54,939\n欢迎光临普通话学习网\n\n56\n0:02:54,939 --> 0:02:56,000\n3w.png.com\n\n57\n0:02:56,000 --> 0:02:58,819\npthxx.com\n","metadata":{"detected_language":"zh","processing_time_seconds":33.22,"model_used":"large-v3"}}(whisper) root@DESKTOP-8IU6393:/home/gpu3090/vscode/M5-应用集成# 

在这里插入图片描述

3.实现过程

3.1 搭建环境

(base) root@DESKTOP-8IU6393:/home/gpu3090/vscode/M5-应用集成# conda activate whisper
(whisper) root@DESKTOP-8IU6393:/home/gpu3090/vscode/M5-应用集成#pip install fastapi "uvicorn[standard]" python-multipart
(whisper) root@DESKTOP-8IU6393:/home/gpu3090/vscode/M5-应用集成# uvicorn M5-1-API:app --reload --host 0.0.0.0 --port 8080
INFO:     Will watch for changes in these directories: ['/home/gpu3090/vscode/M5-应用集成']
INFO:     Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
INFO:     Started reloader process [3065] using WatchFiles
INFO:     Started server process [3067]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
2025-08-08 22:21:39,839 - INFO - 接收到文件: 【AI玩出花】MultiTalk实测:只需图片和音频,让画中人开口讲故事!(在线+本地部署).mp3 (类型: audio/mpeg)
2025-08-08 22:21:39,839 - INFO - 请求参数: model_name='large-v3', language='zh'
2025-08-08 22:21:40,040 - INFO - 正在使用设备: cuda
2025-08-08 22:21:40,060 - INFO - 音频文件已临时保存到: /tmp/tmpmtuvmmbc.mp3
2025-08-08 22:21:40,060 - INFO - 正在加载 Whisper 模型: large-v3...
2025-08-08 22:22:06,710 - INFO - 开始转录...
100%|████████████████████████████████████████████████████████████████████████| 92828/92828 [03:43<00:00, 416.21frames/s]
2025-08-08 22:25:53,535 - INFO - 转录完成,耗时: 226.822025-08-08 22:25:53,540 - INFO - 已清理临时文件: /tmp/tmpmtuvmmbc.mp3
INFO:     127.0.0.1:2553 - "POST /transcribe/ HTTP/1.1" 200 OK

3.1.1 在浏览器中打开 http://127.0.0.1:8080/docs 可以看到自动生成的交互式 API 文档。

在这里插入图片描述

3.2 代码

import os
import whisper
import datetime
import torch
import tempfile
import logging
from fastapi import FastAPI, UploadFile, File, HTTPException, Form
from fastapi.responses import JSONResponse# --- 配置日志 ---
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')# --- 初始化 FastAPI 应用 ---
app = FastAPI(title="Whisper Transcription API",description="一个使用 OpenAI Whisper 进行语音转录和字幕生成的 API。",version="1.0.0"
)# --- 全局变量与模型加载 ---
# 在生产环境中,推荐在应用启动时加载模型,避免每次请求都加载。
# 但对于开发和简单应用,按需加载也可以接受。
# 这里我们选择在函数内部加载,以支持动态选择模型。# --- 辅助函数:SRT 生成器 (从 M4 稳定版复制) ---
def generate_srt_from_segments(segments):"""根据 Whisper 的分段信息,生成 SRT 格式的字符串。"""srt_content = []for i, segment in enumerate(segments):start_time = datetime.timedelta(seconds=int(segment['start']))end_time = datetime.timedelta(seconds=int(segment['end']))# 格式化时间为 SRT 标准格式: HH:MM:SS,msstart_str = str(start_time).split('.')[0] + f",{int((segment['start'] % 1) * 1000):03d}"end_str = str(end_time).split('.')[0] + f",{int((segment['end'] % 1) * 1000):03d}"text = segment['text'].strip()srt_content.append(f"{i + 1}")srt_content.append(f"{start_str} --> {end_str}")srt_content.append(f"{text}\n")return "\n".join(srt_content)# --- API 端点定义 ---
@app.post("/transcribe/", summary="转录音频文件", description="上传一个音频文件,获取全文转录和SRT字幕。")
async def transcribe_audio(# 使用 File(...) 接收文件上传audio_file: UploadFile = File(..., description="要转录的音频文件 (如 .mp3, .wav, .m4a)"),# 使用 Form(...) 接收表单数据model_name: str = Form("base", description="要使用的 Whisper 模型 (如 'tiny', 'base', 'medium', 'large-v3')"),language: str = Form(None, description="音频的语言代码 (如 'en', 'zh')。如果留空,Whisper 会自动检测。")
):"""处理音频转录请求的核心函数。"""logging.info(f"接收到文件: {audio_file.filename} (类型: {audio_file.content_type})")logging.info(f"请求参数: model_name='{model_name}', language='{language}'")# 检查设备device = "cuda" if torch.cuda.is_available() else "cpu"logging.info(f"正在使用设备: {device}")# 使用临时文件来处理上传的音频# 这是处理上传文件的标准且安全的方式try:with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(audio_file.filename)[1]) as temp_audio_file:# 将上传的文件内容写入临时文件content = await audio_file.read()temp_audio_file.write(content)temp_audio_path = temp_audio_file.namelogging.info(f"音频文件已临时保存到: {temp_audio_path}")# 加载 Whisper 模型logging.info(f"正在加载 Whisper 模型: {model_name}...")model = whisper.load_model(model_name, device=device)# 执行转录logging.info("开始转录...")start_time = datetime.datetime.now()# 如果 language 为 None 或空字符串,Whisper 会自动检测lang_option = language if language and language.strip() else Noneresult = model.transcribe(temp_audio_path, language=lang_option, verbose=False)end_time = datetime.datetime.now()processing_time = (end_time - start_time).total_seconds()logging.info(f"转录完成,耗时: {processing_time:.2f} 秒")# 生成 SRT 字幕srt_subtitles = generate_srt_from_segments(result['segments'])# 准备返回的 JSON 数据response_data = {"full_text": result['text'],"srt_subtitles": srt_subtitles,"metadata": {"detected_language": result['language'],"processing_time_seconds": round(processing_time, 2),"model_used": model_name}}return JSONResponse(content=response_data)except Exception as e:logging.error(f"处理过程中发生错误: {e}", exc_info=True)# 如果发生任何错误,都返回一个 HTTP 500 错误raise HTTPException(status_code=500, detail=f"An error occurred: {str(e)}")finally:# 确保临时文件在处理完成后被删除if 'temp_audio_path' in locals() and os.path.exists(temp_audio_path):os.remove(temp_audio_path)logging.info(f"已清理临时文件: {temp_audio_path}")# --- 健康检查端点 ---
@app.get("/", summary="API 根目录与健康检查")
async def read_root():return {"message": "Whisper Transcription API 正在运行。请访问 /docs 查看 API 文档。"}
http://www.dtcms.com/a/322934.html

相关文章:

  • NVIDIA Jetson JetPack 全面解析:从硬件到定制镜像
  • 智能情趣设备、爆 bug:可被远程操控。。。
  • 目标检测数据集 - 无人机检测数据集下载「包含COCO、YOLO两种格式」
  • Python 中的 Mixin
  • 二十、MySQL-DQL-条件查询
  • 第八章:终极合体 —— 实现智能一键分组
  • 【Python 工具人快餐 · 第 1 份】
  • 【代码随想录|232.用栈实现队列、225.用队列实现栈、20.有效的括号、1047.删除字符串中的所有相邻重复项】
  • 第05章 排序与分页
  • 模板方法模式:优雅封装算法骨架
  • Python-UV-portry项目管理流程
  • redis8.0.3部署于mac
  • C++ 中的智能指针
  • Python 继承和多态
  • ElaWidgetTools qt5+vs2019编译
  • 1.JavaScript 介绍
  • 基于STM32的智能电表设计与实现
  • 计算机组成原理2-4-1:浮点数的表示
  • Linux 安装 JDK 8u291 教程(jdk-8u291-linux-x64.tar.gz 解压配置详细步骤)​
  • 【c++】探秘Loop机制:C++中优雅的双向数据交互模式
  • 低速CAN 高速CAN是否兼容?
  • 功能测试详解
  • 【面试题】cookie和session 的区别
  • Ubuntu下Nginx的部署后端项目(Java为例),配置Nginx代理
  • 自编教材实操课程学习笔记
  • 商品、股指及ETF期权五档盘口Tick级与分钟级历史行情数据多维解析
  • dify离线插件安装
  • Spring Boot Starter 自动化配置原理深度剖析
  • 【工具变量】地市人力资本水平数据集(2003-2023年)
  • 聊聊经常用的微服务