added files
Browse files- .gitignore +162 -0
- app.py +84 -0
- config/config.py +7 -0
- config/openai_config.py +4 -0
- requirements.txt +4 -0
- tools/tools.py +20 -0
.gitignore
ADDED
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Byte-compiled / optimized / DLL files
|
2 |
+
__pycache__/
|
3 |
+
*.py[cod]
|
4 |
+
*$py.class
|
5 |
+
|
6 |
+
# C extensions
|
7 |
+
*.so
|
8 |
+
|
9 |
+
# Distribution / packaging
|
10 |
+
.Python
|
11 |
+
build/
|
12 |
+
develop-eggs/
|
13 |
+
dist/
|
14 |
+
downloads/
|
15 |
+
eggs/
|
16 |
+
.eggs/
|
17 |
+
lib/
|
18 |
+
lib64/
|
19 |
+
parts/
|
20 |
+
sdist/
|
21 |
+
var/
|
22 |
+
wheels/
|
23 |
+
share/python-wheels/
|
24 |
+
*.egg-info/
|
25 |
+
.installed.cfg
|
26 |
+
*.egg
|
27 |
+
MANIFEST
|
28 |
+
|
29 |
+
# PyInstaller
|
30 |
+
# Usually these files are written by a python script from a template
|
31 |
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
32 |
+
*.manifest
|
33 |
+
*.spec
|
34 |
+
|
35 |
+
# Installer logs
|
36 |
+
pip-log.txt
|
37 |
+
pip-delete-this-directory.txt
|
38 |
+
|
39 |
+
# Unit test / coverage reports
|
40 |
+
htmlcov/
|
41 |
+
.tox/
|
42 |
+
.nox/
|
43 |
+
.coverage
|
44 |
+
.coverage.*
|
45 |
+
.cache
|
46 |
+
nosetests.xml
|
47 |
+
coverage.xml
|
48 |
+
*.cover
|
49 |
+
*.py,cover
|
50 |
+
.hypothesis/
|
51 |
+
.pytest_cache/
|
52 |
+
cover/
|
53 |
+
|
54 |
+
# Translations
|
55 |
+
*.mo
|
56 |
+
*.pot
|
57 |
+
|
58 |
+
# Django stuff:
|
59 |
+
*.log
|
60 |
+
local_settings.py
|
61 |
+
db.sqlite3
|
62 |
+
db.sqlite3-journal
|
63 |
+
|
64 |
+
# Flask stuff:
|
65 |
+
instance/
|
66 |
+
.webassets-cache
|
67 |
+
|
68 |
+
# Scrapy stuff:
|
69 |
+
.scrapy
|
70 |
+
|
71 |
+
# Sphinx documentation
|
72 |
+
docs/_build/
|
73 |
+
|
74 |
+
# PyBuilder
|
75 |
+
.pybuilder/
|
76 |
+
target/
|
77 |
+
|
78 |
+
# Jupyter Notebook
|
79 |
+
.ipynb_checkpoints
|
80 |
+
|
81 |
+
# IPython
|
82 |
+
profile_default/
|
83 |
+
ipython_config.py
|
84 |
+
|
85 |
+
# pyenv
|
86 |
+
# For a library or package, you might want to ignore these files since the code is
|
87 |
+
# intended to run in multiple environments; otherwise, check them in:
|
88 |
+
# .python-version
|
89 |
+
|
90 |
+
# pipenv
|
91 |
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
92 |
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
93 |
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
94 |
+
# install all needed dependencies.
|
95 |
+
#Pipfile.lock
|
96 |
+
|
97 |
+
# poetry
|
98 |
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
99 |
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
100 |
+
# commonly ignored for libraries.
|
101 |
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
102 |
+
#poetry.lock
|
103 |
+
|
104 |
+
# pdm
|
105 |
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
106 |
+
#pdm.lock
|
107 |
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
108 |
+
# in version control.
|
109 |
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
110 |
+
.pdm.toml
|
111 |
+
.pdm-python
|
112 |
+
.pdm-build/
|
113 |
+
|
114 |
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
115 |
+
__pypackages__/
|
116 |
+
|
117 |
+
# Celery stuff
|
118 |
+
celerybeat-schedule
|
119 |
+
celerybeat.pid
|
120 |
+
|
121 |
+
# SageMath parsed files
|
122 |
+
*.sage.py
|
123 |
+
|
124 |
+
# Environments
|
125 |
+
.env
|
126 |
+
.venv
|
127 |
+
env/
|
128 |
+
venv/
|
129 |
+
ENV/
|
130 |
+
env.bak/
|
131 |
+
venv.bak/
|
132 |
+
|
133 |
+
# Spyder project settings
|
134 |
+
.spyderproject
|
135 |
+
.spyproject
|
136 |
+
|
137 |
+
# Rope project settings
|
138 |
+
.ropeproject
|
139 |
+
|
140 |
+
# mkdocs documentation
|
141 |
+
/site
|
142 |
+
|
143 |
+
# mypy
|
144 |
+
.mypy_cache/
|
145 |
+
.dmypy.json
|
146 |
+
dmypy.json
|
147 |
+
|
148 |
+
# Pyre type checker
|
149 |
+
.pyre/
|
150 |
+
|
151 |
+
# pytype static type analyzer
|
152 |
+
.pytype/
|
153 |
+
|
154 |
+
# Cython debug symbols
|
155 |
+
cython_debug/
|
156 |
+
|
157 |
+
# PyCharm
|
158 |
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
159 |
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
160 |
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
161 |
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
162 |
+
#.idea/
|
app.py
ADDED
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# To make a search GPT which will search the internet based on the user query and return the results in a chat format
|
2 |
+
|
3 |
+
# Standard library imports
|
4 |
+
import json
|
5 |
+
from typing import List
|
6 |
+
|
7 |
+
# Third-party imports
|
8 |
+
import gradio as gr
|
9 |
+
import requests
|
10 |
+
|
11 |
+
# Local imports
|
12 |
+
from config.config import SCRAPER_API_KEY as scraper_api_key
|
13 |
+
from config.openai_config import client
|
14 |
+
from tools.tools import tools
|
15 |
+
|
16 |
+
|
17 |
+
class SearchGPT:
|
18 |
+
def __init__(self):
|
19 |
+
self.prompt = "You are a helpful assistant that can search the internet for the user query and return the results in a chat format, help the user with their query. If the user is asking for latest information about anything call the get_user_query tool with the search query as the argument. If the user is asking for anything else that you already know, just answer it. If the user is asking for something you do not know call the get_user_query tool with the search query as the argument and also provide the sources from where the information is fetched in the response after answering the user query. Return the reference links in the response as well."
|
20 |
+
self.messages : List = list() # this will store the conversation history
|
21 |
+
self.model = "gpt-4o-mini"
|
22 |
+
self.tools = tools
|
23 |
+
#this will store the search results in a structured format
|
24 |
+
self.search_results: List = list()
|
25 |
+
|
26 |
+
def make_openai_call(self):
|
27 |
+
response = client.chat.completions.create(
|
28 |
+
model=self.model,
|
29 |
+
messages=self.messages,
|
30 |
+
tools=self.tools,
|
31 |
+
tool_choice="auto",
|
32 |
+
)
|
33 |
+
return response
|
34 |
+
|
35 |
+
def search_internet(self, search_query: str):
|
36 |
+
# using scraper api to search the internet
|
37 |
+
payload = { 'api_key': scraper_api_key, 'query': search_query, 'num': '2', 'additional_params': 'autoparse=True', 'country_code': 'in' }
|
38 |
+
response = requests.get('https://api.scraperapi.com/structured/google/search', params=payload)
|
39 |
+
# print(r.text)
|
40 |
+
return response.text
|
41 |
+
|
42 |
+
def get_response(self, query: str, history):
|
43 |
+
self.messages.append({"role": "user", "content": query})
|
44 |
+
print(query)
|
45 |
+
response = self.make_openai_call()
|
46 |
+
self.messages.append(response.choices[0].to_dict()['message'])
|
47 |
+
return self.handle_response(response)
|
48 |
+
|
49 |
+
def handle_response(self, response):
|
50 |
+
tool_calls = response.choices[0].message.tool_calls
|
51 |
+
if tool_calls:
|
52 |
+
return self.handle_tool_call(tool_calls)
|
53 |
+
assistant_response = response.choices[0].message.content
|
54 |
+
return assistant_response
|
55 |
+
|
56 |
+
def handle_tool_call(self, tool_calls):
|
57 |
+
for tool in tool_calls:
|
58 |
+
if tool.function.name == "get_user_query":
|
59 |
+
search_query = json.loads(tool.function.arguments)['search_query']
|
60 |
+
response = self.search_internet(search_query)
|
61 |
+
self.messages.append(
|
62 |
+
{
|
63 |
+
"role": "tool",
|
64 |
+
"tool_call_id": tool.id,
|
65 |
+
"name": tool.function.name,
|
66 |
+
"content": response,
|
67 |
+
}
|
68 |
+
)
|
69 |
+
response = self.make_openai_call()
|
70 |
+
return response.choices[0].message.content
|
71 |
+
|
72 |
+
if __name__ == "__main__":
|
73 |
+
search_gpt = SearchGPT()
|
74 |
+
|
75 |
+
# Create Gradio interface
|
76 |
+
iface = gr.ChatInterface(
|
77 |
+
fn=search_gpt.get_response,
|
78 |
+
title="SearchGPT",
|
79 |
+
description="Ask me anything, and I'll search the internet for you!",
|
80 |
+
examples=["What are the trending news in India today?", "Tell me about the latest advancements in AI"],
|
81 |
+
theme="soft"
|
82 |
+
)
|
83 |
+
# Launch the interface
|
84 |
+
iface.launch(share=True)
|
config/config.py
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from dotenv import load_dotenv
|
3 |
+
|
4 |
+
load_dotenv()
|
5 |
+
|
6 |
+
OPENAI_API_KEY = os.getenv("OPEN_AI_KEY")
|
7 |
+
SCRAPER_API_KEY = os.getenv("SCRAPER_API_KEY")
|
config/openai_config.py
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from openai import OpenAI
|
2 |
+
from config.config import OPENAI_API_KEY
|
3 |
+
|
4 |
+
client = OpenAI(api_key=OPENAI_API_KEY)
|
requirements.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
gradio
|
2 |
+
openai
|
3 |
+
requests
|
4 |
+
python-dotenv
|
tools/tools.py
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
tools = [
|
2 |
+
{
|
3 |
+
"type": "function",
|
4 |
+
"function": {
|
5 |
+
"name": "get_user_query",
|
6 |
+
"description": "Get the search query from the users message and use a search engine to get the result",
|
7 |
+
"parameters": {
|
8 |
+
"type": "object",
|
9 |
+
"properties": {
|
10 |
+
"search_query": {
|
11 |
+
"type": "string",
|
12 |
+
"description": "The message content provided by the user, e.g., 'What is the weather in San Francisco today?' or 'What is the latest update in the AI space?'"
|
13 |
+
}
|
14 |
+
},
|
15 |
+
"required": ["search_query"],
|
16 |
+
"additionalProperties": False
|
17 |
+
}
|
18 |
+
}
|
19 |
+
}
|
20 |
+
]
|