Spaces:
Running
on
Zero
Running
on
Zero
Update app.py
Browse files
app.py
CHANGED
@@ -1,26 +1,23 @@
|
|
1 |
import gradio as gr
|
|
|
2 |
from transformers import pipeline
|
3 |
from duckduckgo_search import DDGS
|
4 |
from datetime import datetime
|
5 |
-
import asyncio
|
6 |
|
7 |
-
# Initialize a lightweight text generation model (
|
8 |
-
generator = pipeline("text-generation", model="distilgpt2", device
|
9 |
|
10 |
-
# Web search function
|
11 |
-
|
12 |
-
"""Fetch web results
|
13 |
try:
|
14 |
with DDGS() as ddgs:
|
15 |
-
results =
|
16 |
-
return [
|
17 |
-
{"title": r.get("title", "No Title"), "snippet": r["body"], "url": r["href"]}
|
18 |
-
for r in results
|
19 |
-
]
|
20 |
except Exception as e:
|
21 |
return [{"title": "Error", "snippet": f"Failed to fetch results: {str(e)}", "url": "#"}]
|
22 |
|
23 |
-
# Format prompt for the AI model
|
24 |
def format_prompt(query: str, web_results: list) -> str:
|
25 |
"""Create a concise prompt with web context."""
|
26 |
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
@@ -29,70 +26,50 @@ def format_prompt(query: str, web_results: list) -> str:
|
|
29 |
Query: {query}
|
30 |
Web Context:
|
31 |
{context}
|
32 |
-
Provide a
|
33 |
|
34 |
-
#
|
|
|
35 |
def generate_answer(prompt: str) -> str:
|
36 |
-
"""Generate a
|
37 |
-
response = generator(prompt, max_length=
|
38 |
-
|
39 |
-
|
40 |
-
return response[answer_start:].strip()
|
41 |
|
42 |
-
# Format sources for display
|
43 |
def format_sources(web_results: list) -> str:
|
44 |
-
"""Create
|
45 |
if not web_results:
|
46 |
return "<div>No sources available</div>"
|
47 |
-
|
48 |
sources_html = "<div class='sources-list'>"
|
49 |
for i, res in enumerate(web_results, 1):
|
50 |
sources_html += f"""
|
51 |
<div class='source-item'>
|
52 |
<span class='source-number'>[{i}]</span>
|
53 |
-
<a href='{res['url']}' target='_blank'>{res['title']}</a>: {res['snippet'][:
|
54 |
</div>
|
55 |
"""
|
56 |
sources_html += "</div>"
|
57 |
return sources_html
|
58 |
|
59 |
# Main processing function
|
60 |
-
|
61 |
-
"""Handle the deep research process
|
62 |
if not history:
|
63 |
history = []
|
64 |
|
65 |
-
#
|
66 |
-
|
67 |
-
"answer": "*Searching the web...*",
|
68 |
-
"sources": "<div>Fetching sources...</div>",
|
69 |
-
"history": history + [[query, "*Searching...*"]]
|
70 |
-
}
|
71 |
-
|
72 |
-
# Step 2: Fetch web results
|
73 |
-
web_results = await get_web_results(query)
|
74 |
sources_html = format_sources(web_results)
|
75 |
|
76 |
-
#
|
77 |
-
yield {
|
78 |
-
"answer": "*Analyzing results...*",
|
79 |
-
"sources": sources_html,
|
80 |
-
"history": history + [[query, "*Analyzing...*"]]
|
81 |
-
}
|
82 |
-
|
83 |
-
# Step 4: Generate detailed answer
|
84 |
prompt = format_prompt(query, web_results)
|
85 |
answer = generate_answer(prompt)
|
86 |
final_history = history + [[query, answer]]
|
87 |
|
88 |
-
|
89 |
-
yield {
|
90 |
-
"answer": answer,
|
91 |
-
"sources": sources_html,
|
92 |
-
"history": final_history
|
93 |
-
}
|
94 |
|
95 |
-
# Custom CSS for a cool,
|
96 |
css = """
|
97 |
body {
|
98 |
font-family: 'Arial', sans-serif;
|
@@ -100,31 +77,24 @@ body {
|
|
100 |
color: #ffffff;
|
101 |
}
|
102 |
.gradio-container {
|
103 |
-
max-width:
|
104 |
margin: 0 auto;
|
105 |
-
padding:
|
106 |
}
|
107 |
.header {
|
108 |
text-align: center;
|
109 |
-
padding:
|
110 |
background: linear-gradient(135deg, #2c3e50, #3498db);
|
111 |
-
border-radius:
|
112 |
-
margin-bottom:
|
113 |
-
}
|
114 |
-
.header h1 {
|
115 |
-
font-size: 2.5em;
|
116 |
-
margin: 0;
|
117 |
-
color: #ffffff;
|
118 |
-
}
|
119 |
-
.header p {
|
120 |
-
color: #bdc3c7;
|
121 |
-
font-size: 1.1em;
|
122 |
}
|
|
|
|
|
123 |
.search-box {
|
124 |
background: #2c2c2c;
|
125 |
-
padding:
|
126 |
-
border-radius:
|
127 |
-
box-shadow: 0
|
128 |
}
|
129 |
.search-box input {
|
130 |
background: #3a3a3a !important;
|
@@ -136,68 +106,50 @@ body {
|
|
136 |
background: #3498db !important;
|
137 |
border: none !important;
|
138 |
border-radius: 5px !important;
|
139 |
-
transition: background 0.3s;
|
140 |
-
}
|
141 |
-
.search-box button:hover {
|
142 |
-
background: #2980b9 !important;
|
143 |
}
|
144 |
.results-container {
|
145 |
-
margin-top:
|
146 |
display: flex;
|
147 |
-
gap:
|
148 |
}
|
149 |
.answer-box {
|
150 |
flex: 2;
|
151 |
background: #2c2c2c;
|
152 |
-
padding:
|
153 |
-
border-radius:
|
154 |
-
box-shadow: 0
|
155 |
-
}
|
156 |
-
.answer-box .markdown {
|
157 |
-
color: #ecf0f1;
|
158 |
-
line-height: 1.6;
|
159 |
}
|
|
|
160 |
.sources-list {
|
161 |
flex: 1;
|
162 |
background: #2c2c2c;
|
163 |
-
padding:
|
164 |
-
border-radius:
|
165 |
-
box-shadow: 0
|
166 |
-
}
|
167 |
-
.source-item {
|
168 |
-
|
169 |
-
}
|
170 |
-
.source-
|
171 |
-
color: #3498db;
|
172 |
-
font-weight: bold;
|
173 |
-
margin-right: 5px;
|
174 |
-
}
|
175 |
-
.source-item a {
|
176 |
-
color: #3498db;
|
177 |
-
text-decoration: none;
|
178 |
-
}
|
179 |
-
.source-item a:hover {
|
180 |
-
text-decoration: underline;
|
181 |
-
}
|
182 |
.history-box {
|
183 |
-
margin-top:
|
184 |
background: #2c2c2c;
|
185 |
-
padding:
|
186 |
-
border-radius:
|
187 |
-
max-height:
|
188 |
overflow-y: auto;
|
189 |
-
box-shadow: 0
|
190 |
}
|
191 |
"""
|
192 |
|
193 |
-
# Gradio app setup with Blocks
|
194 |
-
with gr.Blocks(title="Deep Research Engine", css=css) as demo:
|
195 |
history_state = gr.State([])
|
196 |
|
197 |
# Header
|
198 |
with gr.Column(elem_classes="header"):
|
199 |
gr.Markdown("# Deep Research Engine")
|
200 |
-
gr.Markdown("
|
201 |
|
202 |
# Search input and button
|
203 |
with gr.Row(elem_classes="search-box"):
|
@@ -216,15 +168,15 @@ with gr.Blocks(title="Deep Research Engine", css=css) as demo:
|
|
216 |
history_display = gr.Chatbot(label="History", elem_classes="history-box")
|
217 |
|
218 |
# Event handling
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
|
223 |
search_btn.click(
|
224 |
fn=handle_search,
|
225 |
inputs=[search_input, history_state],
|
226 |
outputs=[answer_output, sources_output, history_display],
|
227 |
-
_js="() => [document.querySelector('.search-box input').value, null]"
|
228 |
).then(
|
229 |
fn=lambda x: x,
|
230 |
inputs=[history_display],
|
|
|
1 |
import gradio as gr
|
2 |
+
import spaces # Required for ZeroGPU
|
3 |
from transformers import pipeline
|
4 |
from duckduckgo_search import DDGS
|
5 |
from datetime import datetime
|
|
|
6 |
|
7 |
+
# Initialize a lightweight text generation model on CPU (moves to GPU when decorated)
|
8 |
+
generator = pipeline("text-generation", model="distilgpt2", device=-1) # -1 ensures CPU by default
|
9 |
|
10 |
+
# Web search function (CPU-based)
|
11 |
+
def get_web_results(query: str, max_results: int = 3) -> list:
|
12 |
+
"""Fetch web results synchronously for Zero GPU compatibility."""
|
13 |
try:
|
14 |
with DDGS() as ddgs:
|
15 |
+
results = list(ddgs.text(query, max_results=max_results))
|
16 |
+
return [{"title": r.get("title", "No Title"), "snippet": r["body"], "url": r["href"]} for r in results]
|
|
|
|
|
|
|
17 |
except Exception as e:
|
18 |
return [{"title": "Error", "snippet": f"Failed to fetch results: {str(e)}", "url": "#"}]
|
19 |
|
20 |
+
# Format prompt for the AI model (CPU-based)
|
21 |
def format_prompt(query: str, web_results: list) -> str:
|
22 |
"""Create a concise prompt with web context."""
|
23 |
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
26 |
Query: {query}
|
27 |
Web Context:
|
28 |
{context}
|
29 |
+
Provide a concise answer in markdown format with citations [1], [2], etc."""
|
30 |
|
31 |
+
# GPU-decorated answer generation
|
32 |
+
@spaces.GPU(duration=120) # Allow up to 120 seconds of GPU time
|
33 |
def generate_answer(prompt: str) -> str:
|
34 |
+
"""Generate a concise research answer using GPU."""
|
35 |
+
response = generator(prompt, max_length=200, num_return_sequences=1, truncation=True)[0]["generated_text"]
|
36 |
+
answer_start = response.find("Provide a concise") + len("Provide a concise answer in markdown format with citations [1], [2], etc.")
|
37 |
+
return response[answer_start:].strip() if answer_start > -1 else "No detailed answer generated."
|
|
|
38 |
|
39 |
+
# Format sources for display (CPU-based)
|
40 |
def format_sources(web_results: list) -> str:
|
41 |
+
"""Create a simple HTML list of sources."""
|
42 |
if not web_results:
|
43 |
return "<div>No sources available</div>"
|
|
|
44 |
sources_html = "<div class='sources-list'>"
|
45 |
for i, res in enumerate(web_results, 1):
|
46 |
sources_html += f"""
|
47 |
<div class='source-item'>
|
48 |
<span class='source-number'>[{i}]</span>
|
49 |
+
<a href='{res['url']}' target='_blank'>{res['title']}</a>: {res['snippet'][:100]}...
|
50 |
</div>
|
51 |
"""
|
52 |
sources_html += "</div>"
|
53 |
return sources_html
|
54 |
|
55 |
# Main processing function
|
56 |
+
def process_deep_research(query: str, history: list):
|
57 |
+
"""Handle the deep research process."""
|
58 |
if not history:
|
59 |
history = []
|
60 |
|
61 |
+
# Fetch web results (CPU)
|
62 |
+
web_results = get_web_results(query)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
sources_html = format_sources(web_results)
|
64 |
|
65 |
+
# Generate answer (GPU via @spaces.GPU)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
prompt = format_prompt(query, web_results)
|
67 |
answer = generate_answer(prompt)
|
68 |
final_history = history + [[query, answer]]
|
69 |
|
70 |
+
return answer, sources_html, final_history
|
|
|
|
|
|
|
|
|
|
|
71 |
|
72 |
+
# Custom CSS for a cool, lightweight UI
|
73 |
css = """
|
74 |
body {
|
75 |
font-family: 'Arial', sans-serif;
|
|
|
77 |
color: #ffffff;
|
78 |
}
|
79 |
.gradio-container {
|
80 |
+
max-width: 900px;
|
81 |
margin: 0 auto;
|
82 |
+
padding: 15px;
|
83 |
}
|
84 |
.header {
|
85 |
text-align: center;
|
86 |
+
padding: 15px;
|
87 |
background: linear-gradient(135deg, #2c3e50, #3498db);
|
88 |
+
border-radius: 8px;
|
89 |
+
margin-bottom: 15px;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
}
|
91 |
+
.header h1 { font-size: 2em; margin: 0; color: #ffffff; }
|
92 |
+
.header p { color: #bdc3c7; font-size: 1em; }
|
93 |
.search-box {
|
94 |
background: #2c2c2c;
|
95 |
+
padding: 10px;
|
96 |
+
border-radius: 8px;
|
97 |
+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
98 |
}
|
99 |
.search-box input {
|
100 |
background: #3a3a3a !important;
|
|
|
106 |
background: #3498db !important;
|
107 |
border: none !important;
|
108 |
border-radius: 5px !important;
|
|
|
|
|
|
|
|
|
109 |
}
|
110 |
.results-container {
|
111 |
+
margin-top: 15px;
|
112 |
display: flex;
|
113 |
+
gap: 15px;
|
114 |
}
|
115 |
.answer-box {
|
116 |
flex: 2;
|
117 |
background: #2c2c2c;
|
118 |
+
padding: 15px;
|
119 |
+
border-radius: 8px;
|
120 |
+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
|
|
|
|
|
|
|
|
121 |
}
|
122 |
+
.answer-box .markdown { color: #ecf0f1; line-height: 1.5; }
|
123 |
.sources-list {
|
124 |
flex: 1;
|
125 |
background: #2c2c2c;
|
126 |
+
padding: 10px;
|
127 |
+
border-radius: 8px;
|
128 |
+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
129 |
+
}
|
130 |
+
.source-item { margin-bottom: 8px; }
|
131 |
+
.source-number { color: #3498db; font-weight: bold; margin-right: 5px; }
|
132 |
+
.source-item a { color: #3498db; text-decoration: none; }
|
133 |
+
.source-item a:hover { text-decoration: underline; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
134 |
.history-box {
|
135 |
+
margin-top: 15px;
|
136 |
background: #2c2c2c;
|
137 |
+
padding: 10px;
|
138 |
+
border-radius: 8px;
|
139 |
+
max-height: 250px;
|
140 |
overflow-y: auto;
|
141 |
+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
142 |
}
|
143 |
"""
|
144 |
|
145 |
+
# Gradio app setup with Blocks
|
146 |
+
with gr.Blocks(title="Deep Research Engine - ZeroGPU", css=css) as demo:
|
147 |
history_state = gr.State([])
|
148 |
|
149 |
# Header
|
150 |
with gr.Column(elem_classes="header"):
|
151 |
gr.Markdown("# Deep Research Engine")
|
152 |
+
gr.Markdown("Fast, in-depth answers powered by web insights (ZeroGPU).")
|
153 |
|
154 |
# Search input and button
|
155 |
with gr.Row(elem_classes="search-box"):
|
|
|
168 |
history_display = gr.Chatbot(label="History", elem_classes="history-box")
|
169 |
|
170 |
# Event handling
|
171 |
+
def handle_search(query, history):
|
172 |
+
answer, sources, new_history = process_deep_research(query, history)
|
173 |
+
return answer, sources, new_history
|
174 |
|
175 |
search_btn.click(
|
176 |
fn=handle_search,
|
177 |
inputs=[search_input, history_state],
|
178 |
outputs=[answer_output, sources_output, history_display],
|
179 |
+
_js="() => [document.querySelector('.search-box input').value, null]"
|
180 |
).then(
|
181 |
fn=lambda x: x,
|
182 |
inputs=[history_display],
|