pbesa 4.0.36__tar.gz → 4.0.37__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.
Files changed (125) hide show
  1. {pbesa-4.0.36 → pbesa-4.0.37}/PKG-INFO +1 -1
  2. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/cognitive.py +8 -8
  3. pbesa-4.0.37/pbesa/social/sel_dispatcher_team.py +703 -0
  4. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa.egg-info/PKG-INFO +1 -1
  5. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa.egg-info/SOURCES.txt +1 -0
  6. {pbesa-4.0.36 → pbesa-4.0.37}/setup.py +1 -1
  7. {pbesa-4.0.36 → pbesa-4.0.37}/.gitignore +0 -0
  8. {pbesa-4.0.36 → pbesa-4.0.37}/LICENSE +0 -0
  9. {pbesa-4.0.36 → pbesa-4.0.37}/LICENSE.txt +0 -0
  10. {pbesa-4.0.36 → pbesa-4.0.37}/MANIFEST +0 -0
  11. {pbesa-4.0.36 → pbesa-4.0.37}/README.md +0 -0
  12. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/db.sqlite3 +0 -0
  13. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/helloworld/__init__.py +0 -0
  14. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/helloworld/__pycache__/__init__.cpython-36.pyc +0 -0
  15. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/helloworld/__pycache__/pbesa.cpython-36.pyc +0 -0
  16. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/helloworld/__pycache__/settings.cpython-36.pyc +0 -0
  17. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/helloworld/__pycache__/urls.cpython-36.pyc +0 -0
  18. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/helloworld/__pycache__/wsgi.cpython-36.pyc +0 -0
  19. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/helloworld/asgi.py +0 -0
  20. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/helloworld/pbesa.py +0 -0
  21. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/helloworld/settings.py +0 -0
  22. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/helloworld/urls.py +0 -0
  23. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/helloworld/wsgi.py +0 -0
  24. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/manage.py +0 -0
  25. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/__init__.py +0 -0
  26. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/__pycache__/__init__.cpython-36.pyc +0 -0
  27. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/__pycache__/admin.cpython-36.pyc +0 -0
  28. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/__pycache__/apps.cpython-36.pyc +0 -0
  29. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/__pycache__/models.cpython-36.pyc +0 -0
  30. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/__pycache__/urls.cpython-36.pyc +0 -0
  31. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/__pycache__/views.cpython-36.pyc +0 -0
  32. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/admin.py +0 -0
  33. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/apps.py +0 -0
  34. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/mas/controller/__pycache__/translatecontroller.cpython-36.pyc +0 -0
  35. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/mas/controller/__pycache__/translatedelegate.cpython-36.pyc +0 -0
  36. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/mas/controller/__pycache__/translateresponse.cpython-36.pyc +0 -0
  37. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/mas/controller/translatecontroller.py +0 -0
  38. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/mas/controller/translatedelegate.py +0 -0
  39. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/mas/controller/translateresponse.py +0 -0
  40. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/mas/worker/__pycache__/translatetask.cpython-36.pyc +0 -0
  41. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/mas/worker/__pycache__/workeragent.cpython-36.pyc +0 -0
  42. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/mas/worker/translatetask.py +0 -0
  43. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/mas/worker/workeragent.py +0 -0
  44. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/migrations/__init__.py +0 -0
  45. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/migrations/__pycache__/__init__.cpython-36.pyc +0 -0
  46. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/models.py +0 -0
  47. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/tests.py +0 -0
  48. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/urls.py +0 -0
  49. {pbesa-4.0.36 → pbesa-4.0.37}/examples/django/helloworld/translate/views.py +0 -0
  50. {pbesa-4.0.36 → pbesa-4.0.37}/examples/remote/mas/controller/__pycache__/countercontroller.cpython-36.pyc +0 -0
  51. {pbesa-4.0.36 → pbesa-4.0.37}/examples/remote/mas/controller/__pycache__/counterdelegate.cpython-36.pyc +0 -0
  52. {pbesa-4.0.36 → pbesa-4.0.37}/examples/remote/mas/controller/__pycache__/counterresponse.cpython-36.pyc +0 -0
  53. {pbesa-4.0.36 → pbesa-4.0.37}/examples/remote/mas/controller/__pycache__/translatecontroller.cpython-36.pyc +0 -0
  54. {pbesa-4.0.36 → pbesa-4.0.37}/examples/remote/mas/controller/__pycache__/translatedelegate.cpython-36.pyc +0 -0
  55. {pbesa-4.0.36 → pbesa-4.0.37}/examples/remote/mas/controller/__pycache__/translateresponse.cpython-36.pyc +0 -0
  56. {pbesa-4.0.36 → pbesa-4.0.37}/examples/remote/mas/controller/countercontroller.py +0 -0
  57. {pbesa-4.0.36 → pbesa-4.0.37}/examples/remote/mas/controller/counterdelegate.py +0 -0
  58. {pbesa-4.0.36 → pbesa-4.0.37}/examples/remote/mas/controller/counterresponse.py +0 -0
  59. {pbesa-4.0.36 → pbesa-4.0.37}/examples/remote/mas/worker/__pycache__/counteragent.cpython-36.pyc +0 -0
  60. {pbesa-4.0.36 → pbesa-4.0.37}/examples/remote/mas/worker/__pycache__/countertask.cpython-36.pyc +0 -0
  61. {pbesa-4.0.36 → pbesa-4.0.37}/examples/remote/mas/worker/__pycache__/translatetask.cpython-36.pyc +0 -0
  62. {pbesa-4.0.36 → pbesa-4.0.37}/examples/remote/mas/worker/__pycache__/workeragent.cpython-36.pyc +0 -0
  63. {pbesa-4.0.36 → pbesa-4.0.37}/examples/remote/mas/worker/counteragent.py +0 -0
  64. {pbesa-4.0.36 → pbesa-4.0.37}/examples/remote/mas/worker/countertask.py +0 -0
  65. {pbesa-4.0.36 → pbesa-4.0.37}/examples/remote/remote_a.py +0 -0
  66. {pbesa-4.0.36 → pbesa-4.0.37}/examples/remote/remote_b.py +0 -0
  67. {pbesa-4.0.36 → pbesa-4.0.37}/examples/remote/remote_c.py +0 -0
  68. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/__init__.py +0 -0
  69. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/__init__.py +0 -0
  70. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/celula_casos.py +0 -0
  71. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/celula_consultas.py +0 -0
  72. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/celula_conversador.py +0 -0
  73. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/celula_cuestionador.py +0 -0
  74. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/celula_datos_identificables.py +0 -0
  75. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/celula_evaluador.py +0 -0
  76. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/celula_expertos.py +0 -0
  77. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/celula_extraccion.py +0 -0
  78. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/celula_generar_caso.py +0 -0
  79. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/celula_generar_documento.py +0 -0
  80. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/celula_instruccion.py +0 -0
  81. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/celula_parafraseo.py +0 -0
  82. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/celula_pertinencia.py +0 -0
  83. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/celula_preguntas.py +0 -0
  84. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/celula_respuesta.py +0 -0
  85. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/celula_saludos.py +0 -0
  86. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/data_extraction_cel.py +0 -0
  87. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/celulas/web.py +0 -0
  88. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/kernel/__init__.py +0 -0
  89. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/kernel/adapter.py +0 -0
  90. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/kernel/agent.py +0 -0
  91. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/kernel/io/__init__.py +0 -0
  92. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/kernel/io/system_file.py +0 -0
  93. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/kernel/io/tcp_server.py +0 -0
  94. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/kernel/res/__init__.py +0 -0
  95. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/kernel/res/__pycache__/__init__.cpython-36.pyc +0 -0
  96. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/kernel/res/__pycache__/__init__.cpython-37.pyc +0 -0
  97. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/kernel/res/__pycache__/__init__.cpython-38.pyc +0 -0
  98. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/kernel/res/__pycache__/__init__.cpython-39.pyc +0 -0
  99. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/kernel/res/conf.json +0 -0
  100. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/kernel/util.py +0 -0
  101. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/kernel/world.py +0 -0
  102. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/mas.py +0 -0
  103. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/models.py +0 -0
  104. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/remote/__init__.py +0 -0
  105. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/remote/adm_listener.py +0 -0
  106. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/remote/adm_listener_handler.py +0 -0
  107. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/remote/exceptions.py +0 -0
  108. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/remote/remote_adm.py +0 -0
  109. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/remote/remote_adm_handler.py +0 -0
  110. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/simulator/__init__.py +0 -0
  111. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/simulator/dialog_simulator.py +0 -0
  112. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/social/__init__.py +0 -0
  113. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/social/collaborative_team.py +0 -0
  114. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/social/delegator.py +0 -0
  115. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/social/delegator_team.py +0 -0
  116. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/social/dialog.py +0 -0
  117. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/social/dispatcher_team.py +0 -0
  118. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/social/prompts.py +0 -0
  119. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/social/selected_dispatcher_team.py +0 -0
  120. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/social/templates.py +0 -0
  121. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa/social/worker.py +0 -0
  122. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa.egg-info/dependency_links.txt +0 -0
  123. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa.egg-info/requires.txt +0 -0
  124. {pbesa-4.0.36 → pbesa-4.0.37}/pbesa.egg-info/top_level.txt +0 -0
  125. {pbesa-4.0.36 → pbesa-4.0.37}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pbesa
3
- Version: 4.0.36
3
+ Version: 4.0.37
4
4
  License-File: LICENSE
5
5
  License-File: LICENSE.txt
6
6
  Requires-Dist: pymongo>=4.6.3
@@ -1413,14 +1413,14 @@ class Dialog(ABC):
1413
1413
  if not node.is_terminal:
1414
1414
  # Verifica recursion
1415
1415
  if not self.chek_user_interaction(node.children):
1416
- if self.__visited_nodes > 3:
1417
- self.__visited_nodes = 0
1418
- logging.info(f"[Inferencia]:[Recursion]: Deep limit")
1419
- logging.info(f"------------RESET---------------")
1420
- self.reset()
1421
- self.notify(session['session_id'], "STOP")
1422
- res = DialogState.ERROR
1423
- return "Web", DialogState.START, res, "Web"
1416
+ #if self.__visited_nodes > 3:
1417
+ # self.__visited_nodes = 0
1418
+ # logging.info(f"[Inferencia]:[Recursion]: Deep limit")
1419
+ # logging.info(f"------------RESET---------------")
1420
+ # self.reset()
1421
+ # self.notify(session['session_id'], "STOP")
1422
+ # res = DialogState.ERROR
1423
+ # return "Web", DialogState.START, res, "Web"
1424
1424
  logging.info(f"[Inferencia]:[Recursion]:[Performativa]: {node.performative}")
1425
1425
  self.notify(session['session_id'], "efectuando inferencia en profundidad")
1426
1426
  #return self.do_transition(session, owner, node, query)
@@ -0,0 +1,703 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ ----------------------------------------------------------
4
+ -------------------------- PBESA -------------------------
5
+ ----------------------------------------------------------
6
+
7
+ @autor AKEN
8
+ @version 4.0.0
9
+ @date 09/08/24
10
+
11
+ The Dispatcher Team is a group of artificial intelligence
12
+ agents coordinated by a controller that acts as a task
13
+ dispatcher. Unlike teams that consolidate responses,
14
+ in this system, the controller simply assigns the task to
15
+ the first available agent. Each agent operates
16
+ independently and responds through Controller to the
17
+ client once they have processed the assigned task.
18
+
19
+ When the client sends a request, the controller directs
20
+ it to the agent who is free at that moment. If all agents
21
+ are busy, the request is put on hold until one of them
22
+ becomes available to handle it. This approach ensures
23
+ quick and efficient responses, optimizing the use of
24
+ available resources.
25
+
26
+ The Dispatcher Team is ideal for scenarios where fast and
27
+ direct responses are crucial, as it minimizes wait times
28
+ and simplifies task management, allowing the team to
29
+ operate in an agile and effective manner.
30
+ """
31
+
32
+ # --------------------------------------------------------
33
+ # Define resources
34
+ # --------------------------------------------------------
35
+
36
+ import time
37
+ import logging
38
+ import traceback
39
+ import pandas as pd
40
+ from abc import abstractmethod
41
+ from .worker import Task, Worker
42
+ from ..kernel.agent import Queue
43
+ from ..kernel.agent import Agent
44
+ from ..kernel.agent import Action
45
+ from datetime import datetime, timedelta
46
+ from ..kernel.util import generate_short_uuid
47
+ from ..cognitive import Dialog, AugmentedGeneration
48
+ from sklearn.metrics.pairwise import cosine_similarity
49
+ from sklearn.feature_extraction.text import CountVectorizer
50
+
51
+ # ----------------------------------------------------------
52
+ # Defines system component exceptions
53
+ # ----------------------------------------------------------
54
+
55
+ class DispatcherException(Exception):
56
+ """ Base class for exceptions of agent """
57
+ pass
58
+
59
+ # --------------------------------------------------------
60
+ # Define AgentDTO
61
+ # --------------------------------------------------------
62
+
63
+ class AgentDto():
64
+ """ Data Transfer Object """
65
+ def __init__(self, agent_id:str) -> None:
66
+ """ Constructor
67
+ @param agent_id: Agent ID
68
+ """
69
+ self.id = agent_id
70
+
71
+ # --------------------------------------------------------
72
+ # Define Buffer Dispatcher
73
+ # --------------------------------------------------------
74
+
75
+ class BufferDispatcher(Action):
76
+
77
+ def active_timeout(self, ag, time: int) -> None:
78
+ """ Active timeout
79
+ @param time: Time
80
+ """
81
+ logging.info(f"[Delegate] Send event timeout {time}")
82
+ self.adm.send_event(ag, 'timeout', {'time': time, 'command': 'start'})
83
+
84
+ def execute(self, event: any) -> None:
85
+ """
86
+ Response.
87
+ @param data Event event
88
+ """
89
+ try:
90
+ while self.agent.alive:
91
+ for key, item_list in list(self.agent.hold_dict.items()):
92
+ for item in item_list:
93
+ data = item['data']
94
+ mayor_ag_id = item['mayor_ag_id']
95
+ free_dict = self.agent.get_free_dict()
96
+
97
+
98
+ agent_id = None
99
+
100
+ for k in free_dict:
101
+ if mayor_ag_id in k:
102
+ agent_id = k
103
+ break
104
+
105
+
106
+ if agent_id:
107
+ logging.info(f'The agent {agent_id} is assigned')
108
+ self.agent.get_request_dict()[agent_id] = {
109
+ 'gateway': data['gateway'],
110
+ 'dtoList': []
111
+ }
112
+ self.adm.send_event(agent_id, 'task', data['dto'])
113
+ # Remove the item from the hold dict
114
+ self.agent.hold_dict[key].remove(item)
115
+ if len(self.agent.hold_dict[key]) == 0:
116
+ self.agent.hold_dict.pop(key, None)
117
+ # Remove agnebt from free dict
118
+ free_dict.pop(agent_id, None)
119
+ # Check timeout
120
+ if 'timeout' in self.agent.state:
121
+ self.active_timeout(agent_id, self.agent.state['timeout'])
122
+ else:
123
+ data['gateway'].put('ERROR')
124
+ logging.error('[Delegate]: Timeout not defined in the state as "timeout" key')
125
+ break
126
+ else:
127
+ logging.debug('The agent does not match the role')
128
+ if self.agent.check_time(data):
129
+ logging.info(f"[Select]:[Dispacher]: Se mantiene el hold a: {data['dto']['text']}")
130
+ else:
131
+ logging.info(f"[Select]:[Dispacher]: Se elimina el hold a: {data['dto']['text']}")
132
+ self.agent.hold_dict.pop(key, None)
133
+ self.agent.planilla.pop(data['dto']['session']['session_id'], None)
134
+ data['gateway'].put('ERROR')
135
+ logging.error('[Error, toAssign]: The agent is not available')
136
+ logging.info(f"[Select]:[Dispacher]: Hold dict elements {len(self.agent.hold_dict)}")
137
+ time.sleep(10)
138
+ except Exception as e:
139
+ traceback.print_exc()
140
+ logging.error(f"[Delegate][{self.agent.id}]: {str(e)}")
141
+
142
+ class SelectedDispatcher(Action):
143
+ """ An action is a response to the occurrence of an event """
144
+
145
+ def __init__(self) -> None:
146
+ """ Constructor """
147
+ super().__init__()
148
+
149
+ def calculate_close(self, description, data: any) -> bool:
150
+ """ Check close
151
+ @param data: Data
152
+ @return: True if the agent is closed, False otherwise
153
+ """
154
+ text1 = description
155
+ text2 = data['dto']['text'] if data and 'dto' in data and data['dto']['text'] is not None else ''
156
+ logging.info(f"Text1: {text1}")
157
+ logging.info(f"Query: {text2}")
158
+ documents = [text1, text2]
159
+ count_vectorizer = CountVectorizer()
160
+ sparse_matrix = count_vectorizer.fit_transform(documents)
161
+ doc_term_matrix = sparse_matrix.todense()
162
+ df = pd.DataFrame(
163
+ doc_term_matrix,
164
+ columns=count_vectorizer.get_feature_names_out(),
165
+ index=[text1, text2],
166
+ )
167
+ res = cosine_similarity(df, df)
168
+ similarity = res[0][1]
169
+ return similarity
170
+
171
+ @abstractmethod
172
+ def manual_selection(self, data: any) -> object:
173
+ """ Manual selection
174
+ @param data: Data
175
+ @return: Tuple with the agent and the score
176
+ """
177
+ raise NotImplementedError("The method manual_selection must be implemented in the subclass")
178
+
179
+ def execute(self, data: any) -> None:
180
+ """
181
+ Response.
182
+ @param data Event data
183
+ """
184
+ try:
185
+ logging.info('Assign to agent...')
186
+ session_id = data['dto']['session']['session_id'] if 'session' in data['dto'] else None
187
+ agent_list = self.agent.get_agent_list()
188
+ logging.debug('List of agents: ' + str(agent_list))
189
+ if session_id in self.agent.planilla:
190
+ mayor_ag_id = self.agent.planilla[session_id]
191
+ logging.info('The session is already assigned')
192
+ logging.info(f'The agent {mayor_ag_id} will be assigned')
193
+ self.agent.add_to_hold(data, mayor_ag_id)
194
+ else:
195
+ score_mayor = 0
196
+ mayor_ag = self.manual_selection(data['dto'])
197
+ if mayor_ag:
198
+ logging.info(f'The agent {mayor_ag.id} will be assigned')
199
+ self.agent.add_to_hold(data, mayor_ag_id)
200
+ else:
201
+ roles = []
202
+ # Get the agent asocciated with the data.
203
+ for agent_id in agent_list:
204
+ agent = self.adm.get_agent(agent_id)
205
+ # Chec if the agent is instance of AugmentedGeneration
206
+ if isinstance(agent, Dialog) or isinstance(agent, AugmentedGeneration):
207
+ # Get the role
208
+ role = agent.get_role()
209
+
210
+ if not role.name in roles:
211
+ score = self.calculate_close(role.description, data)
212
+ logging.info(f"Score: {score}")
213
+ if score > score_mayor:
214
+ score_mayor = score
215
+ mayor_ag = agent
216
+
217
+ if not role.name in roles:
218
+ roles.append(role.name)
219
+ else:
220
+ logging.info(f"The {agent_id} is not instance of AugmentedGeneration or Dialog")
221
+
222
+ # Check if the mayor agent is the same as the agent
223
+ if mayor_ag:
224
+ logging.info(f'The agent {mayor_ag.id} will be assigned')
225
+ self.agent.add_to_hold(data, mayor_ag.id)
226
+ else:
227
+ logging.error('[Error, toAssign]: No agent found for the request')
228
+ data['gateway'].put('ERROR')
229
+ except Exception as e:
230
+ traceback.print_exc()
231
+ logging.error(f"[Delegate][{self.agent.id}]: {str(e)}")
232
+ data['gateway'].put('ERROR')
233
+
234
+ def get_planilla(self) -> dict:
235
+ return self.agent.planilla
236
+
237
+ # --------------------------------------------------------
238
+ # Define Delegate Action by default
239
+ # --------------------------------------------------------
240
+
241
+ class Delegate(Action):
242
+ """ An action is a response to the occurrence of an event """
243
+
244
+ def active_timeout(self, ag, time: int) -> None:
245
+ """ Active timeout
246
+ @param time: Time
247
+ """
248
+ logging.info(f"[Delegate] Send event timeout {time}")
249
+ self.adm.send_event(ag, 'timeout', {'time': time, 'command': 'start'})
250
+
251
+ def execute(self, data: any) -> None:
252
+ """
253
+ Response.
254
+ @param data Event data
255
+ """
256
+ ag = self.agent.get_free_queue().get()
257
+ self.agent.get_request_dict()[ag] = {
258
+ 'gateway': data['gateway'],
259
+ 'dtoList': []
260
+ }
261
+ logging.info(f"[Delegate][{self.agent.id}]: Assign to agent {ag}")
262
+ self.adm.send_event(ag, 'task', data['dto'])
263
+ logging.info(f"[Delegate][{self.agent.id}]: Agent {ag} assigned")
264
+ if 'timeout' in self.agent.state:
265
+ self.active_timeout(ag, self.agent.state['timeout'])
266
+ else:
267
+ raise DispatcherException('[Delegate]: Timeout not defined in the state as "timeout" key')
268
+
269
+ # --------------------------------------------------------
270
+ # Define Action
271
+ # --------------------------------------------------------
272
+
273
+ class NotifyFreeAction(Action):
274
+ """ An action is a response to the occurrence of an event """
275
+
276
+ def execute(self, data: any) -> None:
277
+ """
278
+ Response.
279
+ @param data Event data
280
+ """
281
+ self.agent.get_free_dict()[data] = None
282
+
283
+ # --------------------------------------------------------
284
+ # Define Action
285
+ # --------------------------------------------------------
286
+
287
+ class ResponseAction(Action):
288
+ """ An action is a response to the occurrence of an event """
289
+
290
+ def send_response(self, request: dict) -> None:
291
+ """ Send response
292
+ @param request: Request
293
+ """
294
+ if len(request['dtoList']) == 1:
295
+ request['gateway'].put(request['dtoList'][0])
296
+ else:
297
+ request['gateway'].put(request['dtoList'])
298
+
299
+ def execute(self, data: dict) -> None:
300
+ """ Execute
301
+ @param data: Data
302
+ """
303
+ #@TODO: Check if the data is valid
304
+ #logging.info(f"[ResponseAction][{self.agent.id}]: Obtiene respuesta")
305
+ if data['source'] in self.agent.get_request_dict():
306
+ request = self.agent.get_request_dict()[data['source']]
307
+
308
+ if 'timeout' in data:
309
+ logging.info(f"[ResponseAction][{self.agent.id}]: Timeout ******************")
310
+ request['gateway'].put("TIMEOUT")
311
+ else:
312
+ request['dtoList'].append(data['result'])
313
+ if len(request['dtoList']) >= self.agent.get_buffer_size():
314
+ self.send_response(request)
315
+ self.adm.send_event(data['source'], 'timeout', {'command': 'stop'})
316
+ if data['reset']:
317
+ logging.info(f"[ResponseAction][{self.agent.id}]: Reset ******************")
318
+ delegate = self.agent.get_delegate()
319
+ print(f"Delegate: {delegate}")
320
+ planilla = delegate.get_planilla()
321
+ print(f"Planilla: {planilla}")
322
+ planilla.pop(data['session_id'], None)
323
+ logging.info(f"[ResponseAction][{self.agent.id}]: Planilla: actualizada")
324
+ else:
325
+ logging.warning(f"[ResponseAction][{self.agent.id}]: Warning ******************")
326
+ logging.warning(f"[ResponseAction][{self.agent.id}]: {data}")
327
+
328
+ # --------------------------------------------------------
329
+ # Define component
330
+ # --------------------------------------------------------
331
+
332
+ class DispatcherController(Agent):
333
+ """ Represents the agent that delegates the execution of actions to other agents """
334
+
335
+ def __init__(self, agent_id:str, buffer_size:int, pool_size:int, delegate=None) -> None:
336
+ """ Constructor
337
+ @param agent_id: Agent ID
338
+ @param type: Pool type
339
+ @param buffer_size: Buffer size
340
+ @param pool_size: Pool size
341
+ """
342
+ self.__buffer_size = buffer_size
343
+ self.__request_dict = {}
344
+ self.__pool_size = pool_size
345
+ self.__free_dict = {}
346
+ self.__agent_list = []
347
+ self.__delegate = delegate
348
+ self.__delegate_obj = None
349
+
350
+ self.alive = True
351
+ self.hold_dict = {}
352
+ self.umbral_cinco_minutos = timedelta(minutes=5)
353
+ self.planilla = {}
354
+
355
+ super().__init__(agent_id)
356
+
357
+ def setup(self) -> None:
358
+ """ Set up method """
359
+ self._social = True
360
+ self.add_behavior('Delegate')
361
+ if self.__delegate:
362
+ self.__delegate_obj = self.__delegate()
363
+ self.bind_action('Delegate', 'delegate', self.__delegate_obj)
364
+ else:
365
+ self.bind_action('Delegate', 'delegate', Delegate())
366
+ self.add_behavior('Notify')
367
+ self.bind_action('Notify', 'notify', NotifyFreeAction())
368
+ self.add_behavior('Response')
369
+ self.bind_action('Response', 'response', ResponseAction())
370
+ self.add_behavior('BufferDispatcher')
371
+ self.bind_action('BufferDispatcher', 'buffer_dispatcher', BufferDispatcher())
372
+ self.build()
373
+
374
+ def suscribe_agent(self, agent:Agent) -> None:
375
+ """ Suscribes an agent to the controller
376
+ @param agent: Agent
377
+ """
378
+ self.__agent_list.append(agent.id)
379
+ agent.set_controller(self.id)
380
+ agent.set_controller_type('POOL')
381
+ if len(self.__agent_list) > self.__pool_size:
382
+ raise DispatcherException('[Warn, suscribeAgent]: The pool is full')
383
+ self.__free_dict[agent.id] = agent
384
+ actions = agent.get_actions()
385
+ for action in actions:
386
+ action.set_is_pool(True)
387
+ action.set_enable_response(True)
388
+
389
+ def suscribe_remote_agent(self, agent_id:str) -> None:
390
+ """ Suscribes an agent to the controller
391
+ @param agent_id: Agent ID
392
+ """
393
+ if not isinstance(agent_id, str):
394
+ raise DispatcherException('[Warn, suscribeRemoteAgent]: The object to subscribe is not an agent ID')
395
+ self.__agent_list.append(agent_id)
396
+ self.__free_dict[agent_id] = None
397
+
398
+ def broadcast_event(self, event:any, data:any) -> None:
399
+ """ Broadcasts an event to the agents
400
+ @param event: Event
401
+ @param data: Data
402
+ """
403
+ from ..mas import Adm
404
+ for agent_id in self.__agent_list:
405
+ Adm().send_event(agent_id, event, data)
406
+
407
+ def check_hold(self, data):
408
+ text = data['dto']['text']
409
+ text_hash = hash(text)
410
+ if text_hash in self.hold_dict:
411
+ for item in self.hold_dict[text_hash]:
412
+ if item['data']['dto']['text'] == text:
413
+ logging.info(f"[Select]:[Dispacher]: La consulta {text} ya esta en hold")
414
+ return True
415
+ return False
416
+
417
+ def check_time(self, data):
418
+ """
419
+ Retorna True si esta por debajo de 5 minutos,
420
+ False en caso contrario.
421
+ """
422
+ item = None
423
+ text = data['dto']['text']
424
+ text_hash = hash(data['dto']['text'])
425
+ current = datetime.now()
426
+ for itm in self.hold_dict[text_hash]:
427
+ if itm['data']['dto']['text'] == text:
428
+ item = itm
429
+ break
430
+ diferencia_tiempo = current - item["lasttime"]
431
+ return diferencia_tiempo < self.umbral_cinco_minutos
432
+
433
+ def add_to_hold(self, data, mayor_ag_id):
434
+ text = data['dto']['text']
435
+ if not self.check_hold(data):
436
+ self.hold_dict[hash(text)] = []
437
+ self.hold_dict[hash(text)].append({
438
+ "data": data,
439
+ "lasttime": datetime.now(),
440
+ "mayor_ag_id": mayor_ag_id
441
+ })
442
+ logging.info(f"[Select]:[Dispacher]: Se asigan en el hold la consulta {data['dto']['text']}")
443
+
444
+
445
+ def star_behavior(self, adm, agent_id) -> None:
446
+ """ Active timeout
447
+ @param time: Time
448
+ """
449
+ logging.info("[Delegate]: Starting periodict behavior...")
450
+ adm.send_event(agent_id, 'buffer_dispatcher', None)
451
+ logging.info("[Delegate]: Periodict behavior started")
452
+
453
+ @abstractmethod
454
+ def build(self) -> None:
455
+ """ Builds the agent """
456
+ pass
457
+
458
+ def get_agent_list(self) -> list:
459
+ """ Gets the agent list
460
+ @return: Agent list
461
+ """
462
+ return self.__agent_list
463
+
464
+ def get_free_dict(self) -> Queue:
465
+ """ Gets the free queue
466
+ @return: Free queue
467
+ """
468
+ return self.__free_dict
469
+
470
+ def get_request_dict(self) -> dict:
471
+ """ Gets the request dictionary
472
+ @return: Request dictionary
473
+ """
474
+ return self.__request_dict
475
+
476
+ def get_buffer_size(self) -> int:
477
+ """ Gets the buffer size
478
+ @return: Buffer size
479
+ """
480
+ return self.__buffer_size
481
+
482
+ def get_delegate(self) -> Action:
483
+ """ Gets the delegate
484
+ @return: Delegate
485
+ """
486
+ return self.__delegate_obj
487
+
488
+ def is_block(self) -> bool:
489
+ """ Checks if the pool is blocking
490
+ @return: True if the pool is blocking, False otherwise
491
+ """
492
+ return True
493
+
494
+
495
+ # --------------------------------------------------------
496
+ # Builder Methods
497
+ # --------------------------------------------------------
498
+
499
+ # --------------------------------------------------------
500
+ # Define Dispacher Agent
501
+
502
+ class DispacherAgent(DispatcherController):
503
+ """ Through a class the concept of agent is defined """
504
+
505
+ def build(self):
506
+ """
507
+ Method that allows defining the structure and
508
+ resources of the agent
509
+ """
510
+ pass
511
+
512
+ def shutdown(self):
513
+ """ Method to free up the resources taken by the agent """
514
+ pass
515
+
516
+ # --------------------------------------------------------
517
+ # Define Worker Agent
518
+
519
+ class WorkerAgent(Worker):
520
+ """ Through a class the concept of agent is defined """
521
+
522
+ def __init__(self, agent_id:str, task:Task) -> None:
523
+ """ Constructor
524
+ @param agent_id: Agent ID
525
+ @param task: Task
526
+ """
527
+ self.__task = task
528
+ super().__init__(agent_id)
529
+
530
+ def build(self):
531
+ """
532
+ Method that allows defining the structure and
533
+ resources of the agent
534
+ """
535
+ # Assign an action to the behavior
536
+ self.bind_task(self.__task)
537
+
538
+ def shutdown(self):
539
+ """ Method to free up the resources taken by the agent """
540
+ pass
541
+
542
+ # --------------------------------------------------------
543
+ # Define build Method
544
+
545
+ def build_dispatcher_controller(name_team:str, agent_count, task_class:Task) -> DispatcherController:
546
+ """ Builds the controller
547
+ @param name_team: Team name
548
+ @param agent_count: Agent count
549
+ @param task_class: Task Class
550
+ @return: Controller
551
+ """
552
+ # Define worker agent list
553
+ w_ag_list = []
554
+ # Iterate over the number of agents
555
+ for i in range(agent_count):
556
+ short_uuid = generate_short_uuid()
557
+ w_id = f"worker-agent-{i}-{short_uuid}"
558
+ # Create the agent
559
+ w_ag = WorkerAgent(w_id, task_class())
560
+ # Start the agent
561
+ w_ag.start()
562
+ # Add the agent to the list
563
+ w_ag_list.append(w_ag)
564
+ # Create the controller
565
+ dispatcher = DispacherAgent(name_team, 1, agent_count)
566
+ # Subscribe the agents to the controller
567
+ for w_ag in w_ag_list:
568
+ dispatcher.suscribe_agent(w_ag)
569
+ # Start the controller
570
+ dispatcher.start()
571
+ # Return the controller
572
+ return dispatcher
573
+
574
+
575
+ class LLMDispatcherDelegate(Action):
576
+ """ An action is a response to the occurrence of an event """
577
+
578
+ def __init__(self) -> None:
579
+ """ Constructor """
580
+ super().__init__()
581
+ self.__rewier = {}
582
+ self.planilla = {}
583
+
584
+ def active_timeout(self, ag, time: int) -> None:
585
+ """ Active timeout
586
+ @param time: Time
587
+ """
588
+ logging.info(f"[Delegate] Send event timeout {time}")
589
+ self.adm.send_event(ag, 'timeout', {'time': time, 'command': 'start'})
590
+
591
+ @abstractmethod
592
+ def manual_selection(self, data: any) -> object:
593
+ """ Manual selection
594
+ @param data: Data
595
+ @return: Tuple with the agent and the score
596
+ """
597
+ raise NotImplementedError("The method manual_selection must be implemented in the subclass")
598
+
599
+ def execute(self, data: any) -> None:
600
+ """
601
+ Response.
602
+ @param data Event data
603
+ """
604
+ try:
605
+ response = None
606
+ logging.info('Assign to agent...')
607
+ session_id = data['dto']['session']['session_id'] if 'session' in data['dto'] else None
608
+ agent_list = self.agent.get_agent_list()
609
+ agent_count = len(agent_list)
610
+ logging.debug('List of agents: ' + str(agent_list))
611
+ if session_id in self.planilla:
612
+ mayor_ag_id = self.planilla[session_id]
613
+ logging.info('The session is already assigned')
614
+ logging.info(f'The agent {mayor_ag_id} will be assigned')
615
+ exit = False
616
+ while not exit:
617
+ ag = self.agent.get_free_queue().get()
618
+ agent_obj = self.adm.get_agent(ag)
619
+ # Get the role
620
+ if mayor_ag_id == agent_obj.id:
621
+ logging.info(f'The agent {ag} is assigned')
622
+ self.agent.get_request_dict()[ag] = {
623
+ 'gateway': data['gateway'],
624
+ 'dtoList': []
625
+ }
626
+ self.adm.send_event(ag, 'task', data['dto'])
627
+ self.__rewier[ag] = 0
628
+ exit = True
629
+ else:
630
+ logging.debug('The agent does not match the role')
631
+ self.adm.send_event(agent_obj.get_controller(), 'notify', ag)
632
+ if ag in self.__rewier:
633
+ self.__rewier[ag] = self.__rewier[ag] + 1
634
+ else:
635
+ self.__rewier[ag] = 0
636
+ if self.__rewier[ag] >= agent_count * 3:
637
+ data['gateway'].put('ERROR')
638
+ logging.error('[Error, toAssign]: The agent is not available')
639
+ else:
640
+ select_agent = self.manual_selection(data['dto'])
641
+ # Check if agent was selected
642
+ if not select_agent:
643
+ select_agent, response = self.agent.special_dispatch(data)
644
+ # Check if agent was selected
645
+ if select_agent:
646
+ logging.info(f'The agent {select_agent} will be assigned')
647
+ exit = False
648
+ while not exit:
649
+ ag = self.agent.get_free_queue().get()
650
+ agent_obj = self.adm.get_agent(ag)
651
+ # Chec if the agent is instance of AugmentedGeneration
652
+ if isinstance(agent_obj, Dialog):
653
+ # Get the role
654
+ tipo = "-".join(agent_obj.id.split('-')[0:-1])
655
+ if select_agent == tipo:
656
+ logging.info(f'The agent {ag} is assigned')
657
+ self.agent.get_request_dict()[ag] = {
658
+ 'gateway': data['gateway'],
659
+ 'dtoList': []
660
+ }
661
+ if response:
662
+ data['dto']['rq_query'] = response
663
+ self.adm.send_event(ag, 'task', data['dto'])
664
+ self.__rewier[ag] = 0
665
+ exit = True
666
+ self.planilla[session_id] = agent_obj.id
667
+ else:
668
+ logging.debug('The agent does not match the role')
669
+ self.adm.send_event(agent_obj.get_controller(), 'notify', ag)
670
+ if ag in self.__rewier:
671
+ self.__rewier[ag] = self.__rewier[ag] + 1
672
+ else:
673
+ self.__rewier[ag] = 0
674
+ if self.__rewier[ag] >= agent_count * 3:
675
+ data['gateway'].put('ERROR')
676
+ logging.error('[Error, toAssign]: The agent is not available')
677
+ else:
678
+ self.agent.get_request_dict()[ag] = {
679
+ 'gateway': data['gateway'],
680
+ 'dtoList': []
681
+ }
682
+ self.adm.send_event(ag, 'task', data['dto'])
683
+ exit = True
684
+ else:
685
+ ag = self.agent.get_free_queue().get()
686
+ self.agent.get_request_dict()[ag] = {
687
+ 'gateway': data['gateway'],
688
+ 'dtoList': []
689
+ }
690
+ self.adm.send_event(ag, 'task', data['dto'])
691
+ # Check timeout
692
+ if 'timeout' in self.agent.state:
693
+ self.active_timeout(ag, self.agent.state['timeout'])
694
+ else:
695
+ data['gateway'].put('ERROR')
696
+ logging.error('[Delegate]: Timeout not defined in the state as "timeout" key')
697
+ except Exception as e:
698
+ traceback.print_exc()
699
+ logging.error(f"[Delegate][{self.agent.id}]: {str(e)}")
700
+ data['gateway'].put('ERROR')
701
+
702
+ def get_planilla(self) -> dict:
703
+ return self.planilla
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pbesa
3
- Version: 4.0.36
3
+ Version: 4.0.37
4
4
  License-File: LICENSE
5
5
  License-File: LICENSE.txt
6
6
  Requires-Dist: pymongo>=4.6.3
@@ -118,6 +118,7 @@ pbesa/social/delegator_team.py
118
118
  pbesa/social/dialog.py
119
119
  pbesa/social/dispatcher_team.py
120
120
  pbesa/social/prompts.py
121
+ pbesa/social/sel_dispatcher_team.py
121
122
  pbesa/social/selected_dispatcher_team.py
122
123
  pbesa/social/templates.py
123
124
  pbesa/social/worker.py
@@ -4,7 +4,7 @@ from setuptools import setup, find_packages
4
4
 
5
5
  setup(
6
6
  name='pbesa',
7
- version='4.0.36',
7
+ version='4.0.37',
8
8
  packages=find_packages(),
9
9
  install_requires=[
10
10
  'pymongo>=4.6.3',
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes