luanpoppe commited on
Commit
012cf60
·
2 Parent(s): ecc78bf 75f900c

Merge branch 'feat-adicionar-etapas-ao-gerar-documento' of https://github.com/luanpoppe/vella-backend into tests

Browse files
_utils/gerar_documento.py CHANGED
@@ -53,7 +53,7 @@ async def gerar_documento(
53
  contextual_retriever = ContextualRetriever(serializer)
54
 
55
  # Initialize enhanced summarizer
56
- summarizer = GerarDocumento(serializer)
57
 
58
  all_PDFs_chunks, full_text_as_array = await get_full_text_and_all_PDFs_chunks(
59
  listaPDFs,
 
53
  contextual_retriever = ContextualRetriever(serializer)
54
 
55
  # Initialize enhanced summarizer
56
+ summarizer = GerarDocumento(serializer, axiom_instance)
57
 
58
  all_PDFs_chunks, full_text_as_array = await get_full_text_and_all_PDFs_chunks(
59
  listaPDFs,
_utils/gerar_relatorio_modelo_usuario/GerarDocumento.py CHANGED
@@ -1,8 +1,11 @@
 
1
  import os
2
  from typing import Any, List, Dict, Literal, Tuple, Optional, Union, cast
3
 
4
  from pydantic import SecretStr
 
5
  from _utils.langchain_utils.LLM_class import LLM
 
6
  from _utils.langchain_utils.Vector_store_class import VectorStore
7
  from gerar_documento.serializer import (
8
  GerarDocumentoComPDFProprioSerializerData,
@@ -27,6 +30,8 @@ from cohere import Client
27
  from _utils.langchain_utils.Splitter_class import Splitter
28
  import time
29
 
 
 
30
 
31
  def reciprocal_rank_fusion(result_lists, weights=None):
32
  """Combine multiple ranked lists using reciprocal rank fusion"""
@@ -47,16 +52,51 @@ def reciprocal_rank_fusion(result_lists, weights=None):
47
  return sorted_results
48
 
49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  class GerarDocumento:
51
  openai_api_key = os.environ.get("OPENAI_API_KEY", "")
52
  cohere_api_key = os.environ.get("COHERE_API_KEY", "")
53
  resumo_gerado = ""
 
54
 
55
  def __init__(
56
  self,
57
  serializer: Union[
58
  GerarDocumentoSerializerData, GerarDocumentoComPDFProprioSerializerData, Any
59
  ],
 
60
  ):
61
  self.config = RetrievalConfig(
62
  num_chunks=serializer.num_chunks_retrieval,
@@ -77,8 +117,11 @@ class GerarDocumento:
77
  self.num_k_rerank = serializer.num_k_rerank
78
  self.model_cohere_rerank = serializer.model_cohere_rerank
79
  self.splitter = Splitter(serializer.chunk_size, serializer.chunk_overlap)
 
 
80
 
81
  self.vector_store = VectorStore(serializer.hf_embedding)
 
82
 
83
  def retrieve_with_rank_fusion(
84
  self, vector_store: Chroma, bm25: BM25Okapi, chunk_ids: List[str], query: str
@@ -205,17 +248,18 @@ class GerarDocumento:
205
  input_variables=["context"],
206
  )
207
 
 
 
208
  documento_gerado = ""
209
  tentativas = 0
 
 
 
 
210
 
211
  while tentativas < 5 and not documento_gerado:
212
  tentativas += 1
213
- llm = self.select_model_for_last_requests(llm_ultimas_requests) # type: ignore
214
- resposta = llm.invoke(
215
- prompt_gerar_documento.format(
216
- context="\n\n".join(contexts),
217
- )
218
- )
219
  if hasattr(resposta, "content") and resposta.content.strip(): # type: ignore
220
  documento_gerado = resposta.content.strip() # type: ignore
221
  else:
@@ -223,44 +267,48 @@ class GerarDocumento:
223
  time.sleep(5)
224
 
225
  if not documento_gerado:
226
- llm = self.select_model_for_last_requests("gpt-4o-mini")
227
- resposta = llm.invoke(
228
- prompt_gerar_documento.format(
229
- context="\n\n".join(contexts),
230
- )
231
  )
232
- documento_gerado = resposta.content.strip() # type: ignore
233
- if not documento_gerado:
234
- raise Exception(
235
- "Falha ao tentar gerar o documento final por 5 tentativas e também ao tentar na última tentativa com o chat-gpt 4o mini."
236
  )
 
237
 
238
- # Split the response into paragraphs
239
- summaries = [p.strip() for p in documento_gerado.split("\n\n") if p.strip()]
240
 
241
- # Create structured output
242
- structured_output = []
243
- for idx, summary in enumerate(summaries):
244
- source_idx = min(idx, len(sources) - 1)
245
- structured_output.append(
246
- {
247
- "content": summary,
248
- "source": {
249
- "page": sources[source_idx]["page"],
250
- "text": sources[source_idx]["content"][:200] + "...",
251
- "context": sources[source_idx]["context"],
252
- "relevance_score": sources[source_idx]["relevance_score"],
253
- "chunk_id": sources[source_idx]["chunk_id"],
254
- },
255
- }
 
 
256
  )
 
 
257
 
 
 
 
 
 
 
 
 
258
  return structured_output
259
 
260
  except Exception as e:
261
  self.logger.error(f"Error generating enhanced summary: {str(e)}")
262
  raise
263
-
264
- async def validar_conteudo_documento_final(self):
265
- documento_gerado = ""
266
- tentativas = 0
 
1
+ from dataclasses import dataclass
2
  import os
3
  from typing import Any, List, Dict, Literal, Tuple, Optional, Union, cast
4
 
5
  from pydantic import SecretStr
6
+ from _utils.langchain_utils.Chain_class import Chain
7
  from _utils.langchain_utils.LLM_class import LLM
8
+ from _utils.langchain_utils.Prompt_class import Prompt
9
  from _utils.langchain_utils.Vector_store_class import VectorStore
10
  from gerar_documento.serializer import (
11
  GerarDocumentoComPDFProprioSerializerData,
 
30
  from _utils.langchain_utils.Splitter_class import Splitter
31
  import time
32
 
33
+ from setup.logging import Axiom
34
+
35
 
36
  def reciprocal_rank_fusion(result_lists, weights=None):
37
  """Combine multiple ranked lists using reciprocal rank fusion"""
 
52
  return sorted_results
53
 
54
 
55
+ @dataclass
56
+ class GerarDocumentoUtils:
57
+ def criar_output_estruturado(self, summaries: List[str | Any], sources: Any):
58
+ structured_output = []
59
+ for idx, summary in enumerate(summaries):
60
+ source_idx = min(idx, len(sources) - 1)
61
+ structured_output.append(
62
+ {
63
+ "content": summary,
64
+ "source": {
65
+ "page": sources[source_idx]["page"],
66
+ "text": sources[source_idx]["content"][:200] + "...",
67
+ "context": sources[source_idx]["context"],
68
+ "relevance_score": sources[source_idx]["relevance_score"],
69
+ "chunk_id": sources[source_idx]["chunk_id"],
70
+ },
71
+ }
72
+ )
73
+
74
+ return structured_output
75
+
76
+ def ultima_tentativa_requisicao(self, prompt_gerar_documento_formatado):
77
+ llm = LLM()
78
+ resposta = llm.open_ai().invoke(prompt_gerar_documento_formatado)
79
+ documento_gerado = resposta.content.strip() # type: ignore
80
+ if not documento_gerado:
81
+ raise Exception(
82
+ "Falha ao tentar gerar o documento final por 5 tentativas e também ao tentar na última tentativa com o chat-gpt 4o mini."
83
+ )
84
+ else:
85
+ return documento_gerado
86
+
87
+
88
  class GerarDocumento:
89
  openai_api_key = os.environ.get("OPENAI_API_KEY", "")
90
  cohere_api_key = os.environ.get("COHERE_API_KEY", "")
91
  resumo_gerado = ""
92
+ gerar_documento_utils = GerarDocumentoUtils()
93
 
94
  def __init__(
95
  self,
96
  serializer: Union[
97
  GerarDocumentoSerializerData, GerarDocumentoComPDFProprioSerializerData, Any
98
  ],
99
+ axiom_instance: Axiom,
100
  ):
101
  self.config = RetrievalConfig(
102
  num_chunks=serializer.num_chunks_retrieval,
 
117
  self.num_k_rerank = serializer.num_k_rerank
118
  self.model_cohere_rerank = serializer.model_cohere_rerank
119
  self.splitter = Splitter(serializer.chunk_size, serializer.chunk_overlap)
120
+ self.prompt_gerar_documento_etapa_2 = serializer.prompt_gerar_documento_etapa_2
121
+ self.prompt_gerar_documento_etapa_3 = serializer.prompt_gerar_documento_etapa_3
122
 
123
  self.vector_store = VectorStore(serializer.hf_embedding)
124
+ self.axiom_instance: Axiom = axiom_instance
125
 
126
  def retrieve_with_rank_fusion(
127
  self, vector_store: Chroma, bm25: BM25Okapi, chunk_ids: List[str], query: str
 
248
  input_variables=["context"],
249
  )
250
 
251
+ llm = self.select_model_for_last_requests(llm_ultimas_requests) # type: ignore
252
+ prompt_instance = Prompt()
253
  documento_gerado = ""
254
  tentativas = 0
255
+ context_do_prompt_primeira_etapa = "\n\n".join(contexts)
256
+ prompt_primeira_etapa = prompt_gerar_documento.format(
257
+ context=context_do_prompt_primeira_etapa,
258
+ )
259
 
260
  while tentativas < 5 and not documento_gerado:
261
  tentativas += 1
262
+ resposta = llm.invoke(prompt_primeira_etapa)
 
 
 
 
 
263
  if hasattr(resposta, "content") and resposta.content.strip(): # type: ignore
264
  documento_gerado = resposta.content.strip() # type: ignore
265
  else:
 
267
  time.sleep(5)
268
 
269
  if not documento_gerado:
270
+ self.axiom_instance.send_axiom(
271
+ "TENTANDO GERAR DOCUMENTO FINAL COM GPT 4o-mini COMO ÚLTIMA TENTATIVA"
 
 
 
272
  )
273
+ documento_gerado = (
274
+ self.gerar_documento_utils.ultima_tentativa_requisicao(
275
+ prompt_primeira_etapa
 
276
  )
277
+ )
278
 
279
+ resposta_primeira_etapa = documento_gerado
 
280
 
281
+ if self.prompt_gerar_documento_etapa_2:
282
+ self.axiom_instance.send_axiom("GERANDO DOCUMENTO - COMEÇANDO ETAPA 2")
283
+ prompt_etapa_2 = prompt_instance.create_and_invoke_prompt(
284
+ self.prompt_gerar_documento_etapa_2,
285
+ dynamic_dict={"context": context_do_prompt_primeira_etapa},
286
+ )
287
+ documento_gerado = llm.invoke(prompt_etapa_2).content
288
+ resposta_segunda_etapa = documento_gerado
289
+ self.axiom_instance.send_axiom(f"RESULTADO ETAPA 2: {documento_gerado}")
290
+
291
+ if self.prompt_gerar_documento_etapa_3:
292
+ self.axiom_instance.send_axiom("GERANDO DOCUMENTO - COMEÇANDO ETAPA 3")
293
+ prompt_etapa_3 = prompt_instance.create_and_invoke_prompt(
294
+ self.prompt_gerar_documento_etapa_3,
295
+ dynamic_dict={
296
+ "context": f"{resposta_primeira_etapa}\n\n{resposta_segunda_etapa}"
297
+ },
298
  )
299
+ documento_gerado = llm.invoke(prompt_etapa_3).content
300
+ self.axiom_instance.send_axiom(f"RESULTADO ETAPA 3: {documento_gerado}")
301
 
302
+ # Split the response into paragraphs
303
+ summaries = [
304
+ p.strip() for p in documento_gerado.split("\n\n") if p.strip() # type: ignore
305
+ ]
306
+
307
+ structured_output = self.gerar_documento_utils.criar_output_estruturado(
308
+ summaries, sources
309
+ )
310
  return structured_output
311
 
312
  except Exception as e:
313
  self.logger.error(f"Error generating enhanced summary: {str(e)}")
314
  raise
 
 
 
 
gerar_documento/serializer.py CHANGED
@@ -1,5 +1,6 @@
1
  from dataclasses import dataclass, field
2
- from typing import List, Optional
 
3
  from rest_framework import serializers
4
  from _utils.gerar_relatorio_modelo_usuario.prompts import (
5
  prompt_gerar_documento,
@@ -64,12 +65,11 @@ class GerarDocumentoSerializer(GerarDocumentoInitialSerializer):
64
  required=False, default="version-test"
65
  ) # Será o valor utilizado dentro da URL da requisição pro Bubble
66
 
67
- # prompt_auxiliar = serializers.CharField(
68
- # required=False, default=prompt_auxiliar_padrao
69
- # )
70
  prompt_gerar_documento = serializers.CharField(
71
  required=False, default=prompt_gerar_documento
72
  )
 
 
73
  user_message = serializers.CharField(required=False, default=user_message)
74
  num_chunks_retrieval = serializers.IntegerField(default=20)
75
  embedding_weight = serializers.FloatField(default=0.5)
@@ -101,6 +101,8 @@ class GerarDocumentoSerializer(GerarDocumentoInitialSerializer):
101
 
102
  @dataclass
103
  class GerarDocumentoSerializerData(GerarDocumentoInitialSerializerData):
 
 
104
  files: List[FileInfoSerializerData]
105
  bubble_editor_version: str = "version-test"
106
  prompt_gerar_documento: str = ""
@@ -132,6 +134,8 @@ class GerarDocumentoComPDFProprioSerializer(GerarDocumentoInitialSerializer):
132
  prompt_gerar_documento = serializers.CharField(
133
  required=False, default=prompt_gerar_documento
134
  )
 
 
135
  user_message = serializers.CharField(required=False, default=user_message)
136
  num_chunks_retrieval = serializers.IntegerField(default=20)
137
  embedding_weight = serializers.FloatField(default=0.5)
@@ -158,6 +162,8 @@ class GerarDocumentoComPDFProprioSerializer(GerarDocumentoInitialSerializer):
158
 
159
  @dataclass
160
  class GerarDocumentoComPDFProprioSerializerData(GerarDocumentoInitialSerializerData):
 
 
161
  prompt_gerar_documento: Optional[str] = field(default=None)
162
  user_message: Optional[str] = field(default=None)
163
  num_chunks_retrieval: int = field(default=20)
 
1
  from dataclasses import dataclass, field
2
+ from email.policy import default
3
+ from typing import List, Optional, Union
4
  from rest_framework import serializers
5
  from _utils.gerar_relatorio_modelo_usuario.prompts import (
6
  prompt_gerar_documento,
 
65
  required=False, default="version-test"
66
  ) # Será o valor utilizado dentro da URL da requisição pro Bubble
67
 
 
 
 
68
  prompt_gerar_documento = serializers.CharField(
69
  required=False, default=prompt_gerar_documento
70
  )
71
+ prompt_gerar_documento_etapa_2 = serializers.CharField(required=False)
72
+ prompt_gerar_documento_etapa_3 = serializers.CharField(required=False)
73
  user_message = serializers.CharField(required=False, default=user_message)
74
  num_chunks_retrieval = serializers.IntegerField(default=20)
75
  embedding_weight = serializers.FloatField(default=0.5)
 
101
 
102
  @dataclass
103
  class GerarDocumentoSerializerData(GerarDocumentoInitialSerializerData):
104
+ prompt_gerar_documento_etapa_2: Union[str, None] = None
105
+ prompt_gerar_documento_etapa_3: Union[str, None] = None
106
  files: List[FileInfoSerializerData]
107
  bubble_editor_version: str = "version-test"
108
  prompt_gerar_documento: str = ""
 
134
  prompt_gerar_documento = serializers.CharField(
135
  required=False, default=prompt_gerar_documento
136
  )
137
+ prompt_gerar_documento_etapa_2 = serializers.CharField(required=False)
138
+ prompt_gerar_documento_etapa_3 = serializers.CharField(required=False)
139
  user_message = serializers.CharField(required=False, default=user_message)
140
  num_chunks_retrieval = serializers.IntegerField(default=20)
141
  embedding_weight = serializers.FloatField(default=0.5)
 
162
 
163
  @dataclass
164
  class GerarDocumentoComPDFProprioSerializerData(GerarDocumentoInitialSerializerData):
165
+ prompt_gerar_documento_etapa_2: Union[str, None] = None
166
+ prompt_gerar_documento_etapa_3: Union[str, None] = None
167
  prompt_gerar_documento: Optional[str] = field(default=None)
168
  user_message: Optional[str] = field(default=None)
169
  num_chunks_retrieval: int = field(default=20)