"""AgroStar PDF (печатная форма анализа) → AgrostarParseResult.""" from __future__ import annotations import re from typing import Any from app.lab.etl.agrostar_tabular import ( parse_tabular_triplet_lines, rows_to_label_values, sample_from_agro_fields, tabular_rows_to_agro_fields, ) from app.lab.etl.agrostar_xml_import import AgrostarParseResult def _pdf_text(data: bytes) -> str: try: import fitz # pymupdf except ImportError as exc: raise RuntimeError("Для PDF нужен pymupdf (pip install pymupdf)") from exc doc = fitz.open(stream=data, filetype="pdf") parts = [doc[i].get_text() for i in range(doc.page_count)] doc.close() return "\n".join(parts) def _line_after(lines: list[str], marker: str) -> str: for i, line in enumerate(lines): if line == marker and i + 1 < len(lines): return lines[i + 1] return "" def _is_agrostar_pdf(text: str) -> bool: t = text or "" return "ИНФОРМАЦИЯ ОБ ОБРАЗЦЕ" in t or "РЕЗУЛЬТАТЫ АНАЛИЗА" in t def parse_agrostar_pdf(data: bytes) -> AgrostarParseResult: result = AgrostarParseResult(lab_name="АгроСтар") try: text = _pdf_text(data) except RuntimeError as exc: result.errors.append(str(exc)) return result if not _is_agrostar_pdf(text): result.errors.append("Не похоже на отчёт AgroStar (PDF)") return result lines = [ln.strip() for ln in text.splitlines() if ln.strip()] sample_no = _line_after(lines, "Образец №") farm_name = _line_after(lines, "Клиент") date_printed = _line_after(lines, "Дата анализа") desc = _line_after(lines, "Описание") label_parts: list[str] = [] if "Образец" in lines: idx = lines.index("Образец") if idx + 1 < len(lines) and lines[idx + 1] != "Описание": label_parts.append(lines[idx + 1]) if idx + 2 < len(lines) and lines[idx + 2] not in ("Описание", "Клиент"): label_parts.append(lines[idx + 2]) triplets = parse_tabular_triplet_lines(lines) agro_fields = tabular_rows_to_agro_fields(rows_to_label_values(triplets)) if not agro_fields: result.errors.append("В PDF не найдены показатели анализа") return result sample = sample_from_agro_fields( sample_no=sample_no, farm_name=farm_name, date_printed=date_printed, desc_1=desc or " ".join(label_parts), agro_fields=agro_fields, ) result.samples.append(sample) return result def looks_like_agrostar_pdf(data: bytes) -> bool: try: text = _pdf_text(data) except RuntimeError: return False return _is_agrostar_pdf(text)