victorafarias commited on
Commit
a81bbe2
·
1 Parent(s): 0c6d84c

Correções e evoluções

Browse files
Files changed (1) hide show
  1. app.py +43 -8
app.py CHANGED
@@ -24,14 +24,20 @@ from rag_processor import get_relevant_context
24
 
25
  app = Flask(__name__)
26
 
 
 
 
 
27
  app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024
28
 
29
  @app.route('/')
30
  def index():
 
31
  return render_template('index.html')
32
 
33
  @app.route('/process', methods=['POST'])
34
  def process():
 
35
  form_data = request.form
36
  files = request.files.getlist('files')
37
  mode = form_data.get('mode', 'real')
@@ -41,15 +47,18 @@ def process():
41
  if mode == 'real':
42
  for file in files:
43
  if file and file.filename:
44
- unique_filename = str(uuid.uuid4()) + "_" + file.filename
 
45
  file_path = os.path.join('uploads', unique_filename)
46
  file.save(file_path)
47
  temp_file_paths.append(file_path)
48
 
49
  def generate_stream(current_mode, form_data, file_paths):
 
50
  solicitacao_usuario = form_data.get('solicitacao', '')
51
 
52
  if current_mode == 'test':
 
53
  mock_text = form_data.get('mock_text', 'Este é um texto de simulação.')
54
  mock_html = markdown2.markdown(mock_text, extras=["fenced-code-blocks", "tables"])
55
  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"
@@ -57,6 +66,7 @@ def process():
57
  yield f"data: {json.dumps({'partial_result': {'id': 'sonnet-output', 'content': mock_html}})}\n\n"
58
  yield f"data: {json.dumps({'partial_result': {'id': 'gemini-output', 'content': mock_html}})}\n\n"
59
  else:
 
60
  if not solicitacao_usuario:
61
  yield f"data: {json.dumps({'error': 'Solicitação não fornecida.'})}\n\n"
62
  return
@@ -66,10 +76,12 @@ def process():
66
  rag_context = get_relevant_context(file_paths, solicitacao_usuario)
67
 
68
  if processing_mode == 'atomic':
 
69
  results = {}
70
  threads = []
71
 
72
  def run_chain_with_timeout(chain, inputs, key, timeout=300):
 
73
  def task():
74
  return chain.invoke(inputs)['text']
75
 
@@ -77,6 +89,7 @@ def process():
77
  future = executor.submit(task)
78
  try:
79
  result = future.result(timeout=timeout)
 
80
  if not result or not result.strip():
81
  results[key] = "Error:EmptyResponse"
82
  else:
@@ -99,11 +112,12 @@ def process():
99
  for thread in threads:
100
  thread.join()
101
 
 
102
  for key, result in results.items():
103
  if result == "Error:EmptyResponse" or "Erro ao processar" in result:
104
  error_msg = result if "Erro ao processar" in result else f"Falha no serviço {key.upper()}: Sem resposta."
105
  yield f"data: {json.dumps({'error': error_msg})}\n\n"
106
- return
107
 
108
  yield f"data: {json.dumps({'progress': 80, 'message': 'Todos os modelos responderam. Formatando saída...'})}\n\n"
109
 
@@ -115,13 +129,19 @@ def process():
115
  yield f"data: {json.dumps({'partial_result': {'id': 'gemini-output', 'content': gemini_html}})}\n\n"
116
 
117
  yield f"data: {json.dumps({'progress': 100, 'message': 'Processamento Atômico concluído!', 'done': True, 'mode': 'atomic'})}\n\n"
 
118
  else:
119
  # --- LÓGICA HIERÁRQUICA (SEQUENCIAL) ---
120
- yield f"data: {json.dumps({'progress': 15, 'message': 'O GROK está processando sua solicitação com os arquivos...'})}\n\n"
121
  prompt_grok = PromptTemplate(template=PROMPT_HIERARQUICO_GROK, input_variables=["solicitacao_usuario", "rag_context"])
122
  chain_grok = LLMChain(llm=grok_llm, prompt=prompt_grok)
123
  resposta_grok = chain_grok.invoke({"solicitacao_usuario": solicitacao_usuario, "rag_context": rag_context})['text']
124
- if not resposta_grok or not resposta_grok.strip(): raise ValueError("Falha no serviço GROK: Sem resposta.")
 
 
 
 
 
125
  grok_html = markdown2.markdown(resposta_grok, extras=["fenced-code-blocks", "tables"])
126
  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"
127
 
@@ -129,14 +149,24 @@ def process():
129
  claude_with_max_tokens = claude_llm.bind(max_tokens=20000)
130
  chain_sonnet = LLMChain(llm=claude_with_max_tokens, prompt=prompt_sonnet)
131
  resposta_sonnet = chain_sonnet.invoke({"solicitacao_usuario": solicitacao_usuario, "texto_para_analise": resposta_grok})['text']
132
- if not resposta_sonnet or not resposta_sonnet.strip(): raise ValueError("Falha no serviço Claude Sonnet: Sem resposta.")
 
 
 
 
 
133
  sonnet_html = markdown2.markdown(resposta_sonnet, extras=["fenced-code-blocks", "tables"])
134
- yield f"data: {json.dumps({'progress': 66, 'message': 'Estamos quase lá! Seu texto está passando por uma revisão final com o Gemini...', 'partial_result': {'id': 'sonnet-output', 'content': sonnet_html}})}\n\n"
135
 
136
  prompt_gemini = PromptTemplate(template=PROMPT_HIERARQUICO_GEMINI, input_variables=["solicitacao_usuario", "texto_para_analise"])
137
  chain_gemini = LLMChain(llm=gemini_llm, prompt=prompt_gemini)
138
  resposta_gemini = chain_gemini.invoke({"solicitacao_usuario": solicitacao_usuario, "texto_para_analise": resposta_sonnet})['text']
139
- if not resposta_gemini or not resposta_gemini.strip(): raise ValueError("Falha no serviço Gemini: Sem resposta.")
 
 
 
 
 
140
  gemini_html = markdown2.markdown(resposta_gemini, extras=["fenced-code-blocks", "tables"])
141
  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"
142
 
@@ -149,9 +179,11 @@ def process():
149
  # --- ROTA PARA O MERGE ---
150
  @app.route('/merge', methods=['POST'])
151
  def merge():
 
152
  data = request.get_json()
153
 
154
  def generate_merge_stream():
 
155
  try:
156
  yield f"data: {json.dumps({'progress': 0, 'message': 'Iniciando o processo de merge...'})}\n\n"
157
 
@@ -168,8 +200,10 @@ def merge():
168
  "texto_para_analise_gemini": data.get('gemini_text')
169
  })['text']
170
 
 
171
  if not resposta_merge or not resposta_merge.strip():
172
- raise ValueError("Falha no serviço de Merge (GROK): Sem resposta.")
 
173
 
174
  word_count = len(resposta_merge.split())
175
  merge_html = markdown2.markdown(resposta_merge, extras=["fenced-code-blocks", "tables"])
@@ -183,4 +217,5 @@ def merge():
183
  return Response(generate_merge_stream(), mimetype='text/event-stream')
184
 
185
  if __name__ == '__main__':
 
186
  app.run(debug=True)
 
24
 
25
  app = Flask(__name__)
26
 
27
+ # Garante que o diretório de uploads exista
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():
35
+ """Renderiza a página inicial da aplicação."""
36
  return render_template('index.html')
37
 
38
  @app.route('/process', methods=['POST'])
39
  def process():
40
+ """Processa a solicitação do usuário nos modos Hierárquico ou Atômico."""
41
  form_data = request.form
42
  files = request.files.getlist('files')
43
  mode = form_data.get('mode', 'real')
 
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)
54
  temp_file_paths.append(file_path)
55
 
56
  def generate_stream(current_mode, form_data, file_paths):
57
+ """Gera a resposta em streaming para o front-end."""
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
  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
 
76
  rag_context = get_relevant_context(file_paths, solicitacao_usuario)
77
 
78
  if processing_mode == 'atomic':
79
+ # --- LÓGICA ATÔMICA (PARALELA) ---
80
  results = {}
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
 
 
89
  future = executor.submit(task)
90
  try:
91
  result = future.result(timeout=timeout)
92
+ # Validação de resposta vazia
93
  if not result or not result.strip():
94
  results[key] = "Error:EmptyResponse"
95
  else:
 
112
  for thread in threads:
113
  thread.join()
114
 
115
+ # Verifica se alguma thread falhou ou retornou vazio
116
  for key, result in results.items():
117
  if result == "Error:EmptyResponse" or "Erro ao processar" in result:
118
  error_msg = result if "Erro ao processar" in result else f"Falha no serviço {key.upper()}: Sem resposta."
119
  yield f"data: {json.dumps({'error': error_msg})}\n\n"
120
+ return # Interrompe todo o processo
121
 
122
  yield f"data: {json.dumps({'progress': 80, 'message': 'Todos os modelos responderam. Formatando saída...'})}\n\n"
123
 
 
129
  yield f"data: {json.dumps({'partial_result': {'id': 'gemini-output', 'content': gemini_html}})}\n\n"
130
 
131
  yield f"data: {json.dumps({'progress': 100, 'message': 'Processamento Atômico concluído!', 'done': True, 'mode': 'atomic'})}\n\n"
132
+
133
  else:
134
  # --- LÓGICA HIERÁRQUICA (SEQUENCIAL) ---
135
+ yield f"data: {json.dumps({'progress': 15, 'message': 'O GROK está processando sua solicitação...'})}\n\n"
136
  prompt_grok = PromptTemplate(template=PROMPT_HIERARQUICO_GROK, input_variables=["solicitacao_usuario", "rag_context"])
137
  chain_grok = LLMChain(llm=grok_llm, prompt=prompt_grok)
138
  resposta_grok = chain_grok.invoke({"solicitacao_usuario": solicitacao_usuario, "rag_context": rag_context})['text']
139
+
140
+ # ✅ VALIDAÇÃO APRIMORADA
141
+ if not resposta_grok or not resposta_grok.strip():
142
+ yield f"data: {json.dumps({'error': 'Falha no serviço GROK: Sem resposta. O processo foi interrompido.'})}\n\n"
143
+ return
144
+
145
  grok_html = markdown2.markdown(resposta_grok, extras=["fenced-code-blocks", "tables"])
146
  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"
147
 
 
149
  claude_with_max_tokens = claude_llm.bind(max_tokens=20000)
150
  chain_sonnet = LLMChain(llm=claude_with_max_tokens, prompt=prompt_sonnet)
151
  resposta_sonnet = chain_sonnet.invoke({"solicitacao_usuario": solicitacao_usuario, "texto_para_analise": resposta_grok})['text']
152
+
153
+ # ✅ VALIDAÇÃO APRIMORADA
154
+ if not resposta_sonnet or not resposta_sonnet.strip():
155
+ yield f"data: {json.dumps({'error': 'Falha no serviço Claude Sonnet: Sem resposta. O processo foi interrompido.'})}\n\n"
156
+ return
157
+
158
  sonnet_html = markdown2.markdown(resposta_sonnet, extras=["fenced-code-blocks", "tables"])
159
+ yield f"data: {json.dumps({'progress': 66, 'message': 'Revisão final com o Gemini...'})}\n\n"
160
 
161
  prompt_gemini = PromptTemplate(template=PROMPT_HIERARQUICO_GEMINI, input_variables=["solicitacao_usuario", "texto_para_analise"])
162
  chain_gemini = LLMChain(llm=gemini_llm, prompt=prompt_gemini)
163
  resposta_gemini = chain_gemini.invoke({"solicitacao_usuario": solicitacao_usuario, "texto_para_analise": resposta_sonnet})['text']
164
+
165
+ # ✅ VALIDAÇÃO APRIMORADA
166
+ if not resposta_gemini or not resposta_gemini.strip():
167
+ yield f"data: {json.dumps({'error': 'Falha no serviço Gemini: Sem resposta. O processo foi interrompido.'})}\n\n"
168
+ return
169
+
170
  gemini_html = markdown2.markdown(resposta_gemini, extras=["fenced-code-blocks", "tables"])
171
  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"
172
 
 
179
  # --- ROTA PARA O MERGE ---
180
  @app.route('/merge', methods=['POST'])
181
  def merge():
182
+ """Recebe os textos do modo Atômico e os consolida usando um LLM."""
183
  data = request.get_json()
184
 
185
  def generate_merge_stream():
186
+ """Gera a resposta do merge em streaming."""
187
  try:
188
  yield f"data: {json.dumps({'progress': 0, 'message': 'Iniciando o processo de merge...'})}\n\n"
189
 
 
200
  "texto_para_analise_gemini": data.get('gemini_text')
201
  })['text']
202
 
203
+ # ✅ VALIDAÇÃO APRIMORADA
204
  if not resposta_merge or not resposta_merge.strip():
205
+ yield f"data: {json.dumps({'error': 'Falha no serviço de Merge (GROK): Sem resposta.'})}\n\n"
206
+ return
207
 
208
  word_count = len(resposta_merge.split())
209
  merge_html = markdown2.markdown(resposta_merge, extras=["fenced-code-blocks", "tables"])
 
217
  return Response(generate_merge_stream(), mimetype='text/event-stream')
218
 
219
  if __name__ == '__main__':
220
+ # Executa a aplicação Flask em modo de depuração
221
  app.run(debug=True)