Spaces:
Running
Running
Commit
·
6d1db38
1
Parent(s):
f975500
Melhorias no metodo Atomico
Browse files- app.py +119 -69
- config.py +2 -0
- templates/index.html +56 -6
app.py
CHANGED
@@ -46,6 +46,36 @@ def log_print(message):
|
|
46 |
print(f"[DEBUG] {message}", flush=True)
|
47 |
sys.stdout.flush()
|
48 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
# Função para renderização com fallback: tenta MarkdownIt, depois markdown2
|
50 |
def render_markdown_cascata(texto: str) -> str:
|
51 |
try:
|
@@ -97,6 +127,18 @@ def convert():
|
|
97 |
converted_html = render_markdown_cascata(text_to_convert)
|
98 |
return jsonify({'html': converted_html})
|
99 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
@app.route('/process', methods=['POST'])
|
101 |
def process():
|
102 |
"""Processa a solicitação do usuário nos modos Hierárquico ou Atômico."""
|
@@ -127,19 +169,24 @@ def process():
|
|
127 |
if current_mode == 'test':
|
128 |
log_print("=== MODO TESTE EXECUTADO ===")
|
129 |
mock_text = form_data.get('mock_text', 'Este é um **texto** de `simulação`.')
|
130 |
-
|
|
|
131 |
if processing_mode == 'atomic':
|
132 |
-
|
133 |
-
yield f"data: {
|
|
|
|
|
134 |
else:
|
135 |
if not solicitacao_usuario:
|
136 |
log_print("=== ERRO: SOLICITAÇÃO VAZIA ===")
|
137 |
-
|
|
|
138 |
return
|
139 |
|
140 |
try:
|
141 |
log_print("=== INICIANDO PROCESSAMENTO REAL ===")
|
142 |
-
|
|
|
143 |
rag_context = get_relevant_context(file_paths, solicitacao_usuario)
|
144 |
log_print(f"=== RAG CONTEXT OBTIDO: {len(rag_context)} chars ===")
|
145 |
|
@@ -172,7 +219,8 @@ def process():
|
|
172 |
models = {'grok': grok_llm, 'sonnet': claude_atomic_llm, 'gemini': gemini_llm}
|
173 |
|
174 |
prompt = PromptTemplate(template=PROMPT_ATOMICO_INICIAL, input_variables=["solicitacao_usuario", "rag_context"])
|
175 |
-
|
|
|
176 |
|
177 |
for name, llm in models.items():
|
178 |
chain = prompt | llm | output_parser
|
@@ -186,30 +234,37 @@ def process():
|
|
186 |
for key, result in results.items():
|
187 |
if result == "Error:EmptyResponse" or "Erro ao processar" in result:
|
188 |
error_msg = result if "Erro ao processar" in result else f"Falha no serviço {key.upper()}: Sem resposta."
|
189 |
-
|
|
|
190 |
return
|
191 |
|
192 |
-
|
|
|
193 |
|
194 |
# MUDANÇA: Envia o texto bruto para cada modelo
|
195 |
grok_text = results.get('grok', '')
|
196 |
log_print(f"--- Resposta Bruta do GROK (Atômico) ---\n{grok_text[:200]}...\n--------------------------------------")
|
197 |
-
|
|
|
198 |
|
199 |
sonnet_text = results.get('sonnet', '')
|
200 |
log_print(f"--- Resposta Bruta do Sonnet (Atômico) ---\n{sonnet_text[:200]}...\n----------------------------------------")
|
201 |
-
|
|
|
202 |
|
203 |
gemini_text = results.get('gemini', '')
|
204 |
log_print(f"--- Resposta Bruta do Gemini (Atômico) ---\n{gemini_text[:200]}...\n----------------------------------------")
|
205 |
-
|
|
|
206 |
|
207 |
-
|
|
|
208 |
|
209 |
else:
|
210 |
log_print("=== MODO HIERÁRQUICO SELECIONADO ===")
|
211 |
# --- LÓGICA HIERÁRQUICA (SEQUENCIAL) ---
|
212 |
-
|
|
|
213 |
|
214 |
log_print("=== PROCESSANDO GROK ===")
|
215 |
prompt_grok = PromptTemplate(template=PROMPT_HIERARQUICO_GROK, input_variables=["solicitacao_usuario", "rag_context"])
|
@@ -220,11 +275,13 @@ def process():
|
|
220 |
|
221 |
if not resposta_grok or not resposta_grok.strip():
|
222 |
log_print("=== ERRO: GROK VAZIO ===")
|
223 |
-
|
|
|
224 |
return
|
225 |
|
226 |
log_print("=== ENVIANDO RESPOSTA GROK PARA FRONTEND ===")
|
227 |
-
|
|
|
228 |
|
229 |
log_print("=== PROCESSANDO SONNET ===")
|
230 |
prompt_sonnet = PromptTemplate(template=PROMPT_HIERARQUICO_SONNET, input_variables=["solicitacao_usuario", "texto_para_analise"])
|
@@ -236,52 +293,13 @@ def process():
|
|
236 |
|
237 |
if not resposta_sonnet or not resposta_sonnet.strip():
|
238 |
log_print("=== ERRO: SONNET VAZIO ===")
|
239 |
-
|
|
|
240 |
return
|
241 |
|
242 |
-
log_print("===
|
243 |
-
|
244 |
-
|
245 |
-
try:
|
246 |
-
# Primeiro, vamos testar criar o JSON sem enviar
|
247 |
-
test_data = {
|
248 |
-
'progress': 66,
|
249 |
-
'message': 'Gemini está processando...',
|
250 |
-
'partial_result': {
|
251 |
-
'id': 'sonnet-output',
|
252 |
-
'content': resposta_sonnet
|
253 |
-
}
|
254 |
-
}
|
255 |
-
test_json = json.dumps(test_data)
|
256 |
-
log_print(f"=== JSON SONNET CRIADO COM SUCESSO: {len(test_json)} chars ===")
|
257 |
-
|
258 |
-
# Agora vamos enviar
|
259 |
-
yield f"data: {test_json}\n\n"
|
260 |
-
log_print("=== JSON SONNET ENVIADO COM SUCESSO ===")
|
261 |
-
|
262 |
-
except Exception as json_error:
|
263 |
-
log_print(f"=== ERRO JSON SONNET: {json_error} ===")
|
264 |
-
log_print(f"=== TIPO DA RESPOSTA SONNET: {type(resposta_sonnet)} ===")
|
265 |
-
log_print(f"=== PRIMEIROS 500 CHARS SONNET: {repr(resposta_sonnet[:500])} ===")
|
266 |
-
|
267 |
-
# Vamos tentar limpar a string
|
268 |
-
try:
|
269 |
-
# Remove caracteres problemáticos
|
270 |
-
cleaned_response = resposta_sonnet.encode('utf-8', errors='ignore').decode('utf-8')
|
271 |
-
fallback_data = {
|
272 |
-
'progress': 66,
|
273 |
-
'message': 'Gemini está processando...',
|
274 |
-
'partial_result': {
|
275 |
-
'id': 'sonnet-output',
|
276 |
-
'content': cleaned_response
|
277 |
-
}
|
278 |
-
}
|
279 |
-
yield f"data: {json.dumps(fallback_data)}\n\n"
|
280 |
-
log_print("=== FALLBACK SONNET ENVIADO ===")
|
281 |
-
except Exception as fallback_error:
|
282 |
-
log_print(f"=== FALLBACK TAMBÉM FALHOU: {fallback_error} ===")
|
283 |
-
yield f"data: {json.dumps({'error': f'Erro ao processar resposta do Sonnet: {str(json_error)}'})}\n\n"
|
284 |
-
return
|
285 |
|
286 |
log_print("=== PROCESSANDO GEMINI ===")
|
287 |
prompt_gemini = PromptTemplate(template=PROMPT_HIERARQUICO_GEMINI, input_variables=["solicitacao_usuario", "texto_para_analise"])
|
@@ -292,30 +310,40 @@ def process():
|
|
292 |
|
293 |
if not resposta_gemini or not resposta_gemini.strip():
|
294 |
log_print("=== ERRO: GEMINI VAZIO ===")
|
295 |
-
|
|
|
296 |
return
|
297 |
|
298 |
log_print("=== ENVIANDO RESPOSTA GEMINI ===")
|
299 |
-
|
|
|
300 |
log_print("=== PROCESSAMENTO COMPLETO ===")
|
301 |
|
302 |
except Exception as e:
|
303 |
log_print(f"Ocorreu um erro durante o processamento: {e}")
|
304 |
import traceback
|
305 |
log_print(f"Traceback: {traceback.format_exc()}")
|
306 |
-
|
|
|
307 |
|
308 |
return Response(generate_stream(mode, form_data, temp_file_paths), mimetype='text/event-stream')
|
309 |
|
310 |
@app.route('/merge', methods=['POST'])
|
311 |
def merge():
|
312 |
"""Recebe os textos do modo Atômico e os consolida usando um LLM."""
|
|
|
|
|
313 |
data = request.get_json()
|
|
|
314 |
|
315 |
def generate_merge_stream():
|
316 |
"""Gera a resposta do merge em streaming."""
|
|
|
|
|
317 |
try:
|
318 |
-
|
|
|
|
|
319 |
|
320 |
output_parser = StrOutputParser()
|
321 |
prompt_merge = PromptTemplate(template=PROMPT_ATOMICO_MERGE, input_variables=["solicitacao_usuario", "texto_para_analise_grok", "texto_para_analise_sonnet", "texto_para_analise_gemini"])
|
@@ -323,7 +351,9 @@ def merge():
|
|
323 |
grok_with_max_tokens = grok_llm.bind(max_tokens=20000)
|
324 |
chain_merge = prompt_merge | grok_with_max_tokens | output_parser
|
325 |
|
326 |
-
|
|
|
|
|
327 |
|
328 |
resposta_merge = chain_merge.invoke({
|
329 |
"solicitacao_usuario": data.get('solicitacao_usuario'),
|
@@ -332,19 +362,39 @@ def merge():
|
|
332 |
"texto_para_analise_gemini": data.get('gemini_text')
|
333 |
})
|
334 |
|
|
|
|
|
335 |
if not resposta_merge or not resposta_merge.strip():
|
336 |
-
|
|
|
337 |
return
|
338 |
|
339 |
-
|
|
|
340 |
word_count = len(resposta_merge.split())
|
341 |
|
342 |
-
|
343 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
344 |
|
345 |
except Exception as e:
|
346 |
log_print(f"Erro no processo de merge: {e}")
|
347 |
-
|
|
|
|
|
|
|
348 |
|
349 |
return Response(generate_merge_stream(), mimetype='text/event-stream')
|
350 |
|
|
|
46 |
print(f"[DEBUG] {message}", flush=True)
|
47 |
sys.stdout.flush()
|
48 |
|
49 |
+
def safe_json_dumps(data):
|
50 |
+
"""Função para criar JSON de forma segura, com tratamento de strings muito grandes"""
|
51 |
+
try:
|
52 |
+
json_str = json.dumps(data, ensure_ascii=False)
|
53 |
+
|
54 |
+
# Se o JSON for muito grande (> 50MB), trunca o conteúdo
|
55 |
+
if len(json_str.encode('utf-8')) > 50 * 1024 * 1024:
|
56 |
+
log_print(f"JSON muito grande ({len(json_str)} chars), truncando...")
|
57 |
+
if 'content' in str(data):
|
58 |
+
# Cria uma versão truncada
|
59 |
+
truncated_data = data.copy() if isinstance(data, dict) else {}
|
60 |
+
if 'final_result' in truncated_data and 'content' in truncated_data['final_result']:
|
61 |
+
original_content = truncated_data['final_result']['content']
|
62 |
+
truncated_content = original_content[:10000] + "\n\n[CONTEÚDO TRUNCADO DEVIDO AO TAMANHO - Use o botão 'Copiar' para obter o texto completo]"
|
63 |
+
truncated_data['final_result']['content'] = truncated_content
|
64 |
+
elif 'partial_result' in truncated_data and 'content' in truncated_data['partial_result']:
|
65 |
+
original_content = truncated_data['partial_result']['content']
|
66 |
+
truncated_content = original_content[:10000] + "\n\n[CONTEÚDO TRUNCADO DEVIDO AO TAMANHO - Use o botão 'Copiar' para obter o texto completo]"
|
67 |
+
truncated_data['partial_result']['content'] = truncated_content
|
68 |
+
|
69 |
+
return json.dumps(truncated_data, ensure_ascii=False)
|
70 |
+
|
71 |
+
return json_str
|
72 |
+
except Exception as e:
|
73 |
+
log_print(f"Erro ao criar JSON: {e}")
|
74 |
+
return json.dumps({'error': f'Erro na serialização JSON: {str(e)}'})
|
75 |
+
|
76 |
+
# Variável global para armazenar o conteúdo completo do merge
|
77 |
+
merge_full_content = ""
|
78 |
+
|
79 |
# Função para renderização com fallback: tenta MarkdownIt, depois markdown2
|
80 |
def render_markdown_cascata(texto: str) -> str:
|
81 |
try:
|
|
|
127 |
converted_html = render_markdown_cascata(text_to_convert)
|
128 |
return jsonify({'html': converted_html})
|
129 |
|
130 |
+
# NOVA ROTA: Para obter o conteúdo completo do merge
|
131 |
+
@app.route('/get-full-content', methods=['POST'])
|
132 |
+
def get_full_content():
|
133 |
+
global merge_full_content
|
134 |
+
data = request.get_json()
|
135 |
+
content_type = data.get('type', 'merge')
|
136 |
+
|
137 |
+
if content_type == 'merge' and merge_full_content:
|
138 |
+
return jsonify({'content': merge_full_content})
|
139 |
+
else:
|
140 |
+
return jsonify({'error': 'Conteúdo não encontrado'}), 404
|
141 |
+
|
142 |
@app.route('/process', methods=['POST'])
|
143 |
def process():
|
144 |
"""Processa a solicitação do usuário nos modos Hierárquico ou Atômico."""
|
|
|
169 |
if current_mode == 'test':
|
170 |
log_print("=== MODO TESTE EXECUTADO ===")
|
171 |
mock_text = form_data.get('mock_text', 'Este é um **texto** de `simulação`.')
|
172 |
+
json_data = safe_json_dumps({'progress': 100, 'message': 'Simulação concluída!', 'partial_result': {'id': 'grok-output', 'content': mock_text}, 'done': True, 'mode': 'atomic' if processing_mode == 'atomic' else 'hierarchical'})
|
173 |
+
yield f"data: {json_data}\n\n"
|
174 |
if processing_mode == 'atomic':
|
175 |
+
json_data = safe_json_dumps({'partial_result': {'id': 'sonnet-output', 'content': mock_text}})
|
176 |
+
yield f"data: {json_data}\n\n"
|
177 |
+
json_data = safe_json_dumps({'partial_result': {'id': 'gemini-output', 'content': mock_text}})
|
178 |
+
yield f"data: {json_data}\n\n"
|
179 |
else:
|
180 |
if not solicitacao_usuario:
|
181 |
log_print("=== ERRO: SOLICITAÇÃO VAZIA ===")
|
182 |
+
json_data = safe_json_dumps({'error': 'Solicitação não fornecida.'})
|
183 |
+
yield f"data: {json_data}\n\n"
|
184 |
return
|
185 |
|
186 |
try:
|
187 |
log_print("=== INICIANDO PROCESSAMENTO REAL ===")
|
188 |
+
json_data = safe_json_dumps({'progress': 0, 'message': 'Processando arquivos e extraindo contexto...'})
|
189 |
+
yield f"data: {json_data}\n\n"
|
190 |
rag_context = get_relevant_context(file_paths, solicitacao_usuario)
|
191 |
log_print(f"=== RAG CONTEXT OBTIDO: {len(rag_context)} chars ===")
|
192 |
|
|
|
219 |
models = {'grok': grok_llm, 'sonnet': claude_atomic_llm, 'gemini': gemini_llm}
|
220 |
|
221 |
prompt = PromptTemplate(template=PROMPT_ATOMICO_INICIAL, input_variables=["solicitacao_usuario", "rag_context"])
|
222 |
+
json_data = safe_json_dumps({'progress': 15, 'message': 'Iniciando processamento paralelo...'})
|
223 |
+
yield f"data: {json_data}\n\n"
|
224 |
|
225 |
for name, llm in models.items():
|
226 |
chain = prompt | llm | output_parser
|
|
|
234 |
for key, result in results.items():
|
235 |
if result == "Error:EmptyResponse" or "Erro ao processar" in result:
|
236 |
error_msg = result if "Erro ao processar" in result else f"Falha no serviço {key.upper()}: Sem resposta."
|
237 |
+
json_data = safe_json_dumps({'error': error_msg})
|
238 |
+
yield f"data: {json_data}\n\n"
|
239 |
return
|
240 |
|
241 |
+
json_data = safe_json_dumps({'progress': 80, 'message': 'Todos os modelos responderam. Formatando saídas...'})
|
242 |
+
yield f"data: {json_data}\n\n"
|
243 |
|
244 |
# MUDANÇA: Envia o texto bruto para cada modelo
|
245 |
grok_text = results.get('grok', '')
|
246 |
log_print(f"--- Resposta Bruta do GROK (Atômico) ---\n{grok_text[:200]}...\n--------------------------------------")
|
247 |
+
json_data = safe_json_dumps({'partial_result': {'id': 'grok-output', 'content': grok_text}})
|
248 |
+
yield f"data: {json_data}\n\n"
|
249 |
|
250 |
sonnet_text = results.get('sonnet', '')
|
251 |
log_print(f"--- Resposta Bruta do Sonnet (Atômico) ---\n{sonnet_text[:200]}...\n----------------------------------------")
|
252 |
+
json_data = safe_json_dumps({'partial_result': {'id': 'sonnet-output', 'content': sonnet_text}})
|
253 |
+
yield f"data: {json_data}\n\n"
|
254 |
|
255 |
gemini_text = results.get('gemini', '')
|
256 |
log_print(f"--- Resposta Bruta do Gemini (Atômico) ---\n{gemini_text[:200]}...\n----------------------------------------")
|
257 |
+
json_data = safe_json_dumps({'partial_result': {'id': 'gemini-output', 'content': gemini_text}})
|
258 |
+
yield f"data: {json_data}\n\n"
|
259 |
|
260 |
+
json_data = safe_json_dumps({'progress': 100, 'message': 'Processamento Atômico concluído!', 'done': True, 'mode': 'atomic'})
|
261 |
+
yield f"data: {json_data}\n\n"
|
262 |
|
263 |
else:
|
264 |
log_print("=== MODO HIERÁRQUICO SELECIONADO ===")
|
265 |
# --- LÓGICA HIERÁRQUICA (SEQUENCIAL) ---
|
266 |
+
json_data = safe_json_dumps({'progress': 15, 'message': 'O GROK está processando sua solicitação...'})
|
267 |
+
yield f"data: {json_data}\n\n"
|
268 |
|
269 |
log_print("=== PROCESSANDO GROK ===")
|
270 |
prompt_grok = PromptTemplate(template=PROMPT_HIERARQUICO_GROK, input_variables=["solicitacao_usuario", "rag_context"])
|
|
|
275 |
|
276 |
if not resposta_grok or not resposta_grok.strip():
|
277 |
log_print("=== ERRO: GROK VAZIO ===")
|
278 |
+
json_data = safe_json_dumps({'error': 'Falha no serviço GROK: Sem resposta.'})
|
279 |
+
yield f"data: {json_data}\n\n"
|
280 |
return
|
281 |
|
282 |
log_print("=== ENVIANDO RESPOSTA GROK PARA FRONTEND ===")
|
283 |
+
json_data = safe_json_dumps({'progress': 33, 'message': 'Claude Sonnet está processando...', 'partial_result': {'id': 'grok-output', 'content': resposta_grok}})
|
284 |
+
yield f"data: {json_data}\n\n"
|
285 |
|
286 |
log_print("=== PROCESSANDO SONNET ===")
|
287 |
prompt_sonnet = PromptTemplate(template=PROMPT_HIERARQUICO_SONNET, input_variables=["solicitacao_usuario", "texto_para_analise"])
|
|
|
293 |
|
294 |
if not resposta_sonnet or not resposta_sonnet.strip():
|
295 |
log_print("=== ERRO: SONNET VAZIO ===")
|
296 |
+
json_data = safe_json_dumps({'error': 'Falha no serviço Claude Sonnet: Sem resposta.'})
|
297 |
+
yield f"data: {json_data}\n\n"
|
298 |
return
|
299 |
|
300 |
+
log_print("=== ENVIANDO RESPOSTA SONNET ===")
|
301 |
+
json_data = safe_json_dumps({'progress': 66, 'message': 'Gemini está processando...', 'partial_result': {'id': 'sonnet-output', 'content': resposta_sonnet}})
|
302 |
+
yield f"data: {json_data}\n\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
303 |
|
304 |
log_print("=== PROCESSANDO GEMINI ===")
|
305 |
prompt_gemini = PromptTemplate(template=PROMPT_HIERARQUICO_GEMINI, input_variables=["solicitacao_usuario", "texto_para_analise"])
|
|
|
310 |
|
311 |
if not resposta_gemini or not resposta_gemini.strip():
|
312 |
log_print("=== ERRO: GEMINI VAZIO ===")
|
313 |
+
json_data = safe_json_dumps({'error': 'Falha no serviço Gemini: Sem resposta.'})
|
314 |
+
yield f"data: {json_data}\n\n"
|
315 |
return
|
316 |
|
317 |
log_print("=== ENVIANDO RESPOSTA GEMINI ===")
|
318 |
+
json_data = safe_json_dumps({'progress': 100, 'message': 'Processamento concluído!', 'partial_result': {'id': 'gemini-output', 'content': resposta_gemini}, 'done': True, 'mode': 'hierarchical'})
|
319 |
+
yield f"data: {json_data}\n\n"
|
320 |
log_print("=== PROCESSAMENTO COMPLETO ===")
|
321 |
|
322 |
except Exception as e:
|
323 |
log_print(f"Ocorreu um erro durante o processamento: {e}")
|
324 |
import traceback
|
325 |
log_print(f"Traceback: {traceback.format_exc()}")
|
326 |
+
json_data = safe_json_dumps({'error': f'Ocorreu um erro inesperado na aplicação: {e}'})
|
327 |
+
yield f"data: {json_data}\n\n"
|
328 |
|
329 |
return Response(generate_stream(mode, form_data, temp_file_paths), mimetype='text/event-stream')
|
330 |
|
331 |
@app.route('/merge', methods=['POST'])
|
332 |
def merge():
|
333 |
"""Recebe os textos do modo Atômico e os consolida usando um LLM."""
|
334 |
+
global merge_full_content
|
335 |
+
|
336 |
data = request.get_json()
|
337 |
+
log_print("=== ROTA MERGE ACESSADA ===")
|
338 |
|
339 |
def generate_merge_stream():
|
340 |
"""Gera a resposta do merge em streaming."""
|
341 |
+
global merge_full_content
|
342 |
+
|
343 |
try:
|
344 |
+
log_print("=== INICIANDO MERGE STREAM ===")
|
345 |
+
json_data = safe_json_dumps({'progress': 0, 'message': 'Iniciando o processo de merge...'})
|
346 |
+
yield f"data: {json_data}\n\n"
|
347 |
|
348 |
output_parser = StrOutputParser()
|
349 |
prompt_merge = PromptTemplate(template=PROMPT_ATOMICO_MERGE, input_variables=["solicitacao_usuario", "texto_para_analise_grok", "texto_para_analise_sonnet", "texto_para_analise_gemini"])
|
|
|
351 |
grok_with_max_tokens = grok_llm.bind(max_tokens=20000)
|
352 |
chain_merge = prompt_merge | grok_with_max_tokens | output_parser
|
353 |
|
354 |
+
json_data = safe_json_dumps({'progress': 50, 'message': 'Enviando textos para o GROK para consolidação...'})
|
355 |
+
yield f"data: {json_data}\n\n"
|
356 |
+
log_print("=== INVOCANDO CHAIN DE MERGE ===")
|
357 |
|
358 |
resposta_merge = chain_merge.invoke({
|
359 |
"solicitacao_usuario": data.get('solicitacao_usuario'),
|
|
|
362 |
"texto_para_analise_gemini": data.get('gemini_text')
|
363 |
})
|
364 |
|
365 |
+
log_print(f"=== MERGE CONCLUÍDO: {len(resposta_merge)} chars ===")
|
366 |
+
|
367 |
if not resposta_merge or not resposta_merge.strip():
|
368 |
+
json_data = safe_json_dumps({'error': 'Falha no serviço de Merge (GROK): Sem resposta.'})
|
369 |
+
yield f"data: {json_data}\n\n"
|
370 |
return
|
371 |
|
372 |
+
# Armazena o conteúdo completo na variável global
|
373 |
+
merge_full_content = resposta_merge
|
374 |
word_count = len(resposta_merge.split())
|
375 |
|
376 |
+
log_print(f"=== CRIANDO JSON DE RESPOSTA DO MERGE ===")
|
377 |
+
# Usa a função safe para evitar problemas com JSON muito grande
|
378 |
+
json_data = safe_json_dumps({
|
379 |
+
'progress': 100,
|
380 |
+
'message': 'Merge concluído!',
|
381 |
+
'final_result': {
|
382 |
+
'content': resposta_merge,
|
383 |
+
'word_count': word_count
|
384 |
+
},
|
385 |
+
'done': True
|
386 |
+
})
|
387 |
+
|
388 |
+
log_print(f"=== JSON CRIADO: {len(json_data)} chars ===")
|
389 |
+
yield f"data: {json_data}\n\n"
|
390 |
+
log_print("=== MERGE STREAM FINALIZADO ===")
|
391 |
|
392 |
except Exception as e:
|
393 |
log_print(f"Erro no processo de merge: {e}")
|
394 |
+
import traceback
|
395 |
+
log_print(f"Traceback: {traceback.format_exc()}")
|
396 |
+
json_data = safe_json_dumps({'error': str(e)})
|
397 |
+
yield f"data: {json_data}\n\n"
|
398 |
|
399 |
return Response(generate_merge_stream(), mimetype='text/event-stream')
|
400 |
|
config.py
CHANGED
@@ -89,6 +89,7 @@ PROMPT_HIERARQUICO_SONNET = """
|
|
89 |
|
90 |
<restricoes>
|
91 |
<proibido>fazer reduções do texto</proibido>
|
|
|
92 |
<proibido>fazer resumos</proibido>
|
93 |
<proibido>encurtar o conteúdo original</proibido>
|
94 |
<proibido>usar expressões características de IA como "Não é mera..., mas é..."</proibido>
|
@@ -152,6 +153,7 @@ PROMPT_HIERARQUICO_GEMINI = """
|
|
152 |
<proibido>fazer reduções do texto</proibido>
|
153 |
<proibido>fazer resumos</proibido>
|
154 |
<proibido>encurtar o conteúdo original</proibido>
|
|
|
155 |
<proibido>usar expressões características de IA como "Não é mera..., mas é..."</proibido>
|
156 |
</restricoes>
|
157 |
|
|
|
89 |
|
90 |
<restricoes>
|
91 |
<proibido>fazer reduções do texto</proibido>
|
92 |
+
<proibido>elaborar um texto com mais de 30000 caracteres</proibido>
|
93 |
<proibido>fazer resumos</proibido>
|
94 |
<proibido>encurtar o conteúdo original</proibido>
|
95 |
<proibido>usar expressões características de IA como "Não é mera..., mas é..."</proibido>
|
|
|
153 |
<proibido>fazer reduções do texto</proibido>
|
154 |
<proibido>fazer resumos</proibido>
|
155 |
<proibido>encurtar o conteúdo original</proibido>
|
156 |
+
<proibido>elaborar um texto com mais de 30000 caracteres</proibido>
|
157 |
<proibido>usar expressões características de IA como "Não é mera..., mas é..."</proibido>
|
158 |
</restricoes>
|
159 |
|
templates/index.html
CHANGED
@@ -276,6 +276,18 @@ Use o botão `Converter para MD` para ver a mágica.</textarea>
|
|
276 |
// Processa qualquer dado restante no buffer
|
277 |
if (buffer.trim()) {
|
278 |
debugLog(`Buffer final: ${buffer}`);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
279 |
}
|
280 |
|
281 |
} catch (error) {
|
@@ -301,7 +313,7 @@ Use o botão `Converter para MD` para ver a mágica.</textarea>
|
|
301 |
sonnet_text: rawTexts['sonnet-output'] || '',
|
302 |
gemini_text: rawTexts['gemini-output'] || '',
|
303 |
};
|
304 |
-
debugLog(`Payload do merge
|
305 |
|
306 |
try {
|
307 |
const response = await fetch('/merge', {
|
@@ -311,25 +323,62 @@ Use o botão `Converter para MD` para ver a mágica.</textarea>
|
|
311 |
});
|
312 |
if (!response.ok || !response.body) throw new Error(`Erro na resposta do servidor: ${response.statusText}`);
|
313 |
|
|
|
314 |
const reader = response.body.getReader();
|
315 |
const decoder = new TextDecoder();
|
|
|
|
|
316 |
while (true) {
|
317 |
const { done, value } = await reader.read();
|
318 |
-
if (done)
|
|
|
|
|
|
|
|
|
319 |
const chunk = decoder.decode(value, { stream: true });
|
320 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
321 |
lines.forEach(line => {
|
322 |
if (line.startsWith('data: ')) {
|
323 |
-
const jsonData = line.substring(6);
|
324 |
-
if (jsonData
|
|
|
325 |
try {
|
326 |
const data = JSON.parse(jsonData);
|
|
|
327 |
processStreamData(data, true); // true = é merge
|
328 |
-
} catch (e) {
|
|
|
|
|
|
|
329 |
}
|
330 |
}
|
331 |
});
|
332 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
333 |
} catch (error) {
|
334 |
debugLog(`ERRO NO MERGE: ${error.message}`);
|
335 |
showError("A conexão falhou ao tentar processar o merge.");
|
@@ -467,5 +516,6 @@ Use o botão `Converter para MD` para ver a mágica.</textarea>
|
|
467 |
}
|
468 |
}
|
469 |
</script>
|
|
|
470 |
</body>
|
471 |
</html>
|
|
|
276 |
// Processa qualquer dado restante no buffer
|
277 |
if (buffer.trim()) {
|
278 |
debugLog(`Buffer final: ${buffer}`);
|
279 |
+
// Tenta processar o buffer final como uma linha completa
|
280 |
+
if (buffer.startsWith('data: ')) {
|
281 |
+
const jsonData = buffer.substring(6).trim();
|
282 |
+
if (jsonData) {
|
283 |
+
try {
|
284 |
+
const data = JSON.parse(jsonData);
|
285 |
+
processStreamData(data, false);
|
286 |
+
} catch (e) {
|
287 |
+
console.error("Erro ao parsear JSON do buffer final:", jsonData.substring(0, 200));
|
288 |
+
}
|
289 |
+
}
|
290 |
+
}
|
291 |
}
|
292 |
|
293 |
} catch (error) {
|
|
|
313 |
sonnet_text: rawTexts['sonnet-output'] || '',
|
314 |
gemini_text: rawTexts['gemini-output'] || '',
|
315 |
};
|
316 |
+
debugLog(`Payload do merge preparado com textos de tamanho: G=${payload.grok_text.length}, S=${payload.sonnet_text.length}, G=${payload.gemini_text.length}`);
|
317 |
|
318 |
try {
|
319 |
const response = await fetch('/merge', {
|
|
|
323 |
});
|
324 |
if (!response.ok || !response.body) throw new Error(`Erro na resposta do servidor: ${response.statusText}`);
|
325 |
|
326 |
+
debugLog("=== MERGE FETCH REALIZADO COM SUCESSO, INICIANDO STREAM ===");
|
327 |
const reader = response.body.getReader();
|
328 |
const decoder = new TextDecoder();
|
329 |
+
let buffer = ''; // Buffer para dados incompletos do merge
|
330 |
+
|
331 |
while (true) {
|
332 |
const { done, value } = await reader.read();
|
333 |
+
if (done) {
|
334 |
+
debugLog("=== MERGE STREAM FINALIZADO ===");
|
335 |
+
break;
|
336 |
+
}
|
337 |
+
|
338 |
const chunk = decoder.decode(value, { stream: true });
|
339 |
+
buffer += chunk;
|
340 |
+
debugLog(`Merge chunk recebido: ${chunk.length} chars`);
|
341 |
+
|
342 |
+
// Processa todas as linhas completas no buffer
|
343 |
+
let lines = buffer.split('\n\n');
|
344 |
+
buffer = lines.pop(); // Mantém a última linha (possivelmente incompleta) no buffer
|
345 |
+
|
346 |
lines.forEach(line => {
|
347 |
if (line.startsWith('data: ')) {
|
348 |
+
const jsonData = line.substring(6).trim();
|
349 |
+
if (jsonData) {
|
350 |
+
debugLog(`Merge JSON recebido: ${jsonData.substring(0, 200)}...`);
|
351 |
try {
|
352 |
const data = JSON.parse(jsonData);
|
353 |
+
debugLog(`Merge dados processados: ${JSON.stringify({progress: data.progress, message: data.message, hasFinalResult: !!data.final_result, error: data.error})}`);
|
354 |
processStreamData(data, true); // true = é merge
|
355 |
+
} catch (e) {
|
356 |
+
console.error("Erro ao parsear JSON do merge:", jsonData.substring(0, 500));
|
357 |
+
console.error("Erro:", e);
|
358 |
+
}
|
359 |
}
|
360 |
}
|
361 |
});
|
362 |
}
|
363 |
+
|
364 |
+
// Processa qualquer dado restante no buffer do merge
|
365 |
+
if (buffer.trim()) {
|
366 |
+
debugLog(`Merge buffer final: ${buffer.substring(0, 200)}...`);
|
367 |
+
if (buffer.startsWith('data: ')) {
|
368 |
+
const jsonData = buffer.substring(6).trim();
|
369 |
+
if (jsonData) {
|
370 |
+
try {
|
371 |
+
const data = JSON.parse(jsonData);
|
372 |
+
debugLog("Processando buffer final do merge");
|
373 |
+
processStreamData(data, true);
|
374 |
+
} catch (e) {
|
375 |
+
console.error("Erro ao parsear JSON do merge buffer final:", jsonData.substring(0, 500));
|
376 |
+
console.error("Erro:", e);
|
377 |
+
}
|
378 |
+
}
|
379 |
+
}
|
380 |
+
}
|
381 |
+
|
382 |
} catch (error) {
|
383 |
debugLog(`ERRO NO MERGE: ${error.message}`);
|
384 |
showError("A conexão falhou ao tentar processar o merge.");
|
|
|
516 |
}
|
517 |
}
|
518 |
</script>
|
519 |
+
|
520 |
</body>
|
521 |
</html>
|