ai-parrot 0.1.0__cp311-cp311-manylinux_2_28_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.
- ai_parrot-0.1.0.dist-info/LICENSE +21 -0
- ai_parrot-0.1.0.dist-info/METADATA +299 -0
- ai_parrot-0.1.0.dist-info/RECORD +108 -0
- ai_parrot-0.1.0.dist-info/WHEEL +5 -0
- ai_parrot-0.1.0.dist-info/top_level.txt +3 -0
- parrot/__init__.py +18 -0
- parrot/chatbots/__init__.py +7 -0
- parrot/chatbots/abstract.py +965 -0
- parrot/chatbots/asktroc.py +16 -0
- parrot/chatbots/base.py +257 -0
- parrot/chatbots/basic.py +9 -0
- parrot/chatbots/bose.py +17 -0
- parrot/chatbots/cody.py +17 -0
- parrot/chatbots/copilot.py +100 -0
- parrot/chatbots/dataframe.py +103 -0
- parrot/chatbots/hragents.py +15 -0
- parrot/chatbots/oddie.py +17 -0
- parrot/chatbots/retrievals/__init__.py +515 -0
- parrot/chatbots/retrievals/constitutional.py +19 -0
- parrot/conf.py +108 -0
- parrot/crew/__init__.py +3 -0
- parrot/crew/tools/__init__.py +22 -0
- parrot/crew/tools/bing.py +13 -0
- parrot/crew/tools/config.py +43 -0
- parrot/crew/tools/duckgo.py +62 -0
- parrot/crew/tools/file.py +24 -0
- parrot/crew/tools/google.py +168 -0
- parrot/crew/tools/gtrends.py +16 -0
- parrot/crew/tools/md2pdf.py +25 -0
- parrot/crew/tools/rag.py +42 -0
- parrot/crew/tools/search.py +32 -0
- parrot/crew/tools/url.py +21 -0
- parrot/exceptions.cpython-311-x86_64-linux-gnu.so +0 -0
- parrot/handlers/__init__.py +4 -0
- parrot/handlers/bots.py +196 -0
- parrot/handlers/chat.py +169 -0
- parrot/interfaces/__init__.py +6 -0
- parrot/interfaces/database.py +29 -0
- parrot/llms/__init__.py +0 -0
- parrot/llms/abstract.py +41 -0
- parrot/llms/anthropic.py +36 -0
- parrot/llms/google.py +37 -0
- parrot/llms/groq.py +33 -0
- parrot/llms/hf.py +39 -0
- parrot/llms/openai.py +49 -0
- parrot/llms/pipes.py +103 -0
- parrot/llms/vertex.py +68 -0
- parrot/loaders/__init__.py +20 -0
- parrot/loaders/abstract.py +456 -0
- parrot/loaders/basepdf.py +102 -0
- parrot/loaders/basevideo.py +280 -0
- parrot/loaders/csv.py +42 -0
- parrot/loaders/dir.py +37 -0
- parrot/loaders/excel.py +349 -0
- parrot/loaders/github.py +65 -0
- parrot/loaders/handlers/__init__.py +5 -0
- parrot/loaders/handlers/data.py +213 -0
- parrot/loaders/image.py +119 -0
- parrot/loaders/json.py +52 -0
- parrot/loaders/pdf.py +187 -0
- parrot/loaders/pdfchapters.py +142 -0
- parrot/loaders/pdffn.py +112 -0
- parrot/loaders/pdfimages.py +207 -0
- parrot/loaders/pdfmark.py +88 -0
- parrot/loaders/pdftables.py +145 -0
- parrot/loaders/ppt.py +30 -0
- parrot/loaders/qa.py +81 -0
- parrot/loaders/repo.py +103 -0
- parrot/loaders/rtd.py +65 -0
- parrot/loaders/txt.py +92 -0
- parrot/loaders/utils/__init__.py +1 -0
- parrot/loaders/utils/models.py +25 -0
- parrot/loaders/video.py +96 -0
- parrot/loaders/videolocal.py +107 -0
- parrot/loaders/vimeo.py +106 -0
- parrot/loaders/web.py +216 -0
- parrot/loaders/web_base.py +112 -0
- parrot/loaders/word.py +125 -0
- parrot/loaders/youtube.py +192 -0
- parrot/manager.py +152 -0
- parrot/models.py +347 -0
- parrot/py.typed +0 -0
- parrot/stores/__init__.py +0 -0
- parrot/stores/abstract.py +170 -0
- parrot/stores/milvus.py +540 -0
- parrot/stores/qdrant.py +153 -0
- parrot/tools/__init__.py +16 -0
- parrot/tools/abstract.py +53 -0
- parrot/tools/asknews.py +32 -0
- parrot/tools/bing.py +13 -0
- parrot/tools/duck.py +62 -0
- parrot/tools/google.py +170 -0
- parrot/tools/stack.py +26 -0
- parrot/tools/weather.py +70 -0
- parrot/tools/wikipedia.py +59 -0
- parrot/tools/zipcode.py +179 -0
- parrot/utils/__init__.py +2 -0
- parrot/utils/parsers/__init__.py +5 -0
- parrot/utils/parsers/toml.cpython-311-x86_64-linux-gnu.so +0 -0
- parrot/utils/toml.py +11 -0
- parrot/utils/types.cpython-311-x86_64-linux-gnu.so +0 -0
- parrot/utils/uv.py +11 -0
- parrot/version.py +10 -0
- resources/users/__init__.py +5 -0
- resources/users/handlers.py +13 -0
- resources/users/models.py +205 -0
- settings/__init__.py +0 -0
- settings/settings.py +51 -0
parrot/tools/abstract.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from typing import Optional, Dict, Any, Type
|
|
2
|
+
from abc import abstractmethod
|
|
3
|
+
from langchain_core.pydantic_v1 import BaseModel, Field, Extra
|
|
4
|
+
from langchain_core.callbacks import CallbackManagerForToolRun
|
|
5
|
+
from langchain_core.tools import BaseTool
|
|
6
|
+
|
|
7
|
+
class AbstractToolArgsSchema(BaseModel):
|
|
8
|
+
"""Schema for the arguments to the AbstractTool."""
|
|
9
|
+
|
|
10
|
+
# This Field allows any number of arguments to be passed in.
|
|
11
|
+
args: list = Field(description="A list of arguments to the tool")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AbstractTool(BaseTool):
|
|
15
|
+
"""Abstract class for tools."""
|
|
16
|
+
|
|
17
|
+
args_schema: Type[BaseModel] = AbstractToolArgsSchema
|
|
18
|
+
|
|
19
|
+
class Config:
|
|
20
|
+
"""Configuration for this pydantic object."""
|
|
21
|
+
extra = Extra.forbid
|
|
22
|
+
arbitrary_types_allowed = True
|
|
23
|
+
|
|
24
|
+
@abstractmethod
|
|
25
|
+
def _search(self, query: str) -> str:
|
|
26
|
+
"""Run the tool."""
|
|
27
|
+
|
|
28
|
+
async def _asearch(self, *args, **kwargs):
|
|
29
|
+
"""Run the tool asynchronously."""
|
|
30
|
+
return self._search(*args, **kwargs)
|
|
31
|
+
|
|
32
|
+
def _run(
|
|
33
|
+
self,
|
|
34
|
+
query: str,
|
|
35
|
+
run_manager: Optional[CallbackManagerForToolRun] = None
|
|
36
|
+
) -> Dict[str, Any]:
|
|
37
|
+
args = [a.strip() for a in query.split(',')]
|
|
38
|
+
try:
|
|
39
|
+
return self._search(*args)
|
|
40
|
+
except Exception as e:
|
|
41
|
+
raise ValueError(f"Error running tool: {e}") from e
|
|
42
|
+
|
|
43
|
+
async def _arun(
|
|
44
|
+
self,
|
|
45
|
+
query: str,
|
|
46
|
+
run_manager: Optional[CallbackManagerForToolRun] = None
|
|
47
|
+
) -> Dict[str, Any]:
|
|
48
|
+
"""Use the tool asynchronously."""
|
|
49
|
+
args = [a.strip() for a in query.split(',')]
|
|
50
|
+
try:
|
|
51
|
+
return await self._asearch(*args)
|
|
52
|
+
except Exception as e:
|
|
53
|
+
raise ValueError(f"Error running tool: {e}") from e
|
parrot/tools/asknews.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
import os
|
|
3
|
+
from navconfig import config
|
|
4
|
+
from langchain_community.tools.asknews import AskNewsSearch
|
|
5
|
+
from langchain.tools import BaseTool
|
|
6
|
+
|
|
7
|
+
class AskNewsTool(BaseTool):
|
|
8
|
+
"""Tool that searches the AskNews API."""
|
|
9
|
+
name: str = "asknews_search"
|
|
10
|
+
description: str = (
|
|
11
|
+
"This tool allows you to perform a search on up-to-date news and historical "
|
|
12
|
+
"news. If you needs news from more than 48 hours ago, you can estimate the "
|
|
13
|
+
"number of hours back to search."
|
|
14
|
+
)
|
|
15
|
+
search: Any = None
|
|
16
|
+
|
|
17
|
+
def __init__(self, max_results: int = 5, **kwargs):
|
|
18
|
+
super().__init__(**kwargs)
|
|
19
|
+
os.environ["ASKNEWS_CLIENT_ID"] = config.get('ASKNEWS_CLIENT_ID')
|
|
20
|
+
os.environ["ASKNEWS_CLIENT_SECRET"] = config.get('ASKNEWS_CLIENT_SECRET')
|
|
21
|
+
self.search = AskNewsSearch(max_results=5)
|
|
22
|
+
|
|
23
|
+
def _run(
|
|
24
|
+
self,
|
|
25
|
+
query: str
|
|
26
|
+
) -> str:
|
|
27
|
+
"""Use the Wikipedia tool."""
|
|
28
|
+
return self.search.invoke(
|
|
29
|
+
{
|
|
30
|
+
"query": query,
|
|
31
|
+
}
|
|
32
|
+
)
|
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 API"
|
|
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)
|
parrot/tools/duck.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from pydantic import PrivateAttr
|
|
3
|
+
from langchain_community.tools.ddg_search.tool import (
|
|
4
|
+
DuckDuckGoSearchResults,
|
|
5
|
+
DuckDuckGoSearchAPIWrapper
|
|
6
|
+
)
|
|
7
|
+
from duckduckgo_search import DDGS
|
|
8
|
+
from langchain.tools import BaseTool
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class DuckDuckGoSearchTool(BaseTool):
|
|
12
|
+
"""Web Search tool using Duck Duck Go API."""
|
|
13
|
+
name: str = "DuckDuckGo Web Search"
|
|
14
|
+
description: str = "Search the web using DuckDuckGo Search API"
|
|
15
|
+
source: Any = None
|
|
16
|
+
max_results: int = 5
|
|
17
|
+
region: str = None
|
|
18
|
+
|
|
19
|
+
def __init__(self, source: str = "news", results: int = 5, region: str = 'wt-wt', **kwargs: Any):
|
|
20
|
+
super().__init__(**kwargs)
|
|
21
|
+
self.source = source
|
|
22
|
+
self.max_results = results
|
|
23
|
+
self.region = region
|
|
24
|
+
|
|
25
|
+
def _run(self, query: str) -> dict:
|
|
26
|
+
"""Run the DuckDuckGo Search Tool."""
|
|
27
|
+
wrapper = DuckDuckGoSearchAPIWrapper(
|
|
28
|
+
region=self.region,
|
|
29
|
+
time="y",
|
|
30
|
+
max_results=self.max_results
|
|
31
|
+
)
|
|
32
|
+
search = DuckDuckGoSearchResults(
|
|
33
|
+
api_wrapper=wrapper,
|
|
34
|
+
source=self.source
|
|
35
|
+
)
|
|
36
|
+
return search.run(query)
|
|
37
|
+
|
|
38
|
+
class DuckDuckGoRelevantSearch(BaseTool):
|
|
39
|
+
"""Web Search tool using Duck Duck Go API."""
|
|
40
|
+
name: str = "DuckDuckGo Relevant Search"
|
|
41
|
+
description: str = "Search the web using DuckDuckGo Search API"
|
|
42
|
+
_max_results: PrivateAttr
|
|
43
|
+
_region: PrivateAttr
|
|
44
|
+
|
|
45
|
+
def __init__(self, results: int = 5, region: str = 'wt-wt', **kwargs: Any):
|
|
46
|
+
super().__init__(**kwargs)
|
|
47
|
+
self._max_results = results
|
|
48
|
+
self._region = region
|
|
49
|
+
|
|
50
|
+
def _run(
|
|
51
|
+
self,
|
|
52
|
+
query: str,
|
|
53
|
+
**kwargs: Any,
|
|
54
|
+
) -> Any:
|
|
55
|
+
"""Search Internet for relevant information based on a query."""
|
|
56
|
+
search = DDGS()
|
|
57
|
+
return search.text(
|
|
58
|
+
keywords=query,
|
|
59
|
+
region=self._region,
|
|
60
|
+
safesearch='moderate',
|
|
61
|
+
max_results=self._max_results
|
|
62
|
+
)
|
parrot/tools/google.py
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
import requests
|
|
3
|
+
from googleapiclient.discovery import build
|
|
4
|
+
from pydantic import PrivateAttr
|
|
5
|
+
# from crewai_tools import BaseTool
|
|
6
|
+
from langchain.tools import BaseTool
|
|
7
|
+
from navconfig import config
|
|
8
|
+
from ..conf import GOOGLE_API_KEY
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class GoogleSearchTool(BaseTool):
|
|
12
|
+
"""Web Search tool using Google API."""
|
|
13
|
+
name: str = "Google Web Search"
|
|
14
|
+
description: str = (
|
|
15
|
+
"Search the web using Google Search API, useful when you need to answer questions about current events.",
|
|
16
|
+
" Use this tool more than the Wikipedia tool if you are asked about current events, recent information, or news"
|
|
17
|
+
)
|
|
18
|
+
source: str = 'news'
|
|
19
|
+
max_results: int = 5
|
|
20
|
+
region: str = 'US'
|
|
21
|
+
# Fields populated during init (not required for validation)
|
|
22
|
+
cse_id: Optional[str] = None
|
|
23
|
+
search_key: Optional[str] = None
|
|
24
|
+
kwargs: Optional[dict] = None
|
|
25
|
+
|
|
26
|
+
def __init__(self, source: str = "news", results: int = 5, **kwargs):
|
|
27
|
+
super().__init__(**kwargs)
|
|
28
|
+
self.source = source
|
|
29
|
+
self.max_results = results
|
|
30
|
+
self.cse_id = config.get('GOOGLE_SEARCH_ENGINE_ID')
|
|
31
|
+
self.search_key = config.get('GOOGLE_SEARCH_API_KEY')
|
|
32
|
+
self.kwargs = kwargs
|
|
33
|
+
|
|
34
|
+
def _run(self, query: str) -> list:
|
|
35
|
+
"""Run the Google Search Tool."""
|
|
36
|
+
service = build("customsearch", "v1", developerKey=self.search_key)
|
|
37
|
+
res = service.cse().list( # pylint: disable=no-member
|
|
38
|
+
q=query,
|
|
39
|
+
cx=self.cse_id,
|
|
40
|
+
num=self.max_results,
|
|
41
|
+
**self.kwargs
|
|
42
|
+
).execute()
|
|
43
|
+
results = []
|
|
44
|
+
for item in res['items']:
|
|
45
|
+
results.append(
|
|
46
|
+
{
|
|
47
|
+
'snippet': item['snippet'],
|
|
48
|
+
'title': item['title'],
|
|
49
|
+
'link': item['link'],
|
|
50
|
+
'description': item['snippet']
|
|
51
|
+
}
|
|
52
|
+
)
|
|
53
|
+
return results
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class GoogleSiteSearchTool(BaseTool):
|
|
57
|
+
"""Web Search under a site using Google API."""
|
|
58
|
+
name: str = "Google Web Search"
|
|
59
|
+
description: str = "Search the web using Google Search API"
|
|
60
|
+
source: str = 'news'
|
|
61
|
+
max_results: int = 5
|
|
62
|
+
region: str = ''
|
|
63
|
+
|
|
64
|
+
def __init__(self, site: str = "news", results: int = 5, **kwargs):
|
|
65
|
+
super().__init__(**kwargs)
|
|
66
|
+
self.source = site
|
|
67
|
+
self.max_results = results
|
|
68
|
+
self._cse_id = config.get('GOOGLE_SEARCH_ENGINE_ID')
|
|
69
|
+
self._search_key = config.get('GOOGLE_SEARCH_API_KEY')
|
|
70
|
+
self._kwargs = kwargs
|
|
71
|
+
|
|
72
|
+
def _run(self, query: str) -> dict:
|
|
73
|
+
"""Run the Google Search Tool."""
|
|
74
|
+
service = build("customsearch", "v1", developerKey=self._search_key)
|
|
75
|
+
qs = f'{query} site:{self.source}'
|
|
76
|
+
res = service.cse().list( # pylint: disable=no-member
|
|
77
|
+
q=qs,
|
|
78
|
+
cx=self._cse_id,
|
|
79
|
+
num=self.max_results,
|
|
80
|
+
**self._kwargs
|
|
81
|
+
).execute()
|
|
82
|
+
results = []
|
|
83
|
+
for item in res['items']:
|
|
84
|
+
results.append(
|
|
85
|
+
{
|
|
86
|
+
'snippet': item['snippet'],
|
|
87
|
+
'title': item['title'],
|
|
88
|
+
'link': item['link'],
|
|
89
|
+
'description': item['snippet']
|
|
90
|
+
}
|
|
91
|
+
)
|
|
92
|
+
return results
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class GoogleLocationFinder(BaseTool):
|
|
96
|
+
""" LocationFinder class for finding locations."""
|
|
97
|
+
name: str = "google_maps_location_finder"
|
|
98
|
+
description: str = (
|
|
99
|
+
"Search for location information, use this tool to find latitude, longitude and other geographical information from locations."
|
|
100
|
+
" Provide the complete address to this tool to receive location information"
|
|
101
|
+
)
|
|
102
|
+
google_key: str = None
|
|
103
|
+
base_url: str = "https://maps.googleapis.com/maps/api/geocode/json"
|
|
104
|
+
kwargs: Optional[dict] = None
|
|
105
|
+
|
|
106
|
+
def __init__(self, **kwargs):
|
|
107
|
+
super().__init__(**kwargs)
|
|
108
|
+
self.google_key = kwargs.get('api_key', GOOGLE_API_KEY)
|
|
109
|
+
self.kwargs = kwargs
|
|
110
|
+
|
|
111
|
+
def extract_location(self, data):
|
|
112
|
+
city = state = state_code = zipcode = None
|
|
113
|
+
try:
|
|
114
|
+
for component in data['address_components']:
|
|
115
|
+
if 'locality' in component['types']:
|
|
116
|
+
city = component['long_name']
|
|
117
|
+
elif 'administrative_area_level_1' in component['types']:
|
|
118
|
+
state_code = component['short_name']
|
|
119
|
+
state = component['long_name']
|
|
120
|
+
elif 'postal_code' in component['types']:
|
|
121
|
+
zipcode = component['long_name']
|
|
122
|
+
except Exception:
|
|
123
|
+
pass
|
|
124
|
+
return city, state, state_code, zipcode
|
|
125
|
+
|
|
126
|
+
def _run(self, query: str) -> dict:
|
|
127
|
+
"""Find Location."""
|
|
128
|
+
params = {
|
|
129
|
+
"address": query,
|
|
130
|
+
"key": self.google_key
|
|
131
|
+
}
|
|
132
|
+
response = requests.get(
|
|
133
|
+
self.base_url,
|
|
134
|
+
params=params
|
|
135
|
+
)
|
|
136
|
+
if response.status_code == 200:
|
|
137
|
+
result = response.json()
|
|
138
|
+
if result['status'] == 'OK':
|
|
139
|
+
location = result['results'][0]
|
|
140
|
+
city, state, state_code, zipcode = self.extract_location(
|
|
141
|
+
location
|
|
142
|
+
)
|
|
143
|
+
return {
|
|
144
|
+
"latitude": location['geometry']['location']['lat'],
|
|
145
|
+
"longitude": location['geometry']['location']['lng'],
|
|
146
|
+
"address": location['formatted_address'],
|
|
147
|
+
"place_id": location['place_id'],
|
|
148
|
+
"zipcode": zipcode,
|
|
149
|
+
"city": city,
|
|
150
|
+
"state": state,
|
|
151
|
+
"state_code": state_code
|
|
152
|
+
}
|
|
153
|
+
return None
|
|
154
|
+
else:
|
|
155
|
+
return None
|
|
156
|
+
|
|
157
|
+
class GoogleRouteSearch(BaseTool):
|
|
158
|
+
"""Web Search under a site using Google API."""
|
|
159
|
+
name: str = "google_maps_route_search"
|
|
160
|
+
description: str = "Search for a Route to a location using Google Maps, using this tool if answers questions about how to reach a location."
|
|
161
|
+
google_key: str = None
|
|
162
|
+
base_url: str = 'https://maps.googleapis.com/maps/api/directions/json'
|
|
163
|
+
|
|
164
|
+
def __init__(self, **kwargs):
|
|
165
|
+
super().__init__(**kwargs)
|
|
166
|
+
self._key_ = kwargs.get('api_key', GOOGLE_API_KEY)
|
|
167
|
+
self._kwargs = kwargs
|
|
168
|
+
|
|
169
|
+
def _run(self, query: str) -> dict:
|
|
170
|
+
departure_time = 'now'
|
parrot/tools/stack.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from langchain.tools import Tool
|
|
2
|
+
from langchain.tools import BaseTool
|
|
3
|
+
from langchain_community.utilities import StackExchangeAPIWrapper
|
|
4
|
+
|
|
5
|
+
class StackExchangeTool(BaseTool):
|
|
6
|
+
"""Tool that searches the StackExchangeTool API."""
|
|
7
|
+
name: str = "StackExchangeSearch"
|
|
8
|
+
description: str = (
|
|
9
|
+
"A wrapper around StackExchange API. Stack Exchange is a network of question-and-answer (Q&A) websites on topics in diverse fields, each site covering a specific topic."
|
|
10
|
+
"Useful for when you need to answer general questions about different topics when user requested."
|
|
11
|
+
)
|
|
12
|
+
search: Tool = None
|
|
13
|
+
|
|
14
|
+
def __init__(self, **kwargs):
|
|
15
|
+
super().__init__(**kwargs)
|
|
16
|
+
self.search = StackExchangeAPIWrapper(
|
|
17
|
+
query_type='title',
|
|
18
|
+
max_results=5
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
def _run(
|
|
22
|
+
self,
|
|
23
|
+
query: dict,
|
|
24
|
+
) -> dict:
|
|
25
|
+
"""Use the StackExchangeSearch tool."""
|
|
26
|
+
return self.search.run(query)
|
parrot/tools/weather.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from langchain.tools import BaseTool
|
|
3
|
+
from langchain.tools import Tool
|
|
4
|
+
from langchain_community.utilities import OpenWeatherMapAPIWrapper
|
|
5
|
+
from navconfig import config
|
|
6
|
+
import orjson
|
|
7
|
+
|
|
8
|
+
class OpenWeatherMapTool(BaseTool):
|
|
9
|
+
"""Tool that searches the OpenWeatherMap API."""
|
|
10
|
+
name: str = "OpenWeatherMap"
|
|
11
|
+
description: str = (
|
|
12
|
+
"A wrapper around OpenWeatherMap. "
|
|
13
|
+
"Useful for when you need to answer general questions about "
|
|
14
|
+
"weather, temperature, humidity, wind speed, or other weather-related information. "
|
|
15
|
+
)
|
|
16
|
+
search: Tool = None
|
|
17
|
+
|
|
18
|
+
def __init__(self, **kwargs):
|
|
19
|
+
super().__init__(**kwargs)
|
|
20
|
+
self.search = OpenWeatherMapAPIWrapper(
|
|
21
|
+
openweathermap_api_key=config.get('OPENWEATHER_APPID')
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
def _run(
|
|
25
|
+
self,
|
|
26
|
+
query: dict,
|
|
27
|
+
) -> dict:
|
|
28
|
+
"""Use the OpenWeatherMap tool."""
|
|
29
|
+
return self.search.run(query)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class OpenWeather(BaseTool):
|
|
33
|
+
"""
|
|
34
|
+
Tool to get weather information about a location.
|
|
35
|
+
"""
|
|
36
|
+
name: str = 'openweather_tool'
|
|
37
|
+
description: str = (
|
|
38
|
+
"Get weather information about a location, use this tool to answer questions about weather or weather forecast."
|
|
39
|
+
" Input should be the latitude and longitude of the location you want weather information about."
|
|
40
|
+
)
|
|
41
|
+
base_url: str = 'http://api.openweathermap.org/'
|
|
42
|
+
units: str = 'metric'
|
|
43
|
+
days: int = 3
|
|
44
|
+
appid: str = None
|
|
45
|
+
request: str = 'weather'
|
|
46
|
+
country: str = 'us'
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def __init__(self, request: str = 'weather', country: str = 'us', **kwargs):
|
|
50
|
+
super().__init__(**kwargs)
|
|
51
|
+
self.request = request
|
|
52
|
+
self.country = country
|
|
53
|
+
self.appid = config.get('OPENWEATHER_APPID')
|
|
54
|
+
|
|
55
|
+
def _run(self, query: dict) -> dict:
|
|
56
|
+
q = orjson.loads(query) # pylint: disable=no-member
|
|
57
|
+
if 'latitude' in q and 'longitude' in q:
|
|
58
|
+
lat = q['latitude']
|
|
59
|
+
lon = q['longitude']
|
|
60
|
+
if self.request == 'weather':
|
|
61
|
+
url = f"{self.base_url}data/2.5/weather?lat={lat}&lon={lon}&units={self.units}&appid={self.appid}"
|
|
62
|
+
elif self.request == 'forecast':
|
|
63
|
+
url = f"{self.base_url}data/2.5/forecast?lat={lat}&lon={lon}&units={self.units}&cnt={self.days}&appid={self.appid}"
|
|
64
|
+
else:
|
|
65
|
+
return {'error': 'Latitude and longitude are required'}
|
|
66
|
+
response = requests.get(url)
|
|
67
|
+
return response.json()
|
|
68
|
+
|
|
69
|
+
async def _arun(self, query: dict) -> dict:
|
|
70
|
+
raise NotImplementedError("Async method not implemented yet")
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from typing import Optional, Any
|
|
2
|
+
from langchain_core.callbacks import CallbackManagerForToolRun
|
|
3
|
+
from langchain_community.tools import WikipediaQueryRun
|
|
4
|
+
from langchain_community.utilities import WikipediaAPIWrapper
|
|
5
|
+
from langchain_community.tools.wikidata.tool import WikidataAPIWrapper, WikidataQueryRun
|
|
6
|
+
from langchain.tools import BaseTool
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class WikipediaTool(BaseTool):
|
|
10
|
+
"""Tool that searches the Wikipedia API."""
|
|
11
|
+
name = "Wikipedia"
|
|
12
|
+
description: str = (
|
|
13
|
+
"A wrapper around Wikipedia. "
|
|
14
|
+
"Useful for searching Wikipedia for general information. "
|
|
15
|
+
"Useful for when you need to answer general questions about "
|
|
16
|
+
"people, places, companies, facts, historical events, or other subjects. "
|
|
17
|
+
"Input should be a search query."
|
|
18
|
+
)
|
|
19
|
+
search: Any = None
|
|
20
|
+
|
|
21
|
+
def __init__(self, **kwargs):
|
|
22
|
+
super().__init__(**kwargs)
|
|
23
|
+
self.search = WikipediaQueryRun(
|
|
24
|
+
api_wrapper=WikipediaAPIWrapper()
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
def _run(
|
|
28
|
+
self,
|
|
29
|
+
query: str,
|
|
30
|
+
run_manager: Optional[CallbackManagerForToolRun] = None,
|
|
31
|
+
) -> str:
|
|
32
|
+
"""Use the Wikipedia tool."""
|
|
33
|
+
return self.search.run(query)
|
|
34
|
+
|
|
35
|
+
class WikidataTool(BaseTool):
|
|
36
|
+
"""Tool that searches the Wikidata API."""
|
|
37
|
+
name: str = "Wikidata"
|
|
38
|
+
description: str = (
|
|
39
|
+
"A wrapper around Wikidata. "
|
|
40
|
+
"Useful for when you need to answer general questions about "
|
|
41
|
+
"people, places, companies, facts, historical events, or other subjects. "
|
|
42
|
+
"Input should be the exact name of the item you want information about "
|
|
43
|
+
"or a Wikidata QID."
|
|
44
|
+
)
|
|
45
|
+
search: Any = None
|
|
46
|
+
|
|
47
|
+
def __init__(self, **kwargs):
|
|
48
|
+
super().__init__(**kwargs)
|
|
49
|
+
self.search = WikidataQueryRun(
|
|
50
|
+
api_wrapper=WikidataAPIWrapper()
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
def _run(
|
|
54
|
+
self,
|
|
55
|
+
query: str,
|
|
56
|
+
run_manager: Optional[CallbackManagerForToolRun] = None,
|
|
57
|
+
) -> str:
|
|
58
|
+
"""Use the Wikipedia tool."""
|
|
59
|
+
return self.search.run(query)
|
parrot/tools/zipcode.py
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
from typing import List, Dict, Any, Optional, Type, Union
|
|
2
|
+
import httpx
|
|
3
|
+
from langchain_core.callbacks import CallbackManagerForToolRun
|
|
4
|
+
from langchain_core.tools import BaseToolkit
|
|
5
|
+
from langchain_core.pydantic_v1 import BaseModel, Field, Extra
|
|
6
|
+
from langchain_core.tools import BaseTool
|
|
7
|
+
from navconfig import config
|
|
8
|
+
from .abstract import AbstractTool
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ZipcodeDistanceInput(BaseModel):
|
|
12
|
+
"""Input for the Zipcode Distance Tool."""
|
|
13
|
+
zipcode1: Union[str, int] = Field(description="The first zipcode.")
|
|
14
|
+
zipcode2: Union[str, int] = Field(description="The second zipcode.")
|
|
15
|
+
unit: Optional[str] = Field(description="The unit of the distance.", default="mile")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ZipcodeRadiusInput(BaseModel):
|
|
19
|
+
"""Input for the Zipcode Radius Tool."""
|
|
20
|
+
zipcode: Union[str, int] = Field(description="The zipcode.")
|
|
21
|
+
radius: int = Field(description="The radius in miles.", default=5)
|
|
22
|
+
unit: Optional[str] = Field(description="The unit of the distance.", default="mile")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ZipcodeLocationInput(BaseModel):
|
|
26
|
+
"""Input for the Zipcode Location Tool."""
|
|
27
|
+
zipcode: Union[str, int] = Field(description="The zipcode.")
|
|
28
|
+
unit: Optional[str] = Field(description="The unit of the distance.", default="degrees")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ZipcodeDistance(AbstractTool):
|
|
32
|
+
"""Tool for calculating the distance between two zipcodes."""
|
|
33
|
+
|
|
34
|
+
name: str = "zipcode_distance"
|
|
35
|
+
verbose: bool = True
|
|
36
|
+
args_schema: Type[BaseModel] = ZipcodeDistanceInput
|
|
37
|
+
description: str = (
|
|
38
|
+
"Use this tool to calculate the distance between two zipcodes."
|
|
39
|
+
" Zipcodes must be provided as a couple of strings (e.g., '33066')."
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
class Config:
|
|
43
|
+
"""Configuration for this pydantic object."""
|
|
44
|
+
# extra = Extra.forbid
|
|
45
|
+
arbitrary_types_allowed = True
|
|
46
|
+
|
|
47
|
+
def _search(
|
|
48
|
+
self,
|
|
49
|
+
zipcode1: str,
|
|
50
|
+
zipcode2: str,
|
|
51
|
+
unit: Optional[str] = 'mile',
|
|
52
|
+
run_manager: Optional[CallbackManagerForToolRun] = None,
|
|
53
|
+
) -> Dict[str, Any]: # Changed to Dict
|
|
54
|
+
api_key = config.get('ZIPCODE_API_KEY')
|
|
55
|
+
url = f"https://www.zipcodeapi.com/rest/{api_key}/distance.json/{zipcode1}/{zipcode2}/{unit}"
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
response = httpx.get(url)
|
|
59
|
+
response.raise_for_status() # Check for API errors
|
|
60
|
+
return response.json()
|
|
61
|
+
except httpx.HTTPStatusError as e:
|
|
62
|
+
raise ValueError(f"Error fetching zipcode distance: {e}") from e
|
|
63
|
+
|
|
64
|
+
async def _asearch(
|
|
65
|
+
self,
|
|
66
|
+
zipcode1: str,
|
|
67
|
+
zipcode2: str,
|
|
68
|
+
unit: Optional[str] = 'mile',
|
|
69
|
+
run_manager: Optional[CallbackManagerForToolRun] = None,
|
|
70
|
+
) -> Dict[str, Any]:
|
|
71
|
+
api_key = config.get('ZIPCODE_API_KEY')
|
|
72
|
+
url = f"https://www.zipcodeapi.com/rest/{api_key}/distance.json/{zipcode1}/{zipcode2}/{unit}"
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
async with httpx.AsyncClient() as client:
|
|
76
|
+
response = await client.get(url)
|
|
77
|
+
response.raise_for_status() # Check for API errors
|
|
78
|
+
return response.json()
|
|
79
|
+
except httpx.HTTPStatusError as e:
|
|
80
|
+
raise ValueError(f"Error fetching zipcode distance: {e}") from e
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class ZipcodeRadius(AbstractTool):
|
|
84
|
+
"""Tool for calculating the distance between two zipcodes."""
|
|
85
|
+
|
|
86
|
+
name: str = "zipcodes_by_radius"
|
|
87
|
+
verbose: bool = True
|
|
88
|
+
args_schema: Type[BaseModel] = ZipcodeRadiusInput
|
|
89
|
+
description: str = (
|
|
90
|
+
"Use this Tool to find all US zip codes within a given radius of a zip code."
|
|
91
|
+
" Provides a Zipcode and a radius."
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
class Config:
|
|
95
|
+
"""Configuration for this pydantic object."""
|
|
96
|
+
extra = Extra.forbid
|
|
97
|
+
arbitrary_types_allowed = True
|
|
98
|
+
|
|
99
|
+
def _search(
|
|
100
|
+
self,
|
|
101
|
+
zipcode: Union[str, int],
|
|
102
|
+
radius: int = 5,
|
|
103
|
+
unit: Optional[str] = 'mile',
|
|
104
|
+
) -> Dict[str, Any]: # Changed to Dict
|
|
105
|
+
api_key = config.get('ZIPCODE_API_KEY')
|
|
106
|
+
url = f"https://www.zipcodeapi.com/rest/{api_key}/radius.json/{zipcode}/{radius}/{unit}"
|
|
107
|
+
try:
|
|
108
|
+
response = httpx.get(url)
|
|
109
|
+
response.raise_for_status() # Check for API errors
|
|
110
|
+
return response.json()
|
|
111
|
+
except httpx.HTTPStatusError as e:
|
|
112
|
+
raise ValueError(f"Error fetching zipcode distance: {e}") from e
|
|
113
|
+
|
|
114
|
+
async def _asearch(
|
|
115
|
+
self,
|
|
116
|
+
zipcode: str,
|
|
117
|
+
radius: int,
|
|
118
|
+
unit: Optional[str] = 'mile'
|
|
119
|
+
) -> Dict[str, Any]:
|
|
120
|
+
api_key = config.get('ZIPCODE_API_KEY')
|
|
121
|
+
url = f"https://www.zipcodeapi.com/rest/{api_key}/radius.json/{zipcode}/{radius}/{unit}"
|
|
122
|
+
|
|
123
|
+
try:
|
|
124
|
+
async with httpx.AsyncClient() as client:
|
|
125
|
+
response = await client.get(url)
|
|
126
|
+
response.raise_for_status() # Check for API errors
|
|
127
|
+
return response.json()
|
|
128
|
+
except httpx.HTTPStatusError as e:
|
|
129
|
+
raise ValueError(f"Error fetching zipcode distance: {e}") from e
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class ZipcodeLocation(AbstractTool):
|
|
134
|
+
"""Tool for calculating Geographical information about a Zipcode."""
|
|
135
|
+
|
|
136
|
+
name: str = "zipcode_location"
|
|
137
|
+
verbose: bool = True
|
|
138
|
+
args_schema: Type[BaseModel] = ZipcodeLocationInput
|
|
139
|
+
description: str = (
|
|
140
|
+
"Use this Tool to find out the city, state, latitude, longitude, and time zone information for a US zip code."
|
|
141
|
+
" Use this tool to find geographical information about a zipcode. "
|
|
142
|
+
" Provides only a Zipcode as string."
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
class Config:
|
|
146
|
+
"""Configuration for this pydantic object."""
|
|
147
|
+
extra = Extra.forbid
|
|
148
|
+
arbitrary_types_allowed = True
|
|
149
|
+
|
|
150
|
+
def _search(
|
|
151
|
+
self,
|
|
152
|
+
zipcode: str,
|
|
153
|
+
unit: Optional[str] = 'degrees'
|
|
154
|
+
) -> Dict[str, Any]: # Changed to Dict
|
|
155
|
+
api_key = config.get('ZIPCODE_API_KEY')
|
|
156
|
+
url = f"https://www.zipcodeapi.com/rest/{api_key}/info.json/{zipcode}/{unit}"
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
response = httpx.get(url)
|
|
160
|
+
response.raise_for_status() # Check for API errors
|
|
161
|
+
return response.json()
|
|
162
|
+
except httpx.HTTPStatusError as e:
|
|
163
|
+
raise ValueError(f"Error fetching zipcode distance: {e}") from e
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class ZipcodeAPIToolkit(BaseToolkit):
|
|
167
|
+
"""Toolkit for interacting with ZipcodeAPI.
|
|
168
|
+
"""
|
|
169
|
+
class Config:
|
|
170
|
+
"""Pydantic config."""
|
|
171
|
+
arbitrary_types_allowed = True
|
|
172
|
+
|
|
173
|
+
def get_tools(self) -> List[BaseTool]:
|
|
174
|
+
"""Get the tools in the toolkit."""
|
|
175
|
+
return [
|
|
176
|
+
ZipcodeLocation(),
|
|
177
|
+
ZipcodeRadius(),
|
|
178
|
+
ZipcodeDistance()
|
|
179
|
+
]
|
parrot/utils/__init__.py
ADDED
|
Binary file
|