leonsimon23 commited on
Commit
ae85139
·
verified ·
1 Parent(s): 42ec003

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +129 -0
app.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests
3
+ import google.generativeai as genai
4
+ import logging
5
+ from fastapi import FastAPI, HTTPException
6
+ from fastapi.middleware.cors import CORSMiddleware
7
+ from pydantic import BaseModel
8
+ from typing import List
9
+
10
+ # --- 配置 ---
11
+ logging.basicConfig(level=logging.INFO)
12
+ logger = logging.getLogger(__name__)
13
+
14
+ # 从环境变量获取 API 密钥和后端 URL
15
+ GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
16
+ SEARCH_API_BASE_URL = os.getenv("SEARCH_API_BASE_URL")
17
+
18
+ # 配置 Google Gemini
19
+ genai.configure(api_key=GEMINI_API_KEY)
20
+ # 使用最新的 Flash 模型,性价比高
21
+ gemini_model = genai.GenerativeModel('gemini-2.5-flash')
22
+
23
+ # --- FastAPI 应用设置 ---
24
+ app = FastAPI(
25
+ title="AI Search Agent",
26
+ description="一个使用 Gemini-2.5-Flash 将自然语言转换为学术搜索查询的智能中间层。",
27
+ version="1.0.0"
28
+ )
29
+
30
+ # 配置 CORS,允许您的前端 Space 访问
31
+ # TODO: 为了安全,您应该将 "*" 替换为您的前端 Space 的 URL
32
+ app.add_middleware(
33
+ CORSMiddleware,
34
+ allow_origins=["*"], # 允许所有来源
35
+ allow_credentials=True,
36
+ allow_methods=["*"],
37
+ allow_headers=["*"],
38
+ )
39
+
40
+ # --- 数据模型 ---
41
+ class SearchRequest(BaseModel):
42
+ platform: str
43
+ query: str
44
+ max_results: int = 10
45
+
46
+ # --- 核心 AI 功能 ---
47
+ async def get_ai_keywords(natural_language_query: str) -> str:
48
+ """
49
+ 使用 Gemini 将自然语言查询转换为优化的布尔逻辑搜索关键词。
50
+ """
51
+ if not GEMINI_API_KEY:
52
+ logger.warning("GEMINI_API_KEY 未设置,将使用原始查询。")
53
+ return natural_language_query
54
+
55
+ # 精心设计的 Prompt
56
+ prompt = f"""
57
+ You are an expert academic researcher. Your task is to convert a user's natural language query into a highly effective, concise, boolean-logic keyword string for searching academic databases like PubMed.
58
+ - Use boolean operators like AND, OR.
59
+ - Use parentheses for grouping.
60
+ - Focus on core concepts.
61
+ - Keep the string concise and in English.
62
+ - Do not add any explanation, markdown, or quotation marks. Just return the pure keyword string.
63
+
64
+ User Query: "{natural_language_query}"
65
+ Keyword String:
66
+ """
67
+
68
+ try:
69
+ logger.info(f"向 Gemini 发送请求,查询: '{natural_language_query}'")
70
+ response = await gemini_model.generate_content_async(prompt)
71
+ optimized_query = response.text.strip()
72
+
73
+ logger.info(f"原始查询: '{natural_language_query}' -> Gemini 优化关键词: '{optimized_query}'")
74
+
75
+ # 如果AI返回空,则回退到原始查询
76
+ if not optimized_query:
77
+ logger.warning("Gemini 返回空结果,回退到原始查询。")
78
+ return natural_language_query
79
+
80
+ return optimized_query
81
+ except Exception as e:
82
+ logger.error(f"调用 Gemini API 失败: {e}")
83
+ # 如果AI调用失败,就回退到使用原始查询
84
+ return natural_language_query
85
+
86
+ # --- API 端点 ---
87
+ @app.get("/")
88
+ def read_root():
89
+ return {"status": "AI Search Agent is running"}
90
+
91
+ @app.post("/search")
92
+ async def intelligent_search(request: SearchRequest):
93
+ """
94
+ 接收前端请求,进行 AI 优化,然后代理到搜索后端。
95
+ """
96
+ if not SEARCH_API_BASE_URL:
97
+ raise HTTPException(status_code=500, detail="SEARCH_API_BASE_URL 未配置")
98
+
99
+ # 1. 使用 Gemini 优化查询
100
+ optimized_query = await get_ai_keywords(request.query)
101
+
102
+ # 2. 准备发往 `paper-mcp-agent` 的请求体
103
+ search_payload = {
104
+ "platform": request.platform,
105
+ "query": optimized_query, # 使用优化后的查询
106
+ "max_results": request.max_results
107
+ }
108
+
109
+ # 3. 调用 `paper-mcp-agent` 搜索后端
110
+ try:
111
+ logger.info(f"向搜索后端发送请求: {search_payload}")
112
+ search_url = f"{SEARCH_API_BASE_URL}/search"
113
+ response = requests.post(search_url, json=search_payload, timeout=30)
114
+ response.raise_for_status() # 如果状态码不是 2xx,则抛出异常
115
+
116
+ search_results = response.json()
117
+
118
+ # 在最终结果中包含原始查询和优化后的查询,便于调试
119
+ search_results['original_query'] = request.query
120
+ search_results['optimized_query'] = optimized_query
121
+
122
+ return search_results
123
+
124
+ except requests.exceptions.RequestException as e:
125
+ logger.error(f"调用搜索后端失败: {e}")
126
+ raise HTTPException(status_code=503, detail=f"无法连接到搜索服务: {str(e)}")
127
+ except Exception as e:
128
+ logger.error(f"处理搜索时发生未知错误: {e}")
129
+ raise HTTPException(status_code=500, detail=f"内部服务器错误: {str(e)}")