ai-parrot 0.8.3__cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl

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.

Potentially problematic release.


This version of ai-parrot might be problematic. Click here for more details.

Files changed (128) hide show
  1. ai_parrot-0.8.3.dist-info/LICENSE +21 -0
  2. ai_parrot-0.8.3.dist-info/METADATA +306 -0
  3. ai_parrot-0.8.3.dist-info/RECORD +128 -0
  4. ai_parrot-0.8.3.dist-info/WHEEL +6 -0
  5. ai_parrot-0.8.3.dist-info/top_level.txt +2 -0
  6. parrot/__init__.py +30 -0
  7. parrot/bots/__init__.py +5 -0
  8. parrot/bots/abstract.py +1115 -0
  9. parrot/bots/agent.py +492 -0
  10. parrot/bots/basic.py +9 -0
  11. parrot/bots/bose.py +17 -0
  12. parrot/bots/chatbot.py +271 -0
  13. parrot/bots/cody.py +17 -0
  14. parrot/bots/copilot.py +117 -0
  15. parrot/bots/data.py +730 -0
  16. parrot/bots/dataframe.py +103 -0
  17. parrot/bots/hrbot.py +15 -0
  18. parrot/bots/interfaces/__init__.py +1 -0
  19. parrot/bots/interfaces/retrievers.py +12 -0
  20. parrot/bots/notebook.py +619 -0
  21. parrot/bots/odoo.py +17 -0
  22. parrot/bots/prompts/__init__.py +41 -0
  23. parrot/bots/prompts/agents.py +91 -0
  24. parrot/bots/prompts/data.py +214 -0
  25. parrot/bots/retrievals/__init__.py +1 -0
  26. parrot/bots/retrievals/constitutional.py +19 -0
  27. parrot/bots/retrievals/multi.py +122 -0
  28. parrot/bots/retrievals/retrieval.py +610 -0
  29. parrot/bots/tools/__init__.py +7 -0
  30. parrot/bots/tools/eda.py +325 -0
  31. parrot/bots/tools/pdf.py +50 -0
  32. parrot/bots/tools/plot.py +48 -0
  33. parrot/bots/troc.py +16 -0
  34. parrot/conf.py +170 -0
  35. parrot/crew/__init__.py +3 -0
  36. parrot/crew/tools/__init__.py +22 -0
  37. parrot/crew/tools/bing.py +13 -0
  38. parrot/crew/tools/config.py +43 -0
  39. parrot/crew/tools/duckgo.py +62 -0
  40. parrot/crew/tools/file.py +24 -0
  41. parrot/crew/tools/google.py +168 -0
  42. parrot/crew/tools/gtrends.py +16 -0
  43. parrot/crew/tools/md2pdf.py +25 -0
  44. parrot/crew/tools/rag.py +42 -0
  45. parrot/crew/tools/search.py +32 -0
  46. parrot/crew/tools/url.py +21 -0
  47. parrot/exceptions.cpython-310-x86_64-linux-gnu.so +0 -0
  48. parrot/handlers/__init__.py +4 -0
  49. parrot/handlers/agents.py +292 -0
  50. parrot/handlers/bots.py +196 -0
  51. parrot/handlers/chat.py +192 -0
  52. parrot/interfaces/__init__.py +6 -0
  53. parrot/interfaces/database.py +27 -0
  54. parrot/interfaces/http.py +805 -0
  55. parrot/interfaces/images/__init__.py +0 -0
  56. parrot/interfaces/images/plugins/__init__.py +18 -0
  57. parrot/interfaces/images/plugins/abstract.py +58 -0
  58. parrot/interfaces/images/plugins/exif.py +709 -0
  59. parrot/interfaces/images/plugins/hash.py +52 -0
  60. parrot/interfaces/images/plugins/vision.py +104 -0
  61. parrot/interfaces/images/plugins/yolo.py +66 -0
  62. parrot/interfaces/images/plugins/zerodetect.py +197 -0
  63. parrot/llms/__init__.py +1 -0
  64. parrot/llms/abstract.py +69 -0
  65. parrot/llms/anthropic.py +58 -0
  66. parrot/llms/gemma.py +15 -0
  67. parrot/llms/google.py +44 -0
  68. parrot/llms/groq.py +67 -0
  69. parrot/llms/hf.py +45 -0
  70. parrot/llms/openai.py +61 -0
  71. parrot/llms/pipes.py +114 -0
  72. parrot/llms/vertex.py +89 -0
  73. parrot/loaders/__init__.py +9 -0
  74. parrot/loaders/abstract.py +628 -0
  75. parrot/loaders/files/__init__.py +0 -0
  76. parrot/loaders/files/abstract.py +39 -0
  77. parrot/loaders/files/text.py +63 -0
  78. parrot/loaders/txt.py +26 -0
  79. parrot/manager.py +333 -0
  80. parrot/models.py +504 -0
  81. parrot/py.typed +0 -0
  82. parrot/stores/__init__.py +11 -0
  83. parrot/stores/abstract.py +248 -0
  84. parrot/stores/chroma.py +188 -0
  85. parrot/stores/duck.py +162 -0
  86. parrot/stores/embeddings/__init__.py +10 -0
  87. parrot/stores/embeddings/abstract.py +46 -0
  88. parrot/stores/embeddings/base.py +52 -0
  89. parrot/stores/embeddings/bge.py +20 -0
  90. parrot/stores/embeddings/fastembed.py +17 -0
  91. parrot/stores/embeddings/google.py +18 -0
  92. parrot/stores/embeddings/huggingface.py +20 -0
  93. parrot/stores/embeddings/ollama.py +14 -0
  94. parrot/stores/embeddings/openai.py +26 -0
  95. parrot/stores/embeddings/transformers.py +21 -0
  96. parrot/stores/embeddings/vertexai.py +17 -0
  97. parrot/stores/empty.py +10 -0
  98. parrot/stores/faiss.py +160 -0
  99. parrot/stores/milvus.py +397 -0
  100. parrot/stores/postgres.py +653 -0
  101. parrot/stores/qdrant.py +170 -0
  102. parrot/tools/__init__.py +23 -0
  103. parrot/tools/abstract.py +68 -0
  104. parrot/tools/asknews.py +33 -0
  105. parrot/tools/basic.py +51 -0
  106. parrot/tools/bby.py +359 -0
  107. parrot/tools/bing.py +13 -0
  108. parrot/tools/docx.py +343 -0
  109. parrot/tools/duck.py +62 -0
  110. parrot/tools/execute.py +56 -0
  111. parrot/tools/gamma.py +28 -0
  112. parrot/tools/google.py +170 -0
  113. parrot/tools/gvoice.py +301 -0
  114. parrot/tools/results.py +278 -0
  115. parrot/tools/stack.py +27 -0
  116. parrot/tools/weather.py +70 -0
  117. parrot/tools/wikipedia.py +58 -0
  118. parrot/tools/zipcode.py +198 -0
  119. parrot/utils/__init__.py +2 -0
  120. parrot/utils/parsers/__init__.py +5 -0
  121. parrot/utils/parsers/toml.cpython-310-x86_64-linux-gnu.so +0 -0
  122. parrot/utils/toml.py +11 -0
  123. parrot/utils/types.cpython-310-x86_64-linux-gnu.so +0 -0
  124. parrot/utils/uv.py +11 -0
  125. parrot/version.py +10 -0
  126. resources/users/__init__.py +5 -0
  127. resources/users/handlers.py +13 -0
  128. resources/users/models.py +205 -0
@@ -0,0 +1,63 @@
1
+ import aiofiles
2
+ from .abstract import FilePlugin
3
+
4
+ class TextFile(FilePlugin):
5
+ """
6
+ A class to handle text files asynchronously.
7
+ """
8
+ def __init__(self, path: str, encoding: str = 'utf-8'):
9
+ """
10
+ Initialize the TextFile with a file path.
11
+
12
+ Args:
13
+ path: Path to the text file.
14
+ encoding: File encoding (default: utf-8)
15
+ """
16
+ super().__init__()
17
+ self.path = path
18
+ self.encoding = encoding
19
+ self._file = None
20
+
21
+ async def open(self):
22
+ """
23
+ Asynchronously open the text file.
24
+ """
25
+ try:
26
+ self._file = await aiofiles.open(self.path, mode='r', encoding=self.encoding)
27
+ self.logger.debug(
28
+ f"Successfully opened file: {self.path}"
29
+ )
30
+ except Exception as e:
31
+ self.logger.error(f"Error opening file {self.path}: {str(e)}")
32
+ raise
33
+
34
+ async def close(self):
35
+ """
36
+ Asynchronously close the text file.
37
+ """
38
+ if self._file is not None:
39
+ try:
40
+ await self._file.close()
41
+ self.logger.debug(f"Successfully closed file: {self.path}")
42
+ except Exception as e:
43
+ self.logger.error(f"Error closing file {self.path}: {str(e)}")
44
+ raise
45
+ finally:
46
+ self._file = None
47
+
48
+ async def read(self) -> str:
49
+ """
50
+ Asynchronously read the content of the text file.
51
+
52
+ Returns:
53
+ Content of the text file as a string.
54
+ """
55
+ if self._file is None:
56
+ await self.open()
57
+
58
+ try:
59
+ content = await self._file.read()
60
+ return content
61
+ except Exception as e:
62
+ self.logger.error(f"Error reading file {self.path}: {str(e)}")
63
+ raise
parrot/loaders/txt.py ADDED
@@ -0,0 +1,26 @@
1
+ from typing import List
2
+ from pathlib import Path
3
+ from .abstract import AbstractLoader
4
+ from .files.text import TextFile
5
+
6
+
7
+ class TextLoader(AbstractLoader):
8
+ """
9
+ Loader for Text-based Files.
10
+ """
11
+ extensions: List[str] = ['.txt', '.text', '.md', '.markdown', '.rd']
12
+
13
+ async def _load(self, path: Path, **kwargs) -> list:
14
+ """
15
+ Load a TXT file.
16
+
17
+ Args:
18
+ path (Path): The path to the TXT file.
19
+
20
+ Returns:
21
+ list: A list of Langchain Documents.
22
+ """
23
+ async with TextFile(path) as file:
24
+ content = await file.read()
25
+ return self.create_document(content, path)
26
+ return []
parrot/manager.py ADDED
@@ -0,0 +1,333 @@
1
+ """
2
+ Chatbot Manager.
3
+
4
+ Tool for instanciate, managing and interacting with Chatbot through APIs.
5
+ """
6
+ from typing import Any, Dict, Type
7
+ from importlib import import_module
8
+ from aiohttp import web
9
+ from datamodel.exceptions import ValidationError
10
+ from navconfig.logging import logging
11
+ from asyncdb.exceptions import NoDataFound
12
+ from .bots.abstract import AbstractBot
13
+ from .bots.basic import BasicBot
14
+ from .bots.chatbot import Chatbot
15
+ from .bots.data import PandasAgent
16
+ from .handlers.chat import ChatHandler, BotHandler
17
+ from .handlers.agents import AgentHandler
18
+ from .handlers import ChatbotHandler
19
+ from .models import ChatbotModel, AgentModel
20
+
21
+
22
+ class BotManager:
23
+ """BotManager.
24
+
25
+ Manage Bots/Agents and interact with them through via aiohttp App.
26
+ Deploy and manage chatbots and agents using a RESTful API.
27
+
28
+ """
29
+ app: web.Application = None
30
+
31
+ def __init__(self) -> None:
32
+ self.app = None
33
+ self._bots: Dict[str, AbstractBot] = {}
34
+ self._agents: Dict[str, AbstractBot] = {}
35
+ self.logger = logging.getLogger(
36
+ name='Parrot.Manager'
37
+ )
38
+
39
+ def get_bot_class(self, class_name: str) -> Type[AbstractBot]:
40
+ """
41
+ Dynamically import a Bot class based on the class name
42
+ from the relative module '.bots'.
43
+ Args:
44
+ class_name (str): The name of the Bot class to be imported.
45
+ Returns:
46
+ Type[AbstractBot]: A Bot class derived from AbstractBot.
47
+ """
48
+ module = import_module('.bots', __package__)
49
+ try:
50
+ return getattr(module, class_name)
51
+ except AttributeError:
52
+ raise ImportError(
53
+ f"No class named '{class_name}' found in the module 'bots'."
54
+ )
55
+
56
+ async def load_bots(self, app: web.Application) -> None:
57
+ """Load all chatbots from DB."""
58
+ self.logger.info("Loading chatbots from DB...")
59
+ db = app['database']
60
+ async with await db.acquire() as conn:
61
+ ChatbotModel.Meta.connection = conn
62
+ try:
63
+ bots = await ChatbotModel.filter(enabled=True)
64
+ except Exception as e:
65
+ self.logger.error(
66
+ f"Failed to load chatbots from DB: {e}"
67
+ )
68
+ return
69
+ for bot in bots:
70
+ if bot.bot_type == 'chatbot':
71
+ self.logger.notice(
72
+ f"Loading chatbot '{bot.name}'..."
73
+ )
74
+ cls_name = bot.bot_class
75
+ if cls_name is None:
76
+ class_name = Chatbot
77
+ else:
78
+ class_name = self.get_bot_class(cls_name)
79
+ chatbot = class_name(
80
+ chatbot_id=bot.chatbot_id,
81
+ name=bot.name,
82
+ description=bot.description,
83
+ use_llm=bot.llm,
84
+ model_name=bot.model_name,
85
+ model_config=bot.model_config,
86
+ embedding_model=bot.embedding_model,
87
+ use_vectorstore=bot.vector_store,
88
+ vector_store=bot.database,
89
+ config_file=bot.config_file,
90
+ role=bot.role,
91
+ goal=bot.goal,
92
+ backstory=bot.backstory,
93
+ rationale=bot.rationale,
94
+ pre_instructions=bot.pre_instructions,
95
+ company_information=bot.company_information,
96
+ vector_info=bot.database,
97
+ permissions=bot.permissions,
98
+ attributes=bot.attributes,
99
+ )
100
+ try:
101
+ await chatbot.configure(
102
+ app=app
103
+ )
104
+ except ValidationError as e:
105
+ self.logger.error(
106
+ f"Invalid configuration for chatbot '{chatbot.name}': {e}"
107
+ )
108
+ except Exception as e:
109
+ self.logger.error(
110
+ f"Failed to configure Bot '{chatbot.name}': {e}"
111
+ )
112
+ elif bot.bot_type == 'agent':
113
+ self.logger.notice(
114
+ f"Unsupported kind of Agent '{bot.name}'..."
115
+ )
116
+ chatbot = None
117
+ if chatbot:
118
+ self.add_bot(chatbot)
119
+ self.logger.info(
120
+ ":: Chatbots loaded successfully."
121
+ )
122
+
123
+ async def load_agents(self, app: web.Application) -> None:
124
+ """Load all Agents from DB."""
125
+ self.logger.info("Loading Agents from DB...")
126
+ db = app['database']
127
+ async with await db.acquire() as conn:
128
+ AgentModel.Meta.connection = conn
129
+ try:
130
+ agents = await AgentModel.filter(enabled=True)
131
+ except Exception as e:
132
+ self.logger.error(
133
+ f"Failed to load Agents from DB: {e}"
134
+ )
135
+ return
136
+ for agent in agents:
137
+ cls_name = agent.agent_class
138
+ if cls_name is None:
139
+ class_name = PandasAgent
140
+ else:
141
+ class_name = self.get_bot_class(cls_name)
142
+ # Get the queries before agent creation.
143
+ try:
144
+ queries = await class_name.gen_data(
145
+ query=agent.query,
146
+ agent_name=agent.chatbot_id,
147
+ refresh=False
148
+ )
149
+ except ValueError as e:
150
+ self.logger.error(
151
+ f"Failed to load queries for Agent '{agent.name}': {e}"
152
+ )
153
+ continue
154
+ # then, create the Agent:
155
+ try:
156
+ chatbot = class_name(
157
+ chatbot_id=agent.chatbot_id,
158
+ name=agent.name,
159
+ df=queries,
160
+ query=agent.query,
161
+ description=agent.description,
162
+ use_llm=agent.llm,
163
+ model_name=agent.model_name,
164
+ temperature=agent.temperature,
165
+ tools=agent.tools,
166
+ model_config=agent.model_config,
167
+ role=agent.role,
168
+ goal=agent.goal,
169
+ backstory=agent.backstory,
170
+ rationale=agent.rationale,
171
+ permissions=agent.permissions,
172
+ attributes=agent.attributes,
173
+ capabilities=agent.capabilities,
174
+ )
175
+ except Exception as e:
176
+ self.logger.error(
177
+ f"Failed to configure Agent '{agent.name}': {e}"
178
+ )
179
+ if chatbot:
180
+ await chatbot.configure(
181
+ app=app
182
+ )
183
+ self.add_agent(chatbot)
184
+ self.logger.notice(
185
+ f"Loaded Agent '{agent.name}'..."
186
+ )
187
+ self.logger.info(
188
+ ":: IA Agents were loaded successfully."
189
+ )
190
+
191
+ def create_bot(self, class_name: Any = None, name: str = None, **kwargs) -> AbstractBot:
192
+ """Create a Bot and add it to the manager."""
193
+ if class_name is None:
194
+ class_name = Chatbot
195
+ chatbot = class_name(**kwargs)
196
+ chatbot.name = name
197
+ self.add_bot(chatbot)
198
+ if 'llm' in kwargs:
199
+ llm = kwargs['llm']
200
+ llm_name = llm.pop('name')
201
+ model = llm.pop('model')
202
+ llm = chatbot.load_llm(
203
+ llm_name, model=model, **llm
204
+ )
205
+ chatbot.llm = llm
206
+ return chatbot
207
+
208
+ def add_bot(self, bot: AbstractBot) -> None:
209
+ """Add a Bot to the manager."""
210
+ self._bots[bot.name] = bot
211
+
212
+ def get_bot(self, name: str) -> AbstractBot:
213
+ """Get a Bot by name."""
214
+ return self._bots.get(name)
215
+
216
+ def remove_bot(self, name: str) -> None:
217
+ """Remove a Bot by name."""
218
+ del self._bots[name]
219
+
220
+ def get_bots(self) -> Dict[str, AbstractBot]:
221
+ """Get all Bots declared on Manager."""
222
+ return self._bots
223
+
224
+ async def create_agent(self, class_name: Any = None, name: str = None, **kwargs) -> AbstractBot:
225
+ if class_name is None:
226
+ class_name = PandasAgent
227
+ agent = class_name(name=name, **kwargs)
228
+ self.add_agent(agent)
229
+ if 'llm' in kwargs:
230
+ llm = kwargs['llm']
231
+ llm_name = llm.pop('name')
232
+ model = llm.pop('model')
233
+ llm = agent.load_llm(
234
+ llm_name, model=model, **llm
235
+ )
236
+ agent.llm = llm
237
+ return agent
238
+
239
+ def add_agent(self, agent: AbstractBot) -> None:
240
+ """Add a Agent to the manager."""
241
+ self._agents[str(agent.chatbot_id)] = agent
242
+
243
+ def get_agent(self, name: str) -> AbstractBot:
244
+ """Get a Agent by ID."""
245
+ return self._agents.get(name)
246
+
247
+ def remove_agent(self, agent: AbstractBot) -> None:
248
+ """Remove a Bot by name."""
249
+ del self._agents[str(agent.chatbot_id)]
250
+
251
+ async def save_agent(self, name: str, **kwargs) -> None:
252
+ """Save a Agent to the DB."""
253
+ self.logger.info(f"Saving Agent {name} into DB ...")
254
+ db = self.app['database']
255
+ async with await db.acquire() as conn:
256
+ AgentModel.Meta.connection = conn
257
+ try:
258
+ try:
259
+ agent = await AgentModel.get(name=name)
260
+ except NoDataFound:
261
+ agent = None
262
+ if agent:
263
+ self.logger.info(f"Agent {name} already exists.")
264
+ for key, val in kwargs.items():
265
+ agent.set(key, val)
266
+ await agent.update()
267
+ self.logger.info(f"Agent {name} updated.")
268
+ else:
269
+ self.logger.info(f"Agent {name} not found. Creating new one.")
270
+ # Create a new Agent
271
+ new_agent = AgentModel(
272
+ name=name,
273
+ **kwargs
274
+ )
275
+ await new_agent.insert()
276
+ self.logger.info(f"Agent {name} saved into DB.")
277
+ return True
278
+ except Exception as e:
279
+ self.logger.error(
280
+ f"Failed to Create new Agent {name} from DB: {e}"
281
+ )
282
+ return None
283
+
284
+ def get_app(self) -> web.Application:
285
+ """Get the app."""
286
+ if self.app is None:
287
+ raise RuntimeError("App is not set.")
288
+ return self.app
289
+
290
+ def setup(self, app: web.Application) -> web.Application:
291
+ if isinstance(app, web.Application):
292
+ self.app = app # register the app into the Extension
293
+ else:
294
+ self.app = app.get_app() # Nav Application
295
+ # register signals for startup and shutdown
296
+ self.app.on_startup.append(self.on_startup)
297
+ self.app.on_shutdown.append(self.on_shutdown)
298
+ # Add Manager to main Application:
299
+ self.app['bot_manager'] = self
300
+ ## Configure Routes
301
+ router = self.app.router
302
+ # Chat Information Router
303
+ router.add_view(
304
+ '/api/v1/chats',
305
+ ChatHandler
306
+ )
307
+ router.add_view(
308
+ '/api/v1/chat/{chatbot_name}',
309
+ ChatHandler
310
+ )
311
+ # Agent Handler:
312
+ router.add_view(
313
+ '/api/v1/agent',
314
+ AgentHandler
315
+ )
316
+ router.add_view(
317
+ '/api/v1/agent/{agent_name}',
318
+ AgentHandler
319
+ )
320
+ # ChatBot Manager
321
+ ChatbotHandler.configure(self.app, '/api/v1/bots')
322
+ return self.app
323
+
324
+ async def on_startup(self, app: web.Application) -> None:
325
+ """On startup."""
326
+ # configure all pre-configured chatbots:
327
+ await self.load_bots(app)
328
+ # configure all pre-configured agents:
329
+ await self.load_agents(app)
330
+
331
+ async def on_shutdown(self, app: web.Application) -> None:
332
+ """On shutdown."""
333
+ pass