Spaces:
Build error
Build error
File size: 9,920 Bytes
1879c4c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# -*- coding: utf-8 -*-
"""app.ipynb
Automatically generated by Colab.
Original file is located at
https://colab.research.google.com/drive/1Yo-pZqBc-DxiTzP9TyKKFInBqeeQrlTb
"""
import os
import json
import asyncio
from datetime import datetime
from typing import Dict, List, Any
import streamlit as st
from helper import ChatBot, current_year, save_to_audio, invoke_duckduckgo_news_search
# ============================ FRONT-END SETUP ============================
st.set_page_config(layout="wide") # Set Streamlit layout to wide mode
st.title("SearchBot π€") # App title
# ============================ SIDEBAR SETTINGS ============================
with st.sidebar:
with st.expander("π Instruction Manual"):
st.markdown(
"""
## π§ SearchBot π€ - Your AI-Powered Research Assistant
Welcome to **SearchBot**, an advanced AI assistant that helps you find the latest news, trends, and information
across various sources.
### πΉ How to Use:
1. **π Choose Search Source**
- Select the type of search (News, Research Papers, Web Articles).
2. **π Choose Number of Results**
- Decide how many results you want (1 to 10).
3. **π Set Location**
- Customize search results based on location.
*(e.g., "us-en" for USA, "in-en" for India)*
4. **β³ Filter by Time**
- Search for the most recent news or past articles:
- **Past Day** π (Breaking News)
- **Past Week** π (Trending Topics)
- **Past Month** π
(Major Stories)
- **Past Year** οΏ½οΏ½οΏ½οΏ½ (Deep Research)
5. **π¬ Review Search Results & Chat History**
- View results in an interactive table.
- Chatbot provides summarized responses with references.
---
### πΉ Live Examples You Can Try:
**π° Find Latest News**
- *"What are the latest AI breakthroughs?"*
- *"Recent developments in space exploration."*
**π Research Papers & Analysis**
- *"Most cited papers on quantum computing."*
- *"Deep learning advancements in 2024."*
**π Location-Based Information**
- *"Tech news in Silicon Valley."*
- *"Political updates in the UK."*
**β‘ AI-Powered Chatbot Insights**
- *"Summarize recent news on cryptocurrency."*
- *"Give me top AI news from last week with analysis."*
"""
)
# User inputs for search customization
num: int = st.number_input("π Number of results", value=7, step=1, min_value=1, max_value=10)
location: str = st.text_input("π Location (e.g., us-en, in-en)", value="us-en")
time_filter: str = st.selectbox(
"β³ Time filter",
["Past Day", "Past Week", "Past Month", "Past Year"],
index=1
)
# Convert time filter to DuckDuckGo-compatible format
time_mapping: Dict[str, str] = {"Past Day": "d", "Past Week": "w", "Past Month": "m", "Past Year": "y"}
time_filter = time_mapping[time_filter]
only_use_chatbot: bool = st.checkbox("π¬ Only use chatbot (Disable Search)")
# Clear chat history button
if st.button("π§Ή Clear Session"):
st.session_state.messages = []
st.rerun()
# Footer with dynamic year
st.markdown(f"<h6>π
Copyright Β© 2010-{current_year()} Present</h6>", unsafe_allow_html=True)
# ============================ CHAT HISTORY SETUP ============================
# Initialize chat history
if "messages" not in st.session_state:
st.session_state.messages: List[Dict[str, str]] = []
# Ensure messages are always a list of dictionaries
if not isinstance(st.session_state.messages, list) or not all(isinstance(msg, dict) for msg in st.session_state.messages):
st.session_state.messages = []
# Display past chat history in Streamlit chat UI
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
# ============================ CHAT INPUT & PROCESSING ============================
# Process user input in the chatbox
if prompt := st.chat_input("Ask anything!"):
st.chat_message("user").markdown(prompt)
st.session_state.messages.append({"role": "user", "content": prompt})
# **Initialize ref_table_string to hold search results**
ref_table_string: str = "**No references found.**"
try:
with st.spinner("Searching..."): # Show loading spinner
if only_use_chatbot:
response: str = "<empty>"
else:
# **Call async search function using `asyncio.run()`**
search_results: Dict[str, Any] = asyncio.run(
invoke_duckduckgo_news_search(query=prompt, location=location, num=num, time_filter=time_filter)
)
if search_results["status"] == "success":
md_data: List[Dict[str, Any]] = search_results["results"]
response = f"Here are your search results:\n{md_data}"
def clean_title(title: str) -> str:
"""
Cleans the title by replacing '|' with '-' to ensure proper formatting.
Args:
title (str): The original title.
Returns:
str: The cleaned title with '|' replaced by '-'.
"""
return title.replace("|", " - ").strip() # Replace '|' with ' - ' and remove leading/trailing spaces
def generate_star_rating(rating: str) -> str:
"""
Converts a numeric rating into a star representation (supports half-stars).
Args:
rating (str): The rating value as a string.
Returns:
str: A string representation of the rating using stars (β) and half-stars (βΒ½).
"""
try:
rating_float: float = float(rating) # Convert rating to float
full_stars: int = int(rating_float) # Extract full stars
half_star: str = "βΒ½" if (rating_float - full_stars) >= 0.5 else "" # Add half-star if needed
return "β" * full_stars + half_star # Construct final star rating
except ValueError:
return "N/A" # Fallback for non-numeric ratings
# Start building reference table with proper Markdown formatting
ref_table_string = "| Num | Title | Rating | Context |\n|---|------|--------|---------|\n"
for res in md_data:
# **Fix: Clean the title by replacing '|' with '-'**
title_cleaned = clean_title(res['title'])
# **Ensure the rating is always numeric before converting to stars**
raw_rating = str(res.get('rating', 'N/A')).strip() # Get rating and strip whitespace
# Fix: Only convert rating if itβs a valid number
if raw_rating.replace('.', '', 1).isdigit(): # Check if itβs a valid float
stars = generate_star_rating(raw_rating)
else:
stars = "N/A" # If it's text (like "MIT News"), default to "N/A"
# **Ensure proper clickable links in the Title column**
if res.get('link', '').startswith("http"): # Ensure link exists and is valid
title = f"[{title_cleaned}]({res['link']})"
else:
title = title_cleaned # Fallback to text-only title
# **Properly format Context column (limit to 100 chars)**
context_summary = res.get('summary', '').strip() # Ensure it's a string and strip spaces
summary = context_summary[:100] + "..." if len(context_summary) > 100 else context_summary
# **Final row construction**
ref_table_string += f"| {res['num']} | {title} | {stars} | {summary} |\n"
# **Generate chatbot response based on search results or chat history**
bot = ChatBot()
bot.history = st.session_state.messages.copy()
response = bot.generate_response(
f"""
User prompt: {prompt}
Search results: {response}
Context: {[res['summary'] for res in search_results.get("results", [])]}
If search results exist, use them for the answer.
Otherwise, generate a response based on chat history.
"""
)
except Exception as e:
st.warning(f"Error fetching data: {e}")
response = "We encountered an issue. Please try again later."
# **Convert response to audio**
save_to_audio(response)
# **Display assistant response in chat UI**
with st.chat_message("assistant"):
st.markdown(response, unsafe_allow_html=True)
st.audio("output.mp3", format="audio/mpeg", loop=True)
with st.expander("References:", expanded=True):
st.markdown(ref_table_string, unsafe_allow_html=True)
# **Update chat history with final response**
final_response: str = f"{response}\n\n{ref_table_string}"
st.session_state.messages.append({"role": "assistant", "content": final_response})
|