Автоматизация протоколирования встреч с AI
Система автоматически транскрибирует записи встреч, определяет участников, выделяет решения и задачи, формирует структурированный протокол. Интегрируется с Zoom, Google Meet, MS Teams, Slack, корпоративными системами управления задачами.
Архитектура пайплайна
Запись встречи (аудио/видео)
↓ VAD + диаризация (pyannote.audio)
↓ Транскрибация (Whisper large-v3)
↓ NLP-обработка (GPT-4o / Claude)
↓ Извлечение: решения / задачи / ответственные / дедлайны
↓ Генерация протокола (Markdown / Notion / Jira)
Транскрибация с диаризацией
import whisper
from pyannote.audio import Pipeline
import torch
class MeetingTranscriber:
def __init__(self):
self.whisper = whisper.load_model("large-v3", device="cuda")
self.diarizer = Pipeline.from_pretrained(
"pyannote/speaker-diarization-3.1",
use_auth_token="HF_TOKEN"
)
def transcribe_with_speakers(self, audio_path: str) -> list[dict]:
# Диаризация
diarization = self.diarizer(audio_path)
segments_by_speaker = [
{"speaker": turn.speaker, "start": turn.start, "end": turn.end}
for turn, _, _ in diarization.itertracks(yield_label=True)
]
# Транскрипция
result = self.whisper.transcribe(audio_path, language="ru", word_timestamps=True)
# Мёржим
transcript = []
for seg in result["segments"]:
speaker = self._find_speaker(seg["start"], segments_by_speaker)
transcript.append({
"speaker": speaker,
"start": seg["start"],
"end": seg["end"],
"text": seg["text"].strip()
})
return transcript
def _find_speaker(self, timestamp: float, diar_segments: list) -> str:
for s in diar_segments:
if s["start"] <= timestamp <= s["end"]:
return s["speaker"]
return "UNKNOWN"
NLP-обработка и извлечение структуры
from openai import AsyncOpenAI
import json
client = AsyncOpenAI()
async def extract_meeting_structure(transcript: list[dict]) -> dict:
# Форматируем транскрипт
formatted = "\n".join([
f"[{seg['speaker']} | {int(seg['start']//60):02d}:{int(seg['start']%60):02d}] {seg['text']}"
for seg in transcript
])
response = await client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "system",
"content": """Ты — ассистент для протоколирования встреч.
Проанализируй транскрипт и верни JSON:
{
"summary": "краткое резюме 2-3 предложения",
"participants": ["SPEAKER_00 = Иван Петров", ...],
"agenda_items": [{"topic": "...", "discussion": "..."}],
"decisions": [{"decision": "...", "context": "..."}],
"action_items": [{"task": "...", "owner": "...", "deadline": "..."}],
"next_meeting": "дата/условие следующей встречи если обсуждалась"
}"""
}, {
"role": "user",
"content": f"Транскрипт встречи:\n\n{formatted[:8000]}"
}],
response_format={"type": "json_object"}
)
return json.loads(response.choices[0].message.content)
Генерация протокола
def format_meeting_minutes(structure: dict, transcript: list[dict]) -> str:
date = datetime.now().strftime("%d.%m.%Y")
duration_min = int(transcript[-1]["end"] / 60) if transcript else 0
md = f"""## Протокол встречи от {date}
**Продолжительность:** {duration_min} минут
**Участники:** {", ".join(structure.get("participants", []))}
### Краткое резюме
{structure.get("summary", "")}
### Принятые решения
"""
for d in structure.get("decisions", []):
md += f"- **{d['decision']}**\n _{d.get('context', '')}_\n\n"
md += "### Задачи\n\n"
md += "| Задача | Ответственный | Срок |\n|--------|--------------|------|\n"
for item in structure.get("action_items", []):
md += f"| {item['task']} | {item.get('owner', '—')} | {item.get('deadline', '—')} |\n"
return md
Интеграции
Zoom: через Zoom Recordings API — автоматически получаем mp4/m4a после окончания встречи.
Google Meet: через Google Workspace Events API + Cloud Storage для записей.
MS Teams: через Microsoft Graph API /communications/callRecords.
@app.post("/webhook/zoom/recording")
async def zoom_recording_webhook(payload: dict):
if payload["event"] == "recording.completed":
recording_url = payload["payload"]["object"]["recording_files"][0]["download_url"]
meeting_id = payload["payload"]["object"]["uuid"]
asyncio.create_task(process_meeting_recording(meeting_id, recording_url))
return {"status": "ok"}
Экспорт
class MinutesExporter:
async def to_notion(self, minutes: str, database_id: str): ...
async def to_confluence(self, minutes: str, space_key: str): ...
async def to_jira_tasks(self, action_items: list, project_key: str): ...
async def to_slack(self, summary: str, channel_id: str): ...
async def to_email(self, minutes: str, recipients: list[str]): ...
Сроки: базовый пайплайн (транскрипция + NLP + Markdown) — 1–2 недели. Полноценная система с интеграциями Zoom/Teams/Notion/Jira — 4–6 недель.







