项目文件夹

文件
2024-10-26 02:31:58 +08:00

233 行
8.0 KiB
Python

# This file contains the utility function for performing searches online.
import os
import requests
from dotenv import load_dotenv
from newspaper import Article
from tqdm import tqdm
def parse_url_with_newspaper(url: str) -> str:
"""
This function parses the content of a URL using the newspaper library.
:param url: the URL to parse
:return: the content of the URL, main body only.
"""
article = Article(url)
article.download()
article.parse()
return article.text
def google_search_keyword(keyword: str, top_n=2) -> list:
"""
This function performs a Google search using the Google search API.
:param keyword: the keyword to search
:return: a list of search results in the format of [(title, link), (title, link), ...]
return [(None, None)] if no search results are found
"""
load_dotenv()
google_search_key = os.getenv("google_search_key")
google_search_cx = os.getenv("google_search_cx")
# perform the search
# example query: GET https://www.googleapis.com/customsearch/v1?key=INSERT_YOUR_API_KEY&cx=017576662512468239146:omuauf_lfve&q=lectures
url = f"https://www.googleapis.com/customsearch/v1?key={google_search_key}&cx={google_search_cx}&q={keyword}"
response = requests.get(url).json()
# get the top n search results on the current page
try:
search_results = response["items"][0:top_n]
except KeyError: # if no search results are found or the API is out of quota
return [(None, None)]
# return the search results
return [(result["title"], result["link"]) for result in search_results]
def google_search_keyword_openserp(keyword: str, top_n=1) -> list:
"""
This function performs a Google search via openserp.
:param keyword: the keyword to search
:return: a list of search results in the format of [(title, link), (title, link), ...]
return [(None, None)] if no search results are found
"""
# maintain a blacklist of websites that should not be included in the search results
blacklist = ["medium.com", "github.com"]
# example query: GET http://127.0.0.1:7001/google/search?lang=EN&limit=20&text=hello%20world
url = f"http://127.0.0.1:7001/google/search?lang=EN&limit=10&text={keyword}"
try:
response = requests.get(url, timeout=30).json() # add timeout of 30 seconds
except Exception as e:
print(f"Online Search Request failed: {e};")
return [(None, None)]
# get the top n search results on the current page
search_result = []
i = 0
while len(search_result) < top_n and i < len(response):
try:
# if any elements in the blacklist are in the link, skip the link
if any([item in response[i]["url"] for item in blacklist]):
i += 1
continue
search_results = response[i]
search_result.append((search_results["title"], search_results["url"]))
except Exception as e:
print(f"Error: {e}")
finally:
i += 1
return search_result
def crawl_search(search_results: list) -> list:
"""
This function crawls the search results into a JSON string as RAG.
:param search_results: the search results returned by `search_online`
the search result should be in the format of [(title, link), (title, link), ...]
the search result should be as [None, None] if no search results are found
:return: a list of strings as RAG
"""
rag = []
for title, link in search_results:
# each website info is in the format of {title: "title", link: "link", content: "content"}
if title is None or link is None:
continue
# try with Jina API read first, then fallback to newspaper, then return failed
try:
main_content = jina_read(link)
if main_content is False:
main_content = parse_url_with_newspaper(link)
rag.append({"title": title, "link": link, "content": main_content})
except Exception as e:
print(f"Request failed on {link}: {e}")
rag.append(
{"title": title, "link": link, "content": "Failed to retrieve content"}
)
continue
return rag
def check_search_connection(backend="google"):
"""
This function checks if the search backend is available.
:param backend: the backend to use for searching.
Default is "openserp".
Availables are "google" and "openserp"
"""
if backend == "google":
# perform a sample search
try:
response = google_search_keyword("test")
return response != [(None, None)]
except Exception: # any exception can be handled as False
return False
return False
elif backend == "openserp":
# perform a get request to localhost:7001
try:
response = requests.get(
"http://localhost:7001/google/search?text=test", timeout=30
) ## add timeout of 30 seconds
return response.status_code == 200
except Exception: # any exception can be handled as False
return False
else:
return False
def search_as_RAG(list_of_keywords: list, backend="google") -> list:
"""
This function searches the list of keywords and returns the search results as RAG.
:param list_of_keywords: a list of keywords to search
:param backend: the backend to use for searching.
Default is "openserp".
Availables are "google" and "openserp"
"""
rag = []
for keyword in tqdm(list_of_keywords):
if backend == "google":
search_results = google_search_keyword(keyword)
elif backend == "openserp":
search_results = google_search_keyword_openserp(keyword)
else:
search_results = google_search_keyword_openserp(keyword)
rag.extend(crawl_search(search_results))
return rag
def jina_read(url: str) -> str:
"""
This function reads the content of a URL using the Jina API.
:param url: the URL to read
return
string format of the URL content
"""
JINA_API_KEY = os.getenv("JINA_API_KEY")
base_url = "https://r.jina.ai"
headers = {
"Authorization": f"Bearer {JINA_API_KEY}",
}
url = f"{base_url}/{url}"
# make the query
try:
response = requests.get(url, headers=headers)
if response.status_code == 200:
return response.text
else:
return False
except Exception as e:
return False
def jina_search(text: str) -> str:
"""
This function performs a search using the Jina API.
:param url: the URL to search
return
string format of the search result
"""
JINA_API_KEY = os.getenv("JINA_API_KEY")
base_url = "https://s.jina.ai"
headers = {
"Authorization": f"Bearer {JINA_API_KEY}",
}
url = f"{base_url}/{text}"
# make the query
try:
response = requests.get(url, headers=headers)
if response.status_code == 200:
return response.text
else:
return False
except Exception as e:
return False
if __name__ == "__main__":
print(jina_search("Common Vulnerabilities in Uniswap V3."))
# pre-check: check connection
connection_status = check_search_connection()
print("Connection Status:", connection_status)
if connection_status:
# test 1: search with openserp
result = google_search_keyword_openserp("AAVE Security Considerations")
print(result)
# test 2: crawl information with openserp
rag = search_as_RAG(
["AAVE Security Considerations", "ERC721 Security Considerations"]
)
print(rag)
for item in rag:
print(item["title"], item["link"])
else:
print("Search Backend is not available.")
# use the Google API search
rag = search_as_RAG(
["AAVE Security Considerations", "ERC721 Security Considerations"],
backend="google",
)
print(rag)