要生成器开发实战(Python实现)


背景介绍

在现代职场中,会议占据了大量工作时间,而会后整理纪要往往比会议本身更耗时。传统人工记录方式存在效率低下、关键信息遗漏等问题。本文介绍如何使用Python开发一个智能会议纪要生成器,通过语音识别和自然语言处理技术,自动将会议录音转化为结构化会议纪要。

技术架构

系统采用三层架构设计:
1. 前端:PyQt5图形界面
2. 中间层:Vosk语音识别引擎
3. 后端:规则引擎+文档生成

graph LR
    A[音频输入] --> B(语音识别)
    B --> C(文本预处理)
    C --> D(关键信息提取)
    D --> E(文档生成)

完整实现代码

import sys
import re
from datetime import datetime
from vosk import Model, KaldiRecognizer
from PyQt5.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, 
                            QLabel, QPushButton, QTextEdit, QWidget)
import pythoncom
import win32com.client as win32

class MeetingMinuteGenerator:
    def __init__(self):
        # 初始化语音识别模型
        self.model = Model("vosk-model-small-zh-cn-0.22")
        self.recognizer = KaldiRecognizer(self.model, 16000)

        # 初始化规则库
        self.rules = {
            'resolution': r'(决定|决议|确定)(.*?)(。|\n|$)',
            'responsible': r'由(.*?)负责',
            'deadline': r'(\d{1,2}月\d{1,2}日|[上下]季度)'
        }

    def transcribe_audio(self, audio_path):
        """语音转文字"""
        with open(audio_path, 'rb') as f:
            while True:
                data = f.read(4000)
                if len(data) == 0:
                    break
                if self.recognizer.AcceptWaveform(data):
                    result = self.recognizer.Result()
        return json.loads(result)['text']

    def extract_info(self, text):
        """提取关键信息"""
        results = {}
        for key, pattern in self.rules.items():
            matches = re.findall(pattern, text)
            if matches:
                results[key] = matches[0] if isinstance(matches[0], str) else matches[0][1]
        return results

    def generate_doc(self, data, output_path):
        """生成Word文档"""
        word = win32.Dispatch('Word.Application')
        doc = word.Documents.Add()

        # 添加标题
        doc.Content.Text = "会议纪要\n"

        # 添加内容
        for key, value in data.items():
            doc.Content.InsertAfter(f"{key}: {value}\n")

        doc.SaveAs(output_path)
        doc.Close()
        word.Quit()

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.generator = MeetingMinuteGenerator()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle('智能会议纪要生成器')
        self.setGeometry(100, 100, 600, 400)

        layout = QVBoxLayout()

        self.label = QLabel('选择会议录音文件:')
        layout.addWidget(self.label)

        self.btn_load = QPushButton('加载音频')
        self.btn_load.clicked.connect(self.load_audio)
        layout.addWidget(self.btn_load)

        self.btn_generate = QPushButton('生成纪要')
        self.btn_generate.clicked.connect(self.generate_minutes)
        layout.addWidget(self.btn_generate)

        self.text_output = QTextEdit()
        self.text_output.setReadOnly(True)
        layout.addWidget(self.text_output)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

    def load_audio(self):
        """加载音频文件"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, '选择会议录音', '', '音频文件 (*.wav *.mp3)')
        if file_path:
            self.audio_path = file_path
            self.text_output.append(f"已加载音频文件: {file_path}")

    def generate_minutes(self):
        """生成会议纪要"""
        if not hasattr(self, 'audio_path'):
            self.text_output.append("请先加载音频文件")
            return

        try:
            # 语音转文字
            text = self.generator.transcribe_audio(self.audio_path)
            self.text_output.append("\n=== 识别结果 ===\n")
            self.text_output.append(text)

            # 提取关键信息
            info = self.generator.extract_info(text)
            self.text_output.append("\n=== 关键信息 ===\n")
            for key, value in info.items():
                self.text_output.append(f"{key}: {value}")

            # 生成文档
            output_path = f"会议纪要_{datetime.now().strftime('%Y%m%d')}.docx"
            self.generator.generate_doc(info, output_path)
            self.text_output.append(f"\n纪要已保存到: {output_path}")

        except Exception as e:
            self.text_output.append(f"错误: {str(e)}")

if __name__ == '__main__':
    pythoncom.CoInitialize()
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

关键实现解析

  1. 语音识别模块
# 初始化Vosk模型
model = Model("vosk-model-small-zh-cn-0.22")
recognizer = KaldiRecognizer(model, 16000)

# 音频转文字
while True:
    data = f.read(4000)
    if recognizer.AcceptWaveform(data):
        result = recognizer.Result()
  1. 信息提取引擎
rules = {
    'resolution': r'(决定|决议|确定)(.*?)(。|\n|$)',
    'responsible': r'由(.*?)负责',
    'deadline': r'(\d{1,2}月\d{1,2}日|[上下]季度)'
}

def extract_info(text):
    return {k: re.findall(v, text)[0] for k,v in rules.items() 
            if re.findall(v, text)}
  1. 文档生成模块
def generate_doc(data, output_path):
    word = win32.Dispatch('Word.Application')
    doc = word.Documents.Add()
    doc.Content.Text = "会议纪要\n\n"
    for key, value in data.items():
        doc.Content.InsertAfter(f"{key}: {value}\n")
    doc.SaveAs(output_path)

效果演示

输入示例:

音频文件:meeting_20251215.wav
内容:"经讨论决定下季度销售目标定为200万,由张三负责,1月15日前提交方案"

输出结果:

=== 识别结果 ===
经讨论决定下季度销售目标定为200万,由张三负责,1月15日前提交方案

=== 关键信息 ===
resolution: 下季度销售目标定为200万
responsible: 张三
deadline: 1月15日

纪要已保存到: 会议纪要_20251215.docx

扩展建议

  1. 多语言支持
# 加载不同语言模型
models = {
    'zh': Model("vosk-model-small-zh-cn"),
    'en': Model("vosk-model-small-en-us")
}
  1. 实时录音功能
import pyaudio
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paInt16, channels=1, 
               rate=16000, input=True, frames_per_buffer=8000)
  1. 导出格式扩展
def export_markdown(data, path):
    with open(path, 'w', encoding='utf-8') as f:
        f.write("## 会议纪要\n\n")
        f.write(f"- 决议事项: {data['resolution']}\n")
        f.write(f"- 负责人: {data['responsible']}\n")
        f.write(f"- 截止时间: {data['deadline']}\n")

总结

本项目实现了一个完整的智能会议纪要生成系统,具有以下特点:
1. 离线语音识别保障隐私安全
2. 轻量级规则引擎实现关键信息提取
3. 自动化文档生成
4. 友好的GUI界面

开发过程中需要注意:
– Vosk模型需要提前下载对应语言包
– Word操作依赖本地安装的Office软件
– 正则表达式规则需要根据实际场景调整

完整代码已托管在GitHub:https://github.com/example/meeting-minutes-g


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注