File size: 4,089 Bytes
afd56bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import logging
from typing import Dict, List
from datetime import datetime

try:
    from core.sensitive_data_guard import anonymizer
except ImportError:
    try:
        from backend.core.sensitive_data_guard import anonymizer
    except ImportError:
        anonymizer = None

logger = logging.getLogger(__name__)


class DocumentBuilder:
    """
    Formatyzer sk\u0142adaj\u0105cy cz\u0119\u015bci dokumentu z GeneratorAgent
    w sp\u00f3jny format Markdown gotowy do eksportu docx/pdf.
    Przywraca PII stosuj\u0105c Deanonimizator.
    """

    @staticmethod
    def build_markdown(
        sections_plan: List[Dict[str, str] | str],
        generated_sections: Dict[str, str],
        document_type: str,
        project_title: str = "",
        company_name: str = "",
        traceability_data: Dict[str, List[dict]] = None,
    ) -> str:
        """
        Scala sekcje wed\u0142ug ich oryginalnej kolejno\u015bci ze stanu
        i tworzy reprezentacj\u0119 Markdown.
        """
        logger.info(f"Scalanie dokumentu: {document_type}")

        title = project_title or document_type
        md_lines = [f"# {title}", ""]

        if company_name:
            md_lines += [f"**Wnioskodawca:** {company_name}", ""]

        md_lines += [
            f"**Typ dokumentu:** {document_type}",
            f"**Data wygenerowania:** {datetime.now().strftime('%d.%m.%Y %H:%M')}",
            "",
            "---",
            "",
        ]

        for section_def in sections_plan:
            section = (
                section_def["title"] if isinstance(section_def, dict) else section_def
            )
            content = generated_sections.get(
                section, "*(Sekcja nie zosta艂a wygenerowana)*"
            )
            md_lines.append(f"## {section}")
            md_lines.append(content)
            md_lines.append("")  # odst臋p

        # Za艂膮cznik: 殴r贸d艂a i dokumenty (Traceability)
        if traceability_data:
            md_lines.append("## Za艂膮cznik: 殴r贸d艂a i dokumenty")
            md_lines.append("Poni偶ej znajduje si臋 lista dokument贸w (regulamin贸w, wytycznych), na podstawie kt贸rych sztuczna inteligencja wygenerowa艂a poszczeg贸lne sekcje. Ka偶dy dokument posiada unikalny skr贸t (Hash SHA-256) chroni膮cy przed niezauwa偶alnymi zmianami w przysz艂o艣ci.")
            md_lines.append("")
            
            for sec_name, traces in traceability_data.items():
                if traces:
                    md_lines.append(f"### Sekcja: {sec_name}")
                    for t in traces:
                        md_lines.append(f"- **殴r贸d艂o:** {t.get('source', 'Brak')}")
                        ver_str = t.get('version_id')
                        vf_str = t.get('valid_from')
                        vt_str = t.get('valid_to')
                        if ver_str or vf_str or vt_str:
                            md_lines.append(f"  - **Wersja dokumentu:** {ver_str or 'Nieznana'} (Obowi膮zuje od {vf_str or '-'} do {vt_str or '-'})")
                        md_lines.append(f"  - **Link:** {t.get('url', 'Brak')}")
                        md_lines.append(f"  - **Data pozyskania:** {t.get('date', 'Brak')}")
                        md_lines.append(f"  - **Hash (SHA-256):** `{t.get('hash', 'Brak')}`")
                    md_lines.append("")

        # Stopka AI
        md_lines += [
            "---",
            "",
            "cz\u0119\u015bciowo przy u\u017cyciu modeli j\u0119zykowych (AI). Tre\u015b\u0107 powinna zosta\u0107 "
            "zweryfikowana przez uprawnionego doradc\u0119 przed z\u0142o\u017ceniem wniosku. "
            "Wydawca nie ponosi odpowiedzialno\u015bci za b\u0142\u0119dy merytoryczne wygenerowanego tekstu.",
            "",
        ]

        full_text = "\n".join(md_lines)

        # Deanonimizacja PII (NIP, know-how, etc.)
        if anonymizer:
            try:
                full_text = anonymizer.deanonymize_text(full_text)
            except Exception as e:
                logger.warning(f"Deanonimizacja nie powiod\u0142a si\u0119: {e}")

        return full_text