Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -10,8 +10,8 @@ from tavily import TavilyClient
|
|
| 10 |
import feedparser
|
| 11 |
from fuzzywuzzy import fuzz
|
| 12 |
from fpdf import FPDF
|
| 13 |
-
from io import BytesIO
|
| 14 |
from duckduckgo_search import DDGS
|
|
|
|
| 15 |
|
| 16 |
# --- Load API Keys ---
|
| 17 |
load_dotenv()
|
|
@@ -65,7 +65,7 @@ def call_llm(messages, model="deepseek/deepseek-chat-v3-0324:free", max_tokens=4
|
|
| 65 |
except json.JSONDecodeError:
|
| 66 |
pass
|
| 67 |
|
| 68 |
-
def get_image_urls(query, max_images=
|
| 69 |
with DDGS() as ddgs:
|
| 70 |
return [img["image"] for img in ddgs.images(query, max_results=max_images)]
|
| 71 |
|
|
@@ -163,7 +163,6 @@ def download_threads_as_pdf(chat_threads):
|
|
| 163 |
for msg in chats:
|
| 164 |
role = "You" if msg["role"] == "user" else "Assistant"
|
| 165 |
text = f"{role}: {msg['content']}"
|
| 166 |
-
# Safely encode for Latin-1 by replacing unknown characters
|
| 167 |
try:
|
| 168 |
text = text.encode('latin-1').decode('latin-1')
|
| 169 |
except UnicodeEncodeError:
|
|
@@ -176,11 +175,9 @@ def download_threads_as_pdf(chat_threads):
|
|
| 176 |
pdf_output.seek(0)
|
| 177 |
return pdf_output
|
| 178 |
|
|
|
|
|
|
|
| 179 |
|
| 180 |
-
# --- Streamlit UI ---
|
| 181 |
-
st.set_page_config(page_title="π§ Deep Research Assistant 3.0", layout="centered")
|
| 182 |
-
|
| 183 |
-
# --- Load Memory ---
|
| 184 |
if "memory_bank" not in st.session_state:
|
| 185 |
st.session_state.memory_bank = []
|
| 186 |
if "chat_threads" not in st.session_state:
|
|
@@ -192,20 +189,43 @@ load_session_data()
|
|
| 192 |
|
| 193 |
# --- Sidebar ---
|
| 194 |
with st.sidebar:
|
| 195 |
-
st.
|
| 196 |
-
|
|
|
|
| 197 |
report_type = st.selectbox("π Report Type", ["Summary", "Detailed Report", "Thorough Academic Research"])
|
| 198 |
tone = st.selectbox("π― Tone", ["Objective", "Persuasive", "Narrative"])
|
| 199 |
source_type = st.selectbox("π Sources", ["Web Only", "Academic Only", "Hybrid"])
|
| 200 |
-
custom_domains = st.text_input("π Optional Domains", placeholder="
|
| 201 |
-
research_button = st.button("π
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 202 |
|
| 203 |
-
#
|
| 204 |
-
st.title("π Research Output")
|
| 205 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
if research_button and topic:
|
| 207 |
try:
|
| 208 |
-
with st.status("
|
| 209 |
all_sources = []
|
| 210 |
if source_type in ["Web Only", "Hybrid"]:
|
| 211 |
all_sources += get_sources(topic, custom_domains) if custom_domains.strip() else get_sources(topic)
|
|
@@ -234,13 +254,13 @@ if research_button and topic:
|
|
| 234 |
"Thorough Academic Research": "Craft a full academic paper >1000 words."
|
| 235 |
}[report_type]
|
| 236 |
|
|
|
|
| 237 |
thread_id = str(uuid.uuid4())
|
| 238 |
st.session_state.current_thread_id = thread_id
|
| 239 |
st.session_state.chat_threads[thread_id] = []
|
| 240 |
|
| 241 |
prompt = f"""
|
| 242 |
Use past learnings:
|
| 243 |
-
|
| 244 |
{previous_learnings}
|
| 245 |
|
| 246 |
New Topic:
|
|
@@ -259,6 +279,7 @@ Citations:
|
|
| 259 |
{chr(10).join(citations)}
|
| 260 |
"""
|
| 261 |
|
|
|
|
| 262 |
st.subheader(f"π {report_type} on '{topic}'")
|
| 263 |
output_placeholder = st.empty()
|
| 264 |
final_output = ""
|
|
@@ -274,31 +295,49 @@ Citations:
|
|
| 274 |
except Exception as e:
|
| 275 |
st.error(f"β Error: {e}")
|
| 276 |
|
| 277 |
-
# --- Chat Threads
|
| 278 |
st.divider()
|
| 279 |
st.subheader("π Your Research Threads")
|
| 280 |
|
|
|
|
|
|
|
|
|
|
| 281 |
for tid, chats in st.session_state.chat_threads.items():
|
| 282 |
-
with st.
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 299 |
if st.session_state.chat_threads:
|
|
|
|
|
|
|
| 300 |
pdf_file = download_threads_as_pdf(st.session_state.chat_threads)
|
| 301 |
-
st.download_button("π₯ Download All Threads as PDF", data=pdf_file, file_name="Research_Threads.pdf", mime="application/pdf")
|
| 302 |
|
| 303 |
|
| 304 |
|
|
|
|
| 10 |
import feedparser
|
| 11 |
from fuzzywuzzy import fuzz
|
| 12 |
from fpdf import FPDF
|
|
|
|
| 13 |
from duckduckgo_search import DDGS
|
| 14 |
+
from io import BytesIO
|
| 15 |
|
| 16 |
# --- Load API Keys ---
|
| 17 |
load_dotenv()
|
|
|
|
| 65 |
except json.JSONDecodeError:
|
| 66 |
pass
|
| 67 |
|
| 68 |
+
def get_image_urls(query, max_images=5):
|
| 69 |
with DDGS() as ddgs:
|
| 70 |
return [img["image"] for img in ddgs.images(query, max_results=max_images)]
|
| 71 |
|
|
|
|
| 163 |
for msg in chats:
|
| 164 |
role = "You" if msg["role"] == "user" else "Assistant"
|
| 165 |
text = f"{role}: {msg['content']}"
|
|
|
|
| 166 |
try:
|
| 167 |
text = text.encode('latin-1').decode('latin-1')
|
| 168 |
except UnicodeEncodeError:
|
|
|
|
| 175 |
pdf_output.seek(0)
|
| 176 |
return pdf_output
|
| 177 |
|
| 178 |
+
# --- Streamlit UI Setup ---
|
| 179 |
+
st.set_page_config(page_title="π§ Deep Research Assistant 4.0", layout="centered")
|
| 180 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 181 |
if "memory_bank" not in st.session_state:
|
| 182 |
st.session_state.memory_bank = []
|
| 183 |
if "chat_threads" not in st.session_state:
|
|
|
|
| 189 |
|
| 190 |
# --- Sidebar ---
|
| 191 |
with st.sidebar:
|
| 192 |
+
st.image("https://raw.githubusercontent.com/mk-gurucharan/streamlit-deep-research/main/deep_research_logo.png", use_column_width=True)
|
| 193 |
+
st.markdown("## π Start New Research")
|
| 194 |
+
topic = st.text_input("π§ Topic")
|
| 195 |
report_type = st.selectbox("π Report Type", ["Summary", "Detailed Report", "Thorough Academic Research"])
|
| 196 |
tone = st.selectbox("π― Tone", ["Objective", "Persuasive", "Narrative"])
|
| 197 |
source_type = st.selectbox("π Sources", ["Web Only", "Academic Only", "Hybrid"])
|
| 198 |
+
custom_domains = st.text_input("π Optional Domains", placeholder="forbes.com, mit.edu")
|
| 199 |
+
research_button = st.button("π Run Deep Research", use_container_width=True)
|
| 200 |
+
st.markdown("---")
|
| 201 |
+
st.markdown("Made with β€οΈ by Cutie AI β¨")
|
| 202 |
+
|
| 203 |
+
# --- Main Title ---
|
| 204 |
+
st.title("π Deep Research Assistant 4.0")
|
| 205 |
+
st.markdown("Where serious research meets serious style. π§ π")
|
| 206 |
+
st.divider()
|
| 207 |
|
| 208 |
+
# Continue from here for Main Research Section...
|
|
|
|
| 209 |
|
| 210 |
+
# --- Show Web Images from Topic ---
|
| 211 |
+
if topic and research_button:
|
| 212 |
+
st.subheader("πΌ Related Images from the Web")
|
| 213 |
+
try:
|
| 214 |
+
topic_images = get_image_urls(topic, max_images=6)
|
| 215 |
+
if topic_images:
|
| 216 |
+
img_cols = st.columns(3)
|
| 217 |
+
for idx, img_url in enumerate(topic_images):
|
| 218 |
+
with img_cols[idx % 3]:
|
| 219 |
+
st.image(img_url, use_column_width=True)
|
| 220 |
+
else:
|
| 221 |
+
st.info("No images found for this topic.")
|
| 222 |
+
except Exception as e:
|
| 223 |
+
st.warning(f"Couldn't load topic images. ({e})")
|
| 224 |
+
|
| 225 |
+
# --- Main Research Section ---
|
| 226 |
if research_button and topic:
|
| 227 |
try:
|
| 228 |
+
with st.status("π Gathering sources..."):
|
| 229 |
all_sources = []
|
| 230 |
if source_type in ["Web Only", "Hybrid"]:
|
| 231 |
all_sources += get_sources(topic, custom_domains) if custom_domains.strip() else get_sources(topic)
|
|
|
|
| 254 |
"Thorough Academic Research": "Craft a full academic paper >1000 words."
|
| 255 |
}[report_type]
|
| 256 |
|
| 257 |
+
# Create New Thread
|
| 258 |
thread_id = str(uuid.uuid4())
|
| 259 |
st.session_state.current_thread_id = thread_id
|
| 260 |
st.session_state.chat_threads[thread_id] = []
|
| 261 |
|
| 262 |
prompt = f"""
|
| 263 |
Use past learnings:
|
|
|
|
| 264 |
{previous_learnings}
|
| 265 |
|
| 266 |
New Topic:
|
|
|
|
| 279 |
{chr(10).join(citations)}
|
| 280 |
"""
|
| 281 |
|
| 282 |
+
# --- Generate Report ---
|
| 283 |
st.subheader(f"π {report_type} on '{topic}'")
|
| 284 |
output_placeholder = st.empty()
|
| 285 |
final_output = ""
|
|
|
|
| 295 |
except Exception as e:
|
| 296 |
st.error(f"β Error: {e}")
|
| 297 |
|
| 298 |
+
# --- Chat Threads Section ---
|
| 299 |
st.divider()
|
| 300 |
st.subheader("π Your Research Threads")
|
| 301 |
|
| 302 |
+
user_avatar = "https://cdn-icons-png.flaticon.com/512/9131/9131529.png"
|
| 303 |
+
assistant_avatar = "https://cdn-icons-png.flaticon.com/512/4712/4712107.png"
|
| 304 |
+
|
| 305 |
for tid, chats in st.session_state.chat_threads.items():
|
| 306 |
+
with st.container():
|
| 307 |
+
with st.expander(f"π§΅ Thread {tid[:8]}", expanded=False):
|
| 308 |
+
for msg in chats:
|
| 309 |
+
avatar = user_avatar if msg['role'] == 'user' else assistant_avatar
|
| 310 |
+
bubble_color = "#DCF8C6" if msg['role'] == 'user' else "#F0F0F0"
|
| 311 |
+
align = "flex-end" if msg['role'] == 'user' else "flex-start"
|
| 312 |
+
|
| 313 |
+
st.markdown(f"""
|
| 314 |
+
<div style="display: flex; justify-content: {align}; margin-bottom: 10px;">
|
| 315 |
+
<img src="{avatar}" width="30" style="margin-right: 10px; border-radius: 50%;">
|
| 316 |
+
<div style="background-color: {bubble_color}; padding: 10px 15px; border-radius: 10px; max-width: 70%;">
|
| 317 |
+
{msg['content']}
|
| 318 |
+
</div>
|
| 319 |
+
</div>
|
| 320 |
+
""", unsafe_allow_html=True)
|
| 321 |
+
|
| 322 |
+
followup = st.text_input(f"π¬ Continue Thread {tid[:8]}:", key=f"followup_{tid}")
|
| 323 |
+
if st.button(f"Ask Follow-up {tid}", key=f"button_{tid}"):
|
| 324 |
+
if followup:
|
| 325 |
+
with st.spinner("π€ Assistant is typing..."):
|
| 326 |
+
response = ""
|
| 327 |
+
for chunk in call_llm(st.session_state.chat_threads[tid] + [{"role": "user", "content": followup}], max_tokens=2000):
|
| 328 |
+
response += chunk
|
| 329 |
+
st.markdown(response)
|
| 330 |
+
st.session_state.chat_threads[tid].append({"role": "user", "content": followup})
|
| 331 |
+
st.session_state.chat_threads[tid].append({"role": "assistant", "content": response})
|
| 332 |
+
save_session_data()
|
| 333 |
+
st.experimental_rerun()
|
| 334 |
+
|
| 335 |
+
# --- Download All Threads Section ---
|
| 336 |
if st.session_state.chat_threads:
|
| 337 |
+
st.divider()
|
| 338 |
+
st.subheader("π₯ Export Your Work")
|
| 339 |
pdf_file = download_threads_as_pdf(st.session_state.chat_threads)
|
| 340 |
+
st.download_button("π₯ Download All Threads as PDF", data=pdf_file, file_name="Research_Threads.pdf", mime="application/pdf", use_container_width=True)
|
| 341 |
|
| 342 |
|
| 343 |
|