This commit is contained in:
2026-02-01 17:01:21 +03:00
commit 9575eaf8ee
144 changed files with 24025 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
# Мерж анализа и тегов (шаг 5)
Объединение выхода 2b (финальная валидация согласованности) и выхода 4 (валидация тегов) в один JSON. Этапы 2b и 4 разнесены по времени; шаг 5 выполняется после того, как оба результата готовы.
## Вход
| Источник | Файл | Содержимое |
|----------|------|------------|
| 2b | merge.json | framework, insights, application, limitations |
| 4 | выход_valid_tag.json | tags по категориям, removed |
| 1 (опционально) | вход_главы.json | book_id, chapter_id, chapter_number, chapter_title, book_title, author — для шага 7 |
## Выход
Один JSON: все поля анализа + `tags`, `removed`. Если задан `--input-chapter`, в выход добавляются метаданные главы/книги (book_id, chapter_id, chapter_number, chapter_title, book_title, author). Этот документ передаётся в шаг 6 (генерация эмбеддингов) и в шаг 7 (payload Qdrant).
## Использование
```bash
python3 merge_analysis_tags.py <merge.json> <выход_valid_tag.json> [--input-chapter вход_главы.json] [-o выход.json]
```
Пример (с метаданными для шага 7):
```bash
python3 merge_analysis_tags.py ../2b_финальная_валидация_согласованности/merge.json ../4_валидация_тегов/выход_valid_tag.json --input-chapter ../1_анализ_главы/вход_главы.example.json -o merged_with_tags.json
```
Без `-o` результат выводится в stdout.

View File

@@ -0,0 +1,127 @@
#!/usr/bin/env python3
"""
Этап 5: мерж валидированного анализа главы (2b) и валидированных тегов (4).
Вход:
- merge.json (2b): framework, insights, application, limitations
- выход_valid_tag.json (4): tags по категориям, removed
Выход: один JSON с анализом и тегами для передачи в шаг 6 (генерация эмбеддингов).
"""
import argparse
import json
import sys
from pathlib import Path
from typing import Any
def load_json(path: Path) -> Any:
"""Загружает JSON из файла."""
with open(path, encoding="utf-8") as f:
return json.load(f)
CHAPTER_META_KEYS = ("book_id", "chapter_id", "chapter_number", "chapter_title", "book_title", "author", "chapter_text")
def merge_analysis_and_tags(
analysis: dict[str, Any],
tags_doc: dict[str, Any],
input_chapter: dict[str, Any] | None = None,
) -> dict[str, Any]:
"""
Объединяет анализ главы и валидированные теги в один документ.
Args:
analysis: Результат 2b (framework, insights, application, limitations).
tags_doc: Результат 4 (tags по категориям, removed).
input_chapter: Опционально — вход этапа 1 (book_id, chapter_id, chapter_number, chapter_title, book_title, author).
Returns:
Документ с полями анализа, tags, removed и при наличии — метаданными главы/книги.
"""
result = dict(analysis)
result["tags"] = tags_doc.get("tags", {})
result["removed"] = tags_doc.get("removed", [])
if input_chapter:
for key in CHAPTER_META_KEYS:
if key in input_chapter and input_chapter[key] is not None:
result[key] = input_chapter[key]
return result
def main() -> int:
"""Точка входа CLI."""
parser = argparse.ArgumentParser(
description="Мерж валидированного анализа (2b) и валидированных тегов (4) в один JSON (этап 5).",
)
parser.add_argument(
"analysis",
type=Path,
help="Путь к merge.json (выход 2b).",
)
parser.add_argument(
"tags",
type=Path,
help="Путь к выход_valid_tag.json (выход 4).",
)
parser.add_argument(
"--input-chapter",
type=Path,
default=None,
help="Путь к входному JSON этапа 1 (вход_главы) — book_id, chapter_id, chapter_number, chapter_title, book_title, author, chapter_text. Если задан, эти поля попадают в выход для шагов 7 и 8.",
)
parser.add_argument(
"-o",
"--output",
type=Path,
default=None,
help="Путь к выходному JSON. По умолчанию — stdout.",
)
parser.add_argument(
"--indent",
type=int,
default=2,
help="Отступ для форматирования JSON (по умолчанию 2).",
)
args = parser.parse_args()
if not args.analysis.exists():
print(f"Ошибка: файл не найден: {args.analysis}", file=sys.stderr)
return 1
if not args.tags.exists():
print(f"Ошибка: файл не найден: {args.tags}", file=sys.stderr)
return 1
try:
analysis = load_json(args.analysis)
tags_doc = load_json(args.tags)
except json.JSONDecodeError as e:
print(f"Ошибка разбора JSON: {e}", file=sys.stderr)
return 1
input_chapter = None
if args.input_chapter is not None:
if not args.input_chapter.exists():
print(f"Ошибка: файл не найден: {args.input_chapter}", file=sys.stderr)
return 1
try:
input_chapter = load_json(args.input_chapter)
except json.JSONDecodeError as e:
print(f"Ошибка разбора input-chapter JSON: {e}", file=sys.stderr)
return 1
merged = merge_analysis_and_tags(analysis, tags_doc, input_chapter)
payload = json.dumps(merged, ensure_ascii=False, indent=args.indent)
if args.output is None:
print(payload)
else:
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(payload, encoding="utf-8")
return 0
if __name__ == "__main__":
sys.exit(main())

File diff suppressed because one or more lines are too long