ai-parrot 0.3.4__cp312-cp312-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.

Files changed (109) hide show
  1. ai_parrot-0.3.4.dist-info/LICENSE +21 -0
  2. ai_parrot-0.3.4.dist-info/METADATA +319 -0
  3. ai_parrot-0.3.4.dist-info/RECORD +109 -0
  4. ai_parrot-0.3.4.dist-info/WHEEL +6 -0
  5. ai_parrot-0.3.4.dist-info/top_level.txt +3 -0
  6. parrot/__init__.py +21 -0
  7. parrot/chatbots/__init__.py +7 -0
  8. parrot/chatbots/abstract.py +728 -0
  9. parrot/chatbots/asktroc.py +16 -0
  10. parrot/chatbots/base.py +366 -0
  11. parrot/chatbots/basic.py +9 -0
  12. parrot/chatbots/bose.py +17 -0
  13. parrot/chatbots/cody.py +17 -0
  14. parrot/chatbots/copilot.py +83 -0
  15. parrot/chatbots/dataframe.py +103 -0
  16. parrot/chatbots/hragents.py +15 -0
  17. parrot/chatbots/odoo.py +17 -0
  18. parrot/chatbots/retrievals/__init__.py +578 -0
  19. parrot/chatbots/retrievals/constitutional.py +19 -0
  20. parrot/conf.py +110 -0
  21. parrot/crew/__init__.py +3 -0
  22. parrot/crew/tools/__init__.py +22 -0
  23. parrot/crew/tools/bing.py +13 -0
  24. parrot/crew/tools/config.py +43 -0
  25. parrot/crew/tools/duckgo.py +62 -0
  26. parrot/crew/tools/file.py +24 -0
  27. parrot/crew/tools/google.py +168 -0
  28. parrot/crew/tools/gtrends.py +16 -0
  29. parrot/crew/tools/md2pdf.py +25 -0
  30. parrot/crew/tools/rag.py +42 -0
  31. parrot/crew/tools/search.py +32 -0
  32. parrot/crew/tools/url.py +21 -0
  33. parrot/exceptions.cpython-312-x86_64-linux-gnu.so +0 -0
  34. parrot/handlers/__init__.py +4 -0
  35. parrot/handlers/bots.py +196 -0
  36. parrot/handlers/chat.py +162 -0
  37. parrot/interfaces/__init__.py +6 -0
  38. parrot/interfaces/database.py +29 -0
  39. parrot/llms/__init__.py +137 -0
  40. parrot/llms/abstract.py +47 -0
  41. parrot/llms/anthropic.py +42 -0
  42. parrot/llms/google.py +42 -0
  43. parrot/llms/groq.py +45 -0
  44. parrot/llms/hf.py +45 -0
  45. parrot/llms/openai.py +59 -0
  46. parrot/llms/pipes.py +114 -0
  47. parrot/llms/vertex.py +78 -0
  48. parrot/loaders/__init__.py +20 -0
  49. parrot/loaders/abstract.py +456 -0
  50. parrot/loaders/audio.py +106 -0
  51. parrot/loaders/basepdf.py +102 -0
  52. parrot/loaders/basevideo.py +280 -0
  53. parrot/loaders/csv.py +42 -0
  54. parrot/loaders/dir.py +37 -0
  55. parrot/loaders/excel.py +349 -0
  56. parrot/loaders/github.py +65 -0
  57. parrot/loaders/handlers/__init__.py +5 -0
  58. parrot/loaders/handlers/data.py +213 -0
  59. parrot/loaders/image.py +119 -0
  60. parrot/loaders/json.py +52 -0
  61. parrot/loaders/pdf.py +437 -0
  62. parrot/loaders/pdfchapters.py +142 -0
  63. parrot/loaders/pdffn.py +112 -0
  64. parrot/loaders/pdfimages.py +207 -0
  65. parrot/loaders/pdfmark.py +88 -0
  66. parrot/loaders/pdftables.py +145 -0
  67. parrot/loaders/ppt.py +30 -0
  68. parrot/loaders/qa.py +81 -0
  69. parrot/loaders/repo.py +103 -0
  70. parrot/loaders/rtd.py +65 -0
  71. parrot/loaders/txt.py +92 -0
  72. parrot/loaders/utils/__init__.py +1 -0
  73. parrot/loaders/utils/models.py +25 -0
  74. parrot/loaders/video.py +96 -0
  75. parrot/loaders/videolocal.py +120 -0
  76. parrot/loaders/vimeo.py +106 -0
  77. parrot/loaders/web.py +216 -0
  78. parrot/loaders/web_base.py +112 -0
  79. parrot/loaders/word.py +125 -0
  80. parrot/loaders/youtube.py +192 -0
  81. parrot/manager.py +166 -0
  82. parrot/models.py +372 -0
  83. parrot/py.typed +0 -0
  84. parrot/stores/__init__.py +48 -0
  85. parrot/stores/abstract.py +171 -0
  86. parrot/stores/milvus.py +632 -0
  87. parrot/stores/qdrant.py +153 -0
  88. parrot/tools/__init__.py +12 -0
  89. parrot/tools/abstract.py +53 -0
  90. parrot/tools/asknews.py +32 -0
  91. parrot/tools/bing.py +13 -0
  92. parrot/tools/duck.py +62 -0
  93. parrot/tools/google.py +170 -0
  94. parrot/tools/stack.py +26 -0
  95. parrot/tools/weather.py +70 -0
  96. parrot/tools/wikipedia.py +59 -0
  97. parrot/tools/zipcode.py +179 -0
  98. parrot/utils/__init__.py +2 -0
  99. parrot/utils/parsers/__init__.py +5 -0
  100. parrot/utils/parsers/toml.cpython-312-x86_64-linux-gnu.so +0 -0
  101. parrot/utils/toml.py +11 -0
  102. parrot/utils/types.cpython-312-x86_64-linux-gnu.so +0 -0
  103. parrot/utils/uv.py +11 -0
  104. parrot/version.py +10 -0
  105. resources/users/__init__.py +5 -0
  106. resources/users/handlers.py +13 -0
  107. resources/users/models.py +205 -0
  108. settings/__init__.py +0 -0
  109. settings/settings.py +51 -0
@@ -0,0 +1,3 @@
1
+ """
2
+ NAV Crew is using CrewAI to manage the crew members and their roles.
3
+ """
@@ -0,0 +1,22 @@
1
+ """
2
+ A Directory for adding more Tools to CrewAI
3
+ """
4
+ from .duckgo import DuckDuckGoRelevantSearch, DuckDuckGoSearchTool
5
+ from .rag import RagSearchTool
6
+ from .file import SaveFile
7
+ from .bing import BingSearchTool
8
+ from .md2pdf import MarkdownToPDFTool
9
+ from .google import GoogleSearchTool, GoogleSiteSearchTool, GoogleLocationFinder
10
+
11
+
12
+ __all__ = [
13
+ 'GoogleSearchTool',
14
+ 'GoogleSiteSearchTool',
15
+ 'BingSearchTool',
16
+ 'DuckDuckGoRelevantSearch',
17
+ 'DuckDuckGoSearchTool',
18
+ 'RagSearchTool',
19
+ 'SaveFile',
20
+ 'MarkdownToPDFTool',
21
+ 'GoogleLocationFinder',
22
+ ]
@@ -0,0 +1,13 @@
1
+ from langchain_community.utilities.bing_search import BingSearchAPIWrapper
2
+ from crewai_tools import BaseTool
3
+
4
+
5
+ class BingSearchTool(BaseTool):
6
+ """Microsoft Bing Search Tool."""
7
+ name: str = "Microsoft 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)
@@ -0,0 +1,43 @@
1
+
2
+ def agent_config(
3
+ provider: str = 'vertexai',
4
+ model: str = 'gemini-pro',
5
+ temperature: float = 0.4,
6
+ top_p: int = 0.5,
7
+ stream: bool = True
8
+ ) -> dict:
9
+ agent_config ={
10
+ # "llm": {
11
+ # "provider": provider,
12
+ # "config": {
13
+ # "model": model,
14
+ # "temperature": temperature,
15
+ # "top_p": top_p,
16
+ # "stream": stream
17
+ # }
18
+ # },
19
+ "embedder": {
20
+ "provider": "huggingface",
21
+ "config": {
22
+ "model": "sentence-transformers/sentence-t5-large",
23
+ }
24
+ }
25
+ }
26
+ return agent_config
27
+
28
+
29
+ def agent_embedder(
30
+ provider: str = 'huggingface',
31
+ model: str = 'sentence-transformers/sentence-t5-large',
32
+ **kwargs
33
+ ) -> dict:
34
+ agent_config ={
35
+ "embedder": {
36
+ "provider": "huggingface",
37
+ "config": {
38
+ "model": "sentence-transformers/sentence-t5-large",
39
+ **kwargs
40
+ }
41
+ }
42
+ }
43
+ return agent_config
@@ -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 crewai_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: PrivateAttr
16
+ _max_results: PrivateAttr
17
+ _region: PrivateAttr
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
+ )
@@ -0,0 +1,24 @@
1
+ from typing import Union
2
+ from pathlib import Path, PurePath
3
+ from pydantic import PrivateAttr
4
+ from crewai_tools import BaseTool
5
+
6
+
7
+ class SaveFile(BaseTool):
8
+ """Save a file to a directory."""
9
+ name: str = "Save File"
10
+ description: str = "Save a file to a directory."
11
+ _directory: PrivateAttr
12
+
13
+ def __init__(self, directory: Union[str, PurePath], **kwargs):
14
+ super().__init__(**kwargs)
15
+ if isinstance(directory, str):
16
+ self._directory = Path(directory).resolve()
17
+ self._directory = directory
18
+
19
+ def _run(self, file: str, **kwargs) -> dict:
20
+ """Run the Save File Tool."""
21
+ filename = self._directory.joinpath(file)
22
+ with open(filename, "w") as f:
23
+ f.write(kwargs.get("content", ""))
24
+ return {"file": file}
@@ -0,0 +1,168 @@
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 langchain.tools import Tool
8
+ from navconfig import config
9
+ from ...conf import GOOGLE_API_KEY
10
+
11
+
12
+ class GoogleSearchTool(BaseTool):
13
+ """Web Search tool using Google API."""
14
+ name: str = "Google Web Search"
15
+ description: str = "Search the web using Google Search API, useful when you need to answer questions about current events."
16
+ source: str = 'news'
17
+ max_results: int = 5
18
+ region: str = ''
19
+ # Fields populated during init (not required for validation)
20
+ cse_id: Optional[str] = None
21
+ search_key: Optional[str] = None
22
+ kwargs: Optional[dict] = None
23
+
24
+ def __init__(self, source: str = "news", results: int = 5, **kwargs):
25
+ super().__init__(**kwargs)
26
+ self.source = source
27
+ self.max_results = results
28
+ self.cse_id = config.get('GOOGLE_SEARCH_ENGINE_ID')
29
+ self.search_key = config.get('GOOGLE_SEARCH_API_KEY')
30
+ self.kwargs = kwargs
31
+
32
+ def _run(self, query: str) -> list:
33
+ """Run the Google Search Tool."""
34
+ service = build("customsearch", "v1", developerKey=self.search_key)
35
+ res = service.cse().list(
36
+ q=query,
37
+ cx=self.cse_id,
38
+ num=self.max_results,
39
+ **self.kwargs
40
+ ).execute()
41
+ results = []
42
+ for item in res['items']:
43
+ results.append(
44
+ {
45
+ 'snippet': item['snippet'],
46
+ 'title': item['title'],
47
+ 'link': item['link'],
48
+ 'description': item['snippet']
49
+ }
50
+ )
51
+ return results
52
+
53
+
54
+ class GoogleSiteSearchTool(BaseTool):
55
+ """Web Search under a site using Google API."""
56
+ name: str = "Google Web Search"
57
+ description: str = "Search the web using Google Search API"
58
+ source: str = 'news'
59
+ max_results: int = 5
60
+ region: str = ''
61
+
62
+ def __init__(self, site: str = "news", results: int = 5, **kwargs):
63
+ super().__init__(**kwargs)
64
+ self.source = site
65
+ self.max_results = results
66
+ self._cse_id = config.get('GOOGLE_SEARCH_ENGINE_ID')
67
+ self._search_key = config.get('GOOGLE_SEARCH_API_KEY')
68
+ self._kwargs = kwargs
69
+
70
+ def _run(self, query: str) -> dict:
71
+ """Run the Google Search Tool."""
72
+ service = build("customsearch", "v1", developerKey=self._search_key)
73
+ qs = f'{query} site:{self.source}'
74
+ res = service.cse().list(
75
+ q=qs,
76
+ cx=self._cse_id,
77
+ num=self.max_results,
78
+ **self._kwargs
79
+ ).execute()
80
+ results = []
81
+ for item in res['items']:
82
+ results.append(
83
+ {
84
+ 'snippet': item['snippet'],
85
+ 'title': item['title'],
86
+ 'link': item['link'],
87
+ 'description': item['snippet']
88
+ }
89
+ )
90
+ return results
91
+
92
+
93
+ class GoogleLocationFinder(BaseTool):
94
+ """ LocationFinder class for finding locations."""
95
+ name: str = "google_maps_location_finder"
96
+ description: str = (
97
+ "Search for location information, use this tool to find latitude, longitude and other geographical information from locations."
98
+ " Provide the complete address to this tool to receive location information"
99
+ )
100
+ google_key: str = None
101
+ base_url: str = "https://maps.googleapis.com/maps/api/geocode/json"
102
+ kwargs: Optional[dict] = None
103
+
104
+ def __init__(self, **kwargs):
105
+ super().__init__(**kwargs)
106
+ self.google_key = kwargs.get('api_key', GOOGLE_API_KEY)
107
+ self.kwargs = kwargs
108
+
109
+ def extract_location(self, data):
110
+ city = state = state_code = zipcode = None
111
+ try:
112
+ for component in data['address_components']:
113
+ if 'locality' in component['types']:
114
+ city = component['long_name']
115
+ elif 'administrative_area_level_1' in component['types']:
116
+ state_code = component['short_name']
117
+ state = component['long_name']
118
+ elif 'postal_code' in component['types']:
119
+ zipcode = component['long_name']
120
+ except Exception:
121
+ pass
122
+ return city, state, state_code, zipcode
123
+
124
+ def _run(self, query: str) -> dict:
125
+ """Find Location."""
126
+ params = {
127
+ "address": query,
128
+ "key": self.google_key
129
+ }
130
+ response = requests.get(
131
+ self.base_url,
132
+ params=params
133
+ )
134
+ if response.status_code == 200:
135
+ result = response.json()
136
+ if result['status'] == 'OK':
137
+ location = result['results'][0]
138
+ city, state, state_code, zipcode = self.extract_location(
139
+ location
140
+ )
141
+ return {
142
+ "latitude": location['geometry']['location']['lat'],
143
+ "longitude": location['geometry']['location']['lng'],
144
+ "address": location['formatted_address'],
145
+ "place_id": location['place_id'],
146
+ "zipcode": zipcode,
147
+ "city": city,
148
+ "state": state,
149
+ "state_code": state_code
150
+ }
151
+ return None
152
+ else:
153
+ return None
154
+
155
+ class GoogleRouteSearch(BaseTool):
156
+ """Web Search under a site using Google API."""
157
+ name: str = "google_maps_route_search"
158
+ description: str = "Search for a Route to a location using Google Maps, using this tool if answers questions about how to reach a location."
159
+ google_key: str = None
160
+ base_url: str = 'https://maps.googleapis.com/maps/api/directions/json'
161
+
162
+ def __init__(self, **kwargs):
163
+ super().__init__(**kwargs)
164
+ self._key_ = kwargs.get('api_key', GOOGLE_API_KEY)
165
+ self._kwargs = kwargs
166
+
167
+ def _run(self, query: str) -> dict:
168
+ departure_time = 'now'
@@ -0,0 +1,16 @@
1
+ from langchain_community.tools.google_trends import GoogleTrendsQueryRun
2
+ from langchain_community.utilities.google_trends import GoogleTrendsAPIWrapper
3
+ from crewai_tools import BaseTool
4
+
5
+
6
+ class GoogleTrendsTool(BaseTool):
7
+ """Google Trends Tool."""
8
+ name: str = "Google Trends"
9
+ description: str = "Search the web using Google Trends API"
10
+
11
+ def _run(self, query: str) -> dict:
12
+ """Run the Google Trends Tool."""
13
+ google_trends = GoogleTrendsQueryRun(
14
+ api_wrapper=GoogleTrendsAPIWrapper()
15
+ )
16
+ return google_trends.run(query)
@@ -0,0 +1,25 @@
1
+ from navconfig import BASE_DIR
2
+ from crewai_tools import BaseTool
3
+ import markdown2
4
+ from weasyprint import HTML
5
+
6
+
7
+ class MarkdownToPDFTool(BaseTool):
8
+ """Markdown to PDF Tool."""
9
+ name: str = "MarkdownToPDFTool"
10
+ description: str = "Converts markdown documents to PDF format."
11
+
12
+ def _run(self, markdown_content: str) -> str:
13
+ # Convert Markdown to HTML
14
+ html_content = markdown2.markdown(markdown_content)
15
+ # Convert HTML to PDF (assuming it's a simple conversion without advanced styling)
16
+ pdf = HTML(string=html_content).write_pdf()
17
+
18
+ # Save PDF to a temporary file and return file path
19
+ pdf_file_path = BASE_DIR.joinpath('docs', 'report.pdf')
20
+ with open(str(pdf_file_path), 'wb') as f:
21
+ f.write(pdf)
22
+ return pdf_file_path
23
+
24
+ def __call__(self, markdown_content: str) -> str:
25
+ return self._run(markdown_content)
@@ -0,0 +1,42 @@
1
+ from typing import Union
2
+ from pathlib import Path
3
+ from pydantic import PrivateAttr
4
+ from crewai_tools import BaseTool, RagTool
5
+
6
+ class RagSearchTool(BaseTool):
7
+ """RagTool is designed to answer questions by leveraging the power of RAG by leveraging (EmbedChain)."""
8
+ name: str = "RAG Tool"
9
+ description: str = "enables users to dynamically query a knowledge base"
10
+ _directory: PrivateAttr
11
+
12
+ def __init__(self, directory: Union[Path, str] = None, **kwargs):
13
+ super().__init__(**kwargs)
14
+ self._directory = directory
15
+
16
+ def get_rag(self):
17
+ """Return the RAG Tool."""
18
+ return RagTool(
19
+ config={
20
+ "llm": {
21
+ "provider": "vertexai",
22
+ "config": {
23
+ "model": "gemini-pro",
24
+ "temperature": 0.4,
25
+ "top_p": 1,
26
+ "stream": True
27
+ }
28
+ },
29
+ "embedder": {
30
+ "provider": "vertexai",
31
+ "config": {
32
+ "model": "embedding-001"
33
+ }
34
+ }
35
+ }
36
+ )
37
+
38
+ def _run(self, query: str, **kwargs) -> dict:
39
+ """Query Several sources of information for knowledge base."""
40
+ rag = self.get_rag()
41
+ if self._directory:
42
+ return rag.from_directory(self._directory)
@@ -0,0 +1,32 @@
1
+ from crewai_tools import WebsiteSearchTool
2
+ from crewai_tools import BaseTool
3
+
4
+
5
+ class WebSearchTool(BaseTool):
6
+ """Search on any Website using WebSiteSearch."""
7
+ name: str = "WebSite Search"
8
+ description: str = "Search on a website using WebsiteSearchTool"
9
+
10
+ def _run(self, query: str, **kwargs) -> dict:
11
+ """Run the Google Trends Tool."""
12
+ search = WebsiteSearchTool(
13
+ config={
14
+ "llm": {
15
+ "provider": "google",
16
+ "config": {
17
+ "model": "models/gemini-pro",
18
+ "temperature": 0.4,
19
+ "top_p": 1,
20
+ "stream": True
21
+ }
22
+ },
23
+ "embedder": {
24
+ "provider": "google",
25
+ "config": {
26
+ "model": "models/embedding-001",
27
+ "task_type": "retrieval_document",
28
+ }
29
+ }
30
+ }
31
+ )
32
+ return search.run(query, **kwargs)
@@ -0,0 +1,21 @@
1
+ import requests
2
+ from crewai_tools import BaseTool
3
+
4
+
5
+ class ValidateURLsTool(BaseTool):
6
+ """Validate URLs Tool."""
7
+ name: str = "Validate URLs"
8
+ description: str = "Validate URLs for status code and response time."
9
+
10
+ def _run(self, urls: list) -> dict:
11
+ """Run the Validate URLs Tool."""
12
+ valid_urls = []
13
+ for url in urls:
14
+ try:
15
+ response = requests.head(url, allow_redirects=True)
16
+ if response.status_code == 200:
17
+ valid_urls.append(url)
18
+ except requests.RequestException:
19
+ # Handle exceptions or log errors here
20
+ continue
21
+ return valid_urls
@@ -0,0 +1,4 @@
1
+ """
2
+ Parrot basic Handlers.
3
+ """
4
+ from .bots import ChatbotHandler
@@ -0,0 +1,196 @@
1
+ from asyncdb import AsyncDB
2
+ from navigator.views import (
3
+ ModelView,
4
+ BaseView,
5
+ FormModel
6
+ )
7
+ from parrot.conf import (
8
+ BIGQUERY_CREDENTIALS,
9
+ BIGQUERY_PROJECT_ID,
10
+ )
11
+ from ..models import (
12
+ ChatbotModel,
13
+ ChatbotUsage,
14
+ PromptLibrary,
15
+ ChatbotFeedback,
16
+ FeedbackType
17
+ )
18
+
19
+
20
+ class PromptLibraryManagement(ModelView):
21
+ """
22
+ PromptLibraryManagement.
23
+ description: PromptLibraryManagement for Parrot Application.
24
+ """
25
+
26
+ model = PromptLibrary
27
+ name: str = "Prompt Library Management"
28
+ path: str = '/api/v1/prompt_library'
29
+ pk: str = 'prompt_id'
30
+
31
+ async def _set_created_by(self, value, column, data):
32
+ if not value:
33
+ return await self.get_userid(session=self._session)
34
+ return value
35
+
36
+
37
+ class ChatbotUsageHandler(ModelView):
38
+ """
39
+ ChatbotUsageHandler.
40
+ description: ChatbotUsageHandler for Parrot Application.
41
+ """
42
+
43
+ model = ChatbotUsage
44
+ driver: str = 'scylladb'
45
+ credentials: dict = {
46
+ "credentials": BIGQUERY_CREDENTIALS,
47
+ "project_id": BIGQUERY_PROJECT_ID,
48
+ }
49
+ name: str = "Chatbot Usage"
50
+ path: str = '/api/v1/chatbots/usage'
51
+ pk: str = 'sid'
52
+
53
+
54
+ class ChatbotSharingQuestion(BaseView):
55
+ """
56
+ ChatbotSharingQuestion.
57
+ description: ChatbotSharingQuestion for Parrot Application.
58
+ """
59
+
60
+ def get_connection(self):
61
+ params = {
62
+ "credentials": BIGQUERY_CREDENTIALS,
63
+ "project_id": BIGQUERY_PROJECT_ID,
64
+ }
65
+ return AsyncDB(
66
+ 'bigquery',
67
+ params=params
68
+ )
69
+
70
+ async def get(self):
71
+ qs = self.get_arguments(self.request)
72
+ sid = qs.get('sid', None)
73
+ if not sid:
74
+ return self.error(
75
+ response={
76
+ "message": "You need to Provided a ID of Question"
77
+ },
78
+ status=400
79
+ )
80
+ db = self.get_connection()
81
+ try:
82
+ async with await db.connection() as conn: #pylint: disable=E1101
83
+ ChatbotUsage.Meta.connection = conn
84
+ # Getting a SID from sid
85
+ question = await ChatbotUsage.get(sid=sid)
86
+ if not question:
87
+ return self.error(
88
+ response={
89
+ "message": "Question not found"
90
+ },
91
+ status=404
92
+ )
93
+ return self.json_response(
94
+ {
95
+ "chatbot": question.chatbot_id,
96
+ "question": question.question,
97
+ "answer": question.response,
98
+ "at": question.used_at
99
+ }
100
+ )
101
+ except Exception as e:
102
+ return self.error(
103
+ response={
104
+ "message": f"Error on Chatbot Sharing Question: {e}"
105
+ },
106
+ status=400
107
+ )
108
+
109
+
110
+
111
+ class FeedbackTypeHandler(BaseView):
112
+ """
113
+ FeedbackTypeHandler.
114
+ description: FeedbackTypeHandler for Parrot Application.
115
+ """
116
+
117
+ async def get(self):
118
+ qs = self.get_arguments(self.request)
119
+ category = qs.get('feedback_type', 'good').capitalize()
120
+ feedback_list = FeedbackType.list_feedback(category)
121
+ return self.json_response({
122
+ "feedback": feedback_list
123
+ })
124
+
125
+ # Manage Feedback:
126
+ class ChatbotFeedbackHandler(FormModel):
127
+ """
128
+ ChatbotFeedbackHandler.
129
+ description: ChatbotFeedbackHandler for Parrot Application.
130
+ """
131
+ model = ChatbotFeedback
132
+ path: str = '/api/v1/bot_feedback'
133
+
134
+ def get_connection(self):
135
+ params = {
136
+ "credentials": BIGQUERY_CREDENTIALS,
137
+ "project_id": BIGQUERY_PROJECT_ID,
138
+ }
139
+ return AsyncDB(
140
+ 'bigquery',
141
+ params=params,
142
+ force_closing=False
143
+ )
144
+
145
+ async def post(self):
146
+ feedback = await self.validate_payload()
147
+ if not feedback:
148
+ return self.error(
149
+ response={
150
+ "message": "Error on Bot Feedback"
151
+ },
152
+ status=400
153
+ )
154
+ db = self.get_connection()
155
+ try:
156
+ async with await db.connection() as conn: #pylint: disable=E1101
157
+ data = feedback.to_dict()
158
+ # convert to string (bigquery uses json.dumps to convert to string)
159
+ data['sid'] = str(data['sid'])
160
+ data['chatbot_id'] = str(data['chatbot_id'])
161
+ data['expiration_timestamp'] = str(data['expiration_timestamp'])
162
+ data['feedback_type'] = feedback.feedback_type.value
163
+ # writing directly to bigquery
164
+ await conn.write(
165
+ [data],
166
+ table_id=ChatbotFeedback.Meta.name,
167
+ dataset_id=ChatbotFeedback.Meta.schema,
168
+ use_streams=False,
169
+ use_pandas=False
170
+ )
171
+ return self.json_response({
172
+ "message": "Bot Feedback Submitted, Thank you for your feedback!.",
173
+ "question": f"Question of ID: {feedback.sid} for bot {feedback.chatbot_id}"
174
+ }, status=201)
175
+ except Exception as e:
176
+ return self.error(
177
+ response={
178
+ "message": f"Error on Bot Feedback: {e}"
179
+ },
180
+ status=400
181
+ )
182
+
183
+
184
+ class ChatbotHandler(ModelView):
185
+ """
186
+ ChatbotHandler.
187
+ description: ChatbotHandler for Parrot Application.
188
+ """
189
+
190
+ model = ChatbotModel
191
+ name: str = "Chatbot Management"
192
+ pk: str = 'chatbot_id'
193
+
194
+
195
+ async def _set_created_by(self, value, column, data):
196
+ return await self.get_userid(session=self._session)