Spaces:
Sleeping
Sleeping
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 | |
st.set_page_config(page_title="NeuroPulse AI", page_icon="π§ ", layout="wide") | |
# Optional logo | |
logo_path = os.path.join("app", "static", "logo.png") | |
if os.path.exists(logo_path): | |
st.image(logo_path, width=160) | |
# Session state | |
if "page" not in st.session_state: | |
st.session_state.page = "Home" | |
if "review" not in st.session_state: | |
st.session_state.review = "" | |
# Navigation | |
with st.sidebar: | |
st.title("π§ Navigation") | |
st.session_state.page = st.radio("Go to", ["Home", "Single Review", "Bulk CSV"]) | |
# Text-to-speech | |
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 | |
# Page: Home | |
if st.session_state.page == "Home": | |
st.markdown(""" | |
<div style='text-align: center;'> | |
<h1 style='font-size: 48px;'>π§ NeuroPulse AI</h1> | |
<p style='font-size: 20px;'>Smarter feedback analyzer using GenAI for Summarization, Sentiment, Emotion, Aspects, and GPT Q&A</p> | |
<a href='https://huggingface.co/spaces/your-space-name' target='_blank' style='text-decoration: none;'> | |
<button style='padding: 12px 30px; font-size: 18px; border-radius: 8px; background: linear-gradient(90deg, #6366f1, #4f46e5); color: white; border: none;'>π Try App</button> | |
</a> | |
</div> | |
""", unsafe_allow_html=True) | |
# Page: Single Review | |
elif st.session_state.page == "Single Review": | |
st.title("π§ Analyze Single Review") | |
with st.expander("βοΈ Settings"): | |
sentiment_model = st.selectbox("Sentiment Model", [ | |
"distilbert-base-uncased-finetuned-sst-2-english", | |
"nlptown/bert-base-multilingual-uncased-sentiment"]) | |
industry = st.selectbox("Industry", ["Generic", "E-commerce", "Healthcare"]) | |
product_category = st.text_input("Product Category", "General") | |
device = st.text_input("Device", "Web") | |
use_aspects = st.checkbox("Enable Aspect Analysis") | |
use_smart = st.checkbox("Use Smart Summary") | |
follow_up = st.text_input("Follow-up Question") | |
voice_lang = st.selectbox("Voice Language", ["en", "fr", "es"]) | |
backend_url = st.text_input("Backend URL", "http://0.0.0.0:8000") | |
api_token = st.text_input("API Token", type="password") | |
st.session_state.review = st.text_area("π Enter your review", value=st.session_state.review, height=160) | |
if st.button("π Analyze") and st.session_state.review: | |
with st.spinner("Analyzing..."): | |
payload = { | |
"text": st.session_state.review, | |
"model": sentiment_model, | |
"industry": industry, | |
"aspects": use_aspects, | |
"follow_up": follow_up, | |
"product_category": product_category, | |
"device": device | |
} | |
headers = {"X-API-Key": api_token} | |
params = {"smart": "1"} if use_smart else {} | |
res = requests.post(f"{backend_url}/analyze/", json=payload, headers=headers, params=params) | |
if res.status_code == 200: | |
out = res.json() | |
st.success("β Done") | |
st.markdown(f"### π Summary\n{out['summary']}") | |
st.caption(f"Smart Summary: {use_smart}") | |
audio = speak(out["summary"], lang=voice_lang) | |
st.download_button("β¬οΈ Download Audio", audio.read(), "summary.mp3") | |
st.metric("π Sentiment", out['sentiment']['label'], f"{out['sentiment']['score']:.2%}") | |
st.info(f"π’ Emotion: {out['emotion']}") | |
if out.get("aspects"): | |
st.markdown("### π Aspects") | |
for asp in out["aspects"]: | |
st.write(f"- {asp['aspect']}: {asp['sentiment']} ({asp['score']:.2%})") | |
if out.get("follow_up"): | |
st.warning(f"π§ GPT: {out['follow_up']}") | |
else: | |
st.error(f"β Error: {res.status_code}") | |
# Page: Bulk CSV | |
elif st.session_state.page == "Bulk CSV": | |
st.title("π Analyze CSV in Bulk") | |
uploaded_file = st.file_uploader("Upload CSV with `review` column", type="csv") | |
if uploaded_file: | |
df = pd.read_csv(uploaded_file) | |
if "review" not in df.columns: | |
st.error("CSV must have a 'review' column") | |
else: | |
st.success(f"β {len(df)} reviews loaded") | |
df.fillna("", inplace=True) | |
if st.button("π Run Bulk Analysis"): | |
with st.spinner("Running..."): | |
payload = { | |
"reviews": df["review"].tolist(), | |
"model": sentiment_model, | |
"industry": df["industry"].tolist() if "industry" in df else ["Generic"]*len(df), | |
"product_category": df["product_category"].tolist() if "product_category" in df else [""]*len(df), | |
"device": df["device"].tolist() if "device" in df else [""]*len(df), | |
"aspects": use_aspects | |
} | |
headers = {"X-API-Key": api_token} | |
params = {"smart": "1"} if use_smart else {} | |
res = requests.post(f"{backend_url}/bulk/", json=payload, headers=headers, params=params) | |
if res.status_code == 200: | |
results = pd.DataFrame(res.json()["results"]) | |
st.dataframe(results) | |
st.download_button("β¬οΈ Download CSV", results.to_csv(index=False), "results.csv") | |
else: | |
st.error(f"β Failed: {res.status_code}") | |
with st.expander("π Sample CSV"): | |
st.markdown(""" | |
Download sample CSV [here](https://huggingface.co/datasets/hasi-labs/sample-neuropulse-csv/raw/main/sample.csv) | |
Required column: `review` (Optional: `industry`, `product_category`, `device`) | |
""") | |