dindizz commited on
Commit
3514ed3
·
verified ·
1 Parent(s): 7ccfd71

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -52
app.py CHANGED
@@ -12,7 +12,7 @@ import requests
12
  # Config
13
  # -----------------------------
14
  BASE_RSS = "https://sachet.ndma.gov.in/cap_public_website/rss"
15
- UA = "SachetMapRSS/1.0 (+https://huggingface.co/spaces)"
16
 
17
  # Known tricky slugs or long names -> explicit mapping to RSS file names (without '.xml')
18
  MANUAL_SLUGS: Dict[str, str] = {
@@ -28,7 +28,7 @@ MANUAL_SLUGS: Dict[str, str] = {
28
  "dadra and nagar haveli": "dadra_and_nagar_haveli_and_daman_and_diu",
29
  }
30
 
31
- # State/UT centroids (approx.) for click targets (lat, lon).
32
  # 36 entities: 28 States + 8 UTs
33
  STATES = [
34
  ("Andhra Pradesh", 15.9, 79.7),
@@ -80,14 +80,13 @@ def _slugify(name: str) -> str:
80
  key = name.strip().lower()
81
  if key in MANUAL_SLUGS:
82
  return MANUAL_SLUGS[key]
83
- # Generic rule: replace non-alnum with underscores; collapse repeats
84
  import re
85
  s = re.sub(r"[^a-z0-9]+", "_", key).strip("_")
86
  return s
87
 
88
  def state_to_feed(name: str, mapping_override: Dict[str, str] | None = None) -> str:
89
  """
90
- Build a candidate RSS URL for a state/UT. Accepts optional overrides:
91
  {'Tamil Nadu': 'https://.../rss_tamil_nadu.xml'}
92
  """
93
  if mapping_override and name in mapping_override:
@@ -153,7 +152,7 @@ def render_items_html(feed_title: str, items: List[Dict]) -> str:
153
 
154
 
155
  # -----------------------------
156
- # Plotly Map
157
  # -----------------------------
158
  def make_map() -> go.Figure:
159
  lats = [lat for _, lat, _ in STATES]
@@ -165,7 +164,7 @@ def make_map() -> go.Figure:
165
  lat=lats,
166
  lon=lons,
167
  text=names,
168
- customdata=names, # we read this on click
169
  mode="markers+text",
170
  textposition="top center",
171
  marker=dict(size=8),
@@ -216,16 +215,23 @@ CSS = """
216
  .badge { display:inline-block; padding:2px 8px; border:1px solid rgba(127,127,127,.25); border-radius:999px; font-size:12px; color:var(--muted); }
217
  """
218
 
 
 
219
  with gr.Blocks(css=CSS, fill_height=True, theme=gr.themes.Soft()) as demo:
220
  gr.Markdown("## SACHET — India Map of State/UT RSS Feeds (Minimal)")
221
 
222
  with gr.Row():
223
- map_plot = gr.Plot(value=make_map(), label="Click a marker to load the state/UT feed")
224
- with gr.Column(scale=1, min_width=300):
225
- selected = gr.Textbox(label="Selected State/UT", interactive=False)
 
 
 
 
 
226
  feed_url_box = gr.Textbox(label="Resolved Feed URL", interactive=False)
227
  max_items = gr.Slider(5, 50, value=20, step=1, label="Items")
228
- refresh = gr.Button("Refresh")
229
  gr.Markdown(
230
  "### Optional: Custom mapping\n"
231
  "Paste JSON as `{ \"Tamil Nadu\": \"https://.../rss_tamil_nadu.xml\", ... }`"
@@ -237,24 +243,14 @@ with gr.Blocks(css=CSS, fill_height=True, theme=gr.themes.Soft()) as demo:
237
  with gr.Column():
238
  feed_html = gr.HTML(elem_classes=["feedbox"])
239
 
240
- def resolve_and_render(state_click_payload, items_n, mapping_text):
241
- """
242
- state_click_payload: Plotly 'selected' or 'click' data
243
- """
244
- # Extract the state name from click payload
245
- state = None
246
- try:
247
- # Gradio 4: for .select the payload is dict with 'points'
248
- if isinstance(state_click_payload, dict) and "points" in state_click_payload and state_click_payload["points"]:
249
- state = state_click_payload["points"][0].get("customdata") or state_click_payload["points"][0].get("text")
250
- # Some Gradio variants may send just the label
251
- elif isinstance(state_click_payload, str):
252
- state = state_click_payload
253
- except Exception:
254
- state = None
255
-
256
  if not state:
257
- return gr.update(value=""), gr.update(value=""), gr.update(value=""), "<div class='badge'>Select a marker on the map.</div>"
258
 
259
  # Optional mapping overrides (user input)
260
  overrides = {}
@@ -267,46 +263,58 @@ with gr.Blocks(css=CSS, fill_height=True, theme=gr.themes.Soft()) as demo:
267
  overrides = {}
268
 
269
  # Resolve URL
270
- url = state_to_feed(state, overrides)
 
 
 
271
 
272
- # Try fetch and parse; fall back to national feed if 404
273
  try:
274
  title, items = parse_feed(url, max_items=int(items_n))
275
  html_out = render_items_html(f"{state} — {title}", items)
276
  return state, url, "", html_out
277
  except Exception as e:
278
- # Try a secondary slug variant: remove underscores
279
- alt_url = url.replace("_", "")
280
- try:
281
- title, items = parse_feed(alt_url, max_items=int(items_n))
282
- html_out = render_items_html(f"{state} — {title}", items)
283
- return state, alt_url, f"Note: primary URL failed, used fallback.", html_out
284
- except Exception as e2:
285
- # Fall back to national feed to keep UI useful
286
  try:
287
- title, items = parse_feed(NATIONAL_FEED, max_items=int(items_n))
288
- html_out = (
289
- f"<div class='badge'>Could not load <code>{html.escape(url)}</code>. "
290
- f"Showing national feed instead.</div>"
291
- ) + render_items_html(f"India — {title}", items)
292
- return state, url, f"⚠️ {type(e2).__name__}: {e2}", html_out
293
- except Exception as e3:
294
- return state, url, f"⚠️ {type(e3).__name__}: {e3}", "<div class='empty'>No data.</div>"
295
-
296
- # Initial: show national feed
297
- def initial_load(n_items):
 
 
 
 
 
 
298
  try:
299
  title, items = parse_feed(NATIONAL_FEED, max_items=int(n_items))
300
  return render_items_html(f"India — {title}", items)
301
  except Exception as e:
302
  return f"<div class='empty'>Could not load national feed. {html.escape(str(e))}</div>"
303
 
 
304
  demo.load(lambda n: initial_load(n), [max_items], [feed_html])
305
 
306
- # Wire both click and select events for robustness
307
- map_plot.select(resolve_and_render, [map_plot, max_items, mapping_json], [selected, feed_url_box, error_box, feed_html])
308
- map_plot.click(resolve_and_render, [map_plot, max_items, mapping_json], [selected, feed_url_box, error_box, feed_html])
309
- refresh.click(resolve_and_render, [map_plot, max_items, mapping_json], [selected, feed_url_box, error_box, feed_html])
 
 
 
 
 
 
 
310
 
311
  if __name__ == "__main__":
312
  demo.launch()
 
12
  # Config
13
  # -----------------------------
14
  BASE_RSS = "https://sachet.ndma.gov.in/cap_public_website/rss"
15
+ UA = "SachetMapRSS/1.1 (+https://huggingface.co/spaces)"
16
 
17
  # Known tricky slugs or long names -> explicit mapping to RSS file names (without '.xml')
18
  MANUAL_SLUGS: Dict[str, str] = {
 
28
  "dadra and nagar haveli": "dadra_and_nagar_haveli_and_daman_and_diu",
29
  }
30
 
31
+ # State/UT centroids (approx.) for display markers (lat, lon).
32
  # 36 entities: 28 States + 8 UTs
33
  STATES = [
34
  ("Andhra Pradesh", 15.9, 79.7),
 
80
  key = name.strip().lower()
81
  if key in MANUAL_SLUGS:
82
  return MANUAL_SLUGS[key]
 
83
  import re
84
  s = re.sub(r"[^a-z0-9]+", "_", key).strip("_")
85
  return s
86
 
87
  def state_to_feed(name: str, mapping_override: Dict[str, str] | None = None) -> str:
88
  """
89
+ Build the RSS URL for a state/UT. Accepts optional overrides:
90
  {'Tamil Nadu': 'https://.../rss_tamil_nadu.xml'}
91
  """
92
  if mapping_override and name in mapping_override:
 
152
 
153
 
154
  # -----------------------------
155
+ # Plotly Map (display only)
156
  # -----------------------------
157
  def make_map() -> go.Figure:
158
  lats = [lat for _, lat, _ in STATES]
 
164
  lat=lats,
165
  lon=lons,
166
  text=names,
167
+ customdata=names, # for potential future use
168
  mode="markers+text",
169
  textposition="top center",
170
  marker=dict(size=8),
 
215
  .badge { display:inline-block; padding:2px 8px; border:1px solid rgba(127,127,127,.25); border-radius:999px; font-size:12px; color:var(--muted); }
216
  """
217
 
218
+ STATE_CHOICES = ["India (National Feed)"] + [s[0] for s in STATES]
219
+
220
  with gr.Blocks(css=CSS, fill_height=True, theme=gr.themes.Soft()) as demo:
221
  gr.Markdown("## SACHET — India Map of State/UT RSS Feeds (Minimal)")
222
 
223
  with gr.Row():
224
+ map_plot = gr.Plot(value=make_map(), label="Reference Map (static)")
225
+ with gr.Column(scale=1, min_width=320):
226
+ state_dropdown = gr.Dropdown(
227
+ choices=STATE_CHOICES,
228
+ value="India (National Feed)",
229
+ label="Select State/UT"
230
+ )
231
+ selected = gr.Textbox(label="Selected", interactive=False)
232
  feed_url_box = gr.Textbox(label="Resolved Feed URL", interactive=False)
233
  max_items = gr.Slider(5, 50, value=20, step=1, label="Items")
234
+ refresh = gr.Button("Load/Refresh", variant="primary")
235
  gr.Markdown(
236
  "### Optional: Custom mapping\n"
237
  "Paste JSON as `{ \"Tamil Nadu\": \"https://.../rss_tamil_nadu.xml\", ... }`"
 
243
  with gr.Column():
244
  feed_html = gr.HTML(elem_classes=["feedbox"])
245
 
246
+ # -------------------------
247
+ # Actions
248
+ # -------------------------
249
+ def resolve_and_render(state_name: str, items_n: int, mapping_text: str):
250
+ # Normalize state label
251
+ state = (state_name or "").strip()
 
 
 
 
 
 
 
 
 
 
252
  if not state:
253
+ return "", "", "", "<div class='badge'>Select a state/UT.</div>"
254
 
255
  # Optional mapping overrides (user input)
256
  overrides = {}
 
263
  overrides = {}
264
 
265
  # Resolve URL
266
+ if state.lower().startswith("india"):
267
+ url = NATIONAL_FEED
268
+ else:
269
+ url = state_to_feed(state, overrides)
270
 
271
+ # Try fetch and parse; fallback to national if error
272
  try:
273
  title, items = parse_feed(url, max_items=int(items_n))
274
  html_out = render_items_html(f"{state} — {title}", items)
275
  return state, url, "", html_out
276
  except Exception as e:
277
+ # Try a secondary slug variant if not India
278
+ if not state.lower().startswith("india"):
279
+ alt_url = url.replace("_", "")
 
 
 
 
 
280
  try:
281
+ title, items = parse_feed(alt_url, max_items=int(items_n))
282
+ html_out = render_items_html(f"{state} — {title}", items)
283
+ return state, alt_url, "Note: primary URL failed, used fallback.", html_out
284
+ except Exception:
285
+ pass
286
+ # Final fallback: national
287
+ try:
288
+ title, items = parse_feed(NATIONAL_FEED, max_items=int(items_n))
289
+ html_out = (
290
+ f"<div class='badge'>Could not load <code>{html.escape(url)}</code>. "
291
+ f"Showing national feed instead.</div>"
292
+ ) + render_items_html(f"India — {title}", items)
293
+ return state, url, f"⚠️ {type(e).__name__}: {e}", html_out
294
+ except Exception as e3:
295
+ return state, url, f"⚠️ {type(e3).__name__}: {e3}", "<div class='empty'>No data.</div>"
296
+
297
+ def initial_load(n_items: int):
298
  try:
299
  title, items = parse_feed(NATIONAL_FEED, max_items=int(n_items))
300
  return render_items_html(f"India — {title}", items)
301
  except Exception as e:
302
  return f"<div class='empty'>Could not load national feed. {html.escape(str(e))}</div>"
303
 
304
+ # Initial content
305
  demo.load(lambda n: initial_load(n), [max_items], [feed_html])
306
 
307
+ # Wire dropdown and button
308
+ state_dropdown.change(
309
+ resolve_and_render,
310
+ [state_dropdown, max_items, mapping_json],
311
+ [selected, feed_url_box, error_box, feed_html],
312
+ )
313
+ refresh.click(
314
+ resolve_and_render,
315
+ [state_dropdown, max_items, mapping_json],
316
+ [selected, feed_url_box, error_box, feed_html],
317
+ )
318
 
319
  if __name__ == "__main__":
320
  demo.launch()