import gradio as gr import json from typing import Dict, List, Any import requests class SearchUI: def __init__(self): self.api_key = "8af097ae8b587bb0569425058e03e5ef33b4c7b8b1a505053764b62e7e4ab9d6" def parse_google_results(self, results: Dict) -> List[Dict]: """解析Google搜索结果""" parsed = [] if 'organic_results' in results: for result in results['organic_results']: parsed.append({ 'title': result.get('title', ''), 'link': result.get('link', ''), 'snippet': result.get('snippet', ''), 'position': result.get('position', 0) }) if 'answer_box' in results: answer = results['answer_box'] parsed.append({ 'title': '直接回答:', 'link': answer.get('link', ''), 'snippet': answer.get('answer', ''), 'position': 0 }) return parsed def parse_bing_results(self, results: Dict) -> List[Dict]: """解析Bing搜索结果""" parsed = [] if 'organic_results' in results: for result in results['organic_results']: parsed.append({ 'title': result.get('title', ''), 'link': result.get('link', ''), 'snippet': result.get('snippet', ''), 'position': result.get('position', 0) }) return parsed def parse_baidu_results(self, results: Dict) -> List[Dict]: """解析百度搜索结果""" parsed = [] if 'organic_results' in results: for result in results['organic_results']: parsed.append({ 'title': result.get('title', ''), 'link': result.get('link', ''), 'snippet': result.get('snippet', ''), 'position': result.get('position', 0) }) if 'answer_box' in results: for answer in results['answer_box']: parsed.append({ 'title': '直接回答:', 'link': answer.get('link', ''), 'snippet': f"{answer.get('answer', '')}\n来源: {answer.get('source', '')}", 'position': 0 }) return parsed def format_results(self, results: List[Dict], engine: str) -> str: """将解析后的结果格式化为HTML卡片""" formatted = "" for result in sorted(results, key=lambda x: x['position']): formatted += f"""
{result['title']}
{result['snippet']}
""" return f'
{formatted}
' def search_all_engines(self, query: str) -> tuple: """在所有搜索引擎中执行搜索并返回格式化结果""" try: results = {} for engine in ["google", "bing", "baidu"]: params = { "api_key": self.api_key, "engine": engine, "q": query } if engine == "google": params.update({"gl": "cn", "hl": "zh-cn"}) response = requests.get('https://serpapi.com/search', params=params) if response.status_code == 200: results[engine] = response.json() else: return f"{engine}搜索出错: HTTP {response.status_code}", "", "" google_parsed = self.parse_google_results(results['google']) google_text = self.format_results(google_parsed, "google") bing_parsed = self.parse_bing_results(results['bing']) bing_text = self.format_results(bing_parsed, "bing") baidu_parsed = self.parse_baidu_results(results['baidu']) baidu_text = self.format_results(baidu_parsed, "baidu") return google_text, bing_text, baidu_text except Exception as e: return f"搜索出错: {str(e)}", f"搜索出错: {str(e)}", f"搜索出错: {str(e)}" def create_ui(): search_ui = SearchUI() custom_css = """ /* 全局样式 */ .container { max-width: 1400px; margin: 0 auto; } /* 搜索引擎区域样式 */ .google-container, .bing-container, .baidu-container { background: white; border-radius: 15px; padding: 15px; height: calc(100vh - 200px); overflow-y: auto; scrollbar-width: thin; } .google-container { border: 2px solid rgba(66, 133, 244, 0.3); } .bing-container { border: 2px solid rgba(0, 169, 157, 0.3); } .baidu-container { border: 2px solid rgba(45, 97, 255, 0.3); } /* 结果卡片样式 */ .result-card { background: white; border-radius: 10px; padding: 15px; margin: 10px 0; box-shadow: 0 2px 4px rgba(0,0,0,0.1); transition: all 0.3s ease; cursor: pointer; overflow: hidden; word-wrap: break-word; } .result-card:hover { transform: translateY(-3px); box-shadow: 0 4px 8px rgba(0,0,0,0.15); } .card-title { font-size: 1.1em; font-weight: bold; color: #1a0dab; margin-bottom: 5px; line-height: 1.4; } .card-link { color: #006621; font-size: 0.9em; margin-bottom: 8px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .card-snippet { color: #545454; font-size: 0.95em; line-height: 1.5; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; } /* 滚动条样式 */ .google-container::-webkit-scrollbar, .bing-container::-webkit-scrollbar, .baidu-container::-webkit-scrollbar { width: 6px; } .google-container::-webkit-scrollbar-thumb { background: rgba(66, 133, 244, 0.3); } .bing-container::-webkit-scrollbar-thumb { background: rgba(0, 169, 157, 0.3); } .baidu-container::-webkit-scrollbar-thumb { background: rgba(45, 97, 255, 0.3); } .google-container::-webkit-scrollbar-track, .bing-container::-webkit-scrollbar-track, .baidu-container::-webkit-scrollbar-track { background: rgba(0, 0, 0, 0.05); } """ with gr.Blocks(title="九鑫多搜索引擎聚合搜索", theme=gr.themes.Soft(), css=custom_css) as demo: gr.Markdown("## 🔍 九鑫多搜索引擎聚合搜索") with gr.Row(): query_input = gr.Textbox( label="搜索关键词", placeholder="请输入要搜索的内容...", lines=1 ) search_button = gr.Button("搜索", variant="primary", scale=0.2) loading_indicator = gr.HTML( """
loading...

正在搜索中...

""", visible=False ) with gr.Row(): with gr.Column(scale=1): gr.Markdown("### 🔵 Google 搜索结果") google_output = gr.HTML(container=False) with gr.Column(scale=1): gr.Markdown("### 🟢 Bing 搜索结果") bing_output = gr.HTML(container=False) with gr.Column(scale=1): gr.Markdown("### 🔷 百度搜索结果") baidu_output = gr.HTML(container=False) def on_search(query): return [True, "", "", ""] def after_search(query): google, bing, baidu = search_ui.search_all_engines(query) return [False, google, bing, baidu] search_button.click( fn=on_search, inputs=[query_input], outputs=[loading_indicator, google_output, bing_output, baidu_output], ).then( fn=after_search, inputs=[query_input], outputs=[loading_indicator, google_output, bing_output, baidu_output], show_progress="minimal" ) return demo if __name__ == "__main__": demo = create_ui() demo.launch(share=True, server_name="0.0.0.0", server_port=10083)