churnsight-ai / frontend.py
Hasitha16's picture
Update frontend.py
96c7e81 verified
raw
history blame
12.6 kB
# --- import statements remain unchanged ---
import streamlit as st
import requests
import pandas as pd
from gtts import gTTS
import base64
from io import BytesIO
from PIL import Image
import os
import plotly.express as px
# --- Config ---
st.set_page_config(page_title="NeuroPulse AI", page_icon="๐Ÿง ", layout="wide")
logo_path = "logo.png"
if os.path.exists(logo_path):
st.image(logo_path, width=180)
# --- Session State ---
if "review" not in st.session_state:
st.session_state.review = ""
if "dark_mode" not in st.session_state:
st.session_state.dark_mode = False
if "intelligence_mode" not in st.session_state:
st.session_state.intelligence_mode = True
if "trigger_example_analysis" not in st.session_state:
st.session_state.trigger_example_analysis = False
# --- Dark Mode Styling ---
if st.session_state.dark_mode:
st.markdown("""
<style>
html, body, [class*="st-"] {
background-color: #121212;
color: #f5f5f5;
}
.stTextInput > div > div > input,
.stTextArea > div > textarea,
.stSelectbox div div,
.stDownloadButton > button,
.stButton > button {
background-color: #1e1e1e;
color: white;
}
</style>
""", unsafe_allow_html=True)
# --- Sidebar ---
with st.sidebar:
st.header("โš™๏ธ Global Settings")
st.session_state.dark_mode = st.toggle("๐ŸŒ™ Dark Mode", value=st.session_state.dark_mode)
st.session_state.intelligence_mode = st.toggle("๐Ÿง  Intelligence Mode", value=st.session_state.intelligence_mode)
DEFAULT_DEMO_TOKEN = "my-secret-key"
api_token = st.text_input("๐Ÿ” API Token", value=DEFAULT_DEMO_TOKEN, type="password")
if not api_token or api_token.strip() == "my-secret-key":
st.warning("๐Ÿงช Running in demo mode โ€” for full access, enter a valid API key.")
backend_url = st.text_input("๐ŸŒ Backend URL", value="http://localhost:8000")
sentiment_model = st.selectbox("๐Ÿ“Š Sentiment Model", [
"distilbert-base-uncased-finetuned-sst-2-english",
"nlptown/bert-base-multilingual-uncased-sentiment"
])
industry = st.selectbox("๐Ÿญ Industry", [
"Auto-detect", "Generic", "E-commerce", "Healthcare", "Education", "Travel", "Banking", "Insurance",
"Gaming", "Food Delivery", "Real Estate", "Fitness", "Entertainment"
])
product_category = st.selectbox("๐Ÿงฉ Product Category", [
"Auto-detect", "General", "Mobile Devices", "Laptops", "Healthcare Devices", "Banking App",
"Travel Service", "Educational Tool", "Insurance Portal", "Streaming App", "Wearables",
"Home Appliances", "Food Apps"
])
use_aspects = st.checkbox("๐Ÿ”ฌ Enable Aspect Analysis")
use_smart_summary = st.checkbox("๐Ÿง  Smart Summary (Single)")
use_smart_summary_bulk = st.checkbox("๐Ÿง  Smart Summary for Bulk")
use_explain_bulk = st.checkbox("๐Ÿง  Generate Explanations (Bulk)")
verbosity = st.radio("๐Ÿ—ฃ๏ธ Response Style", ["Brief", "Detailed"])
voice_lang = st.selectbox("๐Ÿ”ˆ Voice Language", ["en", "fr", "es", "de", "hi", "zh"])
# --- TTS ---
def speak(text, lang='en'):
tts = gTTS(text, lang=lang)
mp3 = BytesIO()
tts.write_to_fp(mp3)
b64 = base64.b64encode(mp3.getvalue()).decode()
st.markdown(f'<audio controls><source src="data:audio/mp3;base64,{b64}" type="audio/mp3"></audio>', unsafe_allow_html=True)
mp3.seek(0)
return mp3
# --- Tabs ---
tab1, tab2 = st.tabs(["๐Ÿง  Single Review", "๐Ÿ“š Bulk CSV"])
# -------------------
# SINGLE REVIEW TAB
# -------------------
with tab1:
st.title("๐Ÿง  NeuroPulse AI โ€“ Multimodal Review Analyzer")
st.markdown("<div style='font-size:16px;color:#888;'>Minimum 20โ€“50 words recommended.</div>", unsafe_allow_html=True)
review = st.text_area("๐Ÿ“ Enter Review", value=st.session_state.review, height=180)
col1, col2, col3 = st.columns(3)
with col1:
analyze = st.button("๐Ÿ” Analyze", use_container_width=True, disabled=not api_token)
with col2:
if st.button("๐ŸŽฒ Example", use_container_width=True):
st.session_state.review = (
"I love this phone! Super fast performance, great battery, and smooth UI. "
"Camera is awesome too, though the price is a bit high. Overall, very happy."
)
st.session_state.trigger_example_analysis = True
st.rerun()
with col3:
if st.button("๐Ÿงน Clear", use_container_width=True):
st.session_state.review = ""
st.rerun()
if st.session_state.trigger_example_analysis and st.session_state.review:
analyze = True
st.session_state.trigger_example_analysis = False
if analyze and review:
if len(review.split()) < 20:
st.warning("โš ๏ธ Please enter at least 20 words.")
else:
with st.spinner("Analyzing..."):
try:
payload = {
"text": review,
"model": sentiment_model,
"industry": industry,
"aspects": use_aspects,
"follow_up": None,
"product_category": product_category,
"verbosity": verbosity,
"intelligence": st.session_state.intelligence_mode,
"explain": True
}
headers = {"x-api-key": st.session_state.get("api_token", api_token)}
params = {"smart": "1"} if use_smart_summary else {}
res = requests.post(f"{backend_url}/analyze/", json=payload, headers=headers, params=params)
if res.status_code == 200:
data = res.json()
st.success("โœ… Analysis Complete")
st.subheader("๐Ÿ“Œ Summary")
st.info(data["summary"])
st.caption(f"๐Ÿง  Summary Type: {'Smart' if use_smart_summary else 'Standard'} | {verbosity} Response")
st.markdown(f"**Context:** `{data['industry']}` | `{data['product_category']}` | `Web`")
st.subheader("๐Ÿ”Š Audio")
audio = speak(data["summary"], lang=voice_lang)
st.download_button("โฌ‡๏ธ Download Summary Audio", audio.read(), "summary.mp3", mime="audio/mp3")
st.metric("๐Ÿ“Š Sentiment", data["sentiment"]["label"], delta=f"{data['sentiment']['score']:.2%}")
st.info(f"๐Ÿ’ข Emotion: {data['emotion']}")
if data.get("explanation"):
st.subheader("๐Ÿงฎ Explanation")
st.markdown(data["explanation"])
st.markdown("### ๐Ÿ” Got questions?")
st.info("๐Ÿ’ฌ Ask a follow-up question about this review.")
sample_questions = [
"What did the user like most?",
"Any complaints mentioned?",
"Is it positive overall?",
"What are the improvement areas?"
]
selected_q = st.selectbox("๐Ÿ’ก Sample Questions", ["Type your own..."] + sample_questions)
custom_q = st.text_input("๐Ÿ” Ask a follow-up", value="" if selected_q == "Type your own..." else selected_q)
if custom_q:
with st.spinner("Thinking..."):
payload["follow_up"] = custom_q
res = requests.post(f"{backend_url}/analyze/", json=payload, headers=headers, params=params)
if res.status_code == 200:
follow = res.json().get("follow_up")
if follow:
st.subheader("๐Ÿ” Follow-Up Answer")
if isinstance(follow, list):
for q in follow:
st.write("โžก๏ธ", q)
else:
st.warning(follow)
else:
st.error(f"โŒ Follow-up failed: {res.json().get('detail')}")
else:
st.error(f"โŒ API Error {res.status_code}: {res.json().get('detail', 'Unknown error')}")
except Exception as e:
st.error(f"๐Ÿšซ Exception occurred: {e}")
# -------------------
# BULK CSV TAB
# -------------------
with tab2:
st.title("๐Ÿ“š Bulk CSV Upload")
st.markdown("""
Upload a CSV with the following columns:<br>
<code>review</code> (required), <code>industry</code>, <code>product_category</code>, <code>device</code>, <code>follow_up</code> (optional)
""", unsafe_allow_html=True)
with st.expander("๐Ÿ“„ Sample CSV"):
with open("sample_reviews.csv", "rb") as f:
st.download_button("โฌ‡๏ธ Download sample CSV", f, file_name="sample_reviews.csv")
uploaded_file = st.file_uploader("๐Ÿ“ Upload your CSV", type="csv")
if uploaded_file:
if not api_token:
st.error("๐Ÿ” Please enter your API token in the sidebar.")
else:
try:
df = pd.read_csv(uploaded_file)
if "review" not in df.columns:
st.error("CSV must contain a `review` column.")
else:
st.success(f"โœ… Loaded {len(df)} reviews")
for col in ["industry", "product_category", "device", "follow_up"]:
if col not in df.columns:
df[col] = ["Auto-detect"] * len(df)
df[col] = df[col].fillna("Auto-detect").astype(str)
df["industry"] = df["industry"].apply(lambda x: "Generic" if x.lower() == "auto-detect" else x)
df["product_category"] = df["product_category"].apply(lambda x: "General" if x.lower() == "auto-detect" else x)
df["device"] = df["device"].apply(lambda x: "Web" if x.lower() == "auto-detect" else x)
if st.button("๐Ÿ“Š Analyze Bulk Reviews", use_container_width=True):
with st.spinner("Processing..."):
try:
payload = {
"reviews": df["review"].tolist(),
"model": sentiment_model,
"aspects": use_aspects,
"industry": df["industry"].tolist(),
"product_category": df["product_category"].tolist(),
"device": df["device"].tolist(),
"follow_up": df["follow_up"].tolist(),
"explain": use_explain_bulk,
"intelligence": st.session_state.intelligence_mode,
}
res = requests.post(
f"{backend_url}/bulk/?token={st.session_state.get('api_token', api_token)}",
json=payload
)
if res.status_code == 200:
results = pd.DataFrame(res.json()["results"])
st.dataframe(results)
if "sentiment" in results.columns:
fig = px.pie(results, names="sentiment", title="Sentiment Distribution")
st.plotly_chart(fig)
st.download_button("โฌ‡๏ธ Download Results CSV", results.to_csv(index=False), "results.csv", mime="text/csv")
else:
st.error(f"โŒ Bulk Error {res.status_code}: {res.json().get('detail', 'Unknown error')}")
except Exception as e:
st.error(f"๐Ÿšจ Processing Error: {e}")
except Exception as e:
st.error(f"โŒ File Read Error: {e}")