sagar007's picture
Update app.py
60c475d verified
raw
history blame
7.27 kB
import gradio as gr
from transformers import pipeline
from duckduckgo_search import DDGS
from datetime import datetime
import asyncio
# Initialize a lightweight text generation model (distilgpt2 for speed)
generator = pipeline("text-generation", model="distilgpt2", device=0 if gr.cuda.is_available() else -1)
# Web search function using DuckDuckGo
async def get_web_results(query: str, max_results: int = 5) -> list:
"""Fetch web results asynchronously for deep research."""
try:
with DDGS() as ddgs:
results = await asyncio.to_thread(lambda: list(ddgs.text(query, max_results=max_results)))
return [
{"title": r.get("title", "No Title"), "snippet": r["body"], "url": r["href"]}
for r in results
]
except Exception as e:
return [{"title": "Error", "snippet": f"Failed to fetch results: {str(e)}", "url": "#"}]
# Format prompt for the AI model
def format_prompt(query: str, web_results: list) -> str:
"""Create a concise prompt with web context."""
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
context = "\n".join([f"- {r['title']}: {r['snippet']}" for r in web_results])
return f"""Time: {current_time}
Query: {query}
Web Context:
{context}
Provide a detailed, well-structured answer in markdown format with citations [1], [2], etc."""
# Generate answer using the AI model
def generate_answer(prompt: str) -> str:
"""Generate a detailed research answer."""
response = generator(prompt, max_length=300, num_return_sequences=1, truncation=True)[0]["generated_text"]
# Extract the answer after the prompt
answer_start = response.find("Provide a detailed") + len("Provide a detailed, well-structured answer in markdown format with citations [1], [2], etc.")
return response[answer_start:].strip()
# Format sources for display
def format_sources(web_results: list) -> str:
"""Create an HTML list of sources."""
if not web_results:
return "<div>No sources available</div>"
sources_html = "<div class='sources-list'>"
for i, res in enumerate(web_results, 1):
sources_html += f"""
<div class='source-item'>
<span class='source-number'>[{i}]</span>
<a href='{res['url']}' target='_blank'>{res['title']}</a>: {res['snippet'][:150]}...
</div>
"""
sources_html += "</div>"
return sources_html
# Main processing function
async def process_deep_research(query: str, history: list):
"""Handle the deep research process with progressive updates."""
if not history:
history = []
# Step 1: Initial loading state
yield {
"answer": "*Searching the web...*",
"sources": "<div>Fetching sources...</div>",
"history": history + [[query, "*Searching...*"]]
}
# Step 2: Fetch web results
web_results = await get_web_results(query)
sources_html = format_sources(web_results)
# Step 3: Update with web search completed
yield {
"answer": "*Analyzing results...*",
"sources": sources_html,
"history": history + [[query, "*Analyzing...*"]]
}
# Step 4: Generate detailed answer
prompt = format_prompt(query, web_results)
answer = generate_answer(prompt)
final_history = history + [[query, answer]]
# Step 5: Final result
yield {
"answer": answer,
"sources": sources_html,
"history": final_history
}
# Custom CSS for a cool, modern UI
css = """
body {
font-family: 'Arial', sans-serif;
background: #1a1a1a;
color: #ffffff;
}
.gradio-container {
max-width: 1000px;
margin: 0 auto;
padding: 20px;
}
.header {
text-align: center;
padding: 20px;
background: linear-gradient(135deg, #2c3e50, #3498db);
border-radius: 10px;
margin-bottom: 20px;
}
.header h1 {
font-size: 2.5em;
margin: 0;
color: #ffffff;
}
.header p {
color: #bdc3c7;
font-size: 1.1em;
}
.search-box {
background: #2c2c2c;
padding: 15px;
border-radius: 10px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
}
.search-box input {
background: #3a3a3a !important;
color: #ffffff !important;
border: none !important;
border-radius: 5px !important;
}
.search-box button {
background: #3498db !important;
border: none !important;
border-radius: 5px !important;
transition: background 0.3s;
}
.search-box button:hover {
background: #2980b9 !important;
}
.results-container {
margin-top: 20px;
display: flex;
gap: 20px;
}
.answer-box {
flex: 2;
background: #2c2c2c;
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
}
.answer-box .markdown {
color: #ecf0f1;
line-height: 1.6;
}
.sources-list {
flex: 1;
background: #2c2c2c;
padding: 15px;
border-radius: 10px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
}
.source-item {
margin-bottom: 10px;
}
.source-number {
color: #3498db;
font-weight: bold;
margin-right: 5px;
}
.source-item a {
color: #3498db;
text-decoration: none;
}
.source-item a:hover {
text-decoration: underline;
}
.history-box {
margin-top: 20px;
background: #2c2c2c;
padding: 15px;
border-radius: 10px;
max-height: 300px;
overflow-y: auto;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
}
"""
# Gradio app setup with Blocks for better control
with gr.Blocks(title="Deep Research Engine", css=css) as demo:
history_state = gr.State([])
# Header
with gr.Column(elem_classes="header"):
gr.Markdown("# Deep Research Engine")
gr.Markdown("Your gateway to in-depth answers with real-time web insights.")
# Search input and button
with gr.Row(elem_classes="search-box"):
search_input = gr.Textbox(label="", placeholder="Ask anything...", lines=2)
search_btn = gr.Button("Research", variant="primary")
# Results layout
with gr.Row(elem_classes="results-container"):
with gr.Column():
answer_output = gr.Markdown(label="Research Findings", elem_classes="answer-box")
with gr.Column():
sources_output = gr.HTML(label="Sources", elem_classes="sources-list")
# Chat history
with gr.Row():
history_display = gr.Chatbot(label="History", elem_classes="history-box")
# Event handling
async def handle_search(query, history):
async for step in process_deep_research(query, history):
yield step["answer"], step["sources"], step["history"]
search_btn.click(
fn=handle_search,
inputs=[search_input, history_state],
outputs=[answer_output, sources_output, history_display],
_js="() => [document.querySelector('.search-box input').value, null]" # Ensure history is managed
).then(
fn=lambda x: x,
inputs=[history_display],
outputs=[history_state]
)
search_input.submit(
fn=handle_search,
inputs=[search_input, history_state],
outputs=[answer_output, sources_output, history_display]
).then(
fn=lambda x: x,
inputs=[history_display],
outputs=[history_state]
)
# Launch the app
if __name__ == "__main__":
demo.launch()