Spaces:
Sleeping
Sleeping
Merge pull request #3 from leowalker89/EnableBraveSearchAI
Browse files- app.py +159 -88
- brave_ai.py +89 -0
- helpers.py +20 -67
- provider_info.py +18 -0
- requirements.txt +92 -6
- test_func.py +36 -0
app.py
CHANGED
@@ -1,20 +1,32 @@
|
|
1 |
import streamlit as st
|
2 |
import random
|
3 |
-
from helpers import query_you_com, query_tavily, query_perplexity
|
4 |
-
from
|
5 |
-
from
|
|
|
6 |
import time
|
7 |
|
8 |
-
mongo = MongoDBHandler()
|
9 |
|
10 |
# Set Streamlit to wide mode
|
11 |
st.set_page_config(layout="wide")
|
12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
# Define the function to process the question
|
15 |
def ProcessQuestion(question):
|
16 |
-
# Randomly select two out of the
|
17 |
-
functions = [query_you_com, query_tavily, query_perplexity]
|
18 |
selected_functions = random.sample(functions, 2)
|
19 |
|
20 |
# Get answers from the selected functions
|
@@ -22,98 +34,157 @@ def ProcessQuestion(question):
|
|
22 |
answer_b = selected_functions[1](question)
|
23 |
|
24 |
# Log into mongodb
|
25 |
-
try:
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
except Exception as e:
|
38 |
-
|
39 |
-
|
40 |
-
return answer_a, answer_b
|
41 |
|
42 |
|
43 |
# Initialize session state if not already done
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
|
53 |
# Streamlit app layout
|
54 |
st.title("Search Engine Agent Comparison")
|
55 |
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
with input_col:
|
60 |
-
# Text box for user input with character limit
|
61 |
-
question = st.text_area(
|
62 |
-
"Enter your question here (max 1000 characters):", max_chars=1000
|
63 |
-
)
|
64 |
-
|
65 |
-
with control_col:
|
66 |
-
# Submit button
|
67 |
-
submit_button = st.button("Submit")
|
68 |
-
|
69 |
-
if submit_button:
|
70 |
if question:
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
col1, col2 = st.columns(2)
|
90 |
with col1:
|
91 |
-
st.write("###
|
92 |
st.write(st.session_state["answer_a"])
|
93 |
-
a_feedback_grid = st.columns(1)
|
94 |
with col2:
|
95 |
-
st.write("###
|
96 |
st.write(st.session_state["answer_b"])
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
)
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import streamlit as st
|
2 |
import random
|
3 |
+
from helpers import query_you_com, query_tavily, query_perplexity, query_brave
|
4 |
+
from provider_info import search_providers
|
5 |
+
# from mongod_db import MongoDBHandler
|
6 |
+
# from swarms.utils.loguru_logger import logger
|
7 |
import time
|
8 |
|
9 |
+
# mongo = MongoDBHandler()
|
10 |
|
11 |
# Set Streamlit to wide mode
|
12 |
st.set_page_config(layout="wide")
|
13 |
|
14 |
+
# Add information to sidebar
|
15 |
+
st.sidebar.title("About the App")
|
16 |
+
st.sidebar.write("""
|
17 |
+
This app allows you to compare responses from different search engines.
|
18 |
+
Submit a question, and you'll receive answers from two randomly selected search engines.
|
19 |
+
You can then vote on which response you prefer.
|
20 |
+
""")
|
21 |
+
st.sidebar.write("""
|
22 |
+
**[GitHub](https://github.com/leowalker89/SearchArena)**
|
23 |
+
|
24 |
+
""")
|
25 |
|
26 |
# Define the function to process the question
|
27 |
def ProcessQuestion(question):
|
28 |
+
# Randomly select two out of the four functions
|
29 |
+
functions = [query_you_com, query_tavily, query_perplexity, query_brave]
|
30 |
selected_functions = random.sample(functions, 2)
|
31 |
|
32 |
# Get answers from the selected functions
|
|
|
34 |
answer_b = selected_functions[1](question)
|
35 |
|
36 |
# Log into mongodb
|
37 |
+
# try:
|
38 |
+
# logger.info(f"Logging question: {question}")
|
39 |
+
# mongo.add(
|
40 |
+
# {
|
41 |
+
# "question": question,
|
42 |
+
# "answer_a": answer_a,
|
43 |
+
# "answer_b": answer_b,
|
44 |
+
# "selected_functions": [f.__name__ for f in selected_functions],
|
45 |
+
# "query_time": time.time(),
|
46 |
+
# }
|
47 |
+
# )
|
48 |
+
# logger.info("Successfully logged into mongodb")
|
49 |
+
# except Exception as e:
|
50 |
+
# logger.error(f"Error logging into mongodb: {e}")
|
51 |
+
|
52 |
+
return answer_a, answer_b, selected_functions
|
53 |
|
54 |
|
55 |
# Initialize session state if not already done
|
56 |
+
default_values = {
|
57 |
+
"state": "arena_ready",
|
58 |
+
"question": "",
|
59 |
+
"answer_a": "",
|
60 |
+
"answer_b": "",
|
61 |
+
"source_a": "",
|
62 |
+
"source_b": "",
|
63 |
+
"winner": "",
|
64 |
+
"selected_button": ""
|
65 |
+
}
|
66 |
+
|
67 |
+
for key, value in default_values.items():
|
68 |
+
if key not in st.session_state:
|
69 |
+
st.session_state[key] = value
|
70 |
|
71 |
# Streamlit app layout
|
72 |
st.title("Search Engine Agent Comparison")
|
73 |
|
74 |
+
def on_submit():
|
75 |
+
question = st.session_state["question_input"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
if question:
|
77 |
+
answer_a, answer_b, selected_functions = ProcessQuestion(question)
|
78 |
+
st.session_state["question"] = question
|
79 |
+
st.session_state["answer_a"] = answer_a
|
80 |
+
st.session_state["answer_b"] = answer_b
|
81 |
+
st.session_state["source_a"] = selected_functions[0].__name__
|
82 |
+
st.session_state["source_b"] = selected_functions[1].__name__
|
83 |
+
st.session_state["state"] = "arena_review"
|
84 |
+
|
85 |
+
def handle_vote(vote):
|
86 |
+
st.session_state["winner"] = vote
|
87 |
+
st.session_state["state"] = "arena_results"
|
88 |
+
|
89 |
+
def get_provider_info(provider_function_name):
|
90 |
+
provider_name_map = {
|
91 |
+
'query_you_com': 'You.com',
|
92 |
+
'query_tavily': 'Tavily',
|
93 |
+
'query_perplexity': 'Perplexity AI',
|
94 |
+
'query_brave': 'Brave Search'
|
95 |
+
}
|
96 |
+
provider_name = provider_name_map.get(provider_function_name)
|
97 |
+
return next((provider for provider in search_providers if provider['company_name'] == provider_name), {})
|
98 |
+
|
99 |
+
def render_ready_state():
|
100 |
+
st.text_area("Enter your question here (max 1000 characters):",
|
101 |
+
max_chars=1000,
|
102 |
+
key="question_input",
|
103 |
+
on_change=on_submit)
|
104 |
+
st.button("Submit", on_click=on_submit)
|
105 |
+
|
106 |
+
def render_review_state():
|
107 |
+
st.write("## Results")
|
108 |
col1, col2 = st.columns(2)
|
109 |
with col1:
|
110 |
+
st.write("### Answer A")
|
111 |
st.write(st.session_state["answer_a"])
|
|
|
112 |
with col2:
|
113 |
+
st.write("### Answer B")
|
114 |
st.write(st.session_state["answer_b"])
|
115 |
+
st.write("### Vote for the Best Answer")
|
116 |
+
col1, col2, col3, col4 = st.columns(4)
|
117 |
+
if col1.button("It's a Tie 🤝"):
|
118 |
+
handle_vote("Tie")
|
119 |
+
if col2.button("A is better 💪"):
|
120 |
+
handle_vote("A")
|
121 |
+
if col3.button("B is better 🥇"):
|
122 |
+
handle_vote("B")
|
123 |
+
if col4.button("Both are bad 👎"):
|
124 |
+
handle_vote("Both are bad")
|
125 |
+
|
126 |
+
def render_results_state():
|
127 |
+
st.write("## Results")
|
128 |
+
st.write(f"### Question: {st.session_state['question']}")
|
129 |
+
|
130 |
+
provider_info_a = get_provider_info(st.session_state["source_a"])
|
131 |
+
provider_info_b = get_provider_info(st.session_state["source_b"])
|
132 |
+
|
133 |
+
col1, col2 = st.columns(2)
|
134 |
+
with col1:
|
135 |
+
if st.session_state["winner"] == "A":
|
136 |
+
st.write(f"### ⭐ {provider_info_a['company_name']} 🥇")
|
137 |
+
elif st.session_state["winner"] == "Tie":
|
138 |
+
st.write(f"### 🤝 {provider_info_a['company_name']} 🤝")
|
139 |
+
elif st.session_state["winner"] == "Both are bad":
|
140 |
+
st.write(f"### 👎 {provider_info_a['company_name']} 👎")
|
141 |
+
else:
|
142 |
+
st.write(f"### {provider_info_a['company_name']} 🥈")
|
143 |
+
st.write("**Response:**")
|
144 |
+
st.markdown(f"<div style='padding: 10px; border: 1px solid #ddd;'>{st.session_state['answer_a']}</div>", unsafe_allow_html=True)
|
145 |
+
|
146 |
+
with col2:
|
147 |
+
if st.session_state["winner"] == "B":
|
148 |
+
st.write(f"### ⭐ {provider_info_b['company_name']} 🥇")
|
149 |
+
elif st.session_state["winner"] == "Tie":
|
150 |
+
st.write(f"### 🤝 {provider_info_b['company_name']} 🤝")
|
151 |
+
elif st.session_state["winner"] == "Both are bad":
|
152 |
+
st.write(f"### 👎 {provider_info_b['company_name']} 👎")
|
153 |
+
else:
|
154 |
+
st.write(f"### {provider_info_b['company_name']} 🥈")
|
155 |
+
st.write("**Response:**")
|
156 |
+
st.markdown(f"<div style='padding: 10px; border: 1px solid #ddd;'>{st.session_state['answer_b']}</div>", unsafe_allow_html=True)
|
157 |
+
|
158 |
+
st.write("### Feedback")
|
159 |
+
st.text_area("Please provide feedback on why you chose the winner:", key="feedback")
|
160 |
+
st.write("### About the search providers:")
|
161 |
+
col1, col2 = st.columns(2)
|
162 |
+
with col1:
|
163 |
+
st.write(f"**Website:** [{provider_info_a['website']}]({provider_info_a['website']})")
|
164 |
+
st.write(f"**Overview:** {provider_info_a['overview']}")
|
165 |
+
with col2:
|
166 |
+
st.write(f"**Website:** [{provider_info_b['website']}]({provider_info_b['website']})")
|
167 |
+
st.write(f"**Overview:** {provider_info_b['overview']}")
|
168 |
+
|
169 |
+
if st.session_state["state"] == "arena_ready":
|
170 |
+
render_ready_state()
|
171 |
+
elif st.session_state["state"] == "arena_review":
|
172 |
+
render_review_state()
|
173 |
+
elif st.session_state["state"] == "arena_results":
|
174 |
+
render_results_state()
|
175 |
+
|
176 |
+
# Apply custom CSS to highlight the selected button
|
177 |
+
selected_button = st.session_state.get("selected_button", "")
|
178 |
+
|
179 |
+
if selected_button:
|
180 |
+
st.markdown(
|
181 |
+
f"""
|
182 |
+
<style>
|
183 |
+
button[kind="primary"]{{
|
184 |
+
background-color: #4CAF50 !important;
|
185 |
+
color: white !important;
|
186 |
+
}}
|
187 |
+
</style>
|
188 |
+
""",
|
189 |
+
unsafe_allow_html=True
|
190 |
+
)
|
brave_ai.py
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import requests
|
3 |
+
from typing import List, Optional
|
4 |
+
# from langchain_community.document_transformers import MarkdownifyTransformer
|
5 |
+
from langchain_core.documents import Document
|
6 |
+
from langchain_core.pydantic_v1 import BaseModel, Field
|
7 |
+
|
8 |
+
class BraveAIWrapper(BaseModel):
|
9 |
+
api_key: str = Field(..., description="API key for Brave Search")
|
10 |
+
base_search_url: str = Field("https://api.search.brave.com/res/v1/web/search", const=True)
|
11 |
+
base_summarize_url: str = Field("https://api.search.brave.com/res/v1/summarizer/search", const=True)
|
12 |
+
headers: dict = Field(default_factory=dict, description="HTTP headers for API requests")
|
13 |
+
|
14 |
+
class Config:
|
15 |
+
arbitrary_types_allowed = True
|
16 |
+
|
17 |
+
def __init__(self, **data):
|
18 |
+
super().__init__(**data)
|
19 |
+
self.headers = {
|
20 |
+
"X-Subscription-Token": self.api_key,
|
21 |
+
"Accept": "application/json",
|
22 |
+
"Accept-Encoding": "gzip",
|
23 |
+
}
|
24 |
+
|
25 |
+
def get_brave_results(self, query: str, count: int = 3, safe_search: str = 'off') -> Optional[dict]:
|
26 |
+
"""
|
27 |
+
Get search results from Brave Search.
|
28 |
+
|
29 |
+
Args:
|
30 |
+
query (str): The search query.
|
31 |
+
count (int): Number of results to return.
|
32 |
+
safe_search (str): Safe search filter (off, moderate, strict).
|
33 |
+
|
34 |
+
Returns:
|
35 |
+
Optional[dict]: JSON response from Brave Search API or None if an error occurs.
|
36 |
+
"""
|
37 |
+
params = {
|
38 |
+
"q": query,
|
39 |
+
"count": count,
|
40 |
+
"summary": True,
|
41 |
+
"safe_search": safe_search,
|
42 |
+
"extra_snippets": True,
|
43 |
+
}
|
44 |
+
try:
|
45 |
+
response = requests.get(self.base_search_url, headers=self.headers, params=params)
|
46 |
+
response.raise_for_status()
|
47 |
+
return response.json()
|
48 |
+
except requests.exceptions.RequestException as e:
|
49 |
+
print(f"Error: {e}")
|
50 |
+
return None
|
51 |
+
|
52 |
+
def summarize_results(self, summarizer_key: str) -> Optional[dict]:
|
53 |
+
"""
|
54 |
+
Summarize search results using Brave Summarizer.
|
55 |
+
|
56 |
+
Args:
|
57 |
+
summarizer_key (str): The key for the summarizer.
|
58 |
+
|
59 |
+
Returns:
|
60 |
+
Optional[dict]: JSON response from Brave Summarizer API or None if an error occurs.
|
61 |
+
"""
|
62 |
+
params = {"key": summarizer_key}
|
63 |
+
try:
|
64 |
+
response = requests.get(self.base_summarize_url, headers=self.headers, params=params)
|
65 |
+
response.raise_for_status()
|
66 |
+
return response.json()
|
67 |
+
except requests.exceptions.RequestException as e:
|
68 |
+
print(f"Error: {e}")
|
69 |
+
return None
|
70 |
+
|
71 |
+
def get_and_summarize(self, query: str, count: int = 3, safe_search: str = 'off') -> Optional[str]:
|
72 |
+
"""
|
73 |
+
Get and summarize search results from Brave Search.
|
74 |
+
|
75 |
+
Args:
|
76 |
+
query (str): The search query.
|
77 |
+
count (int): Number of results to return.
|
78 |
+
safe_search (str): Safe search filter (off, moderate, strict).
|
79 |
+
|
80 |
+
Returns:
|
81 |
+
Optional[str]: Summarized result or None if an error occurs.
|
82 |
+
"""
|
83 |
+
results = self.get_brave_results(query, count, safe_search)
|
84 |
+
if results and 'summarizer' in results:
|
85 |
+
summarizer_key = results['summarizer']['key']
|
86 |
+
summary = self.summarize_results(summarizer_key)
|
87 |
+
if summary and 'summary' in summary and len(summary['summary']) > 0:
|
88 |
+
return summary['summary'][0]['data']
|
89 |
+
return None
|
helpers.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1 |
import requests
|
2 |
from dotenv import load_dotenv
|
|
|
3 |
import os
|
4 |
|
5 |
# Load environment variables from .env file
|
@@ -9,8 +10,7 @@ load_dotenv()
|
|
9 |
YOU_COM_API_KEY = os.getenv("YOU_API_KEY")
|
10 |
TAVILY_API_KEY = os.getenv("TAVILY_API_KEY")
|
11 |
PERPLEXITY_API_KEY = os.getenv("PPLX_API_KEY")
|
12 |
-
BRAVE_API_KEY = os.getenv("
|
13 |
-
|
14 |
|
15 |
def query_you_com(query):
|
16 |
headers = {"X-API-Key": YOU_COM_API_KEY}
|
@@ -76,71 +76,6 @@ def query_perplexity(query):
|
|
76 |
return f"Request failed with status code: {response.status_code}"
|
77 |
|
78 |
|
79 |
-
# def query_brave(query):
|
80 |
-
# headers = {"X-API-Key": BRAVE_API_KEY}
|
81 |
-
# params = {
|
82 |
-
# "q": query,
|
83 |
-
# "count": 1,
|
84 |
-
# "summary": True
|
85 |
-
# }
|
86 |
-
# response = requests.get("https://api.search.brave.com/res/v1/web/search", params=params, headers=headers)
|
87 |
-
# if response.status_code == 200:
|
88 |
-
# return response.json().get("summary", "No summary available.")
|
89 |
-
# else:
|
90 |
-
# return f"Request failed with status code: {response}"
|
91 |
-
|
92 |
-
|
93 |
-
# def brave_search_summarization(query):
|
94 |
-
# # Endpoint for web search with summary
|
95 |
-
# web_search_url = "https://api.search.brave.com/res/v1/web/search"
|
96 |
-
# summarizer_url = "https://api.search.brave.com/res/v1/summarizer/search"
|
97 |
-
|
98 |
-
# # Headers for the requests
|
99 |
-
# headers = {
|
100 |
-
# "Accept": "application/json",
|
101 |
-
# "Accept-Encoding": "gzip",
|
102 |
-
# "X-Subscription-Token": BRAVE_API_KEY
|
103 |
-
# }
|
104 |
-
|
105 |
-
# # Parameters for the initial web search request
|
106 |
-
# web_search_params = {
|
107 |
-
# "q": query,
|
108 |
-
# "summary": 1
|
109 |
-
# }
|
110 |
-
|
111 |
-
# # Make the initial request to the web search endpoint
|
112 |
-
# web_search_response = requests.get(web_search_url, headers=headers, params=web_search_params)
|
113 |
-
|
114 |
-
# # Check if the request was successful
|
115 |
-
# if web_search_response.status_code != 200:
|
116 |
-
# raise Exception(f"Web search request failed with status code {web_search_response.status_code}")
|
117 |
-
|
118 |
-
# web_search_data = web_search_response.json()
|
119 |
-
|
120 |
-
# # Extract the summarizer key from the response
|
121 |
-
# summarizer_key = web_search_data.get('summarizer', {}).get('key')
|
122 |
-
# if not summarizer_key:
|
123 |
-
# raise Exception("No summarizer key found in the web search response")
|
124 |
-
|
125 |
-
# # Parameters for the summarizer request
|
126 |
-
# summarizer_params = {
|
127 |
-
# "key": summarizer_key,
|
128 |
-
# "entity_info": 1
|
129 |
-
# }
|
130 |
-
|
131 |
-
# # Make the request to the summarizer endpoint
|
132 |
-
# summarizer_response = requests.get(summarizer_url, headers=headers, params=summarizer_params)
|
133 |
-
|
134 |
-
# # Check if the request was successful
|
135 |
-
# if summarizer_response.status_code != 200:
|
136 |
-
# raise Exception(f"Summarizer request failed with status code {summarizer_response.status_code}")
|
137 |
-
|
138 |
-
# summarizer_data = summarizer_response.json()
|
139 |
-
|
140 |
-
# # Return the summarized content
|
141 |
-
# return summarizer_data
|
142 |
-
|
143 |
-
|
144 |
def ProcessQuestion(question, model):
|
145 |
if model == "You.com":
|
146 |
return query_you_com(question)
|
@@ -152,3 +87,21 @@ def ProcessQuestion(question, model):
|
|
152 |
return query_brave(question)
|
153 |
else:
|
154 |
return "Model not supported"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import requests
|
2 |
from dotenv import load_dotenv
|
3 |
+
from typing import Optional
|
4 |
import os
|
5 |
|
6 |
# Load environment variables from .env file
|
|
|
10 |
YOU_COM_API_KEY = os.getenv("YOU_API_KEY")
|
11 |
TAVILY_API_KEY = os.getenv("TAVILY_API_KEY")
|
12 |
PERPLEXITY_API_KEY = os.getenv("PPLX_API_KEY")
|
13 |
+
BRAVE_API_KEY = os.getenv("BRAVE_AI_API_KEY")
|
|
|
14 |
|
15 |
def query_you_com(query):
|
16 |
headers = {"X-API-Key": YOU_COM_API_KEY}
|
|
|
76 |
return f"Request failed with status code: {response.status_code}"
|
77 |
|
78 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
def ProcessQuestion(question, model):
|
80 |
if model == "You.com":
|
81 |
return query_you_com(question)
|
|
|
87 |
return query_brave(question)
|
88 |
else:
|
89 |
return "Model not supported"
|
90 |
+
|
91 |
+
|
92 |
+
from brave_ai import BraveAIWrapper
|
93 |
+
|
94 |
+
def query_brave(query: str) -> Optional[str]:
|
95 |
+
"""
|
96 |
+
Get a summary for the given query using BraveAIWrapper.
|
97 |
+
|
98 |
+
Args:
|
99 |
+
query (str): The search query.
|
100 |
+
api_key (str): The API key for Brave Search.
|
101 |
+
|
102 |
+
Returns:
|
103 |
+
Optional[str]: Summarized result or None if an error occurs.
|
104 |
+
"""
|
105 |
+
brave_ai = BraveAIWrapper(api_key=BRAVE_API_KEY)
|
106 |
+
summary = brave_ai.get_and_summarize(query)
|
107 |
+
return summary
|
provider_info.py
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
search_providers = [
|
2 |
+
{ "company_name": "You.com",
|
3 |
+
"website": "you.com",
|
4 |
+
"overview": "You.com is an AI-powered search engine and productivity tool that aims to provide users with more control, privacy, and customization over their online search experience. Founded in 2020 by Richard Socher, former Chief Scientist at Salesforce, and Bryan McCann, You.com has evolved from a privacy-focused search engine into an AI assistant that supports chat-based search.\n\nKey features of You.com include:\n\n- AI Modes: You.com offers different AI interaction modes tailored to user needs, such as Smart mode for quick tasks and summarization, Genius mode for complex queries requiring multi-step reasoning, and Research mode for in-depth analysis with extensive citations.\n\n- Multimodal search: Beyond text, You.com can generate AI art, data visualizations, and even run Python code to solve math and science questions. It was one of the first search engines to introduce multimodal AI chat capabilities.\n\n- Customization: Users can personalize their search experience by selecting preferred sources, adjusting AI model parameters, and leveraging You.com's developer platform to build custom apps and integrations.\n\n- Privacy: You.com does not track users or sell their personal data. It provides a more secure and private alternative to mainstream search engines.\n\n- Subscription model: While offering a free tier, You.com provides a premium subscription called YouPro that unlocks advanced AI features, unlimited access, and an ad-free experience.\n\nYou.com has gained significant traction, amassing millions of users and raising substantial funding from prominent investors like Salesforce CEO Marc Benioff. In 2023, the company raised $45 million at a $700-900 million valuation.\n\nUnder the leadership of Richard Socher, who was named to Time's TIME100 AI list in 2023, You.com aims to make information more accessible and enhance user productivity through cutting-edge AI technologies. Its unique blend of search and AI assistance capabilities positions You.com as a major player in the rapidly evolving search and productivity tools market.\n\nIn summary, You.com is a next-generation AI search assistant that combines the power of large language models with live web access to deliver highly relevant, contextual, and multimodal search results while prioritizing user privacy and customization. By making information discovery more intuitive and empowering, You.com is reshaping the future of search."
|
5 |
+
},
|
6 |
+
{ "company_name": "Tavily",
|
7 |
+
"website": "tavily.com",
|
8 |
+
"overview": "Tavily is an AI-powered search API and research platform designed specifically for large language models (LLMs) and AI agents. It aims to provide efficient, accurate, and factual search results to enhance the capabilities of AI applications.\n\nKey features of Tavily include:\n\n- Optimized for LLMs: Tavily's search API is tailored for AI agents and delivers real-time, relevant results to reduce hallucinations and bias in AI-generated content.\n\n- In-depth research: It simplifies data gathering by providing aggregated and curated results from multiple sources in a single API call. Tavily searches over 20+ sites per query and uses AI to score, filter, and rank the most relevant content.\n\n- Intelligent query suggestions: Tavily equips AI agents with the ability to iteratively deepen their knowledge through automated, nuanced answers and follow-up query suggestions.\n\n- Customization: The API offers customizable search depths, domain management, and HTML content parsing controls. It can be integrated with any LLM or used with partners like Langchain and LlamaIndex.\n\n- Versatility: Beyond fetching results, Tavily can answer questions, enable cross-agent communication, and complete comprehensive research tasks in seconds by leveraging proprietary data sources.\n\nTavily caters to a range of users, from new creators and researchers to solopreneurs, small teams, and enterprise-level needs. By automating the tedious aspects of online research like searching, scraping, filtering, and extracting relevant information, Tavily enables users to save time and make more informed decisions.\n\nIn summary, Tavily is a powerful AI search and research tool that connects LLMs and AI applications to trusted, real-time knowledge to enhance their performance and capabilities. It streamlines the research workflow and delivers comprehensive, accurate results to your inbox within minutes."
|
9 |
+
},
|
10 |
+
{"company_name": "Perplexity AI",
|
11 |
+
"website": "perplexity.ai",
|
12 |
+
"overview": "Perplexity AI is an AI-powered conversational search engine that provides accurate, concise answers to user queries by searching the web in real-time and leveraging advanced natural language processing capabilities. It aims to make information more accessible and understandable.\n\nKey features of Perplexity AI include:\n\n- Conversational interface: Users can engage with Perplexity AI using natural language, making information discovery as easy as having a conversation. It understands context and nuance to provide relevant answers.\n\n- Transparent sourcing: Perplexity AI cites the sources it uses to generate answers, enabling users to verify information and explore topics further. It aims to build trust through transparency.\n\n- Personalized results: The more a user interacts with Perplexity AI, the more it learns about their interests and preferences, allowing it to tailor future search results and recommendations.\n\n- Multi-model architecture: Perplexity AI utilizes multiple large language models, including GPT-4, Claude, and its own proprietary models, to process queries and generate human-like responses.\n\n- Versatility: Beyond answering questions, Perplexity AI can assist with a wide range of tasks such as writing, coding, analyzing data, and creative projects. It adapts to the user's needs.\n\n- Continuous learning: By indexing the web daily, Perplexity AI stays up-to-date with the latest information to provide relevant, timely answers.\n\nPerplexity AI caters to a broad user base, including researchers, writers, programmers, and curious individuals seeking to learn and explore. It has gained significant traction, amassing over 10 million monthly users as of early 2024.\n\nFounded in 2022 by a team with experience from Google, OpenAI, and other leading tech companies, Perplexity AI has raised over $165 million from prominent investors. Its mission is to democratize access to knowledge and empower people to learn in their own way.\n\nIn summary, Perplexity AI is a powerful AI search engine that combines advanced language understanding, real-time web indexing, and an intuitive conversational interface to deliver accurate, relevant answers and support a wide range of information needs. By making knowledge more accessible and engaging, it is transforming how people discover, learn, and create."
|
13 |
+
},
|
14 |
+
{"company_name": "Brave Search",
|
15 |
+
"website": "search.brave.com",
|
16 |
+
"overview": "Brave Search is a privacy-focused search engine that offers an AI API for developers to integrate search capabilities and generate summaries from search results. The API leverages Brave's own search index and AI models to provide relevant, accurate, and concise information.\n\nKey features of Brave Search's AI API include:\n\n- Two-step process: To use the API, developers first perform a search using the '/search' endpoint, which returns a list of relevant web pages. They can then pass the search results to the '/summarize' endpoint to generate a summary of the information.\n\n- Search quality: Brave Search maintains its own independent search index, ensuring that results are not influenced by biased algorithms or user tracking. The search functionality of the API delivers high-quality, relevant web pages for a given query.\n\n- Summarization: The '/summarize' endpoint uses advanced AI language models to analyze the content of the web pages returned by the search and generate a concise, coherent summary. This saves developers time and effort in extracting key information from search results.\n\n- Customization: Developers can fine-tune the search and summarization process by adjusting parameters such as the number of search results to consider, the length of the summary, and the focus of the summary (e.g., key facts, main ideas, or specific details).\n\n- Privacy: In line with Brave's commitment to privacy, the AI API does not track users or collect personal data. All searches and summarization requests are processed anonymously.\n\nBrave Search's AI API is suitable for a wide range of applications, such as content aggregation platforms, research tools, news summarization services, and chatbots. By providing access to Brave's search capabilities and AI-powered summarization, the API enables developers to create innovative, privacy-respecting applications that deliver valuable insights to users.\n\nThe API offers a free tier with limited requests and a paid tier for higher usage and additional features. Brave Search is committed to expanding the capabilities of its AI API and supporting developers in building next-generation search and language AI applications.\n\nIn summary, Brave Search's AI API combines the power of privacy-focused search with advanced AI summarization capabilities, allowing developers to integrate high-quality search results and concise summaries into their applications. By providing a two-step process of searching and summarizing, the API streamlines information retrieval and synthesis, while prioritizing user privacy."
|
17 |
+
}
|
18 |
+
]
|
requirements.txt
CHANGED
@@ -1,6 +1,92 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
aiohttp==3.9.5
|
2 |
+
altair==5.3.0
|
3 |
+
anyio==4.4.0
|
4 |
+
attrs==23.2.0
|
5 |
+
beautifulsoup4==4.12.3
|
6 |
+
blinker==1.8.2
|
7 |
+
cachetools==5.3.2
|
8 |
+
certifi==2024.6.2
|
9 |
+
charset-normalizer==3.3.2
|
10 |
+
click==8.1.7
|
11 |
+
dataclasses-json==0.6.7
|
12 |
+
dnspython==2.6.1
|
13 |
+
email_validator==2.1.2
|
14 |
+
fastapi==0.111.0
|
15 |
+
filelock==3.15.1
|
16 |
+
frozenlist==1.4.1
|
17 |
+
fsspec==2024.6.0
|
18 |
+
gitdb==4.0.11
|
19 |
+
GitPython==3.1.43
|
20 |
+
google-api-core==2.15.0
|
21 |
+
google-auth==2.26.2
|
22 |
+
google-cloud-aiplatform==1.39.0
|
23 |
+
google-cloud-bigquery==3.16.0
|
24 |
+
google-cloud-core==2.4.1
|
25 |
+
google-cloud-resource-manager==1.11.0
|
26 |
+
google-cloud-storage==2.14.0
|
27 |
+
google-crc32c==1.5.0
|
28 |
+
google-resumable-media==2.7.0
|
29 |
+
googleapis-common-protos==1.62.0
|
30 |
+
grpc-google-iam-v1==0.13.0
|
31 |
+
grpcio-status==1.60.0
|
32 |
+
h11==0.14.0
|
33 |
+
httpcore==1.0.5
|
34 |
+
httptools==0.6.1
|
35 |
+
httpx==0.27.0
|
36 |
+
huggingface-hub==0.23.4
|
37 |
+
idna==3.7
|
38 |
+
Jinja2==3.1.4
|
39 |
+
jsonpatch==1.33
|
40 |
+
jsonpointer==3.0.0
|
41 |
+
jsonschema==4.22.0
|
42 |
+
langchain==0.1.13
|
43 |
+
loguru==0.7.2
|
44 |
+
markdown-it-py==3.0.0
|
45 |
+
markdownify==0.12.1
|
46 |
+
MarkupSafe==2.1.5
|
47 |
+
marshmallow==3.21.3
|
48 |
+
multidict==6.0.5
|
49 |
+
networkx==3.3
|
50 |
+
numpy==1.26.4
|
51 |
+
openai==1.34.0
|
52 |
+
orjson==3.10.5
|
53 |
+
packaging==23.2
|
54 |
+
pandas==2.2.2
|
55 |
+
pillow==10.3.0
|
56 |
+
proto-plus==1.23.0
|
57 |
+
protobuf==4.25.3
|
58 |
+
pymongo==4.7.3
|
59 |
+
pypdf==4.1.0
|
60 |
+
python-dotenv==1.0.1
|
61 |
+
pytz==2024.1
|
62 |
+
PyYAML==6.0.1
|
63 |
+
ratelimit==2.2.1
|
64 |
+
referencing==0.35.1
|
65 |
+
requests==2.32.3
|
66 |
+
rich==13.7.1
|
67 |
+
rsa==4.9
|
68 |
+
safetensors==0.4.3
|
69 |
+
sentry-sdk==2.5.1
|
70 |
+
shapely==2.0.2
|
71 |
+
six==1.16.0
|
72 |
+
sniffio==1.3.1
|
73 |
+
soupsieve==2.5
|
74 |
+
SQLAlchemy==2.0.30
|
75 |
+
starlette==0.37.2
|
76 |
+
streamlit==1.35.0
|
77 |
+
sympy==1.12.1
|
78 |
+
tenacity==8.3.0
|
79 |
+
termcolor==2.4.0
|
80 |
+
tqdm==4.66.4
|
81 |
+
transformers==4.41.2
|
82 |
+
typer==0.12.3
|
83 |
+
typing-inspect==0.9.0
|
84 |
+
typing_extensions==4.8.0
|
85 |
+
tzdata==2024.1
|
86 |
+
ujson==5.10.0
|
87 |
+
urllib3==2.2.1
|
88 |
+
uvicorn==0.30.1
|
89 |
+
uvloop==0.19.0
|
90 |
+
watchfiles==0.22.0
|
91 |
+
websockets==12.0
|
92 |
+
yarl==1.9.4
|
test_func.py
CHANGED
@@ -24,7 +24,43 @@ def test_queries():
|
|
24 |
# print("\nTesting Brave.com API:")
|
25 |
# brave_result = brave_search_summarization(test_query)
|
26 |
# print(brave_result)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
|
28 |
|
29 |
if __name__ == "__main__":
|
30 |
test_queries()
|
|
|
|
24 |
# print("\nTesting Brave.com API:")
|
25 |
# brave_result = brave_search_summarization(test_query)
|
26 |
# print(brave_result)
|
27 |
+
|
28 |
+
def test_brave_ai_wrapper():
|
29 |
+
# Initialize the BraveAIWrapper with your API key
|
30 |
+
api_key = "your_api_key_here"
|
31 |
+
brave_ai = BraveAIWrapper(api_key=api_key)
|
32 |
+
|
33 |
+
# Define the test query
|
34 |
+
query = "What is some of the best mountain biking near Crested Butte, CO?"
|
35 |
+
|
36 |
+
# Test get_brave_results
|
37 |
+
print("Testing get_brave_results...")
|
38 |
+
results = brave_ai.get_brave_results(query)
|
39 |
+
if results:
|
40 |
+
print("get_brave_results output:", json.dumps(results, indent=2))
|
41 |
+
else:
|
42 |
+
print("get_brave_results failed.")
|
43 |
+
|
44 |
+
# Test get_and_summarize
|
45 |
+
print("\nTesting get_and_summarize...")
|
46 |
+
summary = brave_ai.get_and_summarize(query)
|
47 |
+
if summary:
|
48 |
+
print("get_and_summarize output:", summary)
|
49 |
+
else:
|
50 |
+
print("get_and_summarize failed.")
|
51 |
+
|
52 |
+
# Test download_documents
|
53 |
+
print("\nTesting download_documents...")
|
54 |
+
documents = brave_ai.download_documents(query)
|
55 |
+
if documents:
|
56 |
+
for doc in documents:
|
57 |
+
print("Document metadata:", doc.metadata)
|
58 |
+
print("Document content:", doc.page_content[:200]) # Print first 200 characters
|
59 |
+
print("-" * 40)
|
60 |
+
else:
|
61 |
+
print("download_documents failed.")
|
62 |
|
63 |
|
64 |
if __name__ == "__main__":
|
65 |
test_queries()
|
66 |
+
test_brave_ai_wrapper()
|