luanpoppe commited on
Commit
63cd221
·
1 Parent(s): aae4d3d

feat: adicionando mais refatorações e a nova rota para chamadas simples a LLMs

Browse files
_utils/gerar_documento_utils/GerarDocumento.py CHANGED
@@ -42,6 +42,7 @@ import time
42
  from setup.tokens import openai_api_key, cohere_api_key
43
  from setup.logging import Axiom
44
  import tiktoken
 
45
 
46
 
47
  def reciprocal_rank_fusion(result_lists, weights=None):
@@ -65,6 +66,10 @@ def reciprocal_rank_fusion(result_lists, weights=None):
65
 
66
  @dataclass
67
  class GerarDocumentoUtils:
 
 
 
 
68
  def criar_output_estruturado(self, summaries: List[str | Any], sources: Any):
69
  structured_output = []
70
  for idx, summary in enumerate(summaries):
@@ -109,6 +114,65 @@ class GerarDocumentoUtils:
109
  chunk_overlap=serializer.chunk_overlap,
110
  )
111
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
  class GerarDocumento:
114
  lista_pdfs: List[str]
@@ -118,7 +182,7 @@ class GerarDocumento:
118
  isBubble: bool
119
  chunks_processados: List[ContextualizedChunk] | List[DocumentChunk]
120
  resumo_auxiliar: str
121
- gerar_documento_utils = GerarDocumentoUtils()
122
  utils = UtilsClass()
123
  llm = LLM()
124
  enhanced_vector_store: tuple[Chroma, BM25Okapi, List[str]]
@@ -143,6 +207,7 @@ class GerarDocumento:
143
  self.config = self.gerar_documento_utils.create_retrieval_config(serializer)
144
  self.logger = logging.getLogger(__name__)
145
  # self.prompt_auxiliar = prompt_auxiliar
 
146
  self.gpt_model = serializer.model
147
  self.gpt_temperature = serializer.gpt_temperature
148
  self.prompt_gerar_documento = serializer.prompt_gerar_documento
@@ -318,29 +383,6 @@ class GerarDocumento:
318
 
319
  return sources, contexts
320
 
321
- def select_model_for_last_requests(
322
- self,
323
- llm_ultimas_requests: Literal[
324
- "gpt-4o-mini", "deepseek-chat", "gemini-2.0-flash", "gemini-2.5-pro"
325
- ],
326
- ):
327
- llm_instance = LLM()
328
- if llm_ultimas_requests == "gpt-4o-mini":
329
- llm = ChatOpenAI(
330
- temperature=self.gpt_temperature,
331
- model=self.gpt_model,
332
- api_key=SecretStr(openai_api_key),
333
- )
334
- elif llm_ultimas_requests == "deepseek-chat":
335
- llm = llm_instance.deepseek()
336
- elif llm_ultimas_requests == "gemini-2.0-flash":
337
- llm = llm_instance.google_gemini("gemini-2.0-flash")
338
- elif llm_ultimas_requests == "gemini-2.5-pro":
339
- llm = llm_instance.google_gemini("gemini-2.5-pro-preview-05-06")
340
- elif llm_ultimas_requests == "gemini-2.5-flash":
341
- llm = llm_instance.google_gemini("gemini-2.5-flash-preview-04-17")
342
- return llm
343
-
344
  async def do_last_requests(
345
  self,
346
  ) -> List[Dict]:
@@ -361,14 +403,15 @@ class GerarDocumento:
361
  )
362
 
363
  llm_ultimas_requests = self.llm_ultimas_requests
364
- llm = self.select_model_for_last_requests(llm_ultimas_requests) # type: ignore
365
  prompt_instance = Prompt()
366
  context_do_prompt_primeira_etapa = "\n\n".join(contexts)
367
  prompt_primeira_etapa = prompt_gerar_documento.format(
368
  context=context_do_prompt_primeira_etapa,
369
  )
370
 
371
- documento_gerado = await self.checar_se_resposta_vazia_do_documento_final(
 
 
372
  llm_ultimas_requests, prompt_primeira_etapa
373
  )
374
 
@@ -386,7 +429,7 @@ class GerarDocumento:
386
  dynamic_dict={"context": context_do_prompt_primeira_etapa},
387
  )
388
  # documento_gerado = llm.invoke(prompt_etapa_2).content
389
- documento_gerado = self.checar_se_resposta_vazia_do_documento_final(
390
  llm_ultimas_requests, prompt_etapa_2.to_string()
391
  )
392
  resposta_segunda_etapa = documento_gerado
@@ -404,7 +447,7 @@ class GerarDocumento:
404
  },
405
  )
406
  # documento_gerado = llm.invoke(prompt_etapa_3).content
407
- documento_gerado = self.checar_se_resposta_vazia_do_documento_final(
408
  llm_ultimas_requests, prompt_etapa_3.to_string()
409
  )
410
  texto_final_juntando_as_etapas += f"\n\n{documento_gerado}"
@@ -468,44 +511,6 @@ class GerarDocumento:
468
 
469
  self.axiom_instance.send_axiom("TERMINOU A REQUISIÇÃO FINAL PARA O BUBBLE")
470
 
471
- async def checar_se_resposta_vazia_do_documento_final(
472
- self, llm_ultimas_requests: str, prompt: str
473
- ):
474
- llm = self.select_model_for_last_requests(llm_ultimas_requests) # type: ignore
475
- documento_gerado = ""
476
- tentativas = 0
477
-
478
- while tentativas < 5 and not documento_gerado:
479
- tentativas += 1
480
- try:
481
- resposta = llm.invoke(prompt)
482
- if hasattr(resposta, "content") and resposta.content.strip(): # type: ignore
483
- if isinstance(resposta.content, list):
484
- resposta.content = "\n".join(resposta.content) # type: ignore
485
-
486
- documento_gerado = resposta.content.strip() # type: ignore
487
- else:
488
- print(f"Tentativa {tentativas}: resposta vazia ou inexistente.")
489
- except Exception as e:
490
- llm = self.select_model_for_last_requests("gemini-2.0-flash")
491
- print(f"Tentativa {tentativas}: erro ao invocar o modelo: {e}")
492
- time.sleep(5)
493
-
494
- if not documento_gerado:
495
- try:
496
- self.axiom_instance.send_axiom(
497
- "TENTANDO GERAR DOCUMENTO FINAL COM GPT 4o-mini COMO ÚLTIMA TENTATIVA"
498
- )
499
- documento_gerado = (
500
- self.gerar_documento_utils.ultima_tentativa_requisicao(prompt)
501
- )
502
- except Exception as e:
503
- raise Exception(
504
- "Falha ao gerar o documento final na última tentativa."
505
- ) from e
506
-
507
- return documento_gerado
508
-
509
  async def gerar_ementa_final(
510
  self,
511
  llm_ultimas_requests: str,
@@ -516,7 +521,7 @@ class GerarDocumento:
516
  llm = self.select_model_for_last_requests(llm_ultimas_requests) # type: ignore
517
  prompt_instance = Prompt()
518
 
519
- documento_gerado = await self.checar_se_resposta_vazia_do_documento_final(
520
  llm_ultimas_requests, prompt_primeira_etapa
521
  )
522
 
 
42
  from setup.tokens import openai_api_key, cohere_api_key
43
  from setup.logging import Axiom
44
  import tiktoken
45
+ from setup.environment import default_model
46
 
47
 
48
  def reciprocal_rank_fusion(result_lists, weights=None):
 
66
 
67
  @dataclass
68
  class GerarDocumentoUtils:
69
+ axiom_instance: Axiom
70
+ temperature = 0.0
71
+ model = default_model
72
+
73
  def criar_output_estruturado(self, summaries: List[str | Any], sources: Any):
74
  structured_output = []
75
  for idx, summary in enumerate(summaries):
 
114
  chunk_overlap=serializer.chunk_overlap,
115
  )
116
 
117
+ async def checar_se_resposta_vazia_do_documento_final(
118
+ self, llm_ultimas_requests: str, prompt: str
119
+ ):
120
+ llm = self.select_model_for_last_requests(llm_ultimas_requests) # type: ignore
121
+ documento_gerado = ""
122
+ tentativas = 0
123
+
124
+ while tentativas < 5 and not documento_gerado:
125
+ tentativas += 1
126
+ try:
127
+ resposta = llm.invoke(prompt)
128
+ if hasattr(resposta, "content") and resposta.content.strip(): # type: ignore
129
+ if isinstance(resposta.content, list):
130
+ resposta.content = "\n".join(resposta.content) # type: ignore
131
+
132
+ documento_gerado = resposta.content.strip() # type: ignore
133
+ else:
134
+ print(f"Tentativa {tentativas}: resposta vazia ou inexistente.")
135
+ except Exception as e:
136
+ llm = self.select_model_for_last_requests("gemini-2.0-flash")
137
+ print(f"Tentativa {tentativas}: erro ao invocar o modelo: {e}")
138
+ time.sleep(5)
139
+
140
+ if not documento_gerado:
141
+ try:
142
+ self.axiom_instance.send_axiom(
143
+ "TENTANDO GERAR DOCUMENTO FINAL COM GPT 4o-mini COMO ÚLTIMA TENTATIVA"
144
+ )
145
+ documento_gerado = self.ultima_tentativa_requisicao(prompt)
146
+ except Exception as e:
147
+ raise Exception(
148
+ "Falha ao gerar o documento final na última tentativa."
149
+ ) from e
150
+
151
+ return documento_gerado
152
+
153
+ def select_model_for_last_requests(
154
+ self,
155
+ llm_ultimas_requests: Literal[
156
+ "gpt-4o-mini", "deepseek-chat", "gemini-2.0-flash", "gemini-2.5-pro"
157
+ ],
158
+ ):
159
+ llm_instance = LLM()
160
+ if llm_ultimas_requests == "gpt-4o-mini":
161
+ llm = ChatOpenAI(
162
+ temperature=self.temperature,
163
+ model=self.model,
164
+ api_key=SecretStr(openai_api_key),
165
+ )
166
+ elif llm_ultimas_requests == "deepseek-chat":
167
+ llm = llm_instance.deepseek()
168
+ elif llm_ultimas_requests == "gemini-2.0-flash":
169
+ llm = llm_instance.google_gemini("gemini-2.0-flash")
170
+ elif llm_ultimas_requests == "gemini-2.5-pro":
171
+ llm = llm_instance.google_gemini("gemini-2.5-pro-preview-05-06")
172
+ elif llm_ultimas_requests == "gemini-2.5-flash":
173
+ llm = llm_instance.google_gemini("gemini-2.5-flash-preview-04-17")
174
+ return llm
175
+
176
 
177
  class GerarDocumento:
178
  lista_pdfs: List[str]
 
182
  isBubble: bool
183
  chunks_processados: List[ContextualizedChunk] | List[DocumentChunk]
184
  resumo_auxiliar: str
185
+ gerar_documento_utils: GerarDocumentoUtils
186
  utils = UtilsClass()
187
  llm = LLM()
188
  enhanced_vector_store: tuple[Chroma, BM25Okapi, List[str]]
 
207
  self.config = self.gerar_documento_utils.create_retrieval_config(serializer)
208
  self.logger = logging.getLogger(__name__)
209
  # self.prompt_auxiliar = prompt_auxiliar
210
+ self.gerar_documento_utils = GerarDocumentoUtils(axiom_instance)
211
  self.gpt_model = serializer.model
212
  self.gpt_temperature = serializer.gpt_temperature
213
  self.prompt_gerar_documento = serializer.prompt_gerar_documento
 
383
 
384
  return sources, contexts
385
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
  async def do_last_requests(
387
  self,
388
  ) -> List[Dict]:
 
403
  )
404
 
405
  llm_ultimas_requests = self.llm_ultimas_requests
 
406
  prompt_instance = Prompt()
407
  context_do_prompt_primeira_etapa = "\n\n".join(contexts)
408
  prompt_primeira_etapa = prompt_gerar_documento.format(
409
  context=context_do_prompt_primeira_etapa,
410
  )
411
 
412
+ self.gerar_documento_utils.model = self.gpt_model
413
+ self.gerar_documento_utils.temperature = self.gpt_temperature
414
+ documento_gerado = await self.gerar_documento_utils.checar_se_resposta_vazia_do_documento_final(
415
  llm_ultimas_requests, prompt_primeira_etapa
416
  )
417
 
 
429
  dynamic_dict={"context": context_do_prompt_primeira_etapa},
430
  )
431
  # documento_gerado = llm.invoke(prompt_etapa_2).content
432
+ documento_gerado = self.gerar_documento_utils.checar_se_resposta_vazia_do_documento_final(
433
  llm_ultimas_requests, prompt_etapa_2.to_string()
434
  )
435
  resposta_segunda_etapa = documento_gerado
 
447
  },
448
  )
449
  # documento_gerado = llm.invoke(prompt_etapa_3).content
450
+ documento_gerado = self.gerar_documento_utils.checar_se_resposta_vazia_do_documento_final(
451
  llm_ultimas_requests, prompt_etapa_3.to_string()
452
  )
453
  texto_final_juntando_as_etapas += f"\n\n{documento_gerado}"
 
511
 
512
  self.axiom_instance.send_axiom("TERMINOU A REQUISIÇÃO FINAL PARA O BUBBLE")
513
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
514
  async def gerar_ementa_final(
515
  self,
516
  llm_ultimas_requests: str,
 
521
  llm = self.select_model_for_last_requests(llm_ultimas_requests) # type: ignore
522
  prompt_instance = Prompt()
523
 
524
+ documento_gerado = await self.gerar_documento_utils.checar_se_resposta_vazia_do_documento_final(
525
  llm_ultimas_requests, prompt_primeira_etapa
526
  )
527
 
setup/installed_apps.py CHANGED
@@ -16,4 +16,5 @@ INSTALLED_APPS = config_apps + [
16
  "modelos_usuarios",
17
  "ragas_api",
18
  "gerar_documento",
 
19
  ]
 
16
  "modelos_usuarios",
17
  "ragas_api",
18
  "gerar_documento",
19
+ "simple_llm",
20
  ]
setup/urls.py CHANGED
@@ -19,4 +19,5 @@ urlpatterns = config_urls + [
19
  path("", include("gerar_documento.urls")),
20
  path("", include("ragas_api.urls")),
21
  path("", include("modelos_usuarios.urls")),
 
22
  ]
 
19
  path("", include("gerar_documento.urls")),
20
  path("", include("ragas_api.urls")),
21
  path("", include("modelos_usuarios.urls")),
22
+ path("", include("simple_llm.urls")),
23
  ]
simple_llm/__init__.py ADDED
File without changes
simple_llm/admin.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from django.contrib import admin
2
+
3
+ # Register your models here.
simple_llm/apps.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class SimpleLlmConfig(AppConfig):
5
+ default_auto_field = 'django.db.models.BigAutoField'
6
+ name = 'simple_llm'
simple_llm/migrations/__init__.py ADDED
File without changes
simple_llm/models.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from django.db import models
2
+
3
+ # Create your models here.
simple_llm/serializer.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass, field
2
+ from typing import List, Optional, Union
3
+ from rest_framework import serializers
4
+ from _utils.gerar_documento_utils.prompts import (
5
+ prompt_gerar_documento,
6
+ )
7
+ from gerar_documento.serializer import FileInfoSerializer, FileInfoSerializerData
8
+ from gerar_documento.serializer_base import (
9
+ GerarDocumentoParametros,
10
+ GerarDocumentoParametrosData,
11
+ )
12
+ from setup.environment import default_model
13
+ from django.core.files.uploadedfile import UploadedFile
14
+
15
+ user_message = "What are the main points of this document?"
16
+
17
+
18
+ class SimpleLLMInitialSerializer(serializers.Serializer):
19
+ files = serializers.ListField(child=serializers.FileField(), required=False)
20
+ user_text = serializers.CharField(required=False, default=user_message)
21
+ model = serializers.CharField(required=False, default=default_model)
22
+ prompt = serializers.CharField(required=False, default=prompt_gerar_documento)
23
+ llm_ultimas_requests = serializers.CharField(
24
+ required=False, default="gemini-2.0-flash"
25
+ )
26
+
27
+
28
+ @dataclass
29
+ class SimpleLLMInitialSerializerData:
30
+ files: List[dict] = field(default_factory=list)
31
+ user_text: str = ""
32
+ model: str = default_model
33
+ prompt: str = ""
34
+ llm_ultimas_requests: str = "gemini-2.0-flash"
35
+
36
+
37
+ class SimpleLLMSerializer(SimpleLLMInitialSerializer):
38
+ files = serializers.ListField(child=FileInfoSerializer(), required=False)
39
+ bubble_editor_version = serializers.CharField(
40
+ required=False, default="version-test"
41
+ ) # Será o valor utilizado dentro da URL da requisição pro Bubble
42
+ doc_id = serializers.CharField(required=True)
43
+ form_response_id = serializers.CharField(required=True)
44
+ version = serializers.CharField(required=True)
45
+
46
+ def get_obj(self):
47
+ return SimpleSerializerData(**self.validated_data) # type: ignore
48
+
49
+
50
+ @dataclass
51
+ class SimpleSerializerData(SimpleLLMInitialSerializerData):
52
+ files: List[FileInfoSerializerData] = field(default_factory=list)
53
+ bubble_editor_version: str = "version-test"
54
+
55
+ doc_id: str = ""
56
+ form_response_id: str = ""
57
+ version: str = ""
simple_llm/tests.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from django.test import TestCase
2
+
3
+ # Create your tests here.
simple_llm/urls.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from django.urls import path
2
+
3
+ from simple_llm.views import SimpleLLMView
4
+
5
+ urlpatterns = [
6
+ path(
7
+ "llm",
8
+ SimpleLLMView.as_view(),
9
+ name="simple-llm",
10
+ ),
11
+ ]
simple_llm/views.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from datetime import datetime
2
+ from _utils.custom_exception_handler import custom_exception_handler_without_api_handler
3
+ from _utils.gerar_documento import gerar_documento
4
+ from _utils.gerar_documento_utils.GerarDocumento import (
5
+ GerarDocumento,
6
+ GerarDocumentoUtils,
7
+ )
8
+ from _utils.langchain_utils.Prompt_class import Prompt
9
+ from _utils.utils import convert_markdown_to_HTML
10
+ from setup.logging import Axiom
11
+ from setup.easy_imports import (
12
+ Response,
13
+ AsyncAPIView,
14
+ extend_schema,
15
+ )
16
+ from simple_llm.serializer import SimpleLLMSerializer
17
+
18
+
19
+ class SimpleLLMView(AsyncAPIView):
20
+ # parser_classes = [MultiPartParser]
21
+ serializer = {}
22
+ axiom_instance = Axiom()
23
+
24
+ @extend_schema(
25
+ request=SimpleLLMSerializer,
26
+ )
27
+ async def post(self, request):
28
+ try:
29
+ self.axiom_instance.generate_new_uuid()
30
+ print(f"\n\nDATA E HORA DA REQUISIÇÃO: {datetime.now()}")
31
+ self.axiom_instance.send_axiom(
32
+ f"COMEÇOU NOVA REQUISIÇÃO - request.data: {request.data}"
33
+ )
34
+ serializer = SimpleLLMSerializer(data=request.data)
35
+ if serializer.is_valid(raise_exception=True):
36
+ obj = serializer.get_obj() # type: ignore
37
+ if not serializer.validated_data:
38
+ raise ValueError("Erro no validated_data")
39
+
40
+ self.serializer = obj
41
+
42
+ listaPDFs = [l.link_arquivo for l in obj.files]
43
+ self.axiom_instance.send_axiom(f"listaPDFs: {listaPDFs}")
44
+
45
+ summarizer = GerarDocumentoUtils(self.axiom_instance)
46
+
47
+ prompt_instance = Prompt()
48
+ prompt = prompt_instance.create_and_invoke_prompt(
49
+ obj.prompt,
50
+ dynamic_dict={"context": obj.user_text},
51
+ )
52
+
53
+ resposta_llm = (
54
+ await summarizer.checar_se_resposta_vazia_do_documento_final(
55
+ obj.llm_ultimas_requests, prompt.to_string()
56
+ )
57
+ )
58
+ self.axiom_instance.send_axiom(f"resposta_llm: {resposta_llm}")
59
+
60
+ texto_completo_como_html = convert_markdown_to_HTML(
61
+ resposta_llm
62
+ ).replace("resposta_segunda_etapa:", "<br><br>")
63
+
64
+ self.axiom_instance.send_axiom(
65
+ f"texto_completo_como_html: {texto_completo_como_html}"
66
+ )
67
+
68
+ return Response({"resposta": texto_completo_como_html})
69
+ except Exception as e:
70
+ custom_exception_handler_without_api_handler(
71
+ e, serializer, self.axiom_instance
72
+ )
73
+ raise