File size: 9,237 Bytes
fc94552
 
 
 
 
 
 
 
5224787
 
fc94552
05dad7c
5224787
 
05dad7c
8e27b3a
fc94552
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
05dad7c
fc94552
9aa56c6
fc94552
 
9da624c
90267c3
1a945f1
 
fc94552
05dad7c
fc94552
 
9aa56c6
 
fc94552
 
 
05dad7c
fc94552
 
 
 
 
 
 
 
 
9aa56c6
fc94552
05dad7c
fc94552
8e27b3a
 
9aa56c6
fc94552
 
 
05dad7c
fc94552
05dad7c
 
 
 
 
 
 
 
 
 
 
 
89fb982
9aa56c6
fc94552
 
 
0f55ff6
fc94552
 
 
 
 
 
 
 
05dad7c
fc94552
 
05dad7c
fc94552
 
 
 
 
9aa56c6
fc94552
9aa56c6
fc94552
 
33c45f1
 
 
 
05dad7c
9aa56c6
05dad7c
 
5224787
 
 
 
 
 
63a3c84
05dad7c
 
5224787
 
9aa56c6
 
fc94552
9aa56c6
fc94552
9aa56c6
68804d2
 
 
 
05dad7c
 
 
68804d2
05dad7c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0f55ff6
05dad7c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import streamlit as st
import requests
import pandas as pd
from gtts import gTTS
import base64
from io import BytesIO
import os
import plotly.express as px
from datetime import datetime
import uuid

# Simulated in-memory storage for churn log
if "churn_log" not in st.session_state:
    st.session_state.churn_log = []

st.set_page_config(page_title="ChurnSight AI", page_icon="🧠", layout="wide")

if os.path.exists("logo.png"):
    st.image("logo.png", width=180)

# Session state setup
defaults = {
    "review": "",
    "dark_mode": False,
    "intelligence_mode": True,
    "trigger_example_analysis": False,
    "last_response": None,
    "followup_answer": None
}
for k, v in defaults.items():
    if k not in st.session_state:
        st.session_state[k] = v

# Dark mode styling
if st.session_state.dark_mode:
    st.markdown("""
    <style>
    html, body, [class*="st-"] {
        background-color: #121212;
        color: #f5f5f5;
    }
    </style>
    """, unsafe_allow_html=True)

# Sidebar config
with st.sidebar:
    st.header("βš™οΈ PM Config")
    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)
    api_token = st.text_input("πŸ” API Token", value="my-secret-key", type="password")

    if api_token.strip() == "my-secret-key":
        st.warning("πŸ§ͺ Demo Mode β€” Not all features are active. Add your API token to unlock full features.")
    backend_url = st.text_input("🌐 Backend URL", value="http://localhost:8000")
    sentiment_model = st.selectbox("πŸ“Š Sentiment Model", ["Auto-detect", "distilbert-base-uncased-finetuned-sst-2-english"])
    industry = st.selectbox("🏭 Industry", ["Auto-detect", "Generic", "E-commerce", "Healthcare", "Education"])
    product_category = st.selectbox("🧩 Product Category", ["Auto-detect", "General", "Mobile Devices", "Laptops"])
    use_aspects = st.checkbox("πŸ” Detect Pain Points")
    use_explain_bulk = st.checkbox("🧠 Generate PM Insight (Bulk)")
    verbosity = st.radio("πŸ—£οΈ Response Style", ["Brief", "Detailed"])
    voice_lang = st.selectbox("πŸ”ˆ Voice Language", ["en", "fr", "es", "de", "hi", "zh"])

# 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

tab1, tab2 = st.tabs(["🧠 Analyze Review", "πŸ“š Bulk Reviews"])

# === SINGLE REVIEW ANALYSIS ===
with tab1:
    st.title("πŸ“Š ChurnSight AI β€” Product Feedback Assistant")
    st.markdown("Analyze feedback to detect churn risk, extract pain points, and support product decisions.")
    review = st.text_area("πŸ“ Enter Customer Feedback", value=st.session_state.review, height=180)
    st.session_state.review = review

    col1, col2, col3 = st.columns(3)
    if col1.button("πŸ” Analyze"):
        st.session_state.trigger_example_analysis = False
    if col2.button("🎲 Example"):
        st.session_state.review = (
            "The app crashes every time I try to checkout. It's so slow and unresponsive. "
            "Customer support never replied. I'm switching to another brand."
        )
        st.session_state.trigger_example_analysis = True
        st.rerun()
    if col3.button("🧹 Clear"):
        for key in ["review", "last_response", "followup_answer"]:
            st.session_state[key] = ""
        st.rerun()

    if st.session_state.review and (analyze or st.session_state.trigger_example_analysis):
        with st.spinner("Analyzing feedback..."):
            try:
                payload = {
                    "text": st.session_state.review,
                    "model": "distilbert-base-uncased-finetuned-sst-2-english" if sentiment_model == "Auto-detect" else sentiment_model,
                    "industry": industry,
                    "product_category": product_category,
                    "verbosity": verbosity,
                    "aspects": use_aspects,
                    "intelligence": st.session_state.intelligence_mode
                }
                headers = {"x-api-key": api_token}
                res = requests.post(f"{backend_url}/analyze/", json=payload, headers=headers)
                if res.ok:
                    st.session_state.last_response = res.json()
                else:
                    st.error(f"Error: {res.status_code} - {res.json().get('detail')}")
            except Exception as e:
                st.error(f"🚫 Exception: {e}")

    data = st.session_state.last_response
    if data:
        st.subheader("πŸ“Œ PM Insight Summary")
        st.info(data["summary"])
        st.markdown(f"**Industry:** `{data['industry']}` | **Category:** `{data['product_category']}` | **Device:** Web")
        st.metric("πŸ“Š Sentiment", data["sentiment"]["label"], delta=f"{data['sentiment']['score']:.2%}")
        st.info(f"πŸ’’ Emotion: {data['emotion']}")
        if "churn_risk" in data:
            risk = data["churn_risk"]
            color = "πŸ”΄" if risk == "High Risk" else "🟒"
            st.metric("🚨 Churn Risk", f"{color} {risk}")
        if data.get("pain_points"):
            st.error("πŸ” Pain Points: " + ", ".join(data["pain_points"]))

        # Add to churn log
        try:
            st.session_state.churn_log.append({
                "timestamp": datetime.now(),
                "product": data.get("product_category", "General"),
                "churn_risk": data.get("churn_risk", "Unknown"),
                "session_id": str(uuid.uuid4())
            })
            if len(st.session_state.churn_log) > 1000:
                st.session_state.churn_log = st.session_state.churn_log[-1000:]
        except Exception as e:
            st.warning(f"πŸ§ͺ Logging failed: {e}")

        st.subheader("πŸ”Š Audio Summary")
        audio = speak(data["summary"], lang=voice_lang)
        st.download_button("⬇️ Download Audio", audio.read(), "summary.mp3")

        st.markdown("### πŸ” Ask a Follow-Up")
        sentiment = data["sentiment"]["label"].lower()
        churn = data.get("churn_risk", "")
        pain = data.get("pain_points", [])
        if sentiment == "positive" and churn == "Low Risk":
            suggestions = ["What features impressed the user?", "Would they recommend the product?"]
        elif churn == "High Risk":
            suggestions = ["What made the user upset?", "Is this user likely to churn?"]
        else:
            suggestions = ["What are the key takeaways?", "Is there any concern raised?"]
        selected_q = st.selectbox("πŸ’‘ Suggested Questions", ["Type your own..."] + suggestions)
        q_input = st.text_input("πŸ” Your Question") if selected_q == "Type your own..." else selected_q
        if q_input:
            follow_payload = {"text": st.session_state.review, "question": q_input, "verbosity": verbosity}
            res = requests.post(f"{backend_url}/followup/", json=follow_payload, headers=headers)
            if res.ok:
                st.success(res.json().get("answer"))
            else:
                st.error("Failed to answer.")

        if st.checkbox("πŸ“Š Show Churn Risk Trends"):
            try:
                df = pd.DataFrame(st.session_state.churn_log)
                df["date"] = pd.to_datetime(df["timestamp"]).dt.date
                trend = df.groupby(["date", "churn_risk"]).size().unstack(fill_value=0).reset_index()
                st.markdown("#### πŸ“… Daily Churn Trend")
                fig = px.bar(trend, x="date", y=["High Risk", "Low Risk"], barmode="group")
                st.plotly_chart(fig, use_container_width=True)
                st.download_button("⬇️ Export Trend CSV", trend.to_csv(index=False), "churn_trend.csv")
            except Exception as e:
                st.error(f"Trend error: {e}")

# === BULK REVIEW ANALYSIS ===
with tab2:
    st.title("πŸ“š Bulk Feedback Analysis")
    bulk_input = st.text_area("πŸ“₯ Paste multiple reviews (one per line)", height=250)
    if st.button("πŸš€ Analyze Bulk"):
        lines = [l.strip() for l in bulk_input.strip().splitlines() if l.strip()]
        payload = {
            "reviews": lines,
            "model": "distilbert-base-uncased-finetuned-sst-2-english" if sentiment_model == "Auto-detect" else sentiment_model,
            "industry": None,
            "product_category": None,
            "device": None,
            "aspects": use_aspects,
            "intelligence": st.session_state.intelligence_mode
        }
        try:
            res = requests.post(f"{backend_url}/bulk/?token={api_token}", json=payload)
            if res.ok:
                results = res.json().get("results", [])
                df = pd.DataFrame(results)
                st.dataframe(df)
                st.download_button("⬇️ Export Results CSV", df.to_csv(index=False), "bulk_results.csv")
            else:
                st.error(f"API Error: {res.status_code}")
        except Exception as e:
            st.error(f"Bulk analysis failed: {e}")