victorafarias commited on
Commit
57d2d03
·
1 Parent(s): a53c02f

Evoluções Gerais

Browse files
Files changed (1) hide show
  1. app.py +119 -14
app.py CHANGED
@@ -41,6 +41,9 @@ app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024
41
  # Instancia o conversor de Markdown
42
  md = MarkdownIt()
43
 
 
 
 
44
  def log_print(message):
45
  """Função para garantir que os logs apareçam no container"""
46
  print(f"[DEBUG] {message}", flush=True)
@@ -127,6 +130,14 @@ def convert():
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():
@@ -142,6 +153,9 @@ def get_full_content():
142
  @app.route('/process', methods=['POST'])
143
  def process():
144
  """Processa a solicitação do usuário nos modos Hierárquico ou Atômico."""
 
 
 
145
  log_print("=== ROTA PROCESS ACESSADA ===")
146
 
147
  form_data = request.form
@@ -149,7 +163,12 @@ def process():
149
  mode = form_data.get('mode', 'real')
150
  processing_mode = form_data.get('processing_mode', 'hierarchical')
151
 
 
 
 
 
152
  log_print(f"Mode: {mode}, Processing: {processing_mode}")
 
153
 
154
  temp_file_paths = []
155
  if mode == 'real':
@@ -162,6 +181,8 @@ def process():
162
 
163
  def generate_stream(current_mode, form_data, file_paths):
164
  """Gera a resposta em streaming para o front-end."""
 
 
165
  log_print(f"=== GENERATE_STREAM INICIADO - Mode: {current_mode} ===")
166
 
167
  solicitacao_usuario = form_data.get('solicitacao', '')
@@ -200,13 +221,17 @@ def process():
200
 
201
  def run_chain_with_timeout(chain, inputs, key, timeout=300):
202
  def task():
 
 
203
  return chain.invoke(inputs)
204
 
205
  with concurrent.futures.ThreadPoolExecutor() as executor:
206
  future = executor.submit(task)
207
  try:
208
  result = future.result(timeout=timeout)
209
- if not result or not result.strip():
 
 
210
  results[key] = "Error:EmptyResponse"
211
  else:
212
  results[key] = result
@@ -218,11 +243,22 @@ def process():
218
  claude_atomic_llm = claude_llm.bind(max_tokens=20000)
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
227
  thread = threading.Thread(target=run_chain_with_timeout, args=(chain, {"solicitacao_usuario": solicitacao_usuario, "rag_context": rag_context}, name))
228
  threads.append(thread)
@@ -231,6 +267,12 @@ def process():
231
  for thread in threads:
232
  thread.join()
233
 
 
 
 
 
 
 
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."
@@ -263,16 +305,41 @@ def process():
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"])
271
  chain_grok = prompt_grok | grok_llm | output_parser
272
  resposta_grok = chain_grok.invoke({"solicitacao_usuario": solicitacao_usuario, "rag_context": rag_context})
273
 
274
  log_print(f"=== GROK TERMINOU: {len(resposta_grok)} chars ===")
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.'})
@@ -283,14 +350,24 @@ def process():
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"])
288
  claude_with_max_tokens = claude_llm.bind(max_tokens=20000)
289
  chain_sonnet = prompt_sonnet | claude_with_max_tokens | output_parser
290
  resposta_sonnet = chain_sonnet.invoke({"solicitacao_usuario": solicitacao_usuario, "texto_para_analise": resposta_grok})
291
 
292
  log_print(f"=== SONNET TERMINOU: {len(resposta_sonnet)} chars ===")
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.'})
@@ -301,13 +378,23 @@ def process():
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"])
306
  chain_gemini = prompt_gemini | gemini_llm | output_parser
307
  resposta_gemini = chain_gemini.invoke({"solicitacao_usuario": solicitacao_usuario, "texto_para_analise": resposta_sonnet})
308
 
309
  log_print(f"=== GEMINI TERMINOU: {len(resposta_gemini)} chars ===")
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.'})
@@ -330,30 +417,43 @@ def process():
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"])
350
 
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,10 +462,15 @@ def merge():
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
 
 
41
  # Instancia o conversor de Markdown
42
  md = MarkdownIt()
43
 
44
+ # Variável global para controle de interrupção
45
+ processing_cancelled = False
46
+
47
  def log_print(message):
48
  """Função para garantir que os logs apareçam no container"""
49
  print(f"[DEBUG] {message}", flush=True)
 
130
  converted_html = render_markdown_cascata(text_to_convert)
131
  return jsonify({'html': converted_html})
132
 
133
+ # NOVA ROTA: Para cancelar processamento
134
+ @app.route('/cancel', methods=['POST'])
135
+ def cancel():
136
+ global processing_cancelled
137
+ processing_cancelled = True
138
+ log_print("=== PROCESSAMENTO CANCELADO PELO USUÁRIO ===")
139
+ return jsonify({'status': 'cancelled'})
140
+
141
  # NOVA ROTA: Para obter o conteúdo completo do merge
142
  @app.route('/get-full-content', methods=['POST'])
143
  def get_full_content():
 
153
  @app.route('/process', methods=['POST'])
154
  def process():
155
  """Processa a solicitação do usuário nos modos Hierárquico ou Atômico."""
156
+ global processing_cancelled
157
+ processing_cancelled = False # Reset do flag de cancelamento
158
+
159
  log_print("=== ROTA PROCESS ACESSADA ===")
160
 
161
  form_data = request.form
 
163
  mode = form_data.get('mode', 'real')
164
  processing_mode = form_data.get('processing_mode', 'hierarchical')
165
 
166
+ # NOVOS PARÂMETROS: Tamanho do texto
167
+ min_chars = int(form_data.get('min_chars', 24000))
168
+ max_chars = int(form_data.get('max_chars', 30000))
169
+
170
  log_print(f"Mode: {mode}, Processing: {processing_mode}")
171
+ log_print(f"Tamanho solicitado: {min_chars} - {max_chars} caracteres")
172
 
173
  temp_file_paths = []
174
  if mode == 'real':
 
181
 
182
  def generate_stream(current_mode, form_data, file_paths):
183
  """Gera a resposta em streaming para o front-end."""
184
+ global processing_cancelled
185
+
186
  log_print(f"=== GENERATE_STREAM INICIADO - Mode: {current_mode} ===")
187
 
188
  solicitacao_usuario = form_data.get('solicitacao', '')
 
221
 
222
  def run_chain_with_timeout(chain, inputs, key, timeout=300):
223
  def task():
224
+ if processing_cancelled:
225
+ return "CANCELLED"
226
  return chain.invoke(inputs)
227
 
228
  with concurrent.futures.ThreadPoolExecutor() as executor:
229
  future = executor.submit(task)
230
  try:
231
  result = future.result(timeout=timeout)
232
+ if result == "CANCELLED":
233
+ results[key] = "CANCELLED"
234
+ elif not result or not result.strip():
235
  results[key] = "Error:EmptyResponse"
236
  else:
237
  results[key] = result
 
243
  claude_atomic_llm = claude_llm.bind(max_tokens=20000)
244
  models = {'grok': grok_llm, 'sonnet': claude_atomic_llm, 'gemini': gemini_llm}
245
 
246
+ # Atualizar os prompts com os parâmetros de tamanho
247
+ updated_prompt_template = PROMPT_ATOMICO_INICIAL.replace(
248
+ "<minimum>24000</minimum>\n <maximum>30000</maximum>",
249
+ f"<minimum>{min_chars}</minimum>\n <maximum>{max_chars}</maximum>"
250
+ )
251
+
252
+ prompt = PromptTemplate(template=updated_prompt_template, input_variables=["solicitacao_usuario", "rag_context"])
253
  json_data = safe_json_dumps({'progress': 15, 'message': 'Iniciando processamento paralelo...'})
254
  yield f"data: {json_data}\n\n"
255
 
256
  for name, llm in models.items():
257
+ if processing_cancelled:
258
+ json_data = safe_json_dumps({'error': 'Processamento cancelado pelo usuário.'})
259
+ yield f"data: {json_data}\n\n"
260
+ return
261
+
262
  chain = prompt | llm | output_parser
263
  thread = threading.Thread(target=run_chain_with_timeout, args=(chain, {"solicitacao_usuario": solicitacao_usuario, "rag_context": rag_context}, name))
264
  threads.append(thread)
 
267
  for thread in threads:
268
  thread.join()
269
 
270
+ # Verificar se foi cancelado
271
+ if processing_cancelled or any(result == "CANCELLED" for result in results.values()):
272
+ json_data = safe_json_dumps({'error': 'Processamento cancelado pelo usuário.'})
273
+ yield f"data: {json_data}\n\n"
274
+ return
275
+
276
  for key, result in results.items():
277
  if result == "Error:EmptyResponse" or "Erro ao processar" in result:
278
  error_msg = result if "Erro ao processar" in result else f"Falha no serviço {key.upper()}: Sem resposta."
 
305
  else:
306
  log_print("=== MODO HIERÁRQUICO SELECIONADO ===")
307
  # --- LÓGICA HIERÁRQUICA (SEQUENCIAL) ---
308
+
309
+ # Atualizar prompts hierárquicos com parâmetros de tamanho
310
+ updated_grok_template = PROMPT_HIERARQUICO_GROK.replace(
311
+ "<minimum>24000</minimum>\n <maximum>30000</maximum>",
312
+ f"<minimum>{min_chars}</minimum>\n <maximum>{max_chars}</maximum>"
313
+ )
314
+ updated_sonnet_template = PROMPT_HIERARQUICO_SONNET.replace(
315
+ "**Valide se o texto atingiu a quantidade de caracteres mínimas de 24000 e máxima de 30000 caracteres**.",
316
+ f"**Valide se o texto atingiu a quantidade de caracteres mínimas de {min_chars} e máxima de {max_chars} caracteres**."
317
+ )
318
+ updated_gemini_template = PROMPT_HIERARQUICO_GEMINI.replace(
319
+ "**Valide se o texto atingiu a quantidade de caracteres mínimas de 24000 e máxima de 30000 caracteres**.",
320
+ f"**Valide se o texto atingiu a quantidade de caracteres mínimas de {min_chars} e máxima de {max_chars} caracteres**."
321
+ )
322
+
323
  json_data = safe_json_dumps({'progress': 15, 'message': 'O GROK está processando sua solicitação...'})
324
  yield f"data: {json_data}\n\n"
325
 
326
+ if processing_cancelled:
327
+ json_data = safe_json_dumps({'error': 'Processamento cancelado pelo usuário.'})
328
+ yield f"data: {json_data}\n\n"
329
+ return
330
+
331
  log_print("=== PROCESSANDO GROK ===")
332
+ prompt_grok = PromptTemplate(template=updated_grok_template, input_variables=["solicitacao_usuario", "rag_context"])
333
  chain_grok = prompt_grok | grok_llm | output_parser
334
  resposta_grok = chain_grok.invoke({"solicitacao_usuario": solicitacao_usuario, "rag_context": rag_context})
335
 
336
  log_print(f"=== GROK TERMINOU: {len(resposta_grok)} chars ===")
337
 
338
+ if processing_cancelled:
339
+ json_data = safe_json_dumps({'error': 'Processamento cancelado pelo usuário.'})
340
+ yield f"data: {json_data}\n\n"
341
+ return
342
+
343
  if not resposta_grok or not resposta_grok.strip():
344
  log_print("=== ERRO: GROK VAZIO ===")
345
  json_data = safe_json_dumps({'error': 'Falha no serviço GROK: Sem resposta.'})
 
350
  json_data = safe_json_dumps({'progress': 33, 'message': 'Claude Sonnet está processando...', 'partial_result': {'id': 'grok-output', 'content': resposta_grok}})
351
  yield f"data: {json_data}\n\n"
352
 
353
+ if processing_cancelled:
354
+ json_data = safe_json_dumps({'error': 'Processamento cancelado pelo usuário.'})
355
+ yield f"data: {json_data}\n\n"
356
+ return
357
+
358
  log_print("=== PROCESSANDO SONNET ===")
359
+ prompt_sonnet = PromptTemplate(template=updated_sonnet_template, input_variables=["solicitacao_usuario", "texto_para_analise"])
360
  claude_with_max_tokens = claude_llm.bind(max_tokens=20000)
361
  chain_sonnet = prompt_sonnet | claude_with_max_tokens | output_parser
362
  resposta_sonnet = chain_sonnet.invoke({"solicitacao_usuario": solicitacao_usuario, "texto_para_analise": resposta_grok})
363
 
364
  log_print(f"=== SONNET TERMINOU: {len(resposta_sonnet)} chars ===")
365
 
366
+ if processing_cancelled:
367
+ json_data = safe_json_dumps({'error': 'Processamento cancelado pelo usuário.'})
368
+ yield f"data: {json_data}\n\n"
369
+ return
370
+
371
  if not resposta_sonnet or not resposta_sonnet.strip():
372
  log_print("=== ERRO: SONNET VAZIO ===")
373
  json_data = safe_json_dumps({'error': 'Falha no serviço Claude Sonnet: Sem resposta.'})
 
378
  json_data = safe_json_dumps({'progress': 66, 'message': 'Gemini está processando...', 'partial_result': {'id': 'sonnet-output', 'content': resposta_sonnet}})
379
  yield f"data: {json_data}\n\n"
380
 
381
+ if processing_cancelled:
382
+ json_data = safe_json_dumps({'error': 'Processamento cancelado pelo usuário.'})
383
+ yield f"data: {json_data}\n\n"
384
+ return
385
+
386
  log_print("=== PROCESSANDO GEMINI ===")
387
+ prompt_gemini = PromptTemplate(template=updated_gemini_template, input_variables=["solicitacao_usuario", "texto_para_analise"])
388
  chain_gemini = prompt_gemini | gemini_llm | output_parser
389
  resposta_gemini = chain_gemini.invoke({"solicitacao_usuario": solicitacao_usuario, "texto_para_analise": resposta_sonnet})
390
 
391
  log_print(f"=== GEMINI TERMINOU: {len(resposta_gemini)} chars ===")
392
 
393
+ if processing_cancelled:
394
+ json_data = safe_json_dumps({'error': 'Processamento cancelado pelo usuário.'})
395
+ yield f"data: {json_data}\n\n"
396
+ return
397
+
398
  if not resposta_gemini or not resposta_gemini.strip():
399
  log_print("=== ERRO: GEMINI VAZIO ===")
400
  json_data = safe_json_dumps({'error': 'Falha no serviço Gemini: Sem resposta.'})
 
417
 
418
  @app.route('/merge', methods=['POST'])
419
  def merge():
420
+ """Recebe os textos do modo Atômico e os consolida usando Claude Sonnet."""
421
+ global merge_full_content, processing_cancelled
422
+ processing_cancelled = False # Reset do flag
423
 
424
  data = request.get_json()
425
  log_print("=== ROTA MERGE ACESSADA ===")
426
+ log_print("=== USANDO CLAUDE SONNET PARA MERGE ===")
427
 
428
  def generate_merge_stream():
429
  """Gera a resposta do merge em streaming."""
430
+ global merge_full_content, processing_cancelled
431
 
432
  try:
433
  log_print("=== INICIANDO MERGE STREAM ===")
434
  json_data = safe_json_dumps({'progress': 0, 'message': 'Iniciando o processo de merge...'})
435
  yield f"data: {json_data}\n\n"
436
 
437
+ if processing_cancelled:
438
+ json_data = safe_json_dumps({'error': 'Processamento cancelado pelo usuário.'})
439
+ yield f"data: {json_data}\n\n"
440
+ return
441
+
442
  output_parser = StrOutputParser()
443
  prompt_merge = PromptTemplate(template=PROMPT_ATOMICO_MERGE, input_variables=["solicitacao_usuario", "texto_para_analise_grok", "texto_para_analise_sonnet", "texto_para_analise_gemini"])
444
 
445
+ # MUDANÇA: Usar Claude Sonnet para o merge
446
+ claude_with_max_tokens = claude_llm.bind(max_tokens=100000)
447
+ chain_merge = prompt_merge | claude_with_max_tokens | output_parser
448
 
449
+ json_data = safe_json_dumps({'progress': 50, 'message': 'Enviando textos para o Claude Sonnet para consolidação...'})
450
  yield f"data: {json_data}\n\n"
451
+ log_print("=== INVOCANDO CLAUDE SONNET PARA MERGE ===")
452
+
453
+ if processing_cancelled:
454
+ json_data = safe_json_dumps({'error': 'Processamento cancelado pelo usuário.'})
455
+ yield f"data: {json_data}\n\n"
456
+ return
457
 
458
  resposta_merge = chain_merge.invoke({
459
  "solicitacao_usuario": data.get('solicitacao_usuario'),
 
462
  "texto_para_analise_gemini": data.get('gemini_text')
463
  })
464
 
465
+ log_print(f"=== MERGE CLAUDE SONNET CONCLUÍDO: {len(resposta_merge)} chars ===")
466
+
467
+ if processing_cancelled:
468
+ json_data = safe_json_dumps({'error': 'Processamento cancelado pelo usuário.'})
469
+ yield f"data: {json_data}\n\n"
470
+ return
471
 
472
  if not resposta_merge or not resposta_merge.strip():
473
+ json_data = safe_json_dumps({'error': 'Falha no serviço de Merge (Claude Sonnet): Sem resposta.'})
474
  yield f"data: {json_data}\n\n"
475
  return
476