Spaces:
Running
Running
Create new_app.py
Browse files- new_app.py +200 -0
new_app.py
ADDED
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from docling.document_converter import DocumentConverter
|
3 |
+
import google.generativeai as genai
|
4 |
+
import re
|
5 |
+
import os
|
6 |
+
import logging
|
7 |
+
import json
|
8 |
+
from typing import Dict, List, Tuple
|
9 |
+
from datetime import datetime
|
10 |
+
from transformers import AutoModelForTokenClassification, AutoTokenizer
|
11 |
+
import torch
|
12 |
+
import spacy
|
13 |
+
|
14 |
+
# Configuração de logging
|
15 |
+
logging.basicConfig(
|
16 |
+
level=logging.INFO,
|
17 |
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
18 |
+
handlers=[
|
19 |
+
logging.FileHandler(f'contract_analyzer_{datetime.now().strftime("%Y%m%d")}.log'),
|
20 |
+
logging.StreamHandler()
|
21 |
+
]
|
22 |
+
)
|
23 |
+
logger = logging.getLogger(__name__)
|
24 |
+
|
25 |
+
# Configuração da API do Gemini
|
26 |
+
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
|
27 |
+
if not GOOGLE_API_KEY:
|
28 |
+
logger.error("GOOGLE_API_KEY não encontrada nas variáveis de ambiente")
|
29 |
+
raise ValueError("GOOGLE_API_KEY não configurada")
|
30 |
+
|
31 |
+
genai.configure(api_key=GOOGLE_API_KEY)
|
32 |
+
logger.info("API Gemini configurada com sucesso")
|
33 |
+
|
34 |
+
# Carregar o modelo NER e tokenizador
|
35 |
+
model_name = "dominguesm/ner-legal-bert-base-cased-ptbr"
|
36 |
+
logger.info(f"Carregando o modelo NER: {model_name}")
|
37 |
+
ner_model = AutoModelForTokenClassification.from_pretrained(model_name)
|
38 |
+
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
39 |
+
logger.info("Modelo NER e tokenizador carregados com sucesso")
|
40 |
+
|
41 |
+
# Funções do App 1 (Gemini)
|
42 |
+
def extract_json_from_response(response_text: str) -> str:
|
43 |
+
json_content = response_text.strip()
|
44 |
+
if json_content.startswith('```'):
|
45 |
+
json_content = json_content.split('\n', 1)[1]
|
46 |
+
if json_content.endswith('```'):
|
47 |
+
json_content = json_content.rsplit('\n', 1)[0]
|
48 |
+
return json_content.strip()
|
49 |
+
|
50 |
+
def extract_legal_representatives_gemini(contract_text: str) -> Dict:
|
51 |
+
logger.info("Iniciando extração de representantes legais com Gemini")
|
52 |
+
try:
|
53 |
+
model = genai.GenerativeModel('gemini-pro')
|
54 |
+
prompt = """
|
55 |
+
Analise o seguinte contrato social e extraia:
|
56 |
+
1. Todos os sócios e seus percentuais de participação
|
57 |
+
2. Todos os administradores mencionados
|
58 |
+
|
59 |
+
Formate a resposta como um dicionário JSON com as seguintes chaves:
|
60 |
+
- "socios": lista de dicionários com "nome" e "participacao"
|
61 |
+
- "administradores": lista de nomes
|
62 |
+
|
63 |
+
Contrato Social:
|
64 |
+
{contract_text}
|
65 |
+
"""
|
66 |
+
|
67 |
+
response = model.generate_content(prompt.format(contract_text=contract_text))
|
68 |
+
json_content = extract_json_from_response(response.text)
|
69 |
+
result = json.loads(json_content)
|
70 |
+
|
71 |
+
return result
|
72 |
+
except Exception as e:
|
73 |
+
logger.error(f"Erro na análise Gemini: {str(e)}")
|
74 |
+
return {
|
75 |
+
"socios": [],
|
76 |
+
"administradores": [],
|
77 |
+
"erro": str(e)
|
78 |
+
}
|
79 |
+
|
80 |
+
# Funções do App 2 (NER)
|
81 |
+
def extract_entities(text: str) -> List[Tuple[str, str]]:
|
82 |
+
logger.debug("Iniciando extração de entidades com NER")
|
83 |
+
inputs = tokenizer(text, max_length=512, truncation=True, return_tensors="pt")
|
84 |
+
tokens = inputs.tokens()
|
85 |
+
|
86 |
+
with torch.no_grad():
|
87 |
+
outputs = ner_model(**inputs).logits
|
88 |
+
predictions = torch.argmax(outputs, dim=2)
|
89 |
+
|
90 |
+
entities = []
|
91 |
+
for token, prediction in zip(tokens, predictions[0].numpy()):
|
92 |
+
entity_label = ner_model.config.id2label[prediction]
|
93 |
+
if entity_label != "O":
|
94 |
+
entities.append((token, entity_label))
|
95 |
+
|
96 |
+
return entities
|
97 |
+
|
98 |
+
def extract_representatives_ner(entities: List[Tuple[str, str]]) -> List[str]:
|
99 |
+
representatives = []
|
100 |
+
current_person = ""
|
101 |
+
current_organization = ""
|
102 |
+
|
103 |
+
for token, label in entities:
|
104 |
+
if label in ["B-PESSOA", "I-PESSOA"]:
|
105 |
+
current_person += token.replace("##", "")
|
106 |
+
else:
|
107 |
+
if current_person:
|
108 |
+
representatives.append(current_person)
|
109 |
+
current_person = ""
|
110 |
+
|
111 |
+
if label in ["B-ORGANIZACAO", "I-ORGANIZACAO"]:
|
112 |
+
current_organization += token.replace("##", "")
|
113 |
+
else:
|
114 |
+
if current_organization:
|
115 |
+
representatives.append(current_organization)
|
116 |
+
current_organization = ""
|
117 |
+
|
118 |
+
if current_person:
|
119 |
+
representatives.append(current_person)
|
120 |
+
if current_organization:
|
121 |
+
representatives.append(current_organization)
|
122 |
+
|
123 |
+
return representatives
|
124 |
+
|
125 |
+
def format_output_gemini(analysis_result: Dict) -> str:
|
126 |
+
output = "ANÁLISE DO CONTRATO SOCIAL (Gemini)\n\n"
|
127 |
+
|
128 |
+
output += "SÓCIOS:\n"
|
129 |
+
for socio in analysis_result.get("socios", []):
|
130 |
+
participacao = socio.get('participacao', 'Não especificada')
|
131 |
+
participacao_str = f"{participacao}%" if participacao is not None else "Participação não especificada"
|
132 |
+
output += f"- {socio['nome']}: {participacao_str}\n"
|
133 |
+
|
134 |
+
output += "\nADMINISTRADORES:\n"
|
135 |
+
for admin in analysis_result.get("administradores", []):
|
136 |
+
output += f"- {admin}\n"
|
137 |
+
|
138 |
+
if "erro" in analysis_result:
|
139 |
+
output += f"\nERRO: {analysis_result['erro']}"
|
140 |
+
|
141 |
+
return output
|
142 |
+
|
143 |
+
def format_output_ner(representatives: List[str]) -> str:
|
144 |
+
output = "ANÁLISE DO CONTRATO SOCIAL (NER)\n\n"
|
145 |
+
output += "REPRESENTANTES IDENTIFICADOS:\n"
|
146 |
+
for rep in representatives:
|
147 |
+
output += f"- {rep}\n"
|
148 |
+
return output
|
149 |
+
|
150 |
+
# Função principal que processa o documento
|
151 |
+
def analyze_contract(file, analysis_type: str):
|
152 |
+
logger.info(f"Iniciando análise do arquivo usando {analysis_type}: {file.name}")
|
153 |
+
|
154 |
+
try:
|
155 |
+
converter = DocumentConverter()
|
156 |
+
result = converter.convert(file.name)
|
157 |
+
document_text = result.document.export_to_text()
|
158 |
+
|
159 |
+
if analysis_type == "Gemini":
|
160 |
+
analysis_result = extract_legal_representatives_gemini(document_text)
|
161 |
+
output = format_output_gemini(analysis_result)
|
162 |
+
else: # NER
|
163 |
+
entities = extract_entities(document_text)
|
164 |
+
representatives = extract_representatives_ner(entities)
|
165 |
+
output = format_output_ner(representatives)
|
166 |
+
|
167 |
+
return document_text, output
|
168 |
+
|
169 |
+
except Exception as e:
|
170 |
+
logger.error(f"Erro durante análise do contrato: {str(e)}")
|
171 |
+
return "", f"Erro ao processar o arquivo: {str(e)}"
|
172 |
+
|
173 |
+
# Criar interface Gradio
|
174 |
+
try:
|
175 |
+
logger.info("Iniciando configuração da interface Gradio")
|
176 |
+
iface = gr.Interface(
|
177 |
+
fn=analyze_contract,
|
178 |
+
inputs=[
|
179 |
+
"file",
|
180 |
+
gr.Radio(
|
181 |
+
choices=["Gemini", "NER"],
|
182 |
+
label="Tipo de Análise",
|
183 |
+
value="Gemini"
|
184 |
+
)
|
185 |
+
],
|
186 |
+
outputs=[
|
187 |
+
gr.Textbox(label="Texto do Contrato"),
|
188 |
+
gr.Textbox(label="Resultado da Análise")
|
189 |
+
],
|
190 |
+
title="Analisador de Contratos Sociais",
|
191 |
+
description="Este aplicativo analisa contratos sociais usando Gemini ou NER para identificar representantes legais.",
|
192 |
+
)
|
193 |
+
logger.info("Interface Gradio configurada com sucesso")
|
194 |
+
except Exception as e:
|
195 |
+
logger.error(f"Erro ao configurar interface Gradio: {str(e)}")
|
196 |
+
raise
|
197 |
+
|
198 |
+
if __name__ == "__main__":
|
199 |
+
logger.info("Iniciando aplicação")
|
200 |
+
iface.launch()
|