Danialebrat commited on
Commit
6b02a54
Β·
1 Parent(s): 3637b76

updating wrapper app.py

Browse files
Files changed (1) hide show
  1. app.py +24 -124
app.py CHANGED
@@ -1,8 +1,7 @@
1
  """
2
  Root app.py – HuggingFace Spaces entry point.
3
 
4
- Presents a landing page that lets users pick between the two dashboards,
5
- then dynamically loads the chosen sub-app without touching its source code.
6
 
7
  Run locally : streamlit run app.py
8
  HF Spaces : set "app_file: app.py" in README.md front-matter (default)
@@ -14,136 +13,37 @@ from pathlib import Path
14
 
15
  import streamlit as st
16
 
17
- # ── Paths ──────────────────────────────────────────────────────────────────────
18
  ROOT = Path(__file__).resolve().parent
19
-
20
- _SUB_APPS: dict[str, Path] = {
21
- "sentiment": ROOT / "visualization",
22
- "brand": ROOT / "visualization_brand_sentiment",
23
- }
24
-
25
- # Module-name prefixes that belong to the sub-apps and must be evicted from
26
- # sys.modules when switching dashboards (both apps share identical package names:
27
- # data, utils, components, agents, visualizations).
28
- _SUB_APP_MODULE_PREFIXES = (
29
- "data", "utils", "components", "agents", "visualizations", "_subapp",
30
- )
31
 
32
  # ── Page config (must be the very first Streamlit call) ────────────────────────
33
  st.set_page_config(
34
- page_title="Musora Analytics Suite",
35
  page_icon="πŸ“Š",
36
  layout="wide",
37
  initial_sidebar_state="expanded",
38
  )
39
 
40
- # After we've set the page config, prevent sub-apps from overriding it.
41
- # Both sub-apps call st.set_page_config() at module level; patching the
42
- # function on the streamlit module object makes those calls no-ops.
43
- import streamlit as _st_mod # same object as `st`
44
  _st_mod.set_page_config = lambda *a, **kw: None
45
 
46
-
47
- # ── Helpers ────────────────────────────────────────────────────────────────────
48
-
49
- def _activate_app_path(app_key: str) -> None:
50
- """
51
- Swap out the active sub-app path in sys.path and clear any stale
52
- module cache entries so both apps' identically-named packages resolve
53
- to the correct source tree.
54
- """
55
- # Remove every sub-app directory that may already be on the path.
56
- for path in _SUB_APPS.values():
57
- s = str(path)
58
- while s in sys.path:
59
- sys.path.remove(s)
60
-
61
- # Insert the target sub-app directory at position 0 (highest priority).
62
- sys.path.insert(0, str(_SUB_APPS[app_key]))
63
-
64
- # Evict cached modules that originated from any sub-app so that the
65
- # next import resolves from the newly active path.
66
- for mod_name in list(sys.modules.keys()):
67
- if any(
68
- mod_name == prefix or mod_name.startswith(prefix + ".")
69
- for prefix in _SUB_APP_MODULE_PREFIXES
70
- ):
71
- del sys.modules[mod_name]
72
-
73
-
74
- def _load_and_run(app_key: str) -> None:
75
- """
76
- Dynamically load the selected sub-app module and invoke its main().
77
-
78
- Notes
79
- -----
80
- * exec_module() runs the module's top-level code (config loading,
81
- auth check, CSS injection, etc.) exactly as Streamlit would.
82
- * main() is called explicitly because the sub-apps guard it with
83
- ``if __name__ == "__main__"``, which is False under importlib.
84
- * StopException (raised by st.stop() inside the auth gate) is
85
- re-raised so Streamlit's runner can handle it correctly.
86
- """
87
- _activate_app_path(app_key)
88
-
89
- app_path = _SUB_APPS[app_key] / "app.py"
90
- spec = importlib.util.spec_from_file_location("_subapp", app_path)
91
- mod = importlib.util.module_from_spec(spec)
92
-
93
- try:
94
- spec.loader.exec_module(mod) # runs module-level code (auth, CSS …)
95
- if hasattr(mod, "main"):
96
- mod.main() # renders the full dashboard
97
- except Exception as exc: # noqa: BLE001
98
- # Re-raise Streamlit's internal StopException (triggered by st.stop())
99
- # so the runner knows to halt rendering cleanly.
100
- if "Stop" in type(exc).__name__:
101
- raise
102
- st.error(f"Dashboard error: {exc}")
103
- st.exception(exc)
104
-
105
-
106
- # ── Routing ────────────────────────────────────────────────────────────────────
107
-
108
- choice: str | None = st.session_state.get("app_choice")
109
-
110
- if choice is None:
111
- # ── Landing page ───────────────────────────────────────────────────────────
112
- st.title("πŸ“Š Musora Analytics Suite")
113
- st.markdown("Select a dashboard to get started.")
114
- st.markdown("---")
115
-
116
- col1, col2 = st.columns(2, gap="large")
117
-
118
- with col1:
119
- st.subheader("Musora Sentiment Dashboard")
120
- st.markdown(
121
- "Analyse social-media comment sentiment across YouTube, "
122
- "Facebook, and other platforms. Includes reply-required "
123
- "triage and global date/platform filters."
124
- )
125
- if st.button("Open β†’", key="btn_sentiment", use_container_width=True):
126
- st.session_state.app_choice = "sentiment"
127
- st.rerun()
128
-
129
- with col2:
130
- st.subheader("Sabian Brand Sentiment")
131
- st.markdown(
132
- "Track brand sentiment for Sabian products across Musora "
133
- "forums and YouTube. Covers competitor mentions, purchase "
134
- "intent, and demographic breakdowns."
135
- )
136
- if st.button("Open β†’", key="btn_brand", use_container_width=True):
137
- st.session_state.app_choice = "brand"
138
- st.rerun()
139
-
140
- else:
141
- # ── Sub-app: inject a "back" button at the top of the sidebar ─────────────
142
- with st.sidebar:
143
- if st.button("← Home", key="back_home", use_container_width=True):
144
- st.session_state.app_choice = None
145
- st.rerun()
146
- st.markdown("---")
147
-
148
- # ── Load and render the chosen dashboard ───────────────────────────────────
149
- _load_and_run(choice)
 
1
  """
2
  Root app.py – HuggingFace Spaces entry point.
3
 
4
+ Delegates directly to visualization/app.py.
 
5
 
6
  Run locally : streamlit run app.py
7
  HF Spaces : set "app_file: app.py" in README.md front-matter (default)
 
13
 
14
  import streamlit as st
15
 
 
16
  ROOT = Path(__file__).resolve().parent
17
+ APP_DIR = ROOT / "visualization"
 
 
 
 
 
 
 
 
 
 
 
18
 
19
  # ── Page config (must be the very first Streamlit call) ────────────────────────
20
  st.set_page_config(
21
+ page_title="Musora Sentiment Analysis",
22
  page_icon="πŸ“Š",
23
  layout="wide",
24
  initial_sidebar_state="expanded",
25
  )
26
 
27
+ # Prevent visualization/app.py's module-level st.set_page_config() call from
28
+ # raising an error – patch it to a no-op on the shared streamlit module object.
29
+ import streamlit as _st_mod
 
30
  _st_mod.set_page_config = lambda *a, **kw: None
31
 
32
+ # ── Ensure sub-app packages are importable ─────────────────────────────────────
33
+ app_dir_str = str(APP_DIR)
34
+ if app_dir_str not in sys.path:
35
+ sys.path.insert(0, app_dir_str)
36
+
37
+ # ── Load and run visualization/app.py ─────────────────────────────────────────
38
+ spec = importlib.util.spec_from_file_location("_subapp", APP_DIR / "app.py")
39
+ mod = importlib.util.module_from_spec(spec)
40
+
41
+ try:
42
+ spec.loader.exec_module(mod) # runs module-level code (config, auth, etc.)
43
+ if hasattr(mod, "main"):
44
+ mod.main() # renders the full dashboard
45
+ except Exception as exc:
46
+ if "Stop" in type(exc).__name__: # re-raise st.stop() for Streamlit's runner
47
+ raise
48
+ st.error(f"Dashboard error: {exc}")
49
+ st.exception(exc)