ZENLLC commited on
Commit
2bdf2b8
·
verified ·
1 Parent(s): 1898bc8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +58 -38
app.py CHANGED
@@ -2,7 +2,7 @@ import json, textwrap, time
2
  from datetime import datetime
3
  import gradio as gr
4
 
5
- # ------------- SAMPLE WEEK (edit live on-air) ----------------
6
  STORIES = [
7
  {
8
  "title": "Microsoft 365 Premium launches ($19.99/mo) with integrated Copilot",
@@ -79,11 +79,10 @@ STORIES = [
79
  }
80
  ]
81
 
82
- # Derive categories
83
  def all_categories():
84
  return sorted(list({s["category"] for s in STORIES}))
85
 
86
- # Utilities
87
  def fmt_story(story: dict) -> str:
88
  if not story: return "No story selected."
89
  date = datetime.fromisoformat(story["date"]).strftime("%b %d, %Y")
@@ -111,8 +110,8 @@ def teleprompter_text(story: dict) -> str:
111
  Why it matters: {story['why_it_matters']}"""
112
  return textwrap.fill(text, width=90)
113
 
114
- def list_rows(stories):
115
- return [[s["date"], s["category"], s["title"]] for s in stories]
116
 
117
  def filter_and_search(category, query):
118
  items = STORIES
@@ -123,22 +122,7 @@ def filter_and_search(category, query):
123
  items = [s for s in items if q in s["title"].lower() or q in s["summary"].lower()]
124
  return items
125
 
126
- def pick(idx, items):
127
- if not items:
128
- return "No stories here.", "", "", ""
129
- i = max(0, min(int(idx), len(items)-1))
130
- story = items[i]
131
- # Ticker content (first 12 headlines)
132
- headlines = " • ".join([s["title"] for s in items[:12]])
133
- return (
134
- fmt_story(story),
135
- teleprompter_text(story),
136
- build_ticker_html(headlines),
137
- build_prompter_html(teleprompter_text(story), speed=40, is_playing=True)
138
- )
139
-
140
  def build_ticker_html(text):
141
- # Controlled by script.js via dataset attributes
142
  return f"""
143
  <link rel="stylesheet" href="style.css">
144
  <div class="zen-ticker shell">
@@ -148,9 +132,7 @@ def build_ticker_html(text):
148
  """
149
 
150
  def build_prompter_html(text, speed=40, is_playing=True):
151
- # speed in px/sec; play state toggled via JS buttons
152
  playing = "true" if is_playing else "false"
153
- # Escape < & > minimally for HTML block
154
  safe = text.replace("&","&amp;").replace("<","&lt;").replace(">","&gt;")
155
  return f"""
156
  <link rel="stylesheet" href="style.css">
@@ -173,6 +155,19 @@ def build_prompter_html(text, speed=40, is_playing=True):
173
  <script src="script.js"></script>
174
  """
175
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
  def add_story(json_blob):
177
  try:
178
  obj = json.loads(json_blob)
@@ -200,20 +195,22 @@ def countdown(minutes):
200
  yield f"{mm:02d}:{ss:02d}"
201
  time.sleep(1)
202
 
203
- # -------------------------- UI -------------------------------
204
- with gr.Blocks(css="style.css", fill_height=True, title="ZEN Weekly Live Radar PRO") as demo:
205
  gr.HTML("""<link rel="stylesheet" href="style.css"><script src="script.js"></script>""")
206
 
207
  with gr.Row(elem_classes="row-top"):
208
  gr.Markdown("### 🛰️ ZEN Weekly Live Radar PRO — Paste stories, run teleprompter, scroll ticker")
209
 
210
  with gr.Row():
211
- with gr.Column(scale=1, elem_classes="card">
212
  category = gr.Dropdown(choices=["All"] + all_categories(), value="All", label="Category")
213
  query = gr.Textbox(label="Search", placeholder="Filter titles & summaries…")
214
  list_state = gr.State([])
 
215
  table = gr.Dataframe(headers=["Date","Category","Title"], interactive=False, wrap=True)
216
- idx = gr.Slider(label="Select", minimum=0, maximum=max(0, len(STORIES)-1), step=1, value=0)
 
217
  refresh = gr.Button("Refresh")
218
 
219
  gr.Markdown("#### Add a story (JSON)")
@@ -241,28 +238,51 @@ with gr.Blocks(css="style.css", fill_height=True, title="ZEN Weekly Live Radar P
241
  prompter_html = gr.HTML(build_prompter_html(teleprompter_text(STORIES[0])))
242
  ticker_html = gr.HTML(build_ticker_html(" • ".join([s["title"] for s in STORIES[:12]])))
243
 
244
- # ----- Callbacks -----
245
  def refresh_list(cat, q):
246
  items = filter_and_search(cat, q)
247
  rows = list_rows(items)
248
  mx = max(0, len(items)-1)
249
- initial = 0 if items else 0
250
- sel_story, tele, tick, prom = pick(initial, items)
251
- return items, rows, 0, mx, sel_story, prom, tick
 
 
 
 
 
 
252
 
253
  def on_select(i, cat, q, items):
254
- items = filter_and_search(cat, q) if not items else items
255
- sel_story, tele, tick, prom = pick(i, items)
256
- return sel_story, prom, tick
 
257
 
258
- refresh.click(refresh_list, [category, query], [list_state, table, idx, idx.maximum, story_md, prompter_html, ticker_html])
259
- category.change(refresh_list, [category, query], [list_state, table, idx, idx.maximum, story_md, prompter_html, ticker_html])
260
- query.submit(refresh_list, [category, query], [list_state, table, idx, idx.maximum, story_md, prompter_html, ticker_html])
 
 
 
 
 
 
 
 
 
 
 
 
261
 
262
- idx.release(on_select, [idx, category, query, list_state], [story_md, prompter_html, ticker_html])
 
 
 
 
263
 
264
  add_btn.click(add_story, [blob], [add_status, category]).then(
265
- refresh_list, [category, query], [list_state, table, idx, idx.maximum, story_md, prompter_html, ticker_html]
266
  )
267
 
268
  start.click(countdown, [mins], [time_left])
 
2
  from datetime import datetime
3
  import gradio as gr
4
 
5
+ # ----------------- SAMPLE WEEK (edit live on-air) -----------------
6
  STORIES = [
7
  {
8
  "title": "Microsoft 365 Premium launches ($19.99/mo) with integrated Copilot",
 
79
  }
80
  ]
81
 
 
82
  def all_categories():
83
  return sorted(list({s["category"] for s in STORIES}))
84
 
85
+ # ----------------- Utility fns -----------------
86
  def fmt_story(story: dict) -> str:
87
  if not story: return "No story selected."
88
  date = datetime.fromisoformat(story["date"]).strftime("%b %d, %Y")
 
110
  Why it matters: {story['why_it_matters']}"""
111
  return textwrap.fill(text, width=90)
112
 
113
+ def list_rows(items):
114
+ return [[s["date"], s["category"], s["title"]] for s in items]
115
 
116
  def filter_and_search(category, query):
117
  items = STORIES
 
122
  items = [s for s in items if q in s["title"].lower() or q in s["summary"].lower()]
123
  return items
124
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  def build_ticker_html(text):
 
126
  return f"""
127
  <link rel="stylesheet" href="style.css">
128
  <div class="zen-ticker shell">
 
132
  """
133
 
134
  def build_prompter_html(text, speed=40, is_playing=True):
 
135
  playing = "true" if is_playing else "false"
 
136
  safe = text.replace("&","&amp;").replace("<","&lt;").replace(">","&gt;")
137
  return f"""
138
  <link rel="stylesheet" href="style.css">
 
155
  <script src="script.js"></script>
156
  """
157
 
158
+ def pick(idx, items):
159
+ if not items:
160
+ return ("No stories here.", build_prompter_html(""), build_ticker_html(""), 0)
161
+ i = max(0, min(int(idx), len(items)-1))
162
+ story = items[i]
163
+ headlines = " • ".join([s["title"] for s in items[:12]])
164
+ return (
165
+ fmt_story(story),
166
+ build_prompter_html(teleprompter_text(story)),
167
+ build_ticker_html(headlines),
168
+ i
169
+ )
170
+
171
  def add_story(json_blob):
172
  try:
173
  obj = json.loads(json_blob)
 
195
  yield f"{mm:02d}:{ss:02d}"
196
  time.sleep(1)
197
 
198
+ # --------------------------- UI ----------------------------
199
+ with gr.Blocks(css="style.css", title="ZEN Weekly Live Radar PRO") as demo:
200
  gr.HTML("""<link rel="stylesheet" href="style.css"><script src="script.js"></script>""")
201
 
202
  with gr.Row(elem_classes="row-top"):
203
  gr.Markdown("### 🛰️ ZEN Weekly Live Radar PRO — Paste stories, run teleprompter, scroll ticker")
204
 
205
  with gr.Row():
206
+ with gr.Column(scale=1, elem_classes="card"):
207
  category = gr.Dropdown(choices=["All"] + all_categories(), value="All", label="Category")
208
  query = gr.Textbox(label="Search", placeholder="Filter titles & summaries…")
209
  list_state = gr.State([])
210
+
211
  table = gr.Dataframe(headers=["Date","Category","Title"], interactive=False, wrap=True)
212
+
213
+ slider = gr.Slider(label="Select", minimum=0, maximum=max(0, len(STORIES)-1), step=1, value=0)
214
  refresh = gr.Button("Refresh")
215
 
216
  gr.Markdown("#### Add a story (JSON)")
 
238
  prompter_html = gr.HTML(build_prompter_html(teleprompter_text(STORIES[0])))
239
  ticker_html = gr.HTML(build_ticker_html(" • ".join([s["title"] for s in STORIES[:12]])))
240
 
241
+ # --------------- Callbacks ----------------
242
  def refresh_list(cat, q):
243
  items = filter_and_search(cat, q)
244
  rows = list_rows(items)
245
  mx = max(0, len(items)-1)
246
+ sel_md, prom_html, tick_html, idx_val = pick(0, items)
247
+ return (
248
+ items, # list_state
249
+ rows, # table
250
+ gr.Slider.update(maximum=mx, value=0),
251
+ sel_md, # story_md
252
+ prom_html, # prompter_html
253
+ tick_html # ticker_html
254
+ )
255
 
256
  def on_select(i, cat, q, items):
257
+ # items may be stale; recompute from cat/q for safety
258
+ items = filter_and_search(cat, q)
259
+ sel_md, prom_html, tick_html, _ = pick(i, items)
260
+ return sel_md, prom_html, tick_html
261
 
262
+ refresh.click(
263
+ refresh_list,
264
+ inputs=[category, query],
265
+ outputs=[list_state, table, slider, story_md, prompter_html, ticker_html]
266
+ )
267
+ category.change(
268
+ refresh_list,
269
+ inputs=[category, query],
270
+ outputs=[list_state, table, slider, story_md, prompter_html, ticker_html]
271
+ )
272
+ query.submit(
273
+ refresh_list,
274
+ inputs=[category, query],
275
+ outputs=[list_state, table, slider, story_md, prompter_html, ticker_html]
276
+ )
277
 
278
+ slider.release(
279
+ on_select,
280
+ inputs=[slider, category, query, list_state],
281
+ outputs=[story_md, prompter_html, ticker_html]
282
+ )
283
 
284
  add_btn.click(add_story, [blob], [add_status, category]).then(
285
+ refresh_list, [category, query], [list_state, table, slider, story_md, prompter_html, ticker_html]
286
  )
287
 
288
  start.click(countdown, [mins], [time_left])