🚀

用 Python + Ollama 搭一个会议录音整理器:自动转文字、提炼要点、提取待办

开会录音丢进去,自动转出文字稿、生成摘要、提取待办事项。告别会后整理噩梦,30秒拿到完整会议纪要。

👁️ - 次阅读

你有没有这种经历:开了两小时会,录音录得满满当当,但回去整理纪要能磨蹭一整天。

更惨的是,开会时只顾着听,根本没记下来。散会了才想起来——刚才说的下个月要干啥,谁负责啥,完全没记录。

今天做一个会议录音整理器。录好的音频丢进去,自动转文字、生成摘要、提取待办。整个过程全自动,你只管开会。

项目背景

开会、开会、还是开会。每天三五个会,会后整理纪要是最头疼的事。

市面上的工具要么收费(Otter.ai、讯飞听见),要么要联网(飞书妙记)。本地跑一个,数据不出公司,还能随时改 prompt 适配你的会议风格。

核心流程就三步:

  1. 语音转文字(Whisper)
  2. AI 总结内容(本地 Ollama)
  3. 提取待办事项 + 责任人

全程在本地运行,隐私安全,零月费。

技术选型

组件选型理由
语音转文字Whisper(openai-whisper)开源免费,中文效果好
文本总结Ollama + qwen2.5本地运行,不依赖外部 API
音频处理moviepy / pydub支持各种音频格式
结果保存Markdown方便后续编辑和版本管理

不需要数据库。每个会议一个 Markdown 文件,按日期归档,随时可查。

实现步骤

第一步:安装依赖

pip install openai-whisper pydub moviepy

如果你用 Ubuntu/Debian,还需要:

sudo apt install ffmpeg libavcodec-extra

Ollama 部分:

# 安装 Ollama(如果还没装)
curl -fsSL https://ollama.com/install.sh | sh

# 拉取模型(7B 够用,8GB 显存/内存就能跑)
ollama pull qwen2.5:7b

第二步:编写核心脚本 meeting_organizer.py

#!/usr/bin/env python3
"""
会议录音整理器
自动转文字 → AI 总结 → 提取待办
"""

import os
import json
import re
import subprocess
from pathlib import Path
from datetime import datetime
import whisper
import requests

# ============ 配置区 ============

AUDIO_DIR = Path.home() / "meetings" / "raw"
OUTPUT_DIR = Path.home() / "meetings" / "output"
OLLAMA_URL = "http://localhost:11434/api/generate"
MODEL = "qwen2.5:7b"
WHISPER_MODEL = "base"  # medium / large 效果更好但更慢

# 会议摘要 prompt
SUMMARY_PROMPT = """你是一个专业的会议记录员。请对以下会议录音转写文本进行整理。

输出格式(严格按照以下 JSON 格式,不要添加其他内容):
{{
  "title": "会议主题标题(20字以内)",
  "date": "会议日期(YYYY-MM-DD)",
  "summary": "会议核心内容总结(100字以内)",
  "key_points": ["要点1", "要点2", "要点3"],
  "action_items": [
    {{"owner": "负责人姓名", "task": "待办事项", "due": "截止日期(如有)"}}
  ],
  "decisions": ["会议中做出的重要决定"],
  "next_meeting": "下次会议安排(如有)"
}}

会议文本:
{text}
"""

def transcribe_audio(audio_path: str, model_name: str = WHISPER_MODEL) -> str:
    """使用 Whisper 转录音频"""
    print(f"🎙️ 正在转录: {audio_path}")
    model = whisper.load_model(model_name)
    result = model.transcribe(audio_path, language="zh")
    return result["text"]


def summarize_with_ollama(text: str) -> dict:
    """调用 Ollama 生成会议摘要"""
    prompt = SUMMARY_PROMPT.format(text=text[:4000])  # 限制长度避免超限
    
    try:
        resp = requests.post(
            OLLAMA_URL,
            json={"model": MODEL, "prompt": prompt, "stream": False},
            timeout=120
        )
        response_text = resp.json().get("response", "")
        
        # 提取 JSON
        start = response_text.find("{")
        end = response_text.rfind("}") + 1
        if start >= 0 and end > start:
            return json.loads(response_text[start:end])
        
        # 降级:返回原文
        return {"raw_output": response_text}
    except Exception as e:
        print(f"⚠️ Ollama 请求失败: {e}")
        return {"error": str(e)}


def save_meeting_report(data: dict, date: str) -> Path:
    """保存会议报告为 Markdown"""
    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
    filename = f"{date}_{data.get('title', '未命名')}.md"
    filepath = OUTPUT_DIR / filename
    
    content = f"""# {data.get('title', '会议记录')}

**日期**: {data.get('date', date)}
**整理时间**: {datetime.now().strftime('%Y-%m-%d %H:%M')}

---

## 📋 会议摘要

{data.get('summary', '暂无摘要')}

## 🔑 关键要点

"""
    for i, point in enumerate(data.get("key_points", []), 1):
        content += f"{i}. {point}\n"
    
    content += "\n## ✅ 待办事项\n\n"
    for item in data.get("action_items", []):
        due = f"(截止:{item.get('due', '待定')})" if item.get("due") else ""
        content += f"- [ ] {item.get('task', '未命名任务')} — {item.get('owner', '未知')}{due}\n"
    
    content += "\n## 📌 重要决定\n\n"
    for decision in data.get("decisions", []):
        content += f"- {decision}\n"
    
    if data.get("next_meeting"):
        content += f"\n## 📅 下次会议\n\n{data['next_meeting']}\n"
    
    filepath.write_text(content, encoding="utf-8")
    return filepath


def process_meeting(audio_path: str):
    """处理单个会议音频文件"""
    audio_path = Path(audio_path)
    date_str = datetime.now().strftime("%Y-%m-%d")
    
    # 步骤1:语音转文字
    transcript = transcribe_audio(str(audio_path))
    print(f"✅ 转录完成,共 {len(transcript)} 字")
    
    # 保存原始转写文本
    transcript_dir = OUTPUT_DIR / "transcripts"
    transcript_dir.mkdir(parents=True, exist_ok=True)
    transcript_file = transcript_dir / f"{date_str}_{audio_path.stem}.txt"
    transcript_file.write_text(transcript, encoding="utf-8")
    
    # 步骤2:AI 总结
    print("🤖 正在生成摘要...")
    summary = summarize_with_ollama(transcript)
    
    # 步骤3:保存报告
    report_path = save_meeting_report(summary, date_str)
    print(f"✅ 会议报告已保存: {report_path}")
    
    return report_path


if __name__ == "__main__":
    import sys
    
    if len(sys.argv) < 2:
        print("用法: python meeting_organizer.py <音频文件路径>")
        print("支持格式: mp3, wav, m4a, mp4, webm")
        print("\n示例:")
        print('  python meeting_organizer.py ./录音.mp3')
        print('  python meeting_organizer.py ~/meetings/raw/2026-08-06.mp3')
        sys.exit(1)
    
    process_meeting(sys.argv[1])

第三步:批量处理多个会议文件

如果你想一次性处理多个录音,用这个批量脚本:

# batch_process.py
#!/usr/bin/env python3
import sys
from pathlib import Path
from meeting_organizer import process_meeting

AUDIO_DIR = Path.home() / "meetings" / "raw"

if __name__ == "__main__":
    audio_files = list(AUDIO_DIR.glob("*.mp3")) + \
                  list(AUDIO_DIR.glob("*.m4a")) + \
                  list(AUDIO_DIR.glob("*.wav"))
    
    print(f"📂 找到 {len(audio_files)} 个音频文件\n")
    
    for audio_file in audio_files:
        print(f"\n{'='*50}")
        print(f"处理: {audio_file.name}")
        print('='*50)
        try:
            process_meeting(str(audio_file))
        except Exception as e:
            print(f"❌ 处理失败: {e}")
    
    print("\n🎉 全部处理完成!")

第四步:设置定时整理

把脚本加入 cron,每周自动整理一次:

crontab -e
# 每周日晚上 22:00 整理本周所有会议录音
0 22 * * 0 /usr/bin/python3 ~/meetings/batch_process.py >> ~/meetings/process.log 2>&1

运行效果

python meeting_organizer.py ./meetings/2026-08-06-产品评审.mp3

输出:

🎙️ 正在转录: ./meetings/2026-08-06-产品评审.mp3
✅ 转录完成,共 2847 字
🤖 正在生成摘要...
✅ 会议报告已保存: /home/user/meetings/output/2026-08-06_产品功能评审会.md

生成的 Markdown 报告:

# 产品功能评审会

**日期**: 2026-08-06
**整理时间**: 2026-08-06 15:30

---

## 📋 会议摘要

讨论了 Q3 产品路线图,确定了三个核心功能优先级,分配了各模块负责人。

## 🔑 关键要点

1. 用户反馈系统重构,预计 2 周完成
2. 数据分析看板新增实时指标
3. 移动端适配方案确定

## ✅ 待办事项

- [ ] 完成用户反馈系统 API 设计 — 张三(截止:2026-08-20)
- [ ] 输出数据分析看板原型 — 李四
- [ ] 编写移动端适配技术方案 — 王五(截止:2026-08-15)

## 📌 重要决定

- 用户反馈系统优先级调整为 P0
- 数据分析看板接入实时数据流

优化方向

这个基础版本已经能用了。想进一步打磨可以加这些:

  1. 说话人分离:用 pyannote.audio 识别不同说话人,区分谁说了什么。
  2. 多语言支持: Whisper 支持 99 种语言,自动检测语言类型。
  3. 飞书/钉钉推送:整理完成后自动发送 Markdown 报告到团队群。
  4. 历史对比:记录每周会议内容变化,生成趋势分析。
  5. 关键词提取:自动提取会议中的高频词,生成话题标签。
  6. Web 界面:用 Streamlit 搭个上传页面,手机也能传录音。

成本对比

方案月费隐私准确度
飞书妙记免费版有限数据上云⭐⭐⭐⭐
讯飞听见¥0.13/分钟数据上云⭐⭐⭐⭐⭐
本方案¥0完全本地⭐⭐⭐

本方案完全本地运行,录音数据不离开你的电脑。准确度略低于商业服务,但胜在免费、隐私、可定制。

把今天的会议录音丢进去,看看能省多少整理时间。你公司的会议通常多久?两小时的会,整理纪要至少要半小时吧。

这篇文章对你有帮助吗?