# --- 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(""" """, 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'', 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("
Minimum 20โ€“50 words recommended.
", 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:
review (required), industry, product_category, device, follow_up (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}")