
用蓝牙耳机开会,会后自动得到一份结构化的会议纪要,这件事完全可以在自己的 VPS 上免费实现——不需要买带 AI 的专属耳机,也不需要按分钟付费的商业订阅。本文给出三种自建方案(从轻量脚本到可视化平台),覆盖 Google Meet、Zoom、Teams,并支持英文 / 中文 / 日文三种语言的自动识别与摘要。
一、为什么把会议摘要放到 VPS 上
买一副自带 AI 能力的会议耳机(如讯飞 iFLYBUDS、韶音 OpenFit AI)确实方便,但硬件与云端绑定,长期成本和数据归属都由厂商决定;而 Read AI、Otter、Fathom 这类 SaaS 免费额度有限、按时长计费,会议内容还会离开自己的控制范围。
自建的三个直接收益:
- 零按分钟费用:转录用本地的 faster-whisper,摘要走自有的 OneAPI 网关(可对接 DeepSeek、Gemini Flash、Groq 等免费或低价模型),没有时长上限。
- 数据自持:音频与转写文本只在自己的 VPS 上处理,不进入第三方云。
- 完全可控:摘要模板、语言、输出格式都能随时改。
前提是你已经有一台 VPS(CPU 即可,4GB 内存以上更从容)和一套 OneAPI(One-API / New-API)LLM 网关。本文的示例跑在 CPU-only、约 6GB 内存的 VPS 上,用的是 faster-whisper 的 base 模型 + int8 量化。
二、整体架构
VPS 在云端,无法直接”听”到你蓝牙耳机里的声音,所以流程必然是本地录音 → 上传 VPS → 转写 → 摘要:
[蓝牙耳机] --音频--> [本地录音: Mac BlackHole / Win WASAPI Loopback]
|
v (导出 mp3/m4a/wav 到监控文件夹)
[文件夹监控脚本 watchdog] --HTTP 上传--> [VPS: FastAPI /summarize]
| |
| v
| [faster-whisper 本地转写]
| |
| v
| [OneAPI 网关 → LLM 生成结构化摘要]
v |
[同目录生成 *_SUMMARY.txt] <-------------------+
核心只有两个组件:VPS 上的一个处理 API,和本地 PC 上的一个文件夹监控脚本。装好之后,你开完会只要把录音丢进一个文件夹,几秒到几分钟后同目录就会出现摘要文本。
三、方案一(推荐):轻量 FastAPI + faster-whisper + OneAPI
最省资源、最可控的路径。VPS 上跑一个无界面的处理服务,本地脚本负责上传。
1. 在 VPS 上准备目录与 docker-compose.yml:
version: '3.8'
services:
meeting-processor:
image: python:3.11-slim
container_name: meeting_processor
ports:
- "8000:8000"
environment:
- ONEAPI_URL=http://YOUR_ONEAPI_IP:PORT/v1
- ONEAPI_KEY=your_oneapi_api_key_here
- LLM_MODEL=deepseek-chat # 换成 OneAPI 里你偏好的模型
volumes:
- ./app:/app
working_dir: /app
command: >
bash -c "pip install fastapi uvicorn requests python-multipart faster-whisper && uvicorn main:app --host 0.0.0.0 --port 8000"
restart: unless-stopped
2. 在同级 app/ 目录下保存 main.py:
import os
from fastapi import FastAPI, UploadFile, File
import requests
from faster_whisper import WhisperModel
app = FastAPI()
ONEAPI_URL = os.getenv("ONEAPI_URL")
ONEAPI_KEY = os.getenv("ONEAPI_KEY")
LLM_MODEL = os.getenv("LLM_MODEL")
# CPU 低资源使用 base + int8
print("Loading Whisper Model...")
whisper_model = WhisperModel("base", device="cpu", compute_type="int8")
@app.post("/summarize")
async def summarize_meeting(file: UploadFile = File(...)):
temp_path = f"temp_{file.filename}"
with open(temp_path, "wb") as f:
f.write(await file.read())
# Whisper 自动识别 英文 / 中文 / 日文
print(f"Transcribing {file.filename}...")
segments, info = whisper_model.transcribe(temp_path, beam_size=5)
detected_lang = info.language
transcript = " ".join([s.text for s in segments])
os.remove(temp_path)
headers = {"Authorization": f"Bearer {ONEAPI_KEY}",
"Content-Type": "application/json"}
system_instruction = (
"You are an expert executive secretary. Analyze the transcript, detect the "
"primary language (English, Japanese, or Chinese) and answer in THAT language. "
"Structure the output exactly as: 1. Executive Summary / 核心摘要 / 概要, "
"2. Key Decisions / 关键决策 / 決定事項, "
"3. Action Items with owners / 待办事项与负责人 / タスクと担当者."
)
payload = {
"model": LLM_MODEL,
"messages": [
{"role": "system", "content": system_instruction},
{"role": "user", "content": f"Transcript:\n{transcript}"},
],
"temperature": 0.2,
}
r = requests.post(f"{ONEAPI_URL}/chat/completions", json=payload, headers=headers)
summary = r.json()["choices"][0]["message"]["content"]
return {"success": True, "summary": summary, "language": detected_lang}
3. 启动:
docker compose up -d
四、方案二:Dify 或 Lobe Chat(可视化工作流)
如果你更想要一个网页界面,而不是命令行,可以在 VPS 上用 Docker 部署现成平台,并把模型请求指向自己的 OneAPI。
- Dify:新建一个 Chat App 或 Workflow,在”模型供应商”里选 OpenAI 兼容协议,填入 OneAPI 的
http://<oneapi-ip>:<port>/v1与 Key;开启语音转文字(可接 Whisper API),在系统提示词里写上会议纪要模板。之后打开网页上传录音即可出摘要。 - Lobe Chat:一条命令起一个类 ChatGPT 界面,把 OneAPI 作为上游:
docker run -d -p 3210:3210 \
-e OPENAI_API_KEY=your_oneapi_key_here \
-e OPENAI_PROXY_URL=http://your-oneapi-ip:port/v1 \
--name lobe-chat \
lobehub/lobe-chat
建一个名叫”会议助手”的自定义 Agent,把摘要提示词写进它的系统设定,然后把音频文件直接拖进对话框。
注意:Dify / Lobe Chat 是”人工上传 + 点按钮”的交互式方案,适合偶尔开会、想要界面的人;方案一的脚本是”丢文件自动出结果”,适合每天都开会、追求无感自动化的人。
五、方案三:Nextcloud Assistant(已有网盘时顺手)
如果你的 VPS 本来就用 Nextcloud 做云盘,可以启用它的开源 AI 能力:Voice Recorder 允许在浏览器里直接录音或上传,Assistant 应用通过图形界面调用免费的翻译/摘要接口。好处是全程不碰命令行,代价是相对吃资源、配置链更绕。
六、本地端:Mac 与 Windows 的录音与触发
macOS(推荐 BlackHole,免手写录音)
BlackHole 是免费开源的虚拟声卡,可以把系统声音(对方语音)和你自己的麦克风一起回环录制:
brew install blackhole-2ch,在”音频 MIDI 设置”里新建一个多输出设备,同时勾选你的蓝牙耳机和 BlackHole 2ch,开会时把系统输出切到它。- 用 QuickTime Player 的”新建音频录制”,输入设备选 BlackHole 2ch,录完后导出
m4a/mp3到监控文件夹。
如果希望连这一步都省掉,可以用 Screenpipe 这类本地工具自动抓取任意应用(浏览器或桌面客户端)的会议音频,再交给 VPS 处理。
Windows
用免费的 Audacity:录音主机选 Windows WASAPI,录音设备选对应的 Loopback,即可同时录到系统声音与麦克风,导出后放进监控文件夹。
文件夹监控脚本(跨平台,自动上传)
在本地 PC 上 pip install watchdog requests,保存为 meeting_watcher.py,按需改路径与 VPS 地址:
import os, time, requests
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
HOME_DIR = os.path.expanduser("~")
WATCH_FOLDER = os.path.join(HOME_DIR, "Downloads", "Meetings")
VPS_API_URL = "http://YOUR_VPS_IP:8000/summarize"
class Handler(FileSystemEventHandler):
def on_created(self, event):
if event.is_directory or os.path.basename(event.src_path).startswith('.'):
return
path = event.src_path
if not path.lower().endswith(('.mp3', '.m4a', '.wav')):
return
print(f"New meeting detected: {os.path.basename(path)}")
# 等待文件完全写入(Zoom/Teams/浏览器导出有个过程)
size = -1
while True:
time.sleep(3)
try:
cur = os.path.getsize(path)
if cur == size and cur > 0:
break
size = cur
except OSError:
time.sleep(1)
with open(path, 'rb') as f:
files = {'file': (os.path.basename(path), f, 'audio/mpeg')}
r = requests.post(VPS_API_URL, files=files, timeout=900)
if r.status_code == 200 and r.json().get("success"):
lang = r.json().get("language", "unknown")
out = os.path.splitext(path)[0] + "_SUMMARY.txt"
# UTF-8 写入,保证中文/日文不乱码
with open(out, "w", encoding="utf-8") as o:
o.write(r.json()["summary"])
print(f"Summary generated ({lang}) -> {os.path.basename(out)}")
# macOS 原生通知(可选)
os.system("osascript -e 'display notification \"Summary ready!\" "
"with title \"Meeting Assistant\"'")
else:
print("VPS error:", r.text)
if __name__ == "__main__":
os.makedirs(WATCH_FOLDER, exist_ok=True)
obs = Observer()
obs.schedule(Handler(), path=WATCH_FOLDER, recursive=False)
obs.start()
print("Watching:", WATCH_FOLDER)
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
obs.stop()
obs.join()
在 macOS 上还可以把它做成开机自启的 Launch Agent(~/Library/LaunchAgents/*.plist,RunAtLoad + KeepAlive),不用一直开着终端窗口。
七、Google Meet / Zoom / Teams 各自的触发方式
- Zoom / Teams(桌面客户端):如果你是主持人,客户端本身就能把录像保存到本地——把它们的默认保存目录直接指到监控文件夹(如
~/Downloads/Meetings),会议一结束文件落到这里,脚本立刻接手。 - Google Meet(浏览器):浏览器不会自动把音频落到磁盘。用 Chrome 的 “Audio Capture” 这类免费扩展,或 macOS 上用 QuickTime / Screenpipe 录屏录音,点”停止并保存”到监控文件夹即可。
三条路最终都汇入同一个监控文件夹,脚本不关心音频来自哪个会议软件。
八、三语言(英 / 中 / 日)处理要点
- faster-whisper 会自动检测语言并返回
info.language,中英日混合会议也能处理;语言分界不清时可显式指定language="ja"等参数。 - 让 LLM 用会议的主语言输出摘要(提示词里写明”detect the primary language and answer in that language”),避免把中文会议总结成英文。
- 文件名与摘要文件统一用 UTF-8 写入,防止中文/日文乱码;输出文件与音频同名、后缀不同(
xxx_SUMMARY.txt),便于对照。
九、避坑与调优
- CPU 优先用
base/tiny模型 +compute_type="int8":低配 VPS 上跑大模型会拖垮服务器,准确度与速度取一个平衡点。 - 给上传设足够长的超时:一小时会议转写需要时间,脚本里
timeout=900比默认值稳妥。 - 等待文件写完再上传:录音软件导出是渐进的,脚本里”文件大小连续两次不变”再上传,能避免传到半个文件。
- 把处理服务放在内网或加访问控制:API 端口不要裸奔在公网,尽量只在 Tailscale 等私有网络里暴露。
十、小结
| 方案 | 部署方式 | 交互 | 适合场景 |
|---|---|---|---|
| FastAPI + Whisper + OneAPI | Docker 单容器 | 丢文件自动出摘要 | 每天开会、要无感自动化 |
| Dify / Lobe Chat | Docker 平台 | 网页上传/拖拽 | 偶尔开会、想要界面 |
| Nextcloud Assistant | 已有网盘上扩展 | 图形界面 | 已用 Nextcloud 做云盘 |
三者都复用同一套底层能力——本地 faster-whisper 转录、自有 OneAPI 网关出摘要——因此零按分钟成本、无时长上限、数据不出自己的 VPS。先按方案一把最小闭环跑通,之后再按需要加可视化界面或自动化触发,是最省事的路径。


讨论
订阅评论 RSS加入讨论
分享你的想法与经验,也可以登录后参与讨论。
使用 WordPress 登录