victorafarias commited on
Commit
283dd8f
·
1 Parent(s): 4c8169f

Correções e evoluções

Browse files
Files changed (1) hide show
  1. app.py +28 -45
app.py CHANGED
@@ -1,13 +1,14 @@
1
  # app.py
2
 
3
- from flask import Flask, render_template, request, Response, jsonify
4
  import markdown2
5
  import json
6
  import time
7
  import os
8
  import uuid
9
  import threading
10
- import concurrent.futures # Nova importação para timeout
 
11
 
12
  # Importações do LangChain
13
  from langchain.prompts import PromptTemplate
@@ -28,7 +29,16 @@ app = Flask(__name__)
28
  if not os.path.exists('uploads'):
29
  os.makedirs('uploads')
30
 
31
- app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024
 
 
 
 
 
 
 
 
 
32
 
33
  @app.route('/')
34
  def index():
@@ -47,7 +57,6 @@ def process():
47
  if mode == 'real':
48
  for file in files:
49
  if file and file.filename:
50
- # Cria um nome de arquivo único para evitar conflitos
51
  unique_filename = str(uuid.uuid4()) + "_" + os.path.basename(file.filename)
52
  file_path = os.path.join('uploads', unique_filename)
53
  file.save(file_path)
@@ -58,7 +67,6 @@ def process():
58
  solicitacao_usuario = form_data.get('solicitacao', '')
59
 
60
  if current_mode == 'test':
61
- # Lógica para o modo de teste/simulação
62
  mock_text = form_data.get('mock_text', 'Este é um texto de simulação.')
63
  mock_html = markdown2.markdown(mock_text, extras=["fenced-code-blocks", "tables"])
64
  yield f"data: {json.dumps({'progress': 100, 'message': 'Simulação concluída!', 'partial_result': {'id': 'grok-output', 'content': mock_html}, 'done': True, 'mode': 'atomic' if processing_mode == 'atomic' else 'hierarchical'})}\n\n"
@@ -66,7 +74,6 @@ def process():
66
  yield f"data: {json.dumps({'partial_result': {'id': 'sonnet-output', 'content': mock_html}})}\n\n"
67
  yield f"data: {json.dumps({'partial_result': {'id': 'gemini-output', 'content': mock_html}})}\n\n"
68
  else:
69
- # Lógica para o modo real
70
  if not solicitacao_usuario:
71
  yield f"data: {json.dumps({'error': 'Solicitação não fornecida.'})}\n\n"
72
  return
@@ -81,7 +88,6 @@ def process():
81
  threads = []
82
 
83
  def run_chain_with_timeout(chain, inputs, key, timeout=300):
84
- """Executa uma chain com timeout e trata respostas vazias."""
85
  def task():
86
  return chain.invoke(inputs)['text']
87
 
@@ -98,7 +104,10 @@ def process():
98
  except Exception as e:
99
  results[key] = f"Erro ao processar {key.upper()}: {e}"
100
 
101
- models = {'grok': grok_llm, 'sonnet': claude_llm, 'gemini': gemini_llm}
 
 
 
102
  prompt = PromptTemplate(template=PROMPT_ATOMICO_INICIAL, input_variables=["solicitacao_usuario", "rag_context"])
103
  yield f"data: {json.dumps({'progress': 15, 'message': 'Iniciando processamento paralelo...'})}\n\n"
104
 
@@ -119,35 +128,24 @@ def process():
119
 
120
  yield f"data: {json.dumps({'progress': 80, 'message': 'Todos os modelos responderam. Formatando saídas...'})}\n\n"
121
 
122
- # ✅ VALIDAÇÃO E LOGS PARA O MODO ATÔMICO
123
-
124
  # GROK
125
  grok_text = results.get('grok', '')
126
- print("--- Resposta Bruta do GROK (Atômico) ---")
127
- print(grok_text)
128
- print("---------------------------------------")
129
  grok_html = markdown2.markdown(grok_text, extras=["fenced-code-blocks", "tables"])
130
- if not grok_html or not grok_html.strip():
131
  grok_html = f"<pre>{grok_text}</pre>"
132
  yield f"data: {json.dumps({'partial_result': {'id': 'grok-output', 'content': grok_html}})}\n\n"
133
 
134
  # SONNET
135
  sonnet_text = results.get('sonnet', '')
136
- print("--- Resposta Bruta do Sonnet (Atômico) ---")
137
- print(sonnet_text)
138
- print("-----------------------------------------")
139
  sonnet_html = markdown2.markdown(sonnet_text, extras=["fenced-code-blocks", "tables"])
140
- if not sonnet_html or not sonnet_html.strip():
141
  sonnet_html = f"<pre>{sonnet_text}</pre>"
142
  yield f"data: {json.dumps({'partial_result': {'id': 'sonnet-output', 'content': sonnet_html}})}\n\n"
143
 
144
  # GEMINI
145
  gemini_text = results.get('gemini', '')
146
- print("--- Resposta Bruta do Gemini (Atômico) ---")
147
- print(gemini_text)
148
- print("-----------------------------------------")
149
  gemini_html = markdown2.markdown(gemini_text, extras=["fenced-code-blocks", "tables"])
150
- if not gemini_html or not gemini_html.strip():
151
  gemini_html = f"<pre>{gemini_text}</pre>"
152
  yield f"data: {json.dumps({'partial_result': {'id': 'gemini-output', 'content': gemini_html}})}\n\n"
153
 
@@ -161,17 +159,13 @@ def process():
161
  resposta_grok = chain_grok.invoke({"solicitacao_usuario": solicitacao_usuario, "rag_context": rag_context})['text']
162
 
163
  if not resposta_grok or not resposta_grok.strip():
164
- yield f"data: {json.dumps({'error': 'Falha no serviço GROK: Sem resposta. O processo foi interrompido.'})}\n\n"
165
  return
166
 
167
- print("--- Resposta Bruta do GROK (Hierárquico) ---")
168
- print(resposta_grok)
169
- print("-------------------------------------------")
170
  grok_html = markdown2.markdown(resposta_grok, extras=["fenced-code-blocks", "tables"])
171
- if not grok_html or not grok_html.strip():
172
  grok_html = f"<pre>{resposta_grok}</pre>"
173
-
174
- yield f"data: {json.dumps({'progress': 33, 'message': 'Agora, o Claude Sonnet está aprofundando o texto...', 'partial_result': {'id': 'grok-output', 'content': grok_html}})}\n\n"
175
 
176
  prompt_sonnet = PromptTemplate(template=PROMPT_HIERARQUICO_SONNET, input_variables=["solicitacao_usuario", "texto_para_analise"])
177
  claude_with_max_tokens = claude_llm.bind(max_tokens=20000)
@@ -179,33 +173,25 @@ def process():
179
  resposta_sonnet = chain_sonnet.invoke({"solicitacao_usuario": solicitacao_usuario, "texto_para_analise": resposta_grok})['text']
180
 
181
  if not resposta_sonnet or not resposta_sonnet.strip():
182
- yield f"data: {json.dumps({'error': 'Falha no serviço Claude Sonnet: Sem resposta. O processo foi interrompido.'})}\n\n"
183
  return
184
 
185
- print("--- Resposta Bruta do Sonnet (Hierárquico) ---")
186
- print(resposta_sonnet)
187
- print("---------------------------------------------")
188
  sonnet_html = markdown2.markdown(resposta_sonnet, extras=["fenced-code-blocks", "tables"])
189
- if not sonnet_html or not sonnet_html.strip():
190
  sonnet_html = f"<pre>{resposta_sonnet}</pre>"
191
-
192
- yield f"data: {json.dumps({'progress': 66, 'message': 'Revisão final com o Gemini...', 'partial_result': {'id': 'sonnet-output', 'content': sonnet_html}})}\n\n"
193
 
194
  prompt_gemini = PromptTemplate(template=PROMPT_HIERARQUICO_GEMINI, input_variables=["solicitacao_usuario", "texto_para_analise"])
195
  chain_gemini = LLMChain(llm=gemini_llm, prompt=prompt_gemini)
196
  resposta_gemini = chain_gemini.invoke({"solicitacao_usuario": solicitacao_usuario, "texto_para_analise": resposta_sonnet})['text']
197
 
198
  if not resposta_gemini or not resposta_gemini.strip():
199
- yield f"data: {json.dumps({'error': 'Falha no serviço Gemini: Sem resposta. O processo foi interrompido.'})}\n\n"
200
  return
201
 
202
- print("--- Resposta Bruta do Gemini (Hierárquico) ---")
203
- print(resposta_gemini)
204
- print("---------------------------------------------")
205
  gemini_html = markdown2.markdown(resposta_gemini, extras=["fenced-code-blocks", "tables"])
206
- if not gemini_html or not gemini_html.strip():
207
  gemini_html = f"<pre>{resposta_gemini}</pre>"
208
-
209
  yield f"data: {json.dumps({'progress': 100, 'message': 'Processamento concluído!', 'partial_result': {'id': 'gemini-output', 'content': gemini_html}, 'done': True, 'mode': 'hierarchical'})}\n\n"
210
 
211
  except Exception as e:
@@ -214,7 +200,6 @@ def process():
214
 
215
  return Response(generate_stream(mode, form_data, temp_file_paths), mimetype='text/event-stream')
216
 
217
- # --- ROTA PARA O MERGE ---
218
  @app.route('/merge', methods=['POST'])
219
  def merge():
220
  """Recebe os textos do modo Atômico e os consolida usando um LLM."""
@@ -226,7 +211,6 @@ def merge():
226
  yield f"data: {json.dumps({'progress': 0, 'message': 'Iniciando o processo de merge...'})}\n\n"
227
 
228
  prompt_merge = PromptTemplate(template=PROMPT_ATOMICO_MERGE, input_variables=["solicitacao_usuario", "texto_para_analise_grok", "texto_para_analise_sonnet", "texto_para_analise_gemini"])
229
-
230
  chain_merge = LLMChain(llm=grok_llm, prompt=prompt_merge)
231
 
232
  yield f"data: {json.dumps({'progress': 50, 'message': 'Enviando textos para o GROK para consolidação...'})}\n\n"
@@ -254,5 +238,4 @@ def merge():
254
  return Response(generate_merge_stream(), mimetype='text/event-stream')
255
 
256
  if __name__ == '__main__':
257
- # Executa a aplicação Flask em modo de depuração
258
  app.run(debug=True)
 
1
  # app.py
2
 
3
+ from flask import Flask, render_template, request, Response
4
  import markdown2
5
  import json
6
  import time
7
  import os
8
  import uuid
9
  import threading
10
+ import concurrent.futures
11
+ import re # Importação para expressões regulares
12
 
13
  # Importações do LangChain
14
  from langchain.prompts import PromptTemplate
 
29
  if not os.path.exists('uploads'):
30
  os.makedirs('uploads')
31
 
32
+ app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024
33
+
34
+ def is_html_empty(html: str) -> bool:
35
+ """Verifica se uma string HTML não contém texto visível."""
36
+ if not html:
37
+ return True
38
+ # Remove todas as tags HTML
39
+ text_only = re.sub('<[^<]+?>', '', html)
40
+ # Verifica se o texto restante é apenas espaço em branco
41
+ return not text_only.strip()
42
 
43
  @app.route('/')
44
  def index():
 
57
  if mode == 'real':
58
  for file in files:
59
  if file and file.filename:
 
60
  unique_filename = str(uuid.uuid4()) + "_" + os.path.basename(file.filename)
61
  file_path = os.path.join('uploads', unique_filename)
62
  file.save(file_path)
 
67
  solicitacao_usuario = form_data.get('solicitacao', '')
68
 
69
  if current_mode == 'test':
 
70
  mock_text = form_data.get('mock_text', 'Este é um texto de simulação.')
71
  mock_html = markdown2.markdown(mock_text, extras=["fenced-code-blocks", "tables"])
72
  yield f"data: {json.dumps({'progress': 100, 'message': 'Simulação concluída!', 'partial_result': {'id': 'grok-output', 'content': mock_html}, 'done': True, 'mode': 'atomic' if processing_mode == 'atomic' else 'hierarchical'})}\n\n"
 
74
  yield f"data: {json.dumps({'partial_result': {'id': 'sonnet-output', 'content': mock_html}})}\n\n"
75
  yield f"data: {json.dumps({'partial_result': {'id': 'gemini-output', 'content': mock_html}})}\n\n"
76
  else:
 
77
  if not solicitacao_usuario:
78
  yield f"data: {json.dumps({'error': 'Solicitação não fornecida.'})}\n\n"
79
  return
 
88
  threads = []
89
 
90
  def run_chain_with_timeout(chain, inputs, key, timeout=300):
 
91
  def task():
92
  return chain.invoke(inputs)['text']
93
 
 
104
  except Exception as e:
105
  results[key] = f"Erro ao processar {key.upper()}: {e}"
106
 
107
+ # CORREÇÃO: Aumenta o max_tokens para o Claude Sonnet também no modo atômico
108
+ claude_atomic_llm = claude_llm.bind(max_tokens=20000)
109
+ models = {'grok': grok_llm, 'sonnet': claude_atomic_llm, 'gemini': gemini_llm}
110
+
111
  prompt = PromptTemplate(template=PROMPT_ATOMICO_INICIAL, input_variables=["solicitacao_usuario", "rag_context"])
112
  yield f"data: {json.dumps({'progress': 15, 'message': 'Iniciando processamento paralelo...'})}\n\n"
113
 
 
128
 
129
  yield f"data: {json.dumps({'progress': 80, 'message': 'Todos os modelos responderam. Formatando saídas...'})}\n\n"
130
 
 
 
131
  # GROK
132
  grok_text = results.get('grok', '')
 
 
 
133
  grok_html = markdown2.markdown(grok_text, extras=["fenced-code-blocks", "tables"])
134
+ if is_html_empty(grok_html):
135
  grok_html = f"<pre>{grok_text}</pre>"
136
  yield f"data: {json.dumps({'partial_result': {'id': 'grok-output', 'content': grok_html}})}\n\n"
137
 
138
  # SONNET
139
  sonnet_text = results.get('sonnet', '')
 
 
 
140
  sonnet_html = markdown2.markdown(sonnet_text, extras=["fenced-code-blocks", "tables"])
141
+ if is_html_empty(sonnet_html):
142
  sonnet_html = f"<pre>{sonnet_text}</pre>"
143
  yield f"data: {json.dumps({'partial_result': {'id': 'sonnet-output', 'content': sonnet_html}})}\n\n"
144
 
145
  # GEMINI
146
  gemini_text = results.get('gemini', '')
 
 
 
147
  gemini_html = markdown2.markdown(gemini_text, extras=["fenced-code-blocks", "tables"])
148
+ if is_html_empty(gemini_html):
149
  gemini_html = f"<pre>{gemini_text}</pre>"
150
  yield f"data: {json.dumps({'partial_result': {'id': 'gemini-output', 'content': gemini_html}})}\n\n"
151
 
 
159
  resposta_grok = chain_grok.invoke({"solicitacao_usuario": solicitacao_usuario, "rag_context": rag_context})['text']
160
 
161
  if not resposta_grok or not resposta_grok.strip():
162
+ yield f"data: {json.dumps({'error': 'Falha no serviço GROK: Sem resposta.'})}\n\n"
163
  return
164
 
 
 
 
165
  grok_html = markdown2.markdown(resposta_grok, extras=["fenced-code-blocks", "tables"])
166
+ if is_html_empty(grok_html):
167
  grok_html = f"<pre>{resposta_grok}</pre>"
168
+ yield f"data: {json.dumps({'progress': 33, 'message': 'Claude Sonnet está processando...', 'partial_result': {'id': 'grok-output', 'content': grok_html}})}\n\n"
 
169
 
170
  prompt_sonnet = PromptTemplate(template=PROMPT_HIERARQUICO_SONNET, input_variables=["solicitacao_usuario", "texto_para_analise"])
171
  claude_with_max_tokens = claude_llm.bind(max_tokens=20000)
 
173
  resposta_sonnet = chain_sonnet.invoke({"solicitacao_usuario": solicitacao_usuario, "texto_para_analise": resposta_grok})['text']
174
 
175
  if not resposta_sonnet or not resposta_sonnet.strip():
176
+ yield f"data: {json.dumps({'error': 'Falha no serviço Claude Sonnet: Sem resposta.'})}\n\n"
177
  return
178
 
 
 
 
179
  sonnet_html = markdown2.markdown(resposta_sonnet, extras=["fenced-code-blocks", "tables"])
180
+ if is_html_empty(sonnet_html):
181
  sonnet_html = f"<pre>{resposta_sonnet}</pre>"
182
+ yield f"data: {json.dumps({'progress': 66, 'message': 'Gemini está processando...', 'partial_result': {'id': 'sonnet-output', 'content': sonnet_html}})}\n\n"
 
183
 
184
  prompt_gemini = PromptTemplate(template=PROMPT_HIERARQUICO_GEMINI, input_variables=["solicitacao_usuario", "texto_para_analise"])
185
  chain_gemini = LLMChain(llm=gemini_llm, prompt=prompt_gemini)
186
  resposta_gemini = chain_gemini.invoke({"solicitacao_usuario": solicitacao_usuario, "texto_para_analise": resposta_sonnet})['text']
187
 
188
  if not resposta_gemini or not resposta_gemini.strip():
189
+ yield f"data: {json.dumps({'error': 'Falha no serviço Gemini: Sem resposta.'})}\n\n"
190
  return
191
 
 
 
 
192
  gemini_html = markdown2.markdown(resposta_gemini, extras=["fenced-code-blocks", "tables"])
193
+ if is_html_empty(gemini_html):
194
  gemini_html = f"<pre>{resposta_gemini}</pre>"
 
195
  yield f"data: {json.dumps({'progress': 100, 'message': 'Processamento concluído!', 'partial_result': {'id': 'gemini-output', 'content': gemini_html}, 'done': True, 'mode': 'hierarchical'})}\n\n"
196
 
197
  except Exception as e:
 
200
 
201
  return Response(generate_stream(mode, form_data, temp_file_paths), mimetype='text/event-stream')
202
 
 
203
  @app.route('/merge', methods=['POST'])
204
  def merge():
205
  """Recebe os textos do modo Atômico e os consolida usando um LLM."""
 
211
  yield f"data: {json.dumps({'progress': 0, 'message': 'Iniciando o processo de merge...'})}\n\n"
212
 
213
  prompt_merge = PromptTemplate(template=PROMPT_ATOMICO_MERGE, input_variables=["solicitacao_usuario", "texto_para_analise_grok", "texto_para_analise_sonnet", "texto_para_analise_gemini"])
 
214
  chain_merge = LLMChain(llm=grok_llm, prompt=prompt_merge)
215
 
216
  yield f"data: {json.dumps({'progress': 50, 'message': 'Enviando textos para o GROK para consolidação...'})}\n\n"
 
238
  return Response(generate_merge_stream(), mimetype='text/event-stream')
239
 
240
  if __name__ == '__main__':
 
241
  app.run(debug=True)