ai-parrot 0.3.4__cp311-cp311-manylinux_2_17_x86_64.manylinux2014_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.3.4.dist-info/LICENSE +21 -0
- ai_parrot-0.3.4.dist-info/METADATA +319 -0
- ai_parrot-0.3.4.dist-info/RECORD +109 -0
- ai_parrot-0.3.4.dist-info/WHEEL +6 -0
- ai_parrot-0.3.4.dist-info/top_level.txt +3 -0
- parrot/__init__.py +21 -0
- parrot/chatbots/__init__.py +7 -0
- parrot/chatbots/abstract.py +728 -0
- parrot/chatbots/asktroc.py +16 -0
- parrot/chatbots/base.py +366 -0
- parrot/chatbots/basic.py +9 -0
- parrot/chatbots/bose.py +17 -0
- parrot/chatbots/cody.py +17 -0
- parrot/chatbots/copilot.py +83 -0
- parrot/chatbots/dataframe.py +103 -0
- parrot/chatbots/hragents.py +15 -0
- parrot/chatbots/odoo.py +17 -0
- parrot/chatbots/retrievals/__init__.py +578 -0
- parrot/chatbots/retrievals/constitutional.py +19 -0
- parrot/conf.py +110 -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 +162 -0
- parrot/interfaces/__init__.py +6 -0
- parrot/interfaces/database.py +29 -0
- parrot/llms/__init__.py +137 -0
- parrot/llms/abstract.py +47 -0
- parrot/llms/anthropic.py +42 -0
- parrot/llms/google.py +42 -0
- parrot/llms/groq.py +45 -0
- parrot/llms/hf.py +45 -0
- parrot/llms/openai.py +59 -0
- parrot/llms/pipes.py +114 -0
- parrot/llms/vertex.py +78 -0
- parrot/loaders/__init__.py +20 -0
- parrot/loaders/abstract.py +456 -0
- parrot/loaders/audio.py +106 -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 +437 -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 +120 -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 +166 -0
- parrot/models.py +372 -0
- parrot/py.typed +0 -0
- parrot/stores/__init__.py +48 -0
- parrot/stores/abstract.py +171 -0
- parrot/stores/milvus.py +632 -0
- parrot/stores/qdrant.py +153 -0
- parrot/tools/__init__.py +12 -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/stores/qdrant.py
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from qdrant_client import QdrantClient # pylint: disable=import-error
|
|
3
|
+
from langchain_community.vectorstores import ( # pylint: disable=import-error, E0611
|
|
4
|
+
Qdrant
|
|
5
|
+
)
|
|
6
|
+
from .abstract import AbstractStore
|
|
7
|
+
from ..conf import (
|
|
8
|
+
QDRANT_PROTOCOL,
|
|
9
|
+
QDRANT_HOST,
|
|
10
|
+
QDRANT_PORT,
|
|
11
|
+
QDRANT_USE_HTTPS,
|
|
12
|
+
QDRANT_CONN_TYPE,
|
|
13
|
+
QDRANT_URL
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class QdrantStore(AbstractStore):
|
|
18
|
+
"""QdrantStore class.
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
host (str): Qdrant host.
|
|
23
|
+
port (int): Qdrant port.
|
|
24
|
+
index_name (str): Qdrant index name.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def _create_qdrant_client(self, host, port, url, https, verify, qdrant_args):
|
|
28
|
+
"""
|
|
29
|
+
Creates a Qdrant client based on the provided configuration.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
host: Host of the Qdrant server (if using "server" connection).
|
|
33
|
+
port: Port of the Qdrant server (if using "server" connection).
|
|
34
|
+
url: URL of the Qdrant cloud service (if using "cloud" connection).
|
|
35
|
+
https: Whether to use HTTPS for the connection.
|
|
36
|
+
verify: Whether to verify the SSL certificate.
|
|
37
|
+
qdrant_args: Additional arguments for the Qdrant client.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
A QdrantClient object.
|
|
41
|
+
"""
|
|
42
|
+
if url is not None:
|
|
43
|
+
return QdrantClient(
|
|
44
|
+
url=url,
|
|
45
|
+
port=None,
|
|
46
|
+
verify=verify,
|
|
47
|
+
**qdrant_args
|
|
48
|
+
)
|
|
49
|
+
else:
|
|
50
|
+
return QdrantClient(
|
|
51
|
+
host,
|
|
52
|
+
port=port,
|
|
53
|
+
https=https,
|
|
54
|
+
verify=verify,
|
|
55
|
+
**qdrant_args
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def __init__(self, embeddings = None, **kwargs):
|
|
59
|
+
super().__init__(embeddings, **kwargs)
|
|
60
|
+
self.host = kwargs.get("host", QDRANT_HOST)
|
|
61
|
+
self.port = kwargs.get("port", QDRANT_PORT)
|
|
62
|
+
qdrant_args = kwargs.get("qdrant_args", {})
|
|
63
|
+
connection_type = kwargs.get("connection_type", QDRANT_CONN_TYPE)
|
|
64
|
+
url = kwargs.get("url", QDRANT_URL)
|
|
65
|
+
if connection_type == "server":
|
|
66
|
+
self.client = self._create_qdrant_client(
|
|
67
|
+
self.host, self.port, url, QDRANT_USE_HTTPS, False, qdrant_args
|
|
68
|
+
)
|
|
69
|
+
elif connection_type == "cloud":
|
|
70
|
+
if url is None:
|
|
71
|
+
raise ValueError(
|
|
72
|
+
"A URL is required for 'cloud' connection"
|
|
73
|
+
)
|
|
74
|
+
self.client = self._create_qdrant_client(
|
|
75
|
+
None, None, url, False, False, qdrant_args
|
|
76
|
+
)
|
|
77
|
+
else:
|
|
78
|
+
raise ValueError(
|
|
79
|
+
f"Invalid connection type: {connection_type}"
|
|
80
|
+
)
|
|
81
|
+
if url is not None:
|
|
82
|
+
self.url = url
|
|
83
|
+
else:
|
|
84
|
+
self.url = f"{QDRANT_PROTOCOL}://{self.host}"
|
|
85
|
+
if self.port:
|
|
86
|
+
self.url += f":{self.port}"
|
|
87
|
+
|
|
88
|
+
def get_vectorstore(self):
|
|
89
|
+
if self._embed_ is None:
|
|
90
|
+
_embed_ = self.create_embedding(
|
|
91
|
+
model_name=self.embedding_name
|
|
92
|
+
)
|
|
93
|
+
else:
|
|
94
|
+
_embed_ = self._embed_
|
|
95
|
+
self.vector = Qdrant(
|
|
96
|
+
client=self.client,
|
|
97
|
+
collection_name=self.collection,
|
|
98
|
+
embeddings=_embed_,
|
|
99
|
+
)
|
|
100
|
+
return self.vector
|
|
101
|
+
|
|
102
|
+
async def load_documents(
|
|
103
|
+
self,
|
|
104
|
+
documents: list,
|
|
105
|
+
collection: str = None
|
|
106
|
+
):
|
|
107
|
+
if collection is None:
|
|
108
|
+
collection = self.collection
|
|
109
|
+
|
|
110
|
+
docstore = Qdrant.from_documents(
|
|
111
|
+
documents,
|
|
112
|
+
self._embed_,
|
|
113
|
+
url=self.url,
|
|
114
|
+
# location=":memory:", # Local mode with in-memory storage only
|
|
115
|
+
collection_name=collection,
|
|
116
|
+
force_recreate=False,
|
|
117
|
+
)
|
|
118
|
+
return docstore
|
|
119
|
+
|
|
120
|
+
def upsert(self, payload: dict, collection: str = None) -> None:
|
|
121
|
+
if collection is None:
|
|
122
|
+
collection = self.collection
|
|
123
|
+
self.client.upsert(
|
|
124
|
+
collection_name=collection,
|
|
125
|
+
points=self._embed_,
|
|
126
|
+
payload=payload
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
def search(self, payload: dict, collection: str = None) -> dict:
|
|
130
|
+
pass
|
|
131
|
+
|
|
132
|
+
async def delete_collection(self, collection: str = None) -> dict:
|
|
133
|
+
self.client.delete_collection(
|
|
134
|
+
collection_name=collection
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
async def create_collection(
|
|
138
|
+
self,
|
|
139
|
+
collection_name: str,
|
|
140
|
+
document: Any,
|
|
141
|
+
dimension: int = 768,
|
|
142
|
+
**kwargs
|
|
143
|
+
) -> dict:
|
|
144
|
+
# Here using drop_old=True to force recreate based on the first document
|
|
145
|
+
docstore = Qdrant.from_documents(
|
|
146
|
+
[document],
|
|
147
|
+
self._embed_,
|
|
148
|
+
url=self.url,
|
|
149
|
+
# location=":memory:", # Local mode with in-memory storage only
|
|
150
|
+
collection_name=collection_name,
|
|
151
|
+
force_recreate=True,
|
|
152
|
+
)
|
|
153
|
+
return docstore
|
parrot/tools/__init__.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from langchain_community.tools.yahoo_finance_news import YahooFinanceNewsTool
|
|
2
|
+
from langchain_community.tools import YouTubeSearchTool
|
|
3
|
+
from langchain_community.agent_toolkits import O365Toolkit
|
|
4
|
+
from navconfig import config
|
|
5
|
+
from .wikipedia import WikipediaTool, WikidataTool
|
|
6
|
+
from .asknews import AskNewsTool
|
|
7
|
+
from .duck import DuckDuckGoSearchTool, DuckDuckGoRelevantSearch
|
|
8
|
+
from .weather import OpenWeather, OpenWeatherMapTool
|
|
9
|
+
from .google import GoogleLocationFinder, GoogleSiteSearchTool, GoogleSearchTool
|
|
10
|
+
from .zipcode import ZipcodeAPIToolkit
|
|
11
|
+
from .bing import BingSearchTool
|
|
12
|
+
from .stack import StackExchangeTool
|
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)
|