gsearch_chat / app.py
fudii0921's picture
Update app.py
ab736d9 verified
import gradio as gr
import requests
import groq
import os
from dotenv import load_dotenv
import urllib.parse
import re
from sumy.parsers.html import HtmlParser
from sumy.nlp.tokenizers import Tokenizer
from sumy.summarizers.lsa import LsaSummarizer
load_dotenv(verbose=True)
# APIキーと検索エンジンID
API_KEY = os.environ["API_KEY"]
SEARCH_ENGINE_ID = os.environ["SEARCH_ENGINE_ID"]
search_active = True # 検索処理の状態を管理するフラグ
html = """
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>プリンス オブ ペルシャ 失われた王冠 - 検索結果</title>
<style>
body {
font-family: 'Arial', sans-serif;
line-height: 1.6;
background-color: #f4f4f4;
color: #333;
margin: 0;
padding: 0;
}
.container {
max-width: 800px;
margin: 40px auto;
padding: 20px;
}
.result-card {
background: white;
padding: 15px;
margin-bottom: 15px;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.result-card a {
color: #007bff;
text-decoration: none;
font-weight: bold;
}
.result-card a:hover {
text-decoration: underline;
}
h1 {
text-align: center;
color: #444;
}
</style>
</head>
<body>
<div class="container">
<h1>タイトル - 検索結果</h1>
<div class="result-card">
<a href="https://www.ubisoft.com/ja-jp/game/prince-of-persia/the-lost-crown">プリンス オブ ペルシャ 失われた王冠 | Ubisoft (JP)</a>
</div>
</div>
</body>
</html>
"""
def generate_prompt(keyword: str):
client = groq.Client(api_key=os.environ.get("GROQ_API_KEY"))
completion = client.chat.completions.create(
model="llama3-70b-8192",
messages=[
{"role": "system", "content": "貴方は優秀なプロンプト・エンジニアです。"},
{"role": "user", "content": keyword+"に答えてください。合わせて、主語を含むプロンプトも5つ生成してください。 必ず、日本語で答えてください。"}
],
)
return completion.choices[0].message.content
def stop_search():
global search_active
search_active = False
return "検索が停止されました。"
def update_prompt(search_text):
return search_text
def summarize_webpage(url):
try:
parser = HtmlParser.from_url(url, Tokenizer("japanese"))
summarizer = LsaSummarizer()
summary = summarizer(parser.document, 5) # 5文で要約
return "\n".join(str(sentence) for sentence in summary)
except Exception as e:
return f"エラー: {str(e)}"
# Google Custom Search API を利用して検索する関数
def google_search(query):
global search_active
search_active = True # 検索開始時にフラグを True にする
yield "" # 初期表示を空にする
if not search_active:
yield "" # 処理中メッセージを空にする
return
yield "<div>処理中...</div>"
if (len(query) == 0):
errmsg = '''
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>エラー - キーワード未入力</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f8d7da;
color: #721c24;
text-align: center;
padding: 50px;
}
.error-container {
max-width: 500px;
margin: auto;
background-color: #ffffff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
border: 2px solid #dc3545;
}
.error-icon {
font-size: 50px;
color: #dc3545;
}
h1 {
margin: 10px 0;
}
p {
font-size: 18px;
}
.btn {
display: inline-block;
padding: 10px 20px;
background-color: #dc3545;
color: #fff;
text-decoration: none;
font-size: 16px;
border-radius: 5px;
margin-top: 15px;
}
.btn:hover {
background-color: #c82333;
}
</style>
</head>
<body>
<div class="error-container">
<div class="error-icon">⚠️</div>
<h1>エラー</h1>
<p>キーワードが入力されていません。</p>
</div>
</body>
</html>
'''
yield errmsg
else:
url = f"https://www.googleapis.com/customsearch/v1?q={query}&key={API_KEY}&cx={SEARCH_ENGINE_ID}&sort=date"
response = requests.get(url)
if response.status_code == 200:
data = response.json()
#print("respdata:",data)
results = []
for item in data.get("items", []):
title = item.get("title", "No Title")
link = item.get("link", "No Link")
snippet = item.get("htmlSnippet", "No Snippet")
contents = title + "\n" + snippet
results.append(f"{contents}: {link}")
# URLデコードを適用
decoded_urls = [urllib.parse.unquote(url) for url in results]
decoded ="\n".join(decoded_urls)
# 正規表現を使ってタイトルとURLを抽出
matches = re.findall(r'(.+?):\s*(https?://[^\s]+)', decoded)
# 結果を表示
finale = ""
for title, url in matches:
smry = summarize_webpage(url)
finale = finale+f'<div style="background:white;padding:15px;margin-bottom:15px;border-radius:8px;box-shadow:02px5pxrgba(0,0,0,0.1);"><a style="color: #007bff; text-decoration: none; font-weight: bold;" href="{url}" target="_blank" rel="noopener">{title}</a><br />{smry}</div>\n'
generated = f"""<!DOCTYPE html><html lang="ja"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>{query} - 検結果</title></head><body><div style="max-width: 800px; margin: 40px auto; padding: 20px;"><h1>{query} - 検索結果</h1><ul><li style="background:ghostwhite;border-radius:8px;box-shadow:0 2px 5px rgba(0, 0, 0, 0.1);">{finale}</li></ul></div></body></html>"""
yield generated
else:
yield f"検索に失敗しました: {response.status_code}"
with gr.Blocks(css="footer {visibility: hidden;} #custom_button {width: 400px; margin: 0 auto; background-color: #E0E7FF;}", theme=gr.themes.Soft(), title="Google カスタム検索エージェント") as agent:
gr.HTML('''<div style="display: flex; justify-content: center; align-items: center; font-size: 20px; font-weight: bold; font-family: 'Noto Sans JP', 'Yu Gothic', 'ヒラギノ角ゴシック', 'メイリオ', sans-serif;">Google カスタム検索エージェント</div>''')
with gr.Column():
search_input = gr.Textbox(label="検索キーワードを入力",info="例)著名投資家ウォーレン・バフェット氏が米投資会社バークシャー・ハザウェイの最高経営責任者(CEO)から退く",placeholder="検索するキーワードを入力します。")
search_output = gr.HTML(label="検索結果")
search_btn = gr.Button("検索",elem_id="custom_button")
search_btn.click(google_search, inputs=search_input, outputs=search_output)
stop_output = gr.Textbox(label="ステータス")
stop_btn = gr.Button("停止",elem_id="custom_button")
stop_btn.click(stop_search, inputs=None, outputs=stop_output)
with gr.Column():
prompt_input = gr.Textbox(
label="検索キーワードを入力",
info="例)著名投資家ウォーレン・バフェット氏が米投資会社バークシャー・ハザウェイの最高経営責任者(CEO)から退く",
placeholder="検索するキーワードを入力します。",
)
prompt_output = gr.Textbox(label="推薦プロンプト")
prompt_btn = gr.Button("推薦プロンプト",elem_id="custom_button")
prompt_btn.click(generate_prompt, inputs=prompt_input, outputs=prompt_output)
# search_input の変更を監視し、prompt_input に反映
search_input.change(update_prompt, inputs=search_input, outputs=prompt_input)
agent.launch(favicon_path='favicon.ico')