File size: 11,118 Bytes
bbbd911
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
"""
modelos_loader.py

Módulo para carregar conteúdo de metodologia e anexos dos modelos de avaliação.
Extrai o conteúdo estruturado dos documentos para reconstrução com formatação padrão.
"""

import os
from docx import Document
from docx.shared import Pt, Inches
from typing import Optional, List, Dict, Any, Tuple

# Diretório base dos modelos (relativo ao script principal)
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
MODELOS_DIR = os.path.join(SCRIPT_DIR, "modelos")


def modelo_tem_arquivos(nome_modelo: str) -> bool:
    """Verifica se um modelo possui pasta com arquivos de metodologia e anexos."""
    if not nome_modelo or nome_modelo == "Outros":
        return False
    
    pasta_modelo = os.path.join(MODELOS_DIR, nome_modelo)
    if not os.path.isdir(pasta_modelo):
        return False
    
    metodologia_path = os.path.join(pasta_modelo, "METODOLOGIA.docx")
    anexos_path = os.path.join(pasta_modelo, "ANEXOS.docx")
    
    return os.path.exists(metodologia_path) or os.path.exists(anexos_path)


def get_status_modelo(nome_modelo: str) -> str:
    """Retorna uma string descrevendo o status dos arquivos do modelo."""
    if not nome_modelo or nome_modelo == "Outros":
        return "Modelo genérico (sem arquivos específicos)"
    
    pasta_modelo = os.path.join(MODELOS_DIR, nome_modelo)
    if not os.path.isdir(pasta_modelo):
        return "⚠️ Pasta do modelo não encontrada"
    
    metodologia = os.path.exists(os.path.join(pasta_modelo, "METODOLOGIA.docx"))
    anexos = os.path.exists(os.path.join(pasta_modelo, "ANEXOS.docx"))
    
    if metodologia and anexos:
        return "✅ Metodologia e Anexos disponíveis"
    elif metodologia:
        return "✅ Metodologia disponível | ⚠️ Anexos não encontrados"
    elif anexos:
        return "⚠️ Metodologia não encontrada | ✅ Anexos disponíveis"
    else:
        return "⚠️ Nenhum arquivo encontrado para este modelo"


def extrair_texto_tabela(table) -> List[List[Dict]]:
    """
    Extrai o conteúdo de uma tabela como lista de listas.
    Cada célula é um dict com 'texto' e 'cor' (RGB tuple ou None).
    """
    from docx.shared import RGBColor
    
    dados = []
    for row in table.rows:
        linha = []
        for cell in row.cells:
            texto = cell.text.strip()
            cor = None
            
            # Verificar cor do primeiro run com texto
            for p in cell.paragraphs:
                for run in p.runs:
                    if run.text.strip() and run.font.color and run.font.color.rgb:
                        rgb = run.font.color.rgb
                        # Verificar se é vermelho
                        if rgb[0] > 200 and rgb[1] < 100 and rgb[2] < 100:
                            cor = (rgb[0], rgb[1], rgb[2])
                        break
                if cor:
                    break
            
            linha.append({'texto': texto, 'cor': cor})
        dados.append(linha)
    return dados


def extrair_conteudo_documento(filepath: str) -> List[Dict[str, Any]]:
    """
    Extrai o conteúdo estruturado de um documento DOCX.
    
    Retorna uma lista de elementos, cada um com:
    - tipo: 'secao', 'subsecao', 'subsubsecao', 'subsubsubsecao', 'texto', 'variavel', 'tabela', 'vazio', 'imagem', 'anexo_titulo'
    - conteudo: texto ou dados da tabela
    - negrito: bool (para texto)
    - alinhamento: 'left', 'center', 'right', 'justify'
    - cor: tuple RGB ou None (para texto vermelho)
    """
    if not os.path.exists(filepath):
        return []
    
    try:
        doc = Document(filepath)
    except Exception as e:
        print(f"Erro ao carregar {filepath}: {e}")
        return []
    
    elementos = []
    
    # Mapeamento de estilos para tipos
    mapa_estilos = {
        'LA_X': 'secao',           # Seção principal (ex: 4)
        'LA_X.X': 'subsecao',      # Subseção (ex: 3.2)
        'LA_X.X.X': 'subsubsecao', # Sub-subseção (ex: 3.2.1)
        'LA_X.X.X.X': 'subsubsubsecao',  # Sub-sub-subseção (ex: 3.2.1.1)
        'LA_txt': 'texto',
        'LA_Vars': 'variavel',
        'LA_lb': 'vazio',
        'LA_ANEX': 'anexo_titulo',  # Título de anexo
        'Item N.': 'subtitulo_centralizado',  # Subtítulo centralizado
    }
    
    # Mapeamento de alinhamento
    from docx.enum.text import WD_ALIGN_PARAGRAPH
    from docx.shared import RGBColor
    
    def get_alinhamento(p):
        if p.alignment == WD_ALIGN_PARAGRAPH.CENTER:
            return 'center'
        elif p.alignment == WD_ALIGN_PARAGRAPH.RIGHT:
            return 'right'
        elif p.alignment == WD_ALIGN_PARAGRAPH.JUSTIFY:
            return 'justify'
        return 'left'
    
    def get_cor_predominante(p):
        """Retorna a cor predominante do parágrafo (se for vermelho)."""
        for run in p.runs:
            if run.font.color and run.font.color.rgb:
                cor = run.font.color.rgb
                # Verificar se é vermelho (vários tons)
                r, g, b = cor[0], cor[1], cor[2]
                if r > 200 and g < 100 and b < 100:  # É vermelho
                    return (r, g, b)
        return None
    
    # Criar um iterador que intercala parágrafos e tabelas na ordem do documento
    body = doc.element.body
    
    tabela_idx = 0
    para_idx = 0
    
    for elemento in body:
        tag = elemento.tag.split('}')[-1] if '}' in elemento.tag else elemento.tag
        
        if tag == 'p':
            # É um parágrafo
            if para_idx < len(doc.paragraphs):
                p = doc.paragraphs[para_idx]
                para_idx += 1
                
                estilo = p.style.name if p.style else 'Normal'
                texto = p.text.strip()
                alinhamento = get_alinhamento(p)
                cor = get_cor_predominante(p)
                
                # Verificar se tem negrito nos runs
                tem_negrito = any(run.bold for run in p.runs if run.text.strip())
                
                # Verificar se o parágrafo contém imagem
                tem_imagem = False
                imagem_data = None
                
                # Procurar por drawing/blip no XML do parágrafo
                drawings = elemento.findall('.//{http://schemas.openxmlformats.org/wordprocessingml/2006/main}drawing')
                if drawings:
                    tem_imagem = True
                    # Guardar referência ao elemento XML para copiar depois
                    imagem_data = {
                        'paragraph_element': elemento,
                        'doc': doc
                    }
                
                tipo = mapa_estilos.get(estilo, 'texto')
                
                if tem_imagem:
                    elementos.append({
                        'tipo': 'imagem',
                        'conteudo': texto,
                        'imagem_data': imagem_data,
                        'alinhamento': alinhamento,
                        'estilo_original': estilo,
                        'cor': cor
                    })
                elif not texto:
                    tipo = 'vazio'
                    elementos.append({
                        'tipo': tipo,
                        'conteudo': '',
                        'alinhamento': alinhamento,
                        'estilo_original': estilo,
                        'cor': None
                    })
                else:
                    elementos.append({
                        'tipo': tipo,
                        'conteudo': texto,
                        'negrito': tem_negrito,
                        'alinhamento': alinhamento,
                        'estilo_original': estilo,
                        'cor': cor
                    })
                
        elif tag == 'tbl':
            # É uma tabela
            if tabela_idx < len(doc.tables):
                tabela = doc.tables[tabela_idx]
                tabela_idx += 1
                
                dados_tabela = extrair_texto_tabela(tabela)
                elementos.append({
                    'tipo': 'tabela',
                    'conteudo': dados_tabela,
                    'linhas': len(dados_tabela),
                    'colunas': len(dados_tabela[0]) if dados_tabela else 0
                })
    
    return elementos


def carregar_conteudo_metodologia(nome_modelo: str) -> List[Dict[str, Any]]:
    """Carrega o conteúdo estruturado do arquivo METODOLOGIA.docx."""
    if not nome_modelo or nome_modelo == "Outros":
        return []
    
    filepath = os.path.join(MODELOS_DIR, nome_modelo, "METODOLOGIA.docx")
    return extrair_conteudo_documento(filepath)


def carregar_conteudo_anexos(nome_modelo: str) -> List[Dict[str, Any]]:
    """Carrega o conteúdo estruturado do arquivo ANEXOS.docx."""
    if not nome_modelo or nome_modelo == "Outros":
        return []
    
    filepath = os.path.join(MODELOS_DIR, nome_modelo, "ANEXOS.docx")
    return extrair_conteudo_documento(filepath)


def listar_modelos_com_arquivos() -> list:
    """Lista todos os modelos que possuem arquivos de metodologia/anexos."""
    if not os.path.isdir(MODELOS_DIR):
        return []
    
    modelos = []
    for nome in os.listdir(MODELOS_DIR):
        pasta = os.path.join(MODELOS_DIR, nome)
        if os.path.isdir(pasta):
            metodologia = os.path.exists(os.path.join(pasta, "METODOLOGIA.docx"))
            anexos = os.path.exists(os.path.join(pasta, "ANEXOS.docx"))
            if metodologia or anexos:
                modelos.append({
                    "nome": nome,
                    "tem_metodologia": metodologia,
                    "tem_anexos": anexos
                })
    
    return modelos


# Para teste direto do módulo
if __name__ == "__main__":
    print("=== Teste do Módulo de Carregamento de Modelos ===\n")
    
    modelos = listar_modelos_com_arquivos()
    print(f"Modelos com arquivos: {len(modelos)}")
    
    for modelo in modelos:
        print(f"\n--- {modelo['nome']} ---")
        print(f"  Status: {get_status_modelo(modelo['nome'])}")
        
        if modelo['tem_metodologia']:
            elementos = carregar_conteudo_metodologia(modelo['nome'])
            print(f"\n  Elementos extraídos da metodologia: {len(elementos)}")
            
            # Contar por tipo
            tipos = {}
            for elem in elementos:
                t = elem['tipo']
                tipos[t] = tipos.get(t, 0) + 1
            
            print(f"  Por tipo: {tipos}")
            
            # Mostrar estrutura de títulos
            print("\n  Estrutura de títulos:")
            for elem in elementos:
                if elem['tipo'] in ['secao', 'subsecao', 'subsubsecao', 'subsubsubsecao']:
                    indent = {'secao': '', 'subsecao': '  ', 'subsubsecao': '    ', 'subsubsubsecao': '      '}
                    print(f"    {indent[elem['tipo']]}{elem['tipo'].upper()}: {elem['conteudo'][:50]}...")
                elif elem['tipo'] == 'tabela':
                    print(f"    TABELA: {elem['linhas']}x{elem['colunas']}")