DivYonko commited on
Commit
4e7e689
·
1 Parent(s): 2a149f0

Fix all broken emoji/unicode characters in sidebar and UI

Browse files
Files changed (1) hide show
  1. app.py +18 -18
app.py CHANGED
@@ -362,7 +362,7 @@ def is_scraper_running(slot_idx: int) -> bool:
362
  st.set_page_config(
363
  page_title="LivePulse",
364
  layout="wide",
365
- page_icon="??",
366
  initial_sidebar_state="expanded"
367
  )
368
 
@@ -629,7 +629,7 @@ def plotly_layout(height=280):
629
 
630
  def csv_download(df_export, label, filename):
631
  csv = df_export.to_csv(index=False).encode("utf-8")
632
- st.download_button(label=f"? {label}", data=csv,
633
  file_name=filename, mime="text/csv", key=filename)
634
 
635
 
@@ -655,17 +655,17 @@ def compute_velocity(df_all_json: str, window: int = 20) -> dict:
655
  sentiments = [m.get("sentiment", "Neutral") for m in _json.loads(df_all_json)]
656
  n = len(sentiments)
657
  if n < window * 2:
658
- return {"direction": "?", "delta": 0.0, "label": "Stable", "color": "#eab308"}
659
  recent = sentiments[-window:]
660
  prev = sentiments[-window*2:-window]
661
  r_pos = sum(1 for s in recent if s == "Positive") / window
662
  p_pos = sum(1 for s in prev if s == "Positive") / window
663
  delta = r_pos - p_pos
664
  if delta > 0.08:
665
- return {"direction": "?", "delta": delta, "label": "Rising", "color": "#22c55e"}
666
  elif delta < -0.08:
667
- return {"direction": "?", "delta": delta, "label": "Falling", "color": "#ef4444"}
668
- return {"direction": "?", "delta": delta, "label": "Stable", "color": "#eab308"}
669
 
670
 
671
  @st.cache_data(ttl=10, show_spinner=False)
@@ -733,9 +733,9 @@ def compute_engagement(all_data_json: str, window: int = 50) -> dict:
733
  rate_norm = min(rate / 60, 1.0)
734
  score = round((rate_norm * 0.4 + pos_ratio * 0.4 + q_density * 0.2) * 100)
735
 
736
- if score >= 70: grade = "?? High"
737
- elif score >= 40: grade = "? Medium"
738
- else: grade = "?? Low"
739
 
740
  return {"score": score, "rate": rate, "pos_ratio": pos_ratio, "q_density": q_density, "grade": grade}
741
 
@@ -937,7 +937,7 @@ if "streams" not in st.session_state:
937
  with st.sidebar:
938
  st.markdown(
939
  '<div style="padding:12px 0 20px;">'
940
- '<div style="font-size:1.35rem;font-weight:800;color:var(--text-1);letter-spacing:-0.02em;">?? LivePulse</div>'
941
  '<div style="font-size:0.75rem;color:var(--text-3);margin-top:2px;">YouTube Chat Analytics</div>'
942
  '</div>', unsafe_allow_html=True
943
  )
@@ -989,7 +989,7 @@ with st.sidebar:
989
 
990
  sc1, sc2 = st.columns(2)
991
  with sc1:
992
- if st.button("? Start", key=f"start_{idx}"):
993
  vid = extract_video_id(st.session_state[vid_skey])
994
  rkey = st.session_state[rkey_skey].strip() or f"chat_messages_{label.lower()}"
995
  if vid:
@@ -1006,11 +1006,11 @@ with st.sidebar:
1006
  else:
1007
  _META.pop("video_title", None)
1008
  st.session_state.alert_dismissed = False
1009
- st.success(f"Stream {label} started ? `{rkey}`")
1010
  else:
1011
  st.error("Invalid video ID or URL")
1012
  with sc2:
1013
- if st.button("? Stop", key=f"stop_{idx}"):
1014
  if is_scraper_running(idx):
1015
  stop_scraper(idx)
1016
  st.session_state.streams[idx]["proc"] = None
@@ -1021,7 +1021,7 @@ with st.sidebar:
1021
  running = is_scraper_running(idx)
1022
  dot_color = "#22c55e" if running else "#ef4444"
1023
  status = "running" if running else "stopped"
1024
- st.markdown(f'<div style="font-size:0.72rem;color:{dot_color};margin-bottom:4px;">? {status}</div>', unsafe_allow_html=True)
1025
 
1026
  # Show scraper error if any (only for stream A)
1027
  if idx == 0 and _META.get("scraper_error"):
@@ -1056,7 +1056,7 @@ with st.sidebar:
1056
  st.markdown('<p style="font-size:0.68rem;font-weight:700;color:var(--accent);text-transform:uppercase;letter-spacing:0.1em;margin-bottom:8px;">Pinned Messages</p>', unsafe_allow_html=True)
1057
  pin_count = len(st.session_state.pinned_messages)
1058
  st.markdown(f'<div style="font-size:0.78rem;color:var(--text-3);">{pin_count} message{"s" if pin_count != 1 else ""} pinned</div>', unsafe_allow_html=True)
1059
- if pin_count > 0 and st.button("?? Clear pins"):
1060
  st.session_state.pinned_messages = []
1061
  st.rerun()
1062
  st.divider()
@@ -1081,7 +1081,7 @@ with st.sidebar:
1081
  _fname = f"livepulse_{_rkey}_{_ts}.csv"
1082
  _csv_bytes = _dl_df.to_csv(index=False).encode("utf-8")
1083
  st.download_button(
1084
- label=f"? {_slabel} ({len(_dl_rows)} msgs)",
1085
  data=_csv_bytes,
1086
  file_name=_fname,
1087
  mime="text/csv",
@@ -1095,7 +1095,7 @@ with st.sidebar:
1095
 
1096
  # -- Danger Zone --
1097
  st.markdown('<p style="font-size:0.68rem;font-weight:700;color:#ef4444;text-transform:uppercase;letter-spacing:0.1em;margin-bottom:8px;">Danger Zone</p>', unsafe_allow_html=True)
1098
- if st.button("?? Clear all data"):
1099
  for s in st.session_state.streams:
1100
  store_delete(s["redis_key"])
1101
  st.session_state.pinned_messages = []
@@ -1105,7 +1105,7 @@ with st.sidebar:
1105
  st.markdown(
1106
  '<div style="font-size:0.72rem;color:var(--text-3);text-align:center;line-height:1.6;">'
1107
  'Theme follows Streamlit settings<br>'
1108
- '<span style="font-size:0.65rem;">? ? Settings ? Theme</span>'
1109
  '</div>', unsafe_allow_html=True
1110
  )
1111
 
 
362
  st.set_page_config(
363
  page_title="LivePulse",
364
  layout="wide",
365
+ page_icon="\U0001F4E1",
366
  initial_sidebar_state="expanded"
367
  )
368
 
 
629
 
630
  def csv_download(df_export, label, filename):
631
  csv = df_export.to_csv(index=False).encode("utf-8")
632
+ st.download_button(label=f"\u2b07 {label}", data=csv,
633
  file_name=filename, mime="text/csv", key=filename)
634
 
635
 
 
655
  sentiments = [m.get("sentiment", "Neutral") for m in _json.loads(df_all_json)]
656
  n = len(sentiments)
657
  if n < window * 2:
658
+ return {"direction": "\u2192", "delta": 0.0, "label": "Stable", "color": "#eab308"}
659
  recent = sentiments[-window:]
660
  prev = sentiments[-window*2:-window]
661
  r_pos = sum(1 for s in recent if s == "Positive") / window
662
  p_pos = sum(1 for s in prev if s == "Positive") / window
663
  delta = r_pos - p_pos
664
  if delta > 0.08:
665
+ return {"direction": "\u2191", "delta": delta, "label": "Rising", "color": "#22c55e"}
666
  elif delta < -0.08:
667
+ return {"direction": "\u2193", "delta": delta, "label": "Falling", "color": "#ef4444"}
668
+ return {"direction": "\u2192", "delta": delta, "label": "Stable", "color": "#eab308"}
669
 
670
 
671
  @st.cache_data(ttl=10, show_spinner=False)
 
733
  rate_norm = min(rate / 60, 1.0)
734
  score = round((rate_norm * 0.4 + pos_ratio * 0.4 + q_density * 0.2) * 100)
735
 
736
+ if score >= 70: grade = "\U0001f525 High"
737
+ elif score >= 40: grade = "\u26a1 Medium"
738
+ else: grade = "\U0001f4a4 Low"
739
 
740
  return {"score": score, "rate": rate, "pos_ratio": pos_ratio, "q_density": q_density, "grade": grade}
741
 
 
937
  with st.sidebar:
938
  st.markdown(
939
  '<div style="padding:12px 0 20px;">'
940
+ '<div style="font-size:1.35rem;font-weight:800;color:var(--text-1);letter-spacing:-0.02em;">\U0001F4E1 LivePulse</div>'
941
  '<div style="font-size:0.75rem;color:var(--text-3);margin-top:2px;">YouTube Chat Analytics</div>'
942
  '</div>', unsafe_allow_html=True
943
  )
 
989
 
990
  sc1, sc2 = st.columns(2)
991
  with sc1:
992
+ if st.button("\u25b6 Start", key=f"start_{idx}"):
993
  vid = extract_video_id(st.session_state[vid_skey])
994
  rkey = st.session_state[rkey_skey].strip() or f"chat_messages_{label.lower()}"
995
  if vid:
 
1006
  else:
1007
  _META.pop("video_title", None)
1008
  st.session_state.alert_dismissed = False
1009
+ st.success(f"Stream {label} started -> `{rkey}`")
1010
  else:
1011
  st.error("Invalid video ID or URL")
1012
  with sc2:
1013
+ if st.button("\u23f9 Stop", key=f"stop_{idx}"):
1014
  if is_scraper_running(idx):
1015
  stop_scraper(idx)
1016
  st.session_state.streams[idx]["proc"] = None
 
1021
  running = is_scraper_running(idx)
1022
  dot_color = "#22c55e" if running else "#ef4444"
1023
  status = "running" if running else "stopped"
1024
+ st.markdown(f'<div style="font-size:0.72rem;color:{dot_color};margin-bottom:4px;">\u25cf {status}</div>', unsafe_allow_html=True)
1025
 
1026
  # Show scraper error if any (only for stream A)
1027
  if idx == 0 and _META.get("scraper_error"):
 
1056
  st.markdown('<p style="font-size:0.68rem;font-weight:700;color:var(--accent);text-transform:uppercase;letter-spacing:0.1em;margin-bottom:8px;">Pinned Messages</p>', unsafe_allow_html=True)
1057
  pin_count = len(st.session_state.pinned_messages)
1058
  st.markdown(f'<div style="font-size:0.78rem;color:var(--text-3);">{pin_count} message{"s" if pin_count != 1 else ""} pinned</div>', unsafe_allow_html=True)
1059
+ if pin_count > 0 and st.button("\U0001f5d1 Clear pins"):
1060
  st.session_state.pinned_messages = []
1061
  st.rerun()
1062
  st.divider()
 
1081
  _fname = f"livepulse_{_rkey}_{_ts}.csv"
1082
  _csv_bytes = _dl_df.to_csv(index=False).encode("utf-8")
1083
  st.download_button(
1084
+ label=f"?"\u2b07 {_slabel} ({len(_dl_rows)} msgs)",
1085
  data=_csv_bytes,
1086
  file_name=_fname,
1087
  mime="text/csv",
 
1095
 
1096
  # -- Danger Zone --
1097
  st.markdown('<p style="font-size:0.68rem;font-weight:700;color:#ef4444;text-transform:uppercase;letter-spacing:0.1em;margin-bottom:8px;">Danger Zone</p>', unsafe_allow_html=True)
1098
+ if st.button("\U0001f5d1 Clear all data"):
1099
  for s in st.session_state.streams:
1100
  store_delete(s["redis_key"])
1101
  st.session_state.pinned_messages = []
 
1105
  st.markdown(
1106
  '<div style="font-size:0.72rem;color:var(--text-3);text-align:center;line-height:1.6;">'
1107
  'Theme follows Streamlit settings<br>'
1108
+ '<span style="font-size:0.65rem;">\u2630 \u2192 Settings \u2192 Theme</span>'
1109
  '</div>', unsafe_allow_html=True
1110
  )
1111