pbesa 4.0.12__tar.gz → 4.0.13__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pbesa-4.0.12 → pbesa-4.0.13}/PKG-INFO +1 -1
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/celulas/celula_casos.py +2 -2
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/celulas/celula_consultas.py +2 -2
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/celulas/celula_datos_identificables.py +2 -2
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/celulas/celula_generar_documento.py +2 -2
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/celulas/celula_saludos.py +2 -2
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/cognitive.py +48 -17
- pbesa-4.0.13/pbesa/models.py +314 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/social/dispatcher_team.py +152 -6
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/social/worker.py +4 -2
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa.egg-info/PKG-INFO +1 -1
- {pbesa-4.0.12 → pbesa-4.0.13}/setup.py +1 -1
- pbesa-4.0.12/pbesa/models.py +0 -149
- {pbesa-4.0.12 → pbesa-4.0.13}/.gitignore +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/LICENSE +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/LICENSE.txt +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/MANIFEST +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/README.md +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/db.sqlite3 +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/helloworld/__init__.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/helloworld/__pycache__/__init__.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/helloworld/__pycache__/pbesa.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/helloworld/__pycache__/settings.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/helloworld/__pycache__/urls.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/helloworld/__pycache__/wsgi.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/helloworld/asgi.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/helloworld/pbesa.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/helloworld/settings.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/helloworld/urls.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/helloworld/wsgi.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/manage.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/__init__.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/__pycache__/__init__.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/__pycache__/admin.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/__pycache__/apps.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/__pycache__/models.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/__pycache__/urls.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/__pycache__/views.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/admin.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/apps.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/mas/controller/__pycache__/translatecontroller.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/mas/controller/__pycache__/translatedelegate.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/mas/controller/__pycache__/translateresponse.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/mas/controller/translatecontroller.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/mas/controller/translatedelegate.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/mas/controller/translateresponse.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/mas/worker/__pycache__/translatetask.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/mas/worker/__pycache__/workeragent.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/mas/worker/translatetask.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/mas/worker/workeragent.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/migrations/__init__.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/migrations/__pycache__/__init__.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/models.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/tests.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/urls.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/django/helloworld/translate/views.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/remote/mas/controller/__pycache__/countercontroller.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/remote/mas/controller/__pycache__/counterdelegate.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/remote/mas/controller/__pycache__/counterresponse.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/remote/mas/controller/__pycache__/translatecontroller.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/remote/mas/controller/__pycache__/translatedelegate.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/remote/mas/controller/__pycache__/translateresponse.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/remote/mas/controller/countercontroller.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/remote/mas/controller/counterdelegate.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/remote/mas/controller/counterresponse.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/remote/mas/worker/__pycache__/counteragent.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/remote/mas/worker/__pycache__/countertask.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/remote/mas/worker/__pycache__/translatetask.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/remote/mas/worker/__pycache__/workeragent.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/remote/mas/worker/counteragent.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/remote/mas/worker/countertask.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/remote/remote_a.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/remote/remote_b.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/examples/remote/remote_c.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/__init__.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/celulas/__init__.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/celulas/web.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/kernel/__init__.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/kernel/adapter.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/kernel/agent.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/kernel/io/__init__.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/kernel/io/system_file.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/kernel/io/tcp_server.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/kernel/res/__init__.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/kernel/res/__pycache__/__init__.cpython-36.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/kernel/res/__pycache__/__init__.cpython-37.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/kernel/res/__pycache__/__init__.cpython-38.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/kernel/res/__pycache__/__init__.cpython-39.pyc +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/kernel/res/conf.json +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/kernel/util.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/kernel/world.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/mas.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/remote/__init__.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/remote/adm_listener.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/remote/adm_listener_handler.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/remote/exceptions.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/remote/remote_adm.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/remote/remote_adm_handler.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/social/__init__.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/social/collaborative_team.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/social/delegator.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/social/delegator_team.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/social/dialog.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/social/prompts.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/social/selected_dispatcher_team.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa/social/templates.py +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa.egg-info/SOURCES.txt +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa.egg-info/dependency_links.txt +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa.egg-info/requires.txt +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/pbesa.egg-info/top_level.txt +0 -0
- {pbesa-4.0.12 → pbesa-4.0.13}/setup.cfg +0 -0
@@ -42,13 +42,13 @@ Clasificación:
|
|
42
42
|
"""
|
43
43
|
|
44
44
|
# Efectua la inferencia del modelo.
|
45
|
-
def derive(service, text) -> any:
|
45
|
+
def derive(service, text, max_tkns=4096) -> any:
|
46
46
|
try:
|
47
47
|
logging.info(f"Procesando: {text}")
|
48
48
|
tmp_work_memory = []
|
49
49
|
prompt = PROMPT % text
|
50
50
|
tmp_work_memory.append({"role": "user", "content": prompt})
|
51
|
-
res = service.generate(tmp_work_memory)
|
51
|
+
res = service.generate(tmp_work_memory, max_tokens=max_tkns)
|
52
52
|
logging.info(f"Respuesta: {res}")
|
53
53
|
if not res or res == "":
|
54
54
|
res = text
|
@@ -27,13 +27,13 @@ Clasificación:
|
|
27
27
|
"""
|
28
28
|
|
29
29
|
# Efectua la inferencia del modelo.
|
30
|
-
def derive(service, text) -> any:
|
30
|
+
def derive(service, text, max_tkns=4096) -> any:
|
31
31
|
try:
|
32
32
|
logging.info(f"Procesando: {text}")
|
33
33
|
tmp_work_memory = []
|
34
34
|
prompt = PROMPT % text
|
35
35
|
tmp_work_memory.append({"role": "user", "content": prompt})
|
36
|
-
res = service.generate(tmp_work_memory)
|
36
|
+
res = service.generate(tmp_work_memory, max_tokens=max_tkns)
|
37
37
|
logging.info(f"Respuesta: {res}")
|
38
38
|
if not res or res == "":
|
39
39
|
res = text
|
@@ -35,12 +35,12 @@ Clasificación:
|
|
35
35
|
"""
|
36
36
|
|
37
37
|
# Efectua la inferencia del modelo.
|
38
|
-
def derive(service, text) -> any:
|
38
|
+
def derive(service, text, max_tkns=4096) -> any:
|
39
39
|
try:
|
40
40
|
tmp_work_memory = []
|
41
41
|
prompt = PROMPT % text
|
42
42
|
tmp_work_memory.append({"role": "user", "content": prompt})
|
43
|
-
res = service.generate(tmp_work_memory)
|
43
|
+
res = service.generate(tmp_work_memory, max_tokens=max_tkns)
|
44
44
|
logging.info(f"Procesando: {text}")
|
45
45
|
logging.info(f"Respuesta: {res}")
|
46
46
|
if not res or res == "":
|
@@ -26,13 +26,13 @@ DEMANDA FORMATEADA:
|
|
26
26
|
"""
|
27
27
|
|
28
28
|
# Efectua la inferencia del modelo.
|
29
|
-
def derive(service, formato, text) -> any:
|
29
|
+
def derive(service, formato, text, max_tkns=4096) -> any:
|
30
30
|
try:
|
31
31
|
logging.info(f"Procesando: {text}")
|
32
32
|
tmp_work_memory = []
|
33
33
|
prompt = PROMPT % (formato, text)
|
34
34
|
tmp_work_memory.append({"role": "user", "content": prompt})
|
35
|
-
res = service.generate(tmp_work_memory)
|
35
|
+
res = service.generate(tmp_work_memory, max_tokens=max_tkns)
|
36
36
|
logging.info(f"Respuesta: {res}")
|
37
37
|
if not res or res == "":
|
38
38
|
res = text
|
@@ -23,13 +23,13 @@ Clasificación:
|
|
23
23
|
"""
|
24
24
|
|
25
25
|
# Efectua la inferencia del modelo.
|
26
|
-
def derive(service, text) -> any:
|
26
|
+
def derive(service, text, max_tkns=4096) -> any:
|
27
27
|
try:
|
28
28
|
logging.info(f"Procesando: {text}")
|
29
29
|
tmp_work_memory = []
|
30
30
|
prompt = PROMPT % text
|
31
31
|
tmp_work_memory.append({"role": "user", "content": prompt})
|
32
|
-
res = service.generate(tmp_work_memory)
|
32
|
+
res = service.generate(tmp_work_memory, max_tokens=max_tkns)
|
33
33
|
logging.info(f"Respuesta: {res}")
|
34
34
|
if not res or res == "":
|
35
35
|
res = text
|
@@ -12,7 +12,7 @@
|
|
12
12
|
# --------------------------------------------------------
|
13
13
|
# Define resources
|
14
14
|
# --------------------------------------------------------
|
15
|
-
|
15
|
+
import re
|
16
16
|
import uuid
|
17
17
|
import json
|
18
18
|
import logging
|
@@ -21,13 +21,14 @@ from .mas import Adm
|
|
21
21
|
from pydantic import BaseModel
|
22
22
|
from typing import List, Optional
|
23
23
|
from abc import ABC, abstractmethod
|
24
|
-
from pbesa.models import AIFoundry, AzureInference, GPTService, ServiceProvider
|
24
|
+
from pbesa.models import AIFoundry, AzureInference, AzureOpenAIInference, GPTService, ServiceProvider
|
25
25
|
from pbesa.social.dialog import (
|
26
26
|
DialogState, imprimir_grafo, recorrer_interacciones, extraer_diccionario_nodos,
|
27
27
|
ActionNode, DeclarativeNode, GotoNode)
|
28
28
|
from .celulas import (celula_casos, celula_consultas, celula_saludos, celula_datos_identificables,
|
29
29
|
celula_generar_documento)
|
30
30
|
from pbesa.social.prompts import CLASSIFICATION_PROMPT, DERIVE_PROMPT, RECOVERY_PROMPT, ADAPT_PROMPT
|
31
|
+
|
31
32
|
# --------------------------------------------------------
|
32
33
|
# Define DTOs
|
33
34
|
# --------------------------------------------------------
|
@@ -124,6 +125,9 @@ def define_service_provider(provider, ai_service=None) -> None:
|
|
124
125
|
elif "AZURE_INFERENCE" in provider:
|
125
126
|
service = AzureInference()
|
126
127
|
service_provider.register("AZURE_INFERENCE", service)
|
128
|
+
elif "AZURE_OPEN_AI_INFERENCE" in provider:
|
129
|
+
service = AzureOpenAIInference()
|
130
|
+
service_provider.register("AZURE_INFERENCE", service)
|
127
131
|
return service_provider, service
|
128
132
|
|
129
133
|
# --------------------------------------------------------
|
@@ -703,11 +707,13 @@ class Dialog(ABC):
|
|
703
707
|
logging.info(f'>>>> Response: {response}')
|
704
708
|
return response['message']['response']
|
705
709
|
else:
|
706
|
-
if operation:
|
710
|
+
if operation and not operation == "Ninguno":
|
707
711
|
dto = {
|
708
712
|
"data": {
|
709
713
|
'text': data,
|
710
|
-
'operation': operation
|
714
|
+
'operation': operation,
|
715
|
+
'id_conversacion': self.state['id_conversacion'],
|
716
|
+
'session_id': self.state['session_id'],
|
711
717
|
},
|
712
718
|
}
|
713
719
|
else:
|
@@ -740,7 +746,7 @@ class Dialog(ABC):
|
|
740
746
|
try:
|
741
747
|
prompt = RECOVERY_PROMPT % query
|
742
748
|
temp_work_memory = [{"role": "user", "content": prompt}]
|
743
|
-
res = self.__ai_service.generate(temp_work_memory)
|
749
|
+
res = self.__ai_service.generate(temp_work_memory, max_tokens=500)
|
744
750
|
res = self.get_text(res)
|
745
751
|
if res and not res == "":
|
746
752
|
return self.__recovery['owner'], self.__recovery['performative'], res, self.__recovery['team']
|
@@ -777,14 +783,16 @@ class Dialog(ABC):
|
|
777
783
|
logging.info(f"------------Flujo de excepcion---------------")
|
778
784
|
self.notify("identificando intencion...")
|
779
785
|
# Obtiene discriminadores
|
780
|
-
caso = celula_casos.derive(self.__ai_service, query)
|
781
|
-
consulta = celula_consultas.derive(self.__ai_service, query)
|
782
|
-
saludo = celula_saludos.derive(self.__ai_service, query)
|
786
|
+
caso = celula_casos.derive(self.__ai_service, query, max_tkns=10)
|
787
|
+
consulta = celula_consultas.derive(self.__ai_service, query, max_tkns=10)
|
788
|
+
saludo = celula_saludos.derive(self.__ai_service, query, max_tkns=10)
|
783
789
|
# Verifica si es un saludo
|
784
790
|
es_saludo = ("SALUDO" in saludo) and ("NO_PREGUNTA" in consulta) and ("NO_QUEJA_DEMANDA" in caso) and not ("NO_SALUDO" in saludo)
|
785
791
|
es_consulta = ("PREGUNTA_O_SOLICITUD" in consulta) and ("NO_QUEJA_DEMANDA" in caso) and ("NO_SALUDO" in saludo) and not ("NO_PREGUNTA" in consulta)
|
786
792
|
es_caso = ("QUEJA_DEMANDA" in caso) and ("NO_PREGUNTA" in consulta) and ("NO_SALUDO" in saludo) and not ("NO_QUEJA_DEMANDA" in caso)
|
787
|
-
|
793
|
+
|
794
|
+
print("\n--- Clase ---")
|
795
|
+
logging.info(f"==> Saludo: {saludo}, Consulta: {consulta}, Caso: {caso}")
|
788
796
|
logging.info(f"==> Es saludo: {es_saludo}, Es consulta: {es_consulta}, Es caso: {es_caso}")
|
789
797
|
# Verifica los casos
|
790
798
|
dicriminador = "Ninguno"
|
@@ -806,6 +814,10 @@ class Dialog(ABC):
|
|
806
814
|
dicriminador = "consulta"
|
807
815
|
elif saludo == "SALUDO":
|
808
816
|
dicriminador = "saluda"
|
817
|
+
logging.info(f"==> Discriminador: {dicriminador}")
|
818
|
+
if dicriminador == "Ninguno":
|
819
|
+
dicriminador = "consulta"
|
820
|
+
print("---------------------\n")
|
809
821
|
#--------------------------
|
810
822
|
# Obtiene los hijos del
|
811
823
|
# nodo
|
@@ -865,7 +877,7 @@ class Dialog(ABC):
|
|
865
877
|
prompt = CLASSIFICATION_PROMPT % (query, options)
|
866
878
|
logging.info(f"Query: {query},\n Options:\n{options}")
|
867
879
|
self.__meta_work_memory.append({"role": "user", "content": prompt})
|
868
|
-
res = self.__ai_service.generate(self.__meta_work_memory)
|
880
|
+
res = self.__ai_service.generate(self.__meta_work_memory, max_tokens=10)
|
869
881
|
logging.info(f"Thought: {res}")
|
870
882
|
self.__meta_work_memory = []
|
871
883
|
res = self.get_text(res)
|
@@ -883,9 +895,17 @@ class Dialog(ABC):
|
|
883
895
|
select_node = children[0]
|
884
896
|
else:
|
885
897
|
logging.info("???> Es un nodo terminal o iniciador")
|
886
|
-
logging.warning(f"???> Es un nodo terminal o iniciador: {node
|
887
|
-
logging.warning(f"???> Es un nodo terminal o iniciador: {node
|
898
|
+
logging.warning(f"???> Es un nodo terminal o iniciador: {node}")
|
899
|
+
logging.warning(f"???> Es un nodo terminal o iniciador: {node}")
|
888
900
|
return self.recovery(query)
|
901
|
+
|
902
|
+
# Verifica si el nodo fue seleccionado
|
903
|
+
if not select_node:
|
904
|
+
logging.warning(f"???> No se seleccionó ningún nodo")
|
905
|
+
logging.info(f"------------RESET---------------")
|
906
|
+
self.notify("STOP")
|
907
|
+
self.reset()
|
908
|
+
return "Web", DialogState.START, self.RECOVERY_MSG, "Web"
|
889
909
|
|
890
910
|
#--------------------------
|
891
911
|
# Verifica si es un nodo
|
@@ -987,7 +1007,7 @@ class Dialog(ABC):
|
|
987
1007
|
logging.info("-----")
|
988
1008
|
logging.info("\n%s", json.dumps(self.__work_memory, indent=4))
|
989
1009
|
logging.info("-----")
|
990
|
-
res = self.__ai_service.generate(self.__work_memory)
|
1010
|
+
res = self.__ai_service.generate(self.__work_memory, max_tokens=100)
|
991
1011
|
logging.info(f"-> node tool: {res}")
|
992
1012
|
res = self.get_text(res)
|
993
1013
|
# Check if res is empty
|
@@ -1021,7 +1041,7 @@ class Dialog(ABC):
|
|
1021
1041
|
logging.info("-----")
|
1022
1042
|
logging.info("\n%s", json.dumps(self.__work_memory, indent=4))
|
1023
1043
|
logging.info("-----")
|
1024
|
-
res = self.__ai_service.generate(self.__work_memory)
|
1044
|
+
res = self.__ai_service.generate(self.__work_memory, max_tokens=1000)
|
1025
1045
|
res = self.get_text(res)
|
1026
1046
|
self.__work_memory.append({"role": "system", "content": res})
|
1027
1047
|
# Check if res is empty
|
@@ -1088,7 +1108,7 @@ class Dialog(ABC):
|
|
1088
1108
|
logging.info("-----")
|
1089
1109
|
logging.info("\n%s", json.dumps(self.__work_memory, indent=4))
|
1090
1110
|
logging.info("-----")
|
1091
|
-
res = self.__ai_service.generate(self.__work_memory)
|
1111
|
+
res = self.__ai_service.generate(self.__work_memory, max_tokens=1000)
|
1092
1112
|
res = self.get_text(res)
|
1093
1113
|
self.__work_memory.append({"role": "system", "content": res})
|
1094
1114
|
# Check if res is empty
|
@@ -1190,6 +1210,8 @@ class SpecialDispatch():
|
|
1190
1210
|
# Get the role
|
1191
1211
|
role = agent.get_role()
|
1192
1212
|
self.__options_dict[agent_id] = role.description
|
1213
|
+
# Log
|
1214
|
+
logging.info(f"Agentes disponibles: {self.__options_dict.keys()}")
|
1193
1215
|
|
1194
1216
|
def get_text(self, mensaje) -> str:
|
1195
1217
|
if mensaje:
|
@@ -1218,13 +1240,22 @@ class SpecialDispatch():
|
|
1218
1240
|
prompt = CLASSIFICATION_PROMPT % (query, options)
|
1219
1241
|
logging.info(f"Query: {query},\n Options:\n{options}")
|
1220
1242
|
self.__meta_work_memory.append({"role": "user", "content": prompt})
|
1221
|
-
res = self.__ai_service.generate(self.__meta_work_memory)
|
1243
|
+
res = self.__ai_service.generate(self.__meta_work_memory, max_tokens=10)
|
1222
1244
|
logging.info(f"Thought: {res}")
|
1223
1245
|
self.__meta_work_memory = []
|
1224
1246
|
res = self.get_text(res)
|
1225
1247
|
select_agent = None
|
1248
|
+
compare = re.findall(r'\d+', res)
|
1249
|
+
print(f"Compare: {compare}")
|
1250
|
+
if len(compare) > 0:
|
1251
|
+
compare = compare[0]
|
1252
|
+
else:
|
1253
|
+
compare = res
|
1254
|
+
compare = compare.strip()
|
1255
|
+
print(f"Compare: {compare}")
|
1226
1256
|
for option in range(1, cont+1):
|
1227
|
-
|
1257
|
+
print(f"Option: {option} - Compare: {compare}")
|
1258
|
+
if str(option) == compare:
|
1228
1259
|
select_agent = agent_options[option]
|
1229
1260
|
logging.info(f"Descripcion del agente seleccionado: {select_agent}")
|
1230
1261
|
break
|
@@ -0,0 +1,314 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
"""
|
3
|
+
----------------------------------------------------------
|
4
|
+
-------------------------- PBESA -------------------------
|
5
|
+
----------------------------------------------------------
|
6
|
+
|
7
|
+
@autor AKEN
|
8
|
+
@version 4.0.0
|
9
|
+
@date 08/08/24
|
10
|
+
"""
|
11
|
+
|
12
|
+
# --------------------------------------------------------
|
13
|
+
# Define resources
|
14
|
+
# --------------------------------------------------------
|
15
|
+
|
16
|
+
import traceback
|
17
|
+
from openai import AzureOpenAI
|
18
|
+
from abc import ABC, abstractmethod
|
19
|
+
from azure.ai.projects import AIProjectClient
|
20
|
+
from azure.identity import DefaultAzureCredential
|
21
|
+
from azure.ai.inference import ChatCompletionsClient
|
22
|
+
from azure.core.credentials import AzureKeyCredential
|
23
|
+
|
24
|
+
import time
|
25
|
+
from openai import AzureOpenAI, RateLimitError, APIStatusError
|
26
|
+
from tenacity import (
|
27
|
+
retry,
|
28
|
+
stop_after_attempt,
|
29
|
+
wait_exponential,
|
30
|
+
retry_if_exception_type,
|
31
|
+
wait_fixed
|
32
|
+
)
|
33
|
+
|
34
|
+
# --------------------------------------------------------
|
35
|
+
# Define classes
|
36
|
+
# --------------------------------------------------------
|
37
|
+
|
38
|
+
class AIService(ABC):
|
39
|
+
"""Abstract class for AI services."""
|
40
|
+
|
41
|
+
def __init__(self) -> None:
|
42
|
+
self.model:any = None
|
43
|
+
self.model_conf:dict = None
|
44
|
+
|
45
|
+
@abstractmethod
|
46
|
+
def setup(self, config: dict) -> None:
|
47
|
+
"""Method to setup the AI service."""
|
48
|
+
raise NotImplementedError("Method 'setup' must be implemented.")
|
49
|
+
|
50
|
+
@abstractmethod
|
51
|
+
def generate(self, work_memory, max_tokens=4096, temperature=0, top_p=0.9) -> str:
|
52
|
+
"""Method to generate a response based on user input."""
|
53
|
+
raise NotImplementedError("Method 'setup' must be implemented.")
|
54
|
+
|
55
|
+
class GPTService(AIService):
|
56
|
+
|
57
|
+
def __init__(self) -> None:
|
58
|
+
super().__init__()
|
59
|
+
|
60
|
+
def setup(self, config: dict, work_memory) -> None:
|
61
|
+
try:
|
62
|
+
self.model:any = config['model']
|
63
|
+
self.model_conf:dict = config
|
64
|
+
self.__work_memory:list = work_memory
|
65
|
+
except Exception as e:
|
66
|
+
raise Exception("Could not setup GPTService: check the configuration.")
|
67
|
+
|
68
|
+
def generate(self) -> str:
|
69
|
+
""" Generate method
|
70
|
+
:return: str
|
71
|
+
"""
|
72
|
+
try:
|
73
|
+
# Genera texto con OpenAI.
|
74
|
+
self.model.api_key = self.model_conf['API_KEY']
|
75
|
+
engine = self.model_conf['OPENAI_ENGINE']
|
76
|
+
response = self.model.ChatCompletion.create(
|
77
|
+
model = engine,
|
78
|
+
messages = self.__work_memory
|
79
|
+
)
|
80
|
+
# Verifica si se obtuvo respuesta.
|
81
|
+
if response['choices'][0]['finish_reason'] == 'completed' or response['choices'][0]['finish_reason'] == 'stop':
|
82
|
+
res = response['choices'][0]['message']['content']
|
83
|
+
try:
|
84
|
+
if not res or res == 'null' or res == 'N/A' or 'N/A' in res:
|
85
|
+
#self.log.warning("OpenAI response not completed", extra={'log_data': {'gpt_response': response}})
|
86
|
+
print("OpenAI response not completed")
|
87
|
+
return None
|
88
|
+
#self.log.info("OpenAI response completed", extra={'log_data': {'gpt_response': response}})
|
89
|
+
print("OpenAI response completed")
|
90
|
+
self.__work_memory.append({"role": "assistant", "content": res})
|
91
|
+
return res
|
92
|
+
except:
|
93
|
+
#self.log.warning("OpenAI response not completed", extra={'log_data': {'gpt_response': response}})
|
94
|
+
print("OpenAI response not completed")
|
95
|
+
return None
|
96
|
+
else:
|
97
|
+
#self.log.warning("OpenAI response not completed", extra={'log_data': {'gpt_response': response}})
|
98
|
+
print("OpenAI response not completed")
|
99
|
+
return None
|
100
|
+
except Exception as e:
|
101
|
+
trace_err = traceback.format_exc()
|
102
|
+
err = str(e) + " - " + trace_err
|
103
|
+
print(err)
|
104
|
+
return None
|
105
|
+
|
106
|
+
class AIFoundry(AIService):
|
107
|
+
|
108
|
+
def __init__(self) -> None:
|
109
|
+
super().__init__()
|
110
|
+
|
111
|
+
def setup(self, config: dict, work_memory) -> None:
|
112
|
+
self.model_conf:dict = config
|
113
|
+
self.__work_memory:list = work_memory
|
114
|
+
project = AIProjectClient.from_connection_string(
|
115
|
+
conn_str=config['PROJECT_CONNECTION_STRING'], credential=DefaultAzureCredential()
|
116
|
+
)
|
117
|
+
self.model:any = project.inference.get_chat_completions_client()
|
118
|
+
|
119
|
+
def generate(self) -> str:
|
120
|
+
response = self.model.complete(
|
121
|
+
model=self.model_conf['AIFOUNDRY_MODEL'],
|
122
|
+
messages=self.__work_memory,
|
123
|
+
)
|
124
|
+
return response.choices[0].message.content
|
125
|
+
|
126
|
+
class AzureInference(AIService):
|
127
|
+
|
128
|
+
def __init__(self) -> None:
|
129
|
+
super().__init__()
|
130
|
+
|
131
|
+
def setup(self, config: dict) -> None:
|
132
|
+
self.model_conf:dict = config
|
133
|
+
self.model:any = ChatCompletionsClient(
|
134
|
+
endpoint=config['AZURE_INFERENCE_SDK_ENDPOINT'],
|
135
|
+
credential=AzureKeyCredential(config['AZURE_INFERENCE_SDK_KEY'])
|
136
|
+
)
|
137
|
+
|
138
|
+
def generate(self, work_memory) -> str:
|
139
|
+
response = self.model.complete(
|
140
|
+
messages= work_memory,
|
141
|
+
model =self.model_conf['DEPLOYMENT_NAME'],
|
142
|
+
max_tokens=self.model_conf['MAX_TOKENS']
|
143
|
+
)
|
144
|
+
return response.choices[0].message.content
|
145
|
+
|
146
|
+
# Función auxiliar para determinar la espera basada en el error
|
147
|
+
def wait_strategy_for_rate_limit(retry_state):
|
148
|
+
"""
|
149
|
+
Determina la estrategia de espera.
|
150
|
+
Si es un RateLimitError y hay un header 'Retry-After', lo usa.
|
151
|
+
De lo contrario, usa un backoff exponencial.
|
152
|
+
"""
|
153
|
+
exception = retry_state.outcome.exception()
|
154
|
+
if isinstance(exception, (RateLimitError, APIStatusError)):
|
155
|
+
if hasattr(exception, 'response') and exception.response:
|
156
|
+
headers = exception.response.headers
|
157
|
+
retry_after_seconds = headers.get("Retry-After")
|
158
|
+
if retry_after_seconds:
|
159
|
+
try:
|
160
|
+
wait_time = int(retry_after_seconds)
|
161
|
+
print(f"Rate limit: Respetando header Retry-After: esperando {wait_time} segundos.")
|
162
|
+
return wait_fixed(wait_time)(retry_state) # Usa wait_fixed para el tiempo específico
|
163
|
+
except ValueError:
|
164
|
+
print(f"Rate limit: Retry-After header no es un entero ({retry_after_seconds}). Usando backoff exponencial.")
|
165
|
+
else: # No hay Retry-After, usar backoff exponencial
|
166
|
+
print("Rate limit: No se encontró header Retry-After. Usando backoff exponencial.")
|
167
|
+
else: # No hay objeto response, usar backoff exponencial
|
168
|
+
print("Rate limit: No se encontró objeto response en la excepción. Usando backoff exponencial.")
|
169
|
+
|
170
|
+
# Fallback a backoff exponencial para otros casos o si Retry-After falla
|
171
|
+
return wait_exponential(multiplier=1, min=4, max=60)(retry_state)
|
172
|
+
|
173
|
+
class AzureOpenAIInference(AIService):
|
174
|
+
|
175
|
+
def __init__(self) -> None:
|
176
|
+
super().__init__()
|
177
|
+
|
178
|
+
def setup(self, config: dict) -> None:
|
179
|
+
self.model_conf:dict = config
|
180
|
+
self.model:any = AzureOpenAI(
|
181
|
+
api_version=config['API_VERSION'],
|
182
|
+
azure_endpoint=config['AZURE_INFERENCE_SDK_ENDPOINT'],
|
183
|
+
api_key=config['AZURE_INFERENCE_SDK_KEY'],
|
184
|
+
)
|
185
|
+
self.current_time = time.time()
|
186
|
+
self.total_tokens = 0
|
187
|
+
|
188
|
+
def _log_attempt_number(self, retry_state):
|
189
|
+
"""Función para registrar el número de intento."""
|
190
|
+
print(f"Intento {retry_state.attempt_number} fallido. Reintentando...")
|
191
|
+
|
192
|
+
# Usamos retry_if_exception_type para especificar qué excepciones deben activar un reintento.
|
193
|
+
# wait_strategy_for_rate_limit determinará dinámicamente el tiempo de espera.
|
194
|
+
@retry(
|
195
|
+
retry=retry_if_exception_type((RateLimitError, APIStatusError)), # Reintentar en estos errores
|
196
|
+
wait=wait_strategy_for_rate_limit, # Estrategia de espera personalizada
|
197
|
+
stop=stop_after_attempt(5), # Número máximo de intentos (además del original)
|
198
|
+
before_sleep=_log_attempt_number # Función a llamar antes de esperar/dormir
|
199
|
+
)
|
200
|
+
def generate(self, work_memory, max_tokens=4096, temperature=0, top_p=0.9) -> str:
|
201
|
+
print(f"Generando completion para el modelo: {self.model_conf['DEPLOYMENT_NAME']}")
|
202
|
+
try:
|
203
|
+
|
204
|
+
# Espera 10 segubdos antes de la primera llamada
|
205
|
+
print("Esperando 3 segundos antes de la primera llamada...")
|
206
|
+
time.sleep(3)
|
207
|
+
print("Llamada a la API de OpenAI...")
|
208
|
+
|
209
|
+
|
210
|
+
response = self.model.chat.completions.create(
|
211
|
+
messages=work_memory,
|
212
|
+
max_tokens=max_tokens,
|
213
|
+
temperature=temperature,
|
214
|
+
top_p=top_p,
|
215
|
+
model=self.model_conf['DEPLOYMENT_NAME'],
|
216
|
+
)
|
217
|
+
|
218
|
+
# --- Agrega estas líneas para imprimir el uso de tokens ---
|
219
|
+
if hasattr(response, 'usage') and response.usage is not None:
|
220
|
+
print("\n--- Uso de Tokens ---")
|
221
|
+
print(f"Tokens enviados (prompt): {response.usage.prompt_tokens}")
|
222
|
+
print(f"Tokens recibidos (completion): {response.usage.completion_tokens}")
|
223
|
+
print(f"Tokens totales: {response.usage.total_tokens}")
|
224
|
+
self.total_tokens += response.usage.total_tokens
|
225
|
+
current_t = time.time()
|
226
|
+
elapsed_time = current_t - self.current_time
|
227
|
+
print(f"Tiempo transcurrido para la generación: {elapsed_time:.2f} segundos")
|
228
|
+
# En minutos
|
229
|
+
elapsed_time_minutes = elapsed_time / 60
|
230
|
+
print(f"Tiempo transcurrido para la generación: {elapsed_time_minutes:.2f} minutos")
|
231
|
+
print(f"Total de tokens generados hasta ahora: {self.total_tokens}")
|
232
|
+
|
233
|
+
|
234
|
+
if elapsed_time >= 60:
|
235
|
+
print("Reiniciando el contador de tiempo y tokens...")
|
236
|
+
self.total_tokens = 0
|
237
|
+
|
238
|
+
print("---------------------\n")
|
239
|
+
else:
|
240
|
+
print("\n--- Uso de Tokens no disponible en la respuesta ---")
|
241
|
+
# -------------------------------------------------------
|
242
|
+
|
243
|
+
|
244
|
+
|
245
|
+
return response.choices[0].message.content
|
246
|
+
except RateLimitError as e:
|
247
|
+
# Capturada específicamente para poder inspeccionarla si es necesario,
|
248
|
+
# pero tenacity se encargará del reintento si esta función la vuelve a lanzar.
|
249
|
+
print(f"Error de Límite de Tasa detectado (RateLimitError): {e.message}")
|
250
|
+
# Aquí podríamos añadir lógica específica si el error persiste después de los reintentos de tenacity
|
251
|
+
# o si queremos hacer algo antes de que tenacity lo maneje (aunque `before_sleep` es mejor para eso)
|
252
|
+
raise # Re-lanzar para que tenacity la maneje
|
253
|
+
except APIStatusError as e:
|
254
|
+
# Similar a RateLimitError, pero más general para errores de API con código de estado.
|
255
|
+
# La lógica de reintento de tenacity ya verifica el tipo, pero podemos ser explícitos.
|
256
|
+
print(f"Error de API detectado (APIStatusError): Código {e.status_code}, Mensaje: {e.message}")
|
257
|
+
if e.status_code == 429:
|
258
|
+
# Ya cubierto por retry_if_exception_type y wait_strategy_for_rate_limit
|
259
|
+
pass # Tenacity lo manejará
|
260
|
+
else:
|
261
|
+
# Si es otro APIStatusError que no queremos reintentar con esta política,
|
262
|
+
# podríamos manejarlo aquí o dejar que se propague si no está en retry_if_exception_type.
|
263
|
+
print(f"Error de API no relacionado con límite de tasa: {e.status_code}")
|
264
|
+
raise # Re-lanzar para que tenacity (si aplica) o el llamador lo maneje
|
265
|
+
except Exception as e:
|
266
|
+
print(f"Ocurrió un error inesperado durante la generación: {e}")
|
267
|
+
raise # Re-lanzar otras excepciones
|
268
|
+
|
269
|
+
# --- Ejemplo de Uso ---
|
270
|
+
if __name__ == '__main__':
|
271
|
+
# Simula una configuración
|
272
|
+
mock_config = {
|
273
|
+
'API_VERSION': '2024-02-01', # Reemplaza con tu API version real
|
274
|
+
'AZURE_INFERENCE_SDK_ENDPOINT': 'TU_ENDPOINT_AZURE_OPENAI', # Reemplaza
|
275
|
+
'AZURE_INFERENCE_SDK_KEY': 'TU_API_KEY', # Reemplaza
|
276
|
+
'DEPLOYMENT_NAME': 'gpt-4o' # O tu nombre de despliegue
|
277
|
+
}
|
278
|
+
|
279
|
+
# Reemplaza con tu endpoint y key reales para probar.
|
280
|
+
# ¡CUIDADO! Las siguientes líneas HARÁN LLAMADAS REALES si descomentas y configuras.
|
281
|
+
# Por ahora, para evitar llamadas reales en este ejemplo, el cliente no se usará activamente
|
282
|
+
# a menos que descomentes las líneas de llamada.
|
283
|
+
|
284
|
+
# client = LLMClient(mock_config)
|
285
|
+
# sample_work_memory = [{"role": "user", "content": "Hola, ¿cómo estás?"}]
|
286
|
+
|
287
|
+
# try:
|
288
|
+
# # Para probar el RateLimitError, necesitarías hacer muchas llamadas muy rápido
|
289
|
+
# # o simular que la API devuelve un RateLimitError.
|
290
|
+
# # Por ejemplo, podrías mockear `client.model.chat.completions.create`
|
291
|
+
# # para que lance un RateLimitError la primera vez.
|
292
|
+
# print("Intentando generar contenido...")
|
293
|
+
# # response_content = client.generate(sample_work_memory)
|
294
|
+
# # print("\nRespuesta del modelo:")
|
295
|
+
# # print(response_content)
|
296
|
+
# print("\nEjemplo de simulación (sin llamada real):")
|
297
|
+
# print("Si esto fuera una llamada real y ocurriera un error 429,")
|
298
|
+
# print("verías los mensajes de reintento de tenacity.")
|
299
|
+
|
300
|
+
class ServiceProvider:
|
301
|
+
_services = {}
|
302
|
+
|
303
|
+
@classmethod
|
304
|
+
def register(cls, name: str, service):
|
305
|
+
"""Register a service with a unique name."""
|
306
|
+
cls._services[name] = service
|
307
|
+
|
308
|
+
@classmethod
|
309
|
+
def get(cls, name: str):
|
310
|
+
"""Retrieve a registered service."""
|
311
|
+
service = cls._services.get(name)
|
312
|
+
if not service:
|
313
|
+
raise ValueError(f"Service '{name}' not found!")
|
314
|
+
return service
|