dotoking commited on
Commit
7d786c2
Β·
verified Β·
1 Parent(s): beef058

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +321 -1
app.py CHANGED
@@ -1,3 +1,215 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  if isinstance(per_eff, list) and per_eff:
2
  eff_df = pd.DataFrame(per_eff)
3
  if "platform_name" in eff_df.columns:
@@ -6,7 +218,115 @@
6
  )
7
  eff_df["efficiency_score"] = eff_df["efficiency_score"].round(1)
8
  eff_df = eff_df.sort_values("efficiency_score", ascending=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  else:
10
  eff_df = pd.DataFrame(columns=["platform", "efficiency_score"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
- return summary, eff_df
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ import numpy as np
4
+
5
+ from cear_model import CEARModel
6
+
7
+ cear_analyzer = CEARModel()
8
+
9
+
10
+ def build_dataframe_from_inputs(values):
11
+ """Build a DataFrame from a list of (platform_name, minutes, variety) tuples.
12
+
13
+ values: list[tuple[str, float | None, float | None]]
14
+ Returns: DataFrame with columns [platform_name, minutes_per_week, variety_score]
15
+ """
16
+ rows = []
17
+ for name, minutes, variety in values:
18
+ minutes = 0.0 if minutes is None else float(minutes)
19
+ variety = None if variety is None else float(variety)
20
+ # Keep row if there is any meaningful input
21
+ if minutes > 0 or (variety is not None and not np.isnan(variety)):
22
+ rows.append(
23
+ {
24
+ "platform_name": name,
25
+ "minutes_per_week": minutes,
26
+ "variety_score": variety,
27
+ }
28
+ )
29
+ if not rows:
30
+ return pd.DataFrame(
31
+ columns=["platform_name", "minutes_per_week", "variety_score"]
32
+ )
33
+ return pd.DataFrame(rows)
34
+
35
+
36
+ def analyze_user_data(
37
+ tiktok_minutes,
38
+ tiktok_variety,
39
+ insta_minutes,
40
+ insta_variety,
41
+ youtube_minutes,
42
+ youtube_variety,
43
+ twitter_minutes,
44
+ twitter_variety,
45
+ reddit_minutes,
46
+ reddit_variety,
47
+ facebook_minutes,
48
+ facebook_variety,
49
+ other_minutes,
50
+ other_variety,
51
+ feed_satisfaction,
52
+ fomo_level,
53
+ ):
54
+ # Build the input DataFrame for the core model
55
+ df = build_dataframe_from_inputs(
56
+ [
57
+ ("tiktok", tiktok_minutes, tiktok_variety),
58
+ ("instagram", insta_minutes, insta_variety),
59
+ ("youtube", youtube_minutes, youtube_variety),
60
+ ("twitter", twitter_minutes, twitter_variety),
61
+ ("reddit", reddit_minutes, reddit_variety),
62
+ ("facebook", facebook_minutes, facebook_variety),
63
+ ("other", other_minutes, other_variety),
64
+ ]
65
+ )
66
+
67
+ if df.empty:
68
+ return (
69
+ "Please enter at least one platform with some weekly minutes.",
70
+ "No meaningful screen time was entered, so per-platform efficiency could not be calculated.",
71
+ pd.DataFrame(columns=["platform", "efficiency_score"]),
72
+ )
73
+
74
+ # Call core CEAR model
75
+ scores = cear_analyzer.calculate_scores(
76
+ df, satisfaction=feed_satisfaction, fomo=fomo_level
77
+ )
78
+
79
+ c = float(scores.get("C_Score", 0.0))
80
+ a = float(scores.get("A_Risk", 0.0))
81
+ d = float(scores.get("D_Index", 0.0))
82
+ avg_variety = scores.get("Avg_Variety", None)
83
+ satisfaction = scores.get("Satisfaction", None)
84
+ fomo = scores.get("FOMO", None)
85
+ per_eff = scores.get("Per_Platform_Efficiency", [])
86
+
87
+ # ---------------- Profile based on C & A ---------------- #
88
+ if c >= 70 and a >= 70:
89
+ profile = (
90
+ "You are highly plugged into online culture, but that comes with high "
91
+ "algorithmic risk and a heavy concentration of attention on a small set of feeds."
92
+ )
93
+ elif c >= 70 and a < 70:
94
+ profile = (
95
+ "You are well-connected to online culture without extreme algorithmic concentration. "
96
+ "Your usage is relatively efficient for staying up to date."
97
+ )
98
+ elif c < 40 and a >= 70:
99
+ profile = (
100
+ "You give a lot of attention to a narrow set of feeds without gaining much cultural exposure. "
101
+ "This is a high-risk, low-benefit pattern."
102
+ )
103
+ else:
104
+ profile = (
105
+ "You currently have relatively low exposure to viral trends and also keep algorithmic risk low. "
106
+ "You are either deliberately detached from viral culture or simply under-invested in trend-dense platforms."
107
+ )
108
+
109
+ # ---------------- Variety interpretation ---------------- #
110
+ if avg_variety is None:
111
+ variety_text = (
112
+ "You did not provide variety ratings, so this analysis focuses only on time and platform mix."
113
+ )
114
+ elif avg_variety < 4:
115
+ variety_text = (
116
+ f"Your average variety rating is **{avg_variety:.1f} / 10**, which suggests that your feeds feel "
117
+ "quite repetitive and reinforce a narrow slice of content."
118
+ )
119
+ elif avg_variety > 7:
120
+ variety_text = (
121
+ f"Your average variety rating is **{avg_variety:.1f} / 10**, which suggests that you see a wide range "
122
+ "of topics and styles. This broadens your exposure and slightly offsets some algorithmic risk."
123
+ )
124
+ else:
125
+ variety_text = (
126
+ f"Your average variety rating is **{avg_variety:.1f} / 10**, indicating a moderate mix of content types."
127
+ )
128
+
129
+ # ---------------- Satisfaction & FOMO interpretation ---------------- #
130
+ satisfaction_text = ""
131
+ if satisfaction is not None:
132
+ if satisfaction <= 3:
133
+ satisfaction_text = (
134
+ "You report low satisfaction with your feed, which suggests your current pattern might not "
135
+ "match what you actually want from social media."
136
+ )
137
+ elif satisfaction >= 8:
138
+ satisfaction_text = (
139
+ "You report high satisfaction with your feed, indicating your current usage largely aligns "
140
+ "with what you want out of these platforms."
141
+ )
142
+ else:
143
+ satisfaction_text = (
144
+ "Your satisfaction is in the mid range, which suggests your feed is 'fine' but not fully optimized "
145
+ "for how you would like to spend your attention."
146
+ )
147
+
148
+ fomo_text = ""
149
+ if fomo is not None:
150
+ if fomo >= 7 and c < 50:
151
+ fomo_text = (
152
+ "You feel out of the loop and your relatively low C-Score supports that feeling. "
153
+ "If staying current matters to you, a bit more time on trend-dense platforms could help."
154
+ )
155
+ elif fomo <= 3 and c < 40:
156
+ fomo_text = (
157
+ "You have limited exposure to trends but do not feel much FOMO, which suggests a comfortable "
158
+ "distance from viral culture."
159
+ )
160
+
161
+ # ---------------- Summary header ---------------- #
162
+ summary_lines = [
163
+ "## πŸ“Š CEAR Analysis Summary",
164
+ "",
165
+ f"- **Cultural Connectedness Score (C-Score):** **{c:.2f}**",
166
+ f"- **Algorithmic Risk Score (A-Risk):** **{a:.2f}**",
167
+ f"- **Platform Diversity Index (D-Index):** **{d:.2f}**",
168
+ ]
169
+ if avg_variety is not None:
170
+ summary_lines.append(f"- **Average Variety Rating (0–10):** **{avg_variety:.2f}**")
171
+ if satisfaction is not None:
172
+ summary_lines.append(f"- **Feed Satisfaction (0–10):** **{satisfaction:.1f}**")
173
+ if fomo is not None:
174
+ summary_lines.append(f"- **FOMO / Out-of-the-loop (0–10):** **{fomo:.1f}**")
175
+
176
+ # ---------------- Interpretation section ---------------- #
177
+ summary_lines.extend([
178
+ "",
179
+ "### πŸ“ Interpretation",
180
+ "",
181
+ profile,
182
+ "",
183
+ variety_text,
184
+ ])
185
+ if satisfaction_text:
186
+ summary_lines.append("")
187
+ summary_lines.append(satisfaction_text)
188
+ if fomo_text:
189
+ summary_lines.append("")
190
+ summary_lines.append(fomo_text)
191
+
192
+ # ---------------- Survey explainer ---------------- #
193
+ survey_explainer = """
194
+ ### ℹ️ How your answers are used
195
+
196
+ - **Minutes per week** drive the core scores. More time on high-weight platforms increases both C-Score and A-Risk, with diminishing returns for C-Score.
197
+ - **Per-platform variety (0–10)** is combined into a minutes-weighted average. Low variety means you mainly see one type of content; high variety means you see a wider mix of topics and styles.
198
+ - **Feed satisfaction (0–10)** does not change the scores; it is used to interpret whether your current pattern feels good or frustrating to you.
199
+ - **FOMO (0–10)** is compared with your C-Score: high FOMO with low C-Score means you feel out of the loop, while low FOMO with low C-Score means you are detached by choice.
200
+ """
201
+ summary_lines.append("")
202
+ summary_lines.append(survey_explainer.strip())
203
+
204
+ summary_lines.append(
205
+ "\nThe C-Score uses a logarithmic transform of your weekly minutes, encoding diminishing returns as time increases. "
206
+ "A-Risk reflects your raw time investment and how concentrated it is on a small set of high-weight platforms. "
207
+ "D-Index captures how many platforms you use in a meaningful way (higher values mean your time is spread across more platforms)."
208
+ )
209
+
210
+ summary = "\n".join(summary_lines).strip()
211
+
212
+ # ---------------- Per-platform efficiency table and explanation ---------------- #
213
  if isinstance(per_eff, list) and per_eff:
214
  eff_df = pd.DataFrame(per_eff)
215
  if "platform_name" in eff_df.columns:
 
218
  )
219
  eff_df["efficiency_score"] = eff_df["efficiency_score"].round(1)
220
  eff_df = eff_df.sort_values("efficiency_score", ascending=False)
221
+
222
+ lines = ["### πŸ“ˆ Platform efficiency ranking (0–100)\n"]
223
+ lines.append(
224
+ "Higher scores mean more cultural exposure per minute. "
225
+ "The top platform in your current mix is set to 100 and others are scaled relative to it.\n"
226
+ )
227
+
228
+ for _, row in eff_df.iterrows():
229
+ platform = str(row["platform"])
230
+ score = float(row["efficiency_score"])
231
+ lines.append(f"- **{platform.capitalize()}**: {score:.1f}")
232
+
233
+ lines.append(
234
+ "\nPlatforms near 100 are the ones that give you the most cultural exposure per minute in this configuration. "
235
+ "Platforms with low scores cost more attention for less cultural gain."
236
+ )
237
+
238
+ eff_md = "\n".join(lines)
239
  else:
240
  eff_df = pd.DataFrame(columns=["platform", "efficiency_score"])
241
+ eff_md = (
242
+ "### πŸ“ˆ Platform efficiency ranking\n\n"
243
+ "No meaningful screen time was entered, so per-platform efficiency could not be calculated."
244
+ )
245
+
246
+ return summary, eff_md, eff_df
247
+
248
+
249
+ # ---------------- Gradio UI ---------------- #
250
+
251
+ with gr.Blocks() as demo:
252
+ gr.Markdown(
253
+ "# CEAR – Cultural Exposure & Algorithmic Risk Analyzer\n"
254
+ "Enter your weekly screen time per platform, rate the variety of each feed, and optionally report how satisfied "
255
+ "you are with your feed and how much FOMO you feel."
256
+ )
257
+
258
+ with gr.Row():
259
+ with gr.Column():
260
+ gr.Markdown("### Weekly minutes & per-platform variety (0–10)")
261
+
262
+ tiktok_minutes = gr.Number(label="TikTok minutes/week", value=240, precision=0)
263
+ tiktok_variety = gr.Slider(label="TikTok variety (0–10)", minimum=0, maximum=10, step=1, value=4)
264
+
265
+ insta_minutes = gr.Number(label="Instagram minutes/week", value=180, precision=0)
266
+ insta_variety = gr.Slider(label="Instagram variety (0–10)", minimum=0, maximum=10, step=1, value=5)
267
+
268
+ youtube_minutes = gr.Number(label="YouTube minutes/week", value=120, precision=0)
269
+ youtube_variety = gr.Slider(label="YouTube variety (0–10)", minimum=0, maximum=10, step=1, value=7)
270
+
271
+ twitter_minutes = gr.Number(label="Twitter/X minutes/week", value=60, precision=0)
272
+ twitter_variety = gr.Slider(label="Twitter/X variety (0–10)", minimum=0, maximum=10, step=1, value=6)
273
+
274
+ reddit_minutes = gr.Number(label="Reddit minutes/week", value=90, precision=0)
275
+ reddit_variety = gr.Slider(label="Reddit variety (0–10)", minimum=0, maximum=10, step=1, value=8)
276
+
277
+ facebook_minutes = gr.Number(label="Facebook minutes/week", value=45, precision=0)
278
+ facebook_variety = gr.Slider(label="Facebook variety (0–10)", minimum=0, maximum=10, step=1, value=3)
279
+
280
+ other_minutes = gr.Number(label="Other platforms minutes/week", value=30, precision=0)
281
+ other_variety = gr.Slider(label="Other platforms variety (0–10)", minimum=0, maximum=10, step=1, value=5)
282
+
283
+ with gr.Column():
284
+ gr.Markdown("### Self-report (global)")
285
+
286
+ feed_satisfaction = gr.Slider(
287
+ label="Feed satisfaction (0 = miserable, 10 = very happy)",
288
+ minimum=0,
289
+ maximum=10,
290
+ step=1,
291
+ value=6,
292
+ )
293
+ fomo_level = gr.Slider(
294
+ label="FOMO / out-of-the-loop feeling (0 = none, 10 = extreme)",
295
+ minimum=0,
296
+ maximum=10,
297
+ step=1,
298
+ value=4,
299
+ )
300
+
301
+ run_btn = gr.Button("Analyze")
302
+
303
+ summary_out = gr.Markdown(label="Score Results")
304
+ eff_md_out = gr.Markdown(label="Per-platform Efficiency Summary")
305
+ eff_table_out = gr.Dataframe(label="Per-platform Cultural Efficiency")
306
+
307
+ run_btn.click(
308
+ fn=analyze_user_data,
309
+ inputs=[
310
+ tiktok_minutes,
311
+ tiktok_variety,
312
+ insta_minutes,
313
+ insta_variety,
314
+ youtube_minutes,
315
+ youtube_variety,
316
+ twitter_minutes,
317
+ twitter_variety,
318
+ reddit_minutes,
319
+ reddit_variety,
320
+ facebook_minutes,
321
+ facebook_variety,
322
+ other_minutes,
323
+ other_variety,
324
+ feed_satisfaction,
325
+ fomo_level,
326
+ ],
327
+ outputs=[summary_out, eff_md_out, eff_table_out],
328
+ )
329
+
330
 
331
+ if __name__ == "__main__":
332
+ demo.launch()