transcription/src/rag/formatter.py
keboss-m fee9b9acb1 Add RAG, summary pipeline, and split transcribe/postprocess queue.
Separate ASR (2 workers) from summary/RAG post-processing, add LightRAG chat API, batch upload fixes, and local model mounts for Docker deployment.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-01 17:40:58 +03:00

146 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Форматирование документа совещания для индексации в LightRAG."""
import json
from datetime import datetime
from typing import Any, Dict, List
from src.document import format_time
def format_meeting_document(
segments: List[Dict[str, Any]],
metadata: Dict[str, Any],
source_filename: str,
) -> str:
"""Собирает текстовый документ для вставки в LightRAG.
Сохраняет полную расшифровку + метаданные + извлечённые сущности.
"""
lines = []
lines.append("=== СОВЕЩАНИЕ ===")
lines.append(f"ID: {metadata.get('project', 'unknown')}_{datetime.now().strftime('%Y%m%d_%H%M%S')}")
lines.append(f"Проект: {metadata.get('project', 'unknown')}")
lines.append(f"Раздел: {metadata.get('section', 'Общие вопросы')}")
lines.append(f"Тема: {metadata.get('topic', 'Не определена')}")
lines.append(f"Дата: {metadata.get('date', 'Не указана')}")
lines.append(f"Источник: {source_filename}")
participants = metadata.get("participants", [])
if participants:
lines.append(f"Участники: {', '.join(participants)}")
else:
# fallback — извлечь уникальных спикеров из сегментов
speakers = sorted({seg.get("speaker", "UNKNOWN") for seg in segments})
lines.append(f"Участники: {', '.join(speakers)}")
lines.append("")
lines.append("--- Метаданные ---")
summary = metadata.get("summary", "")
if summary:
lines.append(f"Summary: {summary}")
decisions = metadata.get("key_decisions", [])
if decisions:
lines.append("Решения:")
for i, d in enumerate(decisions, 1):
lines.append(f" {i}. {d}")
actions = metadata.get("action_items", [])
if actions:
lines.append("Action items:")
for a in actions:
who = a.get("who", "?")
what = a.get("what", "")
deadline = a.get("deadline", "")
dl = f" (до {deadline})" if deadline else ""
lines.append(f" - {who}: {what}{dl}")
lines.append("")
lines.append("--- Полная расшифровка ---")
for seg in segments:
ts = format_time(seg.get("start", 0.0))
speaker = seg.get("speaker", "UNKNOWN")
text = seg.get("text", "").strip()
if text:
lines.append(f"[{ts}] {speaker}: {text}")
return "\n".join(lines)
def format_summary_markdown(
metadata: Dict[str, Any],
brief: str,
source_filename: str,
) -> str:
"""Формирует markdown-файл краткого содержания совещания."""
lines = [
"# Краткое содержание совещания",
"",
f"**Проект:** {metadata.get('project', '')} ",
f"**Раздел:** {metadata.get('section', '')} ",
f"**Тема:** {metadata.get('topic', '')} ",
f"**Дата:** {metadata.get('date') or ''} ",
f"**Источник:** {source_filename}",
"",
]
participants = metadata.get("participants") or []
if participants:
lines.append(f"**Участники:** {', '.join(participants)}")
lines.append("")
lines.extend(["## Суть", "", brief.strip(), ""])
problems = metadata.get("problems") or []
if problems:
lines.append("## Ключевые вопросы и проблемы")
lines.append("")
for item in problems:
lines.append(f"- {item}")
lines.append("")
decisions = metadata.get("key_decisions") or []
if decisions:
lines.append("## Принятые решения")
lines.append("")
for item in decisions:
lines.append(f"- {item}")
lines.append("")
actions = metadata.get("action_items") or []
if actions:
lines.append("## Поручения")
lines.append("")
for action in actions:
who = action.get("who", "?")
what = action.get("what", "")
deadline = action.get("deadline")
dl = f" (до {deadline})" if deadline else ""
lines.append(f"- **{who}:** {what}{dl}")
lines.append("")
return "\n".join(lines).strip() + "\n"
def format_global_document(doc_text: str, metadata: Dict[str, Any]) -> str:
"""Формирует версию документа для глобального (межпроектного) индекса.
Добавляет явное указание проекта в начало, чтобы глобальный граф знал связь.
"""
header = f"""=== СОВЕЩАНИЕ (Проект: {metadata.get('project', 'unknown')}) ===
Раздел: {metadata.get('section', 'Общие вопросы')}
Тема: {metadata.get('topic', 'Не определена')}
"""
return header + "\n" + doc_text
def build_meeting_text_only(segments: List[Dict[str, Any]]) -> str:
"""Собирает plain text из сегментов (для отправки в classify_meeting)."""
lines = []
for seg in segments:
speaker = seg.get("speaker", "UNKNOWN")
text = seg.get("text", "").strip()
if text:
lines.append(f"{speaker}: {text}")
return "\n".join(lines)