Hasitha16 commited on
Commit
05dad7c
Β·
verified Β·
1 Parent(s): 63a3c84

Update frontend.py

Browse files
Files changed (1) hide show
  1. frontend.py +80 -112
frontend.py CHANGED
@@ -9,10 +9,10 @@ import plotly.express as px
9
  from datetime import datetime
10
  import uuid
11
 
12
- # Simulated in-memory storage for churn log (replace with a database or file in production)
13
  if "churn_log" not in st.session_state:
14
  st.session_state.churn_log = []
15
-
16
  st.set_page_config(page_title="ChurnSight AI", page_icon="🧠", layout="wide")
17
 
18
  if os.path.exists("logo.png"):
@@ -39,34 +39,17 @@ if st.session_state.dark_mode:
39
  background-color: #121212;
40
  color: #f5f5f5;
41
  }
42
- .stTextInput > div > div > input,
43
- .stTextArea > div > textarea,
44
- .stSelectbox div div,
45
- .stDownloadButton > button,
46
- .stButton > button {
47
- background-color: #1e1e1e;
48
- color: white;
49
- }
50
  </style>
51
  """, unsafe_allow_html=True)
52
 
53
- # Sidebar
54
  with st.sidebar:
55
  st.header("βš™οΈ PM Config")
56
  st.session_state.dark_mode = st.toggle("πŸŒ™ Dark Mode", value=st.session_state.dark_mode)
57
  st.session_state.intelligence_mode = st.toggle("🧠 Intelligence Mode", value=st.session_state.intelligence_mode)
58
-
59
  api_token = st.text_input("πŸ” API Token", value="my-secret-key", type="password")
60
- if not api_token or api_token.strip() == "my-secret-key":
61
- st.warning("πŸ§ͺ Demo Mode β€” Not all features active.")
62
-
63
  backend_url = st.text_input("🌐 Backend URL", value="http://localhost:8000")
64
-
65
- sentiment_model = st.selectbox("πŸ“Š Sentiment Model", [
66
- "Auto-detect",
67
- "distilbert-base-uncased-finetuned-sst-2-english",
68
- "nlptown/bert-base-multilingual-uncased-sentiment"
69
- ])
70
  industry = st.selectbox("🏭 Industry", ["Auto-detect", "Generic", "E-commerce", "Healthcare", "Education"])
71
  product_category = st.selectbox("🧩 Product Category", ["Auto-detect", "General", "Mobile Devices", "Laptops"])
72
  use_aspects = st.checkbox("πŸ” Detect Pain Points")
@@ -74,7 +57,7 @@ with st.sidebar:
74
  verbosity = st.radio("πŸ—£οΈ Response Style", ["Brief", "Detailed"])
75
  voice_lang = st.selectbox("πŸ”ˆ Voice Language", ["en", "fr", "es", "de", "hi", "zh"])
76
 
77
- # TTS
78
  def speak(text, lang='en'):
79
  tts = gTTS(text, lang=lang)
80
  mp3 = BytesIO()
@@ -86,40 +69,34 @@ def speak(text, lang='en'):
86
 
87
  tab1, tab2 = st.tabs(["🧠 Analyze Review", "πŸ“š Bulk Reviews"])
88
 
89
- # === SINGLE REVIEW ===
90
  with tab1:
91
  st.title("πŸ“Š ChurnSight AI β€” Product Feedback Assistant")
92
  st.markdown("Analyze feedback to detect churn risk, extract pain points, and support product decisions.")
93
-
94
  review = st.text_area("πŸ“ Enter Customer Feedback", value=st.session_state.review, height=180)
95
  st.session_state.review = review
96
 
97
  col1, col2, col3 = st.columns(3)
98
- with col1:
99
- analyze = st.button("πŸ” Analyze")
100
- with col2:
101
- if st.button("🎲 Example"):
102
- st.session_state.review = (
103
- "The app crashes every time I try to checkout. It's so slow and unresponsive. "
104
- "Customer support never replied. I'm switching to another brand."
105
- )
106
- st.session_state.trigger_example_analysis = True
107
- st.rerun()
108
- with col3:
109
- if st.button("🧹 Clear"):
110
- for key in ["review", "last_response", "followup_answer"]:
111
- st.session_state[key] = ""
112
- st.rerun()
113
-
114
- if (analyze or st.session_state.trigger_example_analysis) and st.session_state.review:
115
  st.session_state.trigger_example_analysis = False
116
- st.session_state.followup_answer = None
 
 
 
 
 
 
 
 
 
 
 
 
117
  with st.spinner("Analyzing feedback..."):
118
  try:
119
- model = None if sentiment_model == "Auto-detect" else sentiment_model
120
  payload = {
121
  "text": st.session_state.review,
122
- "model": model or "distilbert-base-uncased-finetuned-sst-2-english",
123
  "industry": industry,
124
  "product_category": product_category,
125
  "verbosity": verbosity,
@@ -128,10 +105,10 @@ with tab1:
128
  }
129
  headers = {"x-api-key": api_token}
130
  res = requests.post(f"{backend_url}/analyze/", json=payload, headers=headers)
131
- if res.status_code == 200:
132
  st.session_state.last_response = res.json()
133
  else:
134
- st.error(f"API error: {res.status_code} - {res.json().get('detail')}")
135
  except Exception as e:
136
  st.error(f"🚫 Exception: {e}")
137
 
@@ -139,19 +116,17 @@ with tab1:
139
  if data:
140
  st.subheader("πŸ“Œ PM Insight Summary")
141
  st.info(data["summary"])
142
- st.caption("πŸ”Ž Summary Model: facebook/bart-large-cnn | " + verbosity + " response")
143
  st.markdown(f"**Industry:** `{data['industry']}` | **Category:** `{data['product_category']}` | **Device:** Web")
144
-
145
  st.metric("πŸ“Š Sentiment", data["sentiment"]["label"], delta=f"{data['sentiment']['score']:.2%}")
146
  st.info(f"πŸ’’ Emotion: {data['emotion']}")
147
  if "churn_risk" in data:
148
  risk = data["churn_risk"]
149
  color = "πŸ”΄" if risk == "High Risk" else "🟒"
150
  st.metric("🚨 Churn Risk", f"{color} {risk}")
151
-
152
- if "pain_points" in data and data["pain_points"]:
153
  st.error("πŸ” Pain Points: " + ", ".join(data["pain_points"]))
154
- # Add churn risk to session log
 
155
  try:
156
  st.session_state.churn_log.append({
157
  "timestamp": datetime.now(),
@@ -159,9 +134,8 @@ with tab1:
159
  "churn_risk": data.get("churn_risk", "Unknown"),
160
  "session_id": str(uuid.uuid4())
161
  })
162
- # Keep log lightweight
163
- if len(st.session_state.churn_log) > 1000:
164
- st.session_state.churn_log = st.session_state.churn_log[-1000:]
165
  except Exception as e:
166
  st.warning(f"πŸ§ͺ Logging failed: {e}")
167
 
@@ -170,66 +144,60 @@ with tab1:
170
  st.download_button("⬇️ Download Audio", audio.read(), "summary.mp3")
171
 
172
  st.markdown("### πŸ” Ask a Follow-Up")
173
-
174
- # πŸ’‘ Smarter Follow-Up Suggestion Logic
175
  sentiment = data["sentiment"]["label"].lower()
176
  churn = data.get("churn_risk", "")
177
  pain = data.get("pain_points", [])
178
-
179
  if sentiment == "positive" and churn == "Low Risk":
180
- sample_questions = [
181
- "What features impressed the user?",
182
- "Would they recommend the product?",
183
- "What delighted the customer most?"
184
- ]
185
- elif sentiment == "negative" or churn == "High Risk" or pain:
186
- sample_questions = [
187
- "What made the user upset?",
188
- "Any feature complaints?",
189
- "Is this user likely to churn?"
190
- ]
191
  else:
192
- sample_questions = [
193
- "What are the key takeaways?",
194
- "How can this review guide product changes?",
195
- "Is there any concern raised?"
196
- ]
197
-
198
-
199
- selected_q = st.selectbox("πŸ’‘ Suggested Questions", ["Type your own..."] + sample_questions)
200
- custom_q = selected_q if selected_q != "Type your own..." else st.text_input("πŸ” Follow-up Question")
201
-
202
- if custom_q:
203
- with st.spinner("Thinking..."):
204
- try:
205
- follow_payload = {
206
- "text": st.session_state.review,
207
- "question": custom_q,
208
- "verbosity": verbosity
209
- }
210
- headers = {"x-api-key": api_token}
211
- res = requests.post(f"{backend_url}/followup/", json=follow_payload, headers=headers)
212
- if res.status_code == 200:
213
- st.session_state.followup_answer = res.json().get("answer")
214
- else:
215
- st.error(f"❌ Follow-up failed: {res.json().get('detail')}")
216
- except Exception as e:
217
- st.error(f"⚠️ Follow-up error: {e}")
218
-
219
- if st.session_state.followup_answer:
220
- st.subheader("βœ… Answer")
221
- st.success(st.session_state.followup_answer)
222
- # πŸ“ˆ Show churn trend chart (optional)
223
- if st.checkbox("πŸ“Š Show Churn Risk Trends", value=False):
224
- try:
225
- df = pd.DataFrame(st.session_state.churn_log)
226
- df["date"] = pd.to_datetime(df["timestamp"]).dt.date
227
- trend = df.groupby(["date", "churn_risk"]).size().unstack(fill_value=0).reset_index()
228
-
229
- st.markdown("#### πŸ“… Daily Churn Trend")
230
- fig = px.bar(trend, x="date", y=["High Risk", "Low Risk"], barmode="group", title="Daily Churn Risk Distribution")
231
- st.plotly_chart(fig, use_container_width=True)
232
-
233
- st.download_button("⬇️ Export Trend CSV", trend.to_csv(index=False), "churn_trend.csv", mime="text/csv")
234
- except Exception as e:
235
- st.error(f"❌ Failed to generate trend: {e}")
 
 
 
 
 
 
9
  from datetime import datetime
10
  import uuid
11
 
12
+ # Simulated in-memory storage for churn log
13
  if "churn_log" not in st.session_state:
14
  st.session_state.churn_log = []
15
+
16
  st.set_page_config(page_title="ChurnSight AI", page_icon="🧠", layout="wide")
17
 
18
  if os.path.exists("logo.png"):
 
39
  background-color: #121212;
40
  color: #f5f5f5;
41
  }
 
 
 
 
 
 
 
 
42
  </style>
43
  """, unsafe_allow_html=True)
44
 
45
+ # Sidebar config
46
  with st.sidebar:
47
  st.header("βš™οΈ PM Config")
48
  st.session_state.dark_mode = st.toggle("πŸŒ™ Dark Mode", value=st.session_state.dark_mode)
49
  st.session_state.intelligence_mode = st.toggle("🧠 Intelligence Mode", value=st.session_state.intelligence_mode)
 
50
  api_token = st.text_input("πŸ” API Token", value="my-secret-key", type="password")
 
 
 
51
  backend_url = st.text_input("🌐 Backend URL", value="http://localhost:8000")
52
+ sentiment_model = st.selectbox("πŸ“Š Sentiment Model", ["Auto-detect", "distilbert-base-uncased-finetuned-sst-2-english"])
 
 
 
 
 
53
  industry = st.selectbox("🏭 Industry", ["Auto-detect", "Generic", "E-commerce", "Healthcare", "Education"])
54
  product_category = st.selectbox("🧩 Product Category", ["Auto-detect", "General", "Mobile Devices", "Laptops"])
55
  use_aspects = st.checkbox("πŸ” Detect Pain Points")
 
57
  verbosity = st.radio("πŸ—£οΈ Response Style", ["Brief", "Detailed"])
58
  voice_lang = st.selectbox("πŸ”ˆ Voice Language", ["en", "fr", "es", "de", "hi", "zh"])
59
 
60
+ # Text-to-Speech
61
  def speak(text, lang='en'):
62
  tts = gTTS(text, lang=lang)
63
  mp3 = BytesIO()
 
69
 
70
  tab1, tab2 = st.tabs(["🧠 Analyze Review", "πŸ“š Bulk Reviews"])
71
 
72
+ # === SINGLE REVIEW ANALYSIS ===
73
  with tab1:
74
  st.title("πŸ“Š ChurnSight AI β€” Product Feedback Assistant")
75
  st.markdown("Analyze feedback to detect churn risk, extract pain points, and support product decisions.")
 
76
  review = st.text_area("πŸ“ Enter Customer Feedback", value=st.session_state.review, height=180)
77
  st.session_state.review = review
78
 
79
  col1, col2, col3 = st.columns(3)
80
+ if col1.button("πŸ” Analyze"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  st.session_state.trigger_example_analysis = False
82
+ if col2.button("🎲 Example"):
83
+ st.session_state.review = (
84
+ "The app crashes every time I try to checkout. It's so slow and unresponsive. "
85
+ "Customer support never replied. I'm switching to another brand."
86
+ )
87
+ st.session_state.trigger_example_analysis = True
88
+ st.rerun()
89
+ if col3.button("🧹 Clear"):
90
+ for key in ["review", "last_response", "followup_answer"]:
91
+ st.session_state[key] = ""
92
+ st.rerun()
93
+
94
+ if (st.session_state.review and (st.session_state.trigger_example_analysis or st.button("Refresh"))):
95
  with st.spinner("Analyzing feedback..."):
96
  try:
 
97
  payload = {
98
  "text": st.session_state.review,
99
+ "model": sentiment_model if sentiment_model != "Auto-detect" else None,
100
  "industry": industry,
101
  "product_category": product_category,
102
  "verbosity": verbosity,
 
105
  }
106
  headers = {"x-api-key": api_token}
107
  res = requests.post(f"{backend_url}/analyze/", json=payload, headers=headers)
108
+ if res.ok:
109
  st.session_state.last_response = res.json()
110
  else:
111
+ st.error(f"Error: {res.status_code} - {res.json().get('detail')}")
112
  except Exception as e:
113
  st.error(f"🚫 Exception: {e}")
114
 
 
116
  if data:
117
  st.subheader("πŸ“Œ PM Insight Summary")
118
  st.info(data["summary"])
 
119
  st.markdown(f"**Industry:** `{data['industry']}` | **Category:** `{data['product_category']}` | **Device:** Web")
 
120
  st.metric("πŸ“Š Sentiment", data["sentiment"]["label"], delta=f"{data['sentiment']['score']:.2%}")
121
  st.info(f"πŸ’’ Emotion: {data['emotion']}")
122
  if "churn_risk" in data:
123
  risk = data["churn_risk"]
124
  color = "πŸ”΄" if risk == "High Risk" else "🟒"
125
  st.metric("🚨 Churn Risk", f"{color} {risk}")
126
+ if data.get("pain_points"):
 
127
  st.error("πŸ” Pain Points: " + ", ".join(data["pain_points"]))
128
+
129
+ # Add to churn log
130
  try:
131
  st.session_state.churn_log.append({
132
  "timestamp": datetime.now(),
 
134
  "churn_risk": data.get("churn_risk", "Unknown"),
135
  "session_id": str(uuid.uuid4())
136
  })
137
+ if len(st.session_state.churn_log) > 1000:
138
+ st.session_state.churn_log = st.session_state.churn_log[-1000:]
 
139
  except Exception as e:
140
  st.warning(f"πŸ§ͺ Logging failed: {e}")
141
 
 
144
  st.download_button("⬇️ Download Audio", audio.read(), "summary.mp3")
145
 
146
  st.markdown("### πŸ” Ask a Follow-Up")
 
 
147
  sentiment = data["sentiment"]["label"].lower()
148
  churn = data.get("churn_risk", "")
149
  pain = data.get("pain_points", [])
 
150
  if sentiment == "positive" and churn == "Low Risk":
151
+ suggestions = ["What features impressed the user?", "Would they recommend the product?"]
152
+ elif churn == "High Risk":
153
+ suggestions = ["What made the user upset?", "Is this user likely to churn?"]
 
 
 
 
 
 
 
 
154
  else:
155
+ suggestions = ["What are the key takeaways?", "Is there any concern raised?"]
156
+ selected_q = st.selectbox("πŸ’‘ Suggested Questions", ["Type your own..."] + suggestions)
157
+ q_input = st.text_input("πŸ” Your Question") if selected_q == "Type your own..." else selected_q
158
+ if q_input:
159
+ follow_payload = {"text": st.session_state.review, "question": q_input, "verbosity": verbosity}
160
+ res = requests.post(f"{backend_url}/followup/", json=follow_payload, headers=headers)
161
+ if res.ok:
162
+ st.success(res.json().get("answer"))
163
+ else:
164
+ st.error("Failed to answer.")
165
+
166
+ if st.checkbox("πŸ“Š Show Churn Risk Trends"):
167
+ try:
168
+ df = pd.DataFrame(st.session_state.churn_log)
169
+ df["date"] = pd.to_datetime(df["timestamp"]).dt.date
170
+ trend = df.groupby(["date", "churn_risk"]).size().unstack(fill_value=0).reset_index()
171
+ st.markdown("#### πŸ“… Daily Churn Trend")
172
+ fig = px.bar(trend, x="date", y=["High Risk", "Low Risk"], barmode="group")
173
+ st.plotly_chart(fig, use_container_width=True)
174
+ st.download_button("⬇️ Export Trend CSV", trend.to_csv(index=False), "churn_trend.csv")
175
+ except Exception as e:
176
+ st.error(f"Trend error: {e}")
177
+
178
+ # === BULK REVIEW ANALYSIS ===
179
+ with tab2:
180
+ st.title("πŸ“š Bulk Feedback Analysis")
181
+ bulk_input = st.text_area("πŸ“₯ Paste multiple reviews (one per line)", height=250)
182
+ if st.button("πŸš€ Analyze Bulk"):
183
+ lines = [l.strip() for l in bulk_input.strip().splitlines() if l.strip()]
184
+ payload = {
185
+ "reviews": lines,
186
+ "model": sentiment_model if sentiment_model != "Auto-detect" else None,
187
+ "industry": None,
188
+ "product_category": None,
189
+ "device": None,
190
+ "aspects": use_aspects,
191
+ "intelligence": st.session_state.intelligence_mode
192
+ }
193
+ try:
194
+ res = requests.post(f"{backend_url}/bulk/?token={api_token}", json=payload)
195
+ if res.ok:
196
+ results = res.json().get("results", [])
197
+ df = pd.DataFrame(results)
198
+ st.dataframe(df)
199
+ st.download_button("⬇️ Export Results CSV", df.to_csv(index=False), "bulk_results.csv")
200
+ else:
201
+ st.error(f"API Error: {res.status_code}")
202
+ except Exception as e:
203
+ st.error(f"Bulk analysis failed: {e}")