Spaces:
Running
Running
import streamlit as st | |
from chatbot import setup_db, fetch_reddit_data, get_chatbot_response, get_db_conn | |
import json | |
import re | |
from urllib.parse import urlparse | |
# Helper function to remove image URLs from text. | |
def remove_image_urls(text): | |
# Regex pattern to remove URLs that end with typical image extensions. | |
image_url_pattern = r'https?://\S+\.(?:png|jpg|jpeg|webp)\S*' | |
return re.sub(image_url_pattern, '', text) | |
# Initialize DB and configure Streamlit | |
setup_db() | |
st.set_page_config(layout="wide") | |
st.title("π Reddit Intelligent Chatbot") | |
# Use session state to store selected post ID for chat context | |
if 'selected_post_id' not in st.session_state: | |
st.session_state['selected_post_id'] = None | |
# Sidebar: Enter keyword and fetch data | |
with st.sidebar: | |
st.header("π Fetch Reddit Data") | |
keyword = st.text_input("Enter keyword/topic:") | |
days = st.slider("Days range:", 1, 90, 7) | |
if st.button("Fetch Data"): | |
fetch_reddit_data(keyword, days=days) | |
st.success("Data fetched!") | |
st.session_state['selected_post_id'] = None # Reset selected post on new fetch | |
# Create two columns: Chat area (left) and Posts display (right) | |
chat_col, posts_col = st.columns([3, 2]) | |
# RIGHT SIDE: Display fetched posts with resource-gather style card layout. | |
with posts_col: | |
st.subheader("π Reddit Posts") | |
if keyword.strip(): | |
conn = get_db_conn() | |
cur = conn.cursor() | |
cur.execute(""" | |
SELECT reddit_id, title, post_text, comments, metadata, created_at | |
FROM reddit_posts | |
WHERE keyword = ? | |
ORDER BY datetime(created_at) DESC; | |
""", (keyword,)) | |
posts = cur.fetchall() | |
cur.close() | |
conn.close() | |
if posts: | |
# Set up custom CSS for the card layout. | |
st.markdown( | |
""" | |
<style> | |
.post-card { | |
border: 1px solid #ddd; | |
padding: 10px; | |
margin-bottom: 20px; | |
border-radius: 8px; | |
background-color: #f9f9f9; | |
} | |
.post-title { | |
font-size: 14px; | |
font-weight: bold; | |
margin-bottom: 5px; | |
} | |
.post-snippet { | |
font-size: 12px; | |
color: #444; | |
margin-bottom: 8px; | |
} | |
.post-meta { | |
font-size: 11px; | |
color: #777; | |
margin-bottom: 5px; | |
} | |
.reddit-logo { | |
width: 24px; | |
vertical-align: middle; | |
margin-right: 8px; | |
} | |
</style> | |
""", unsafe_allow_html=True) | |
for post in posts: | |
reddit_id, title, post_text, comments, metadata, created_at = post | |
try: | |
comments_list = json.loads(comments) if isinstance(comments, str) else comments | |
except Exception: | |
comments_list = comments | |
# Convert metadata from JSON string to dict | |
try: | |
metadata = json.loads(metadata) if isinstance(metadata, str) else metadata | |
except Exception as e: | |
metadata = {} | |
post_url = metadata.get('url', "#") | |
subreddit = metadata.get('subreddit', 'N/A') | |
created_str = created_at.strftime('%Y-%m-%d %H:%M:%S') | |
# Remove image URLs from post_text so that they don't show up in the snippet. | |
cleaned_text = remove_image_urls(post_text) | |
snippet = cleaned_text[:200] + ("..." if len(cleaned_text) > 200 else "") | |
# Build the card using HTML. The title itself is a clickable link. | |
card_html = f""" | |
<div class="post-card"> | |
<div style="display: flex; align-items: center;"> | |
<a href="{post_url}" target="_blank" style="font-size: 14px; font-weight: bold; color: blue;">{title}</a> | |
</div> | |
<div class="post-meta"> | |
Subreddit: {metadata.get('subreddit','N/A')} <br> Created: {created_str} | |
</div> | |
<div class="post-snippet"> | |
{snippet} | |
</div> | |
</div> | |
""" | |
st.markdown(card_html, unsafe_allow_html=True) | |
# Expander for comments preview (first 3 comments) | |
with st.expander("Show Comments Preview"): | |
if comments_list: | |
for idx, comment in enumerate(comments_list[:3], start=1): | |
st.write(f"{idx}. {comment[:100]}{'...' if len(comment) > 100 else ''}") | |
else: | |
st.info("No comments available.") | |
# Button to select this post for chat context | |
if st.button("Chat with this Post", key=reddit_id): | |
st.session_state['selected_post_id'] = reddit_id | |
st.success("Post selected for chat!") | |
st.markdown("---") | |
else: | |
st.info("No posts found. Please fetch data using the sidebar.") | |
else: | |
st.info("Please enter a keyword and fetch data from the sidebar.") | |
# LEFT SIDE: Chatbot Interaction Area | |
with chat_col: | |
st.subheader("π¬ Chat with AI") | |
question = st.text_area("Enter your question:", height=150) | |
context_choice = st.radio("Chat Context:", ["All Posts", "Selected Post"]) | |
reddit_id = st.session_state['selected_post_id'] if context_choice == "Selected Post" else None | |
if st.button("Get Response"): | |
if not keyword.strip(): | |
st.warning("Please enter a keyword/topic and fetch data first.") | |
elif not question.strip(): | |
st.warning("Please enter your question.") | |
else: | |
with st.spinner("Generating response..."): | |
response, _ = get_chatbot_response(question, keyword, reddit_id) | |
st.markdown("**Chatbot Response:**") | |
st.write(response) | |