ai-parrot 0.8.3__cp39-cp39-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-39-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-39-x86_64-linux-gnu.so +0 -0
  122. parrot/utils/toml.py +11 -0
  123. parrot/utils/types.cpython-39-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
parrot/tools/bby.py ADDED
@@ -0,0 +1,359 @@
1
+ from typing import List, Dict, Any, Union
2
+ import random
3
+ from orjson import JSONDecodeError
4
+ from pydantic import BaseModel, Field
5
+ # from pydantic.v1 import BaseModel, Field
6
+ from langchain_core.tools import BaseTool, BaseToolkit, StructuredTool, ToolException, Tool
7
+ from datamodel.parsers.json import json_decoder, json_encoder # pylint: disable=E0611
8
+ from datamodel.exceptions import ParserError # pylint: disable=E0611
9
+ from navconfig import config
10
+ from ..interfaces.http import HTTPService, ua
11
+
12
+
13
+ ctt_list: list = [
14
+ "f3dbf688e45146555bb2b8604a993601",
15
+ "06f4dfe367e87866397ef32302f5042e",
16
+ "4e07e03ff03f5debc4e09ac4db9239ac"
17
+ ]
18
+
19
+ sid_list: list = [
20
+ "d4fa1142-2998-4b68-af78-46d821bb3e1f",
21
+ "9627390e-b423-459f-83ee-7964dd05c9a8"
22
+ ]
23
+
24
+ class BestBuyProductAvailabilityInput(BaseModel):
25
+ """Input for the BestBuy product availability tool."""
26
+ zipcode: str = Field(..., description="The ZIP code to check availability in")
27
+ sku: str = Field(..., description="The SKU of the product to check")
28
+ location_id: str = Field(
29
+ ..., description="Optional specific location ID to check"
30
+ )
31
+ show_only_in_stock: bool = Field(
32
+ False, description="Whether to only show stores with product in stock"
33
+ )
34
+
35
+ model_config = {
36
+ "arbitrary_types_allowed": True,
37
+ "extra": "forbid", # Helps with compatibility
38
+ "json_schema_extra": {
39
+ "required": ["zipcode", "sku", "location_id"]
40
+ }
41
+ }
42
+
43
+ class BestBuyToolkit(BaseToolkit):
44
+ """Toolkit for interacting with BestBuy's API."""
45
+
46
+ api_key: str = Field(default=config.get('BESTBUY_APIKEY'))
47
+
48
+ http_service: HTTPService = Field(default_factory=lambda: HTTPService(
49
+ use_proxy=True,
50
+ cookies={
51
+ "CTT": random.choice(ctt_list),
52
+ "SID": random.choice(sid_list),
53
+ "bby_rdp": "l",
54
+ "bm_sz": "9F5ED0110AF18594E2347A89BB4AB998~YAAQxm1lX6EqYHGSAQAAw+apmhkhXIeGYEc4KnzUMsjeac3xEoQmTNz5+of62i3RXQL6fUI+0FvCb/jgSjiVQOcfaSF+LdLkOXP1F4urgeIcqp/dBAhu5MvZXaCQsT06bwr7j21ozhFfTTWhjz1HmZN8wecsE6WGbK6wXp/33ODKlLaGWkTutqHbkzvMiiHXBCs9hT8jVny0REfita4AfqTK85Y6/M6Uq4IaDLPBLnTtJ0cTlPHk1HmkG5EsnI46llghcx1KZnCGnvZfHdb2ME9YZJ2GmC2b7dNmAgyL/gSVpoNdCJOj5Jk6z/MCVhZ81OZfX4S01E2F1mBGq4uV5/1oK2KR4YgZP4dsTN8izEEPybUKGY3CyM1gOUc=~3556420~4277810",
55
+ "bby_cbc_lb": "p-browse-e",
56
+ "intl_splash": "false"
57
+ },
58
+ headers={
59
+ "Host": "www.bestbuy.com",
60
+ "Referer": "https://www.bestbuy.com/",
61
+ "TE": "trailers",
62
+ "Accept-Language": "en-US,en;q=0.5",
63
+ }
64
+ ))
65
+
66
+ # Add this model_config to allow arbitrary types
67
+ model_config = {
68
+ "arbitrary_types_allowed": True
69
+ }
70
+
71
+ def get_tools(self) -> List[BaseTool]:
72
+ """Get the tools in the toolkit."""
73
+ return [
74
+ self._get_availability_tool(),
75
+ self._get_product_information()
76
+ ]
77
+
78
+ def _get_product_information(self) -> StructuredTool:
79
+ """Create a tool for getting product information from BestBuy."""
80
+
81
+ async def _product_information(tool_input: Union[str, dict]) -> List[dict]:
82
+ """Get product information from BestBuy based on SKU, name, or search terms."""
83
+ # https://api.bestbuy.com/v1/products(name={product_name})?format=json&show=sku,name,salePrice,customerReviewAverage,customerReviewCount,manufacturer,modelNumber&apiKey={api_key}
84
+ if isinstance(tool_input, dict):
85
+ # Direct call with dict
86
+ input_data = tool_input
87
+ elif isinstance(tool_input, str):
88
+ # Might be a JSON string from LLM
89
+ try:
90
+ # input_data = json.loads(tool_input)
91
+ input_data = json_decoder(tool_input)
92
+ except (ParserError, JSONDecodeError):
93
+ # Not valid JSON, treat as zipcode with missing other params
94
+ input_data = {"product_name": tool_input}
95
+ else:
96
+ # Some other type that we don't expect
97
+ input_data = {"product_name": str(tool_input)}
98
+
99
+ # Product Name to be used in the search:
100
+ print('PRODUCT > ', input_data)
101
+
102
+ product_name = input_data.get("product_name", None)
103
+ search_terms = input_data.get("search_terms", None)
104
+ print(search_terms)
105
+ if search_terms:
106
+ search_terms = search_terms.split(',')
107
+ # I need in format: search=oven&search=stainless&search=steel
108
+ search_terms = '&'.join([f"search={term.strip()}" for term in search_terms])
109
+ url = f"https://api.bestbuy.com/v1/products({search_terms})?format=json&show=sku,name,salePrice,customerReviewAverage,customerReviewCount,manufacturer,modelNumber&apiKey={self.api_key}"
110
+ elif product_name:
111
+ if ',' in product_name:
112
+ search_terms = product_name.split(',')
113
+ search_terms = '&'.join([f"search={term.strip()}" for term in search_terms])
114
+ else:
115
+ search_terms = f"name={product_name.strip()}"
116
+ url = f"https://api.bestbuy.com/v1/products({search_terms})?format=json&show=sku,name,salePrice,customerReviewAverage,customerReviewCount,manufacturer,modelNumber&apiKey={self.api_key}"
117
+ else:
118
+ raise ToolException(
119
+ "Either product_name or search_terms must be provided."
120
+ )
121
+ # URL for BestBuy's Product API
122
+ result, error = await self.http_service._request(
123
+ url=url,
124
+ method="GET",
125
+ use_json=True,
126
+ use_proxy=True,
127
+ headers={
128
+ "User-Agent": random.choice(ua)
129
+ },
130
+ use_ssl=True,
131
+ follow_redirects=True,
132
+ raise_for_status=True,
133
+ full_response=False
134
+ )
135
+ products = result.get('products', [])
136
+ if not products:
137
+ return "No products found."
138
+
139
+ return products
140
+
141
+
142
+ return StructuredTool.from_function(
143
+ name="product_information",
144
+ description=(
145
+ "Use this tool to search for product information. "
146
+ "Input must be the search terms: "
147
+ "- search terms: different words separated by commas "
148
+ " Example input: {{\"search_terms\": \"oven,stainless\"}}"
149
+ ),
150
+ func=_product_information,
151
+ coroutine=_product_information,
152
+ infer_schema=False,
153
+ return_direct=False,
154
+ handle_tool_error=True
155
+ )
156
+
157
+ def _get_availability_tool(self) -> StructuredTool:
158
+ """Create a tool for checking product availability at BestBuy."""
159
+
160
+ async def _check_availability(tool_input: Union[str, dict]) -> str:
161
+ """Check BestBuy product availability based on SKU and location."""
162
+
163
+ # Input validation
164
+ # tool_input: str
165
+ try:
166
+ if isinstance(tool_input, dict):
167
+ # Direct call with dict
168
+ input_data = tool_input
169
+ elif isinstance(tool_input, str):
170
+ # Might be a JSON string from LLM
171
+ try:
172
+ # input_data = json.loads(tool_input)
173
+ input_data = json_decoder(tool_input)
174
+ except (ParserError, JSONDecodeError):
175
+ # Not valid JSON, treat as zipcode with missing other params
176
+ input_data = {"zipcode": tool_input}
177
+ else:
178
+ # Some other type that we don't expect
179
+ input_data = {"zipcode": str(tool_input)}
180
+ # Extract fields
181
+ zipcode = input_data.get("zipcode")
182
+ sku = input_data.get("sku")
183
+ location_id = input_data.get("location_id")
184
+ show_only_in_stock = input_data.get("show_only_in_stock", False)
185
+
186
+ except Exception as e:
187
+ # Final fallback - treat the entire input as a zipcode
188
+ zipcode = str(tool_input)
189
+ sku = None
190
+ location_id = None
191
+ show_only_in_stock = False
192
+
193
+ # Input validation
194
+ if not zipcode:
195
+ raise ToolException("ZIP code is required to check product availability")
196
+ if not sku:
197
+ raise ToolException("Product SKU is required to check availability")
198
+ if not location_id:
199
+ raise ToolException("Store location ID is required to check availability")
200
+
201
+ # Prepare the payload for the API call
202
+ payload = {
203
+ "locationId": location_id,
204
+ "zipCode": zipcode,
205
+ "showOnShelf": True,
206
+ "lookupInStoreQuantity": True,
207
+ "xboxAllAccess": False,
208
+ "consolidated": True,
209
+ "showOnlyOnShelf": False,
210
+ "showInStore": True,
211
+ "pickupTypes": [
212
+ "UPS_ACCESS_POINT",
213
+ "FEDEX_HAL"
214
+ ],
215
+ "onlyBestBuyLocations": True,
216
+ # TODO: add more products
217
+ "items": [
218
+ {
219
+ "sku": sku,
220
+ "condition": None,
221
+ "quantity": 1,
222
+ "itemSeqNumber": "1",
223
+ "reservationToken": None,
224
+ "selectedServices": [],
225
+ "requiredAccessories": [],
226
+ "isTradeIn": False,
227
+ "isLeased": False
228
+ }
229
+ ]
230
+ }
231
+
232
+ # Make the API call using the HTTP service
233
+ try:
234
+ # URL for BestBuy's availability API
235
+ url = "https://www.bestbuy.com/productfulfillment/c/api/2.0/storeAvailability"
236
+
237
+ # Make POST request with JSON payload
238
+ result, error = await self.http_service._request(
239
+ url=url,
240
+ method="POST",
241
+ data=payload,
242
+ use_json=True,
243
+ use_proxy=True,
244
+ headers={
245
+ "User-Agent": random.choice(ua)
246
+ },
247
+ use_ssl=True,
248
+ follow_redirects=True,
249
+ raise_for_status=True,
250
+ full_response=False
251
+ )
252
+
253
+ if error:
254
+ raise ToolException(
255
+ f"Error checking BestBuy availability: {error}"
256
+ )
257
+
258
+ # Process and format the response
259
+ if not result:
260
+ return "No data was returned from BestBuy. The service may be unavailable."
261
+
262
+ # Extract relevant information from the result
263
+ formatted_result = self._format_availability_response(result, location_id, sku, show_only_in_stock)
264
+ return formatted_result
265
+
266
+ except Exception as e:
267
+ raise ToolException(f"Failed to check BestBuy product availability: {str(e)}")
268
+
269
+ return StructuredTool.from_function(
270
+ name="availability",
271
+ description=(
272
+ "Use this tool to check product availability at a specific Best Buy store or zipcode. "
273
+ "Input must be a JSON object with the following fields: "
274
+ "- zipcode (required): The ZIP code to check availability in. "
275
+ "- sku (required): The SKU of the product to check. "
276
+ "- location_id (required): The specific store location ID to check. "
277
+ "- show_only_in_stock (optional): Whether to only show stores with product in stock. "
278
+ "Example input: {{\"zipcode\": \"33928\", \"sku\": \"6428376\", \"location_id\": \"767\", \"show_only_in_stock\": false}}"
279
+ ),
280
+ func=_check_availability,
281
+ # args_schema=BestBuyProductAvailabilityInput,
282
+ coroutine=_check_availability,
283
+ infer_schema=False,
284
+ return_direct=False,
285
+ handle_tool_error=True
286
+ )
287
+
288
+ def _format_availability_response(
289
+ self, result: Dict[str, Any], location_id: str, sku: str, show_only_in_stock: bool = False
290
+ ) -> str:
291
+ try:
292
+ # Extract store information from the "ispu" locations
293
+ locations = result.get("ispu", {}).get("locations", [])
294
+ # Match on the "id" key rather than "locationId"
295
+ store = next((loc for loc in locations if loc.get("id") == location_id), None)
296
+ if not store:
297
+ return "No matching store location found."
298
+
299
+ store_name = store.get("name", "N/A")
300
+ store_address = store.get("address", "N/A")
301
+ store_city = store.get("city", "N/A")
302
+ store_zip = store.get("zipCode", "N/A")
303
+ store_state = store.get("state", "N/A")
304
+ store_lat = store.get("latitude", "N/A")
305
+ store_long = store.get("longitude", "N/A")
306
+
307
+ # Format store hours if available
308
+ open_times = store.get("openTimesMap", {})
309
+ store_hours_str = (
310
+ "\n".join(f"{day}: {hours}" for day, hours in open_times.items())
311
+ if open_times else "N/A"
312
+ )
313
+
314
+ # Extract product availability from "ispu" items
315
+ items = result.get("ispu", {}).get("items", [])
316
+ item = next((it for it in items if it.get("sku") == sku), None)
317
+ if not item:
318
+ return "No matching product found."
319
+
320
+ print('ITEM > ', item)
321
+
322
+ product_instore = item.get("inStoreAvailable", False)
323
+ product_pickup = item.get("pickupEligible", False)
324
+
325
+ # Extract the location-specific availability from the item's "locations" list
326
+ item_locations = item.get("locations", [])
327
+ availability = next(
328
+ (loc for loc in item_locations if loc.get("locationId") == location_id), None
329
+ )
330
+ if not availability:
331
+ return "No matching product availability found."
332
+
333
+ on_shelf = availability.get("onShelfDisplay", False)
334
+ in_store_quantity = availability.get("inStoreAvailability", {}).get("availableInStoreQuantity", 0)
335
+ available_from = availability.get("inStoreAvailability", {}).get("minDate")
336
+
337
+ # Build and return a formatted result string
338
+ result_str = (
339
+ f"Store Name: {store_name}\n"
340
+ f"Address: {store_address}\n"
341
+ f"City: {store_city}\n"
342
+ f"Zip Code: {store_zip}\n"
343
+ f"State: {store_state}\n"
344
+ f"Latitude: {store_lat}\n"
345
+ f"Longitude: {store_long}\n"
346
+ f"Hours:\n{store_hours_str}\n"
347
+ "--------------------------------\n"
348
+ f"Product SKU: {sku}\n"
349
+ f"In-store Available: {product_instore}\n"
350
+ f"Pickup Eligible: {product_pickup}\n"
351
+ f"On Shelf Display: {on_shelf}\n"
352
+ f"Available Quantity: {in_store_quantity}\n"
353
+ f"Available From: {available_from}\n"
354
+ "--------------------------------\n"
355
+ )
356
+ return result_str
357
+
358
+ except Exception as e:
359
+ return f"Error formatting availability response: {str(e)}"
parrot/tools/bing.py ADDED
@@ -0,0 +1,13 @@
1
+ from langchain_community.utilities.bing_search import BingSearchAPIWrapper
2
+ from langchain.tools import BaseTool
3
+
4
+
5
+ class BingSearchTool(BaseTool):
6
+ """Microsoft Bing Search Tool."""
7
+ name: str = "Bing Search"
8
+ description: str = "Search the web using Microsoft Bing Search, conduct searches using Bing for alternative perspectives and sources."
9
+
10
+ def _run(self, query: str) -> dict:
11
+ """Run the Bing Search Tool."""
12
+ bing = BingSearchAPIWrapper(k=5)
13
+ return bing.results(query=query, num_results=5)