File size: 6,320 Bytes
780413d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
"""
Formatador de saída JSON.

Este módulo contém funções e classes para formatar documentos
processados em formato JSON estruturado.
"""

import json
from datetime import datetime
from pathlib import Path
from typing import Any

from utils.logger import get_logger

# Logger para este módulo
logger = get_logger(__name__)


def format_to_json(
    processed_data: dict[str, Any],
    filename: str,
    include_raw_content: bool = True,
    pretty_print: bool = True
) -> str:
    """
    Formata dados processados em JSON estruturado.

    Args:
        processed_data: Dados retornados pelo DoclingProcessor.
        filename: Nome do arquivo original.
        include_raw_content: Se deve incluir conteúdo completo.
        pretty_print: Se deve formatar com indentação.

    Returns:
        String JSON formatada.
    """
    document = processed_data.get("document")
    metadata = processed_data.get("metadata", {})
    tables = processed_data.get("tables", [])
    language = processed_data.get("language", "desconhecido")

    # Estrutura de saída
    output = {
        "arquivo": filename,
        "idioma": language,
        "processado_em": datetime.now().isoformat(),
        "metadados": metadata,
        "tabelas": tables,
    }

    # Adiciona conteúdo
    if include_raw_content and document:
        try:
            # Tenta exportar para dict
            if hasattr(document, "export_to_dict"):
                output["conteudo"] = document.export_to_dict()
            elif hasattr(document, "export_to_markdown"):
                output["conteudo_markdown"] = document.export_to_markdown()
            elif hasattr(document, "export_to_text"):
                output["conteudo_texto"] = document.export_to_text()
        except Exception as e:
            logger.warning(f"Erro ao exportar conteúdo: {e}")
            output["conteudo"] = None
            output["erro_exportacao"] = str(e)

    # Adiciona tempo de processamento se disponível
    if "processing_time_seconds" in processed_data:
        output["tempo_processamento_segundos"] = processed_data["processing_time_seconds"]

    # Serializa para JSON
    indent = 2 if pretty_print else None

    try:
        return json.dumps(
            output,
            ensure_ascii=False,
            indent=indent,
            default=_json_serializer
        )
    except Exception as e:
        logger.error(f"Erro ao serializar JSON: {e}")
        # Fallback: tenta sem conteúdo complexo
        output.pop("conteudo", None)
        output["erro_serializacao"] = str(e)
        return json.dumps(output, ensure_ascii=False, indent=indent)


def _json_serializer(obj: Any) -> Any:
    """
    Serializador customizado para objetos não-JSON.

    Args:
        obj: Objeto a serializar.

    Returns:
        Representação serializável do objeto.
    """
    if hasattr(obj, "isoformat"):
        return obj.isoformat()
    if hasattr(obj, "__dict__"):
        return obj.__dict__
    if isinstance(obj, bytes):
        return obj.decode("utf-8", errors="replace")
    if isinstance(obj, set):
        return list(obj)
    if isinstance(obj, Path):
        return str(obj)

    return str(obj)


class JSONFormatter:
    """
    Classe para formatação JSON com configurações personalizadas.

    Permite manter configurações consistentes entre múltiplas formatações.
    """

    def __init__(
        self,
        include_raw_content: bool = True,
        pretty_print: bool = True,
        include_tables: bool = True,
        include_metadata: bool = True
    ):
        """
        Inicializa o formatador JSON.

        Args:
            include_raw_content: Se deve incluir conteúdo completo.
            pretty_print: Se deve formatar com indentação.
            include_tables: Se deve incluir tabelas extraídas.
            include_metadata: Se deve incluir metadados.
        """
        self.include_raw_content = include_raw_content
        self.pretty_print = pretty_print
        self.include_tables = include_tables
        self.include_metadata = include_metadata

    def format(
        self,
        processed_data: dict[str, Any],
        filename: str
    ) -> str:
        """
        Formata dados processados em JSON.

        Args:
            processed_data: Dados do DoclingProcessor.
            filename: Nome do arquivo original.

        Returns:
            String JSON formatada.
        """
        # Copia para não modificar original
        data = processed_data.copy()

        # Remove elementos não desejados
        if not self.include_tables:
            data["tables"] = []

        if not self.include_metadata:
            data["metadata"] = {}

        return format_to_json(
            data,
            filename,
            include_raw_content=self.include_raw_content,
            pretty_print=self.pretty_print
        )

    def format_batch(
        self,
        items: list[tuple[dict[str, Any], str]]
    ) -> str:
        """
        Formata múltiplos documentos em um único JSON.

        Args:
            items: Lista de tuplas (processed_data, filename).

        Returns:
            String JSON com array de documentos.
        """
        documents = []

        for processed_data, filename in items:
            # Formata individualmente e converte de volta para dict
            json_str = self.format(processed_data, filename)
            doc = json.loads(json_str)
            documents.append(doc)

        indent = 2 if self.pretty_print else None

        return json.dumps(
            {"documentos": documents, "total": len(documents)},
            ensure_ascii=False,
            indent=indent
        )


def save_json(
    content: str | dict,
    output_path: str | Path,
    encoding: str = "utf-8"
) -> Path:
    """
    Salva conteúdo JSON em arquivo.

    Args:
        content: String JSON ou dicionário.
        output_path: Caminho do arquivo de saída.
        encoding: Encoding do arquivo.

    Returns:
        Path para o arquivo salvo.
    """
    output_path = Path(output_path)

    if isinstance(content, dict):
        content = json.dumps(content, ensure_ascii=False, indent=2)

    output_path.write_text(content, encoding=encoding)
    logger.debug(f"JSON salvo: {output_path}")

    return output_path