Update app.py
Browse files
app.py
CHANGED
|
@@ -1,47 +1,23 @@
|
|
| 1 |
import os
|
| 2 |
import asyncio
|
| 3 |
import time
|
| 4 |
-
from typing import Optional
|
| 5 |
-
from datetime import datetime
|
| 6 |
import httpx
|
| 7 |
import trafilatura
|
| 8 |
import gradio as gr
|
| 9 |
from dateutil import parser as dateparser
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
from fastapi import FastAPI
|
| 11 |
from pydantic import BaseModel
|
| 12 |
-
import google.generativeai as genai
|
| 13 |
-
|
| 14 |
-
# <<< NEW: Dono research modes ke liye alag prompts >>>
|
| 15 |
-
PROMPT_NORMAL = """
|
| 16 |
-
Based on the user's original query, provide a concise summary (3-4 important bullet points) of the following text. Focus only on the most critical information.
|
| 17 |
-
|
| 18 |
-
USER'S QUERY: "{query}"
|
| 19 |
-
|
| 20 |
-
TEXT TO SUMMARIZE:
|
| 21 |
-
---
|
| 22 |
-
{context_text}
|
| 23 |
-
---
|
| 24 |
-
"""
|
| 25 |
-
|
| 26 |
-
PROMPT_DEEP = """
|
| 27 |
-
As a meticulous research analyst, your task is to synthesize the information from the provided web search results into a detailed and comprehensive report.
|
| 28 |
-
**Current Date:** {current_date}.
|
| 29 |
-
**VERY IMPORTANT:** Your top priority is to provide information relevant to this current date and the future. If the user's query is about a recurring event (like an exam), you MUST focus on the upcoming or current event.
|
| 30 |
-
**User's Original Query:** "{query}"
|
| 31 |
-
**Instructions:**
|
| 32 |
-
1. Combine information from different sources to create a coherent and detailed report.
|
| 33 |
-
2. Cite source URLs inline, like this: "(Source: http://...)." The URL is provided in the text.
|
| 34 |
-
3. At the end of your report, create a "## Sources" section and list all the unique URLs you used.
|
| 35 |
-
4. Use clear markdown with headings and bold text.
|
| 36 |
-
|
| 37 |
-
**Provided Search Results:**
|
| 38 |
-
---
|
| 39 |
-
{context_text}
|
| 40 |
-
---
|
| 41 |
-
"""
|
| 42 |
|
| 43 |
# --- Core Search Logic (No Changes) ---
|
| 44 |
async def search_web_logic(query: str, serper_api_key: str, search_type: str, num_results: int) -> str:
|
|
|
|
| 45 |
start_time = time.time()
|
| 46 |
if not serper_api_key: return "Error: Serper API Key is required."
|
| 47 |
num_results = max(1, min(20, num_results))
|
|
@@ -70,104 +46,73 @@ async def search_web_logic(query: str, serper_api_key: str, search_type: str, nu
|
|
| 70 |
chunks.append(chunk)
|
| 71 |
if not chunks: return "Found results, but couldn't extract content."
|
| 72 |
summary = f"Successfully extracted content from {successful_extractions}/{len(results)} results.\n\n---\n\n"
|
| 73 |
-
|
| 74 |
return summary + "\n---\n".join(chunks)
|
| 75 |
except Exception as e:
|
| 76 |
return f"An error occurred during web search: {str(e)}"
|
| 77 |
|
| 78 |
-
#
|
| 79 |
-
async def summarize_with_gemini(text_to_summarize: str, query: str, gemini_key: str, model_name: str
|
| 80 |
try:
|
| 81 |
genai.configure(api_key=gemini_key)
|
| 82 |
model = genai.GenerativeModel(model_name)
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
|
| 93 |
response = await model.generate_content_async(prompt)
|
| 94 |
return response.text
|
| 95 |
except Exception as e:
|
| 96 |
return f"\n\n--- ⚠️ Gemini Summarization Failed ---\nError: {str(e)}\nReturning raw text instead."
|
| 97 |
|
| 98 |
-
# --- Main Orchestrator Function ---
|
| 99 |
-
async def search_and_summarize(query, serper_api_key, search_type, num_results, gemini_api_key, gemini_model, research_mode):
|
| 100 |
-
scraped_text = await search_web_logic(query, serper_api_key, search_type, num_results)
|
| 101 |
-
|
| 102 |
-
if gemini_api_key and "Error:" not in scraped_text:
|
| 103 |
-
summarized_text = await summarize_with_gemini(scraped_text, query, gemini_api_key, gemini_model, research_mode)
|
| 104 |
-
if "⚠️ Gemini Summarization Failed" in summarized_text:
|
| 105 |
-
return scraped_text + summarized_text
|
| 106 |
-
else:
|
| 107 |
-
return summarized_text
|
| 108 |
-
return scraped_text
|
| 109 |
-
|
| 110 |
# --- FastAPI App ---
|
| 111 |
app = FastAPI()
|
| 112 |
|
|
|
|
| 113 |
class SearchRequest(BaseModel):
|
| 114 |
query: str
|
| 115 |
serper_api_key: str
|
| 116 |
search_type: str = "search"
|
| 117 |
num_results: int = 4
|
| 118 |
-
gemini_api_key: Optional[str] = None
|
| 119 |
-
gemini_model: Optional[str] = "gemini-1.5-flash-latest"
|
| 120 |
-
research_mode: str = "normal" # <<< NEW: Research mode field
|
| 121 |
|
| 122 |
@app.post("/api/search")
|
| 123 |
async def api_search(request: SearchRequest):
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
request.
|
| 127 |
)
|
| 128 |
-
return {"result": result}
|
| 129 |
|
| 130 |
-
#
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
search_type_input = gr.Radio(["search", "news"], value="search", label="Search Type")
|
| 141 |
-
num_results_input = gr.Slider(1, 20, value=4, step=1, label="Number of Results")
|
| 142 |
-
|
| 143 |
-
gr.Markdown("### Step 2: AI Summarization")
|
| 144 |
-
# <<< NEW: Research mode ke liye radio buttons >>>
|
| 145 |
-
research_mode_input = gr.Radio(["normal", "deep"], value="normal", label="Research Mode", info="Normal for fast summary, Deep for detailed report.")
|
| 146 |
-
gemini_api_key_input = gr.Textbox(label="Your Gemini API Key", type="password", placeholder="Leave empty to skip summarization")
|
| 147 |
-
gemini_model_input = gr.Textbox(label="Gemini Model", value="gemini-1.5-flash-latest")
|
| 148 |
-
|
| 149 |
-
search_button = gr.Button("Search & Summarize", variant="primary")
|
| 150 |
-
output = gr.Textbox(label="Result", lines=25, max_lines=40)
|
| 151 |
-
|
| 152 |
-
# <<< CHANGE: Naya research_mode_input, inputs list me add kiya gaya >>>
|
| 153 |
-
search_button.click(
|
| 154 |
-
fn=search_and_summarize,
|
| 155 |
-
inputs=[query_input, serper_api_key_input, search_type_input, num_results_input, gemini_api_key_input, gemini_model_input, research_mode_input],
|
| 156 |
-
outputs=output
|
| 157 |
-
)
|
| 158 |
-
with gr.Tab("Analytics"):
|
| 159 |
-
# Analytics tab remains unchanged
|
| 160 |
-
requests_plot = gr.BarPlot(x="date", y="count", title="Daily Requests")
|
| 161 |
-
avg_time_plot = gr.BarPlot(x="date", y="avg_time", title="Avg. Response Time (s)")
|
| 162 |
-
def update_analytics(): return last_n_days_df(14), last_n_days_avg_time_df(14)
|
| 163 |
-
demo.load(update_analytics, [], [requests_plot, avg_time_plot])
|
| 164 |
|
| 165 |
-
return
|
| 166 |
|
| 167 |
-
# ---
|
| 168 |
-
|
| 169 |
-
|
| 170 |
|
|
|
|
| 171 |
if __name__ == "__main__":
|
| 172 |
import uvicorn
|
| 173 |
uvicorn.run(app, host="0.0.0.0", port=7860)
|
|
|
|
| 1 |
import os
|
| 2 |
import asyncio
|
| 3 |
import time
|
| 4 |
+
from typing import Optional, List
|
| 5 |
+
from datetime import datetime
|
| 6 |
import httpx
|
| 7 |
import trafilatura
|
| 8 |
import gradio as gr
|
| 9 |
from dateutil import parser as dateparser
|
| 10 |
+
from limits import parse
|
| 11 |
+
from limits.aio.storage import MemoryStorage
|
| 12 |
+
from limits.aio.strategies import MovingWindowRateLimiter
|
| 13 |
+
from analytics import record_request, last_n_days_df, last_n_days_avg_time_df
|
| 14 |
from fastapi import FastAPI
|
| 15 |
from pydantic import BaseModel
|
| 16 |
+
import google.generativeai as genai # <<< NEW IMPORT
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
# --- Core Search Logic (No Changes) ---
|
| 19 |
async def search_web_logic(query: str, serper_api_key: str, search_type: str, num_results: int) -> str:
|
| 20 |
+
# ... (Ye function bilkul waisa hi hai jaisa pehle tha, isme koi badlav nahi)
|
| 21 |
start_time = time.time()
|
| 22 |
if not serper_api_key: return "Error: Serper API Key is required."
|
| 23 |
num_results = max(1, min(20, num_results))
|
|
|
|
| 46 |
chunks.append(chunk)
|
| 47 |
if not chunks: return "Found results, but couldn't extract content."
|
| 48 |
summary = f"Successfully extracted content from {successful_extractions}/{len(results)} results.\n\n---\n\n"
|
| 49 |
+
await record_request(time.time() - start_time, num_results)
|
| 50 |
return summary + "\n---\n".join(chunks)
|
| 51 |
except Exception as e:
|
| 52 |
return f"An error occurred during web search: {str(e)}"
|
| 53 |
|
| 54 |
+
# <<< NEW: Gemini Summarization Logic >>>
|
| 55 |
+
async def summarize_with_gemini(text_to_summarize: str, query: str, gemini_key: str, model_name: str) -> str:
|
| 56 |
try:
|
| 57 |
genai.configure(api_key=gemini_key)
|
| 58 |
model = genai.GenerativeModel(model_name)
|
| 59 |
+
|
| 60 |
+
prompt = f"""
|
| 61 |
+
Based on the user's original query, provide a concise summary of the following text.
|
| 62 |
+
Focus on the information that directly answers or relates to the query.
|
| 63 |
+
Filter out any irrelevant details, advertisements, or boilerplate content.
|
| 64 |
+
Present the final summary in clean, easy-to-read markdown format.
|
| 65 |
+
|
| 66 |
+
USER'S QUERY: "{query}"
|
| 67 |
+
|
| 68 |
+
TEXT TO SUMMARIZE:
|
| 69 |
+
---
|
| 70 |
+
{text_to_summarize}
|
| 71 |
+
---
|
| 72 |
+
"""
|
| 73 |
|
| 74 |
response = await model.generate_content_async(prompt)
|
| 75 |
return response.text
|
| 76 |
except Exception as e:
|
| 77 |
return f"\n\n--- ⚠️ Gemini Summarization Failed ---\nError: {str(e)}\nReturning raw text instead."
|
| 78 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
# --- FastAPI App ---
|
| 80 |
app = FastAPI()
|
| 81 |
|
| 82 |
+
# <<< CHANGE: FastAPI request model ko naye fields ke sath update kiya gaya >>>
|
| 83 |
class SearchRequest(BaseModel):
|
| 84 |
query: str
|
| 85 |
serper_api_key: str
|
| 86 |
search_type: str = "search"
|
| 87 |
num_results: int = 4
|
| 88 |
+
gemini_api_key: Optional[str] = None # Optional field
|
| 89 |
+
gemini_model: Optional[str] = "gemini-1.5-flash-latest" # Optional field with default
|
|
|
|
| 90 |
|
| 91 |
@app.post("/api/search")
|
| 92 |
async def api_search(request: SearchRequest):
|
| 93 |
+
# Step 1: Web Search
|
| 94 |
+
scraped_text = await search_web_logic(
|
| 95 |
+
request.query, request.serper_api_key, request.search_type, request.num_results
|
| 96 |
)
|
|
|
|
| 97 |
|
| 98 |
+
# Step 2: (Optional) Summarize with Gemini
|
| 99 |
+
if request.gemini_api_key and "Error:" not in scraped_text:
|
| 100 |
+
summarized_text = await summarize_with_gemini(
|
| 101 |
+
scraped_text, request.query, request.gemini_api_key, request.gemini_model
|
| 102 |
+
)
|
| 103 |
+
# Agar summarization fail hota hai, to original text wapas bhej dein
|
| 104 |
+
if "⚠️ Gemini Summarization Failed" in summarized_text:
|
| 105 |
+
return {"result": scraped_text + summarized_text}
|
| 106 |
+
else:
|
| 107 |
+
return {"result": summarized_text}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
|
| 109 |
+
return {"result": scraped_text}
|
| 110 |
|
| 111 |
+
# --- Gradio App (ab iski zaroorat nahi, lekin rakha ja sakta hai) ---
|
| 112 |
+
# ... (Gradio UI ka code abhi ke liye comment out kar sakte hain ya hata sakte hain)
|
| 113 |
+
# ... agar aapko UI bhi chahiye to hum use bhi update kar sakte hain
|
| 114 |
|
| 115 |
+
# --- Server Startup ---
|
| 116 |
if __name__ == "__main__":
|
| 117 |
import uvicorn
|
| 118 |
uvicorn.run(app, host="0.0.0.0", port=7860)
|