Joffrey Thomas commited on
Commit
55eb384
·
1 Parent(s): 177edb4

UI changes

Browse files
Files changed (1) hide show
  1. app.py +16 -55
app.py CHANGED
@@ -76,6 +76,7 @@ def generate_id():
76
  HF_DATASET_REPO = 'jofthomas/geoguessr_game_of_the_day'
77
 
78
  GOOGLE_MAPS_API_KEY = os.getenv('GOOGLE_MAPS_API_KEY')
 
79
  SERVER_HF_TOKEN = os.getenv('HF_TOKEN', '')
80
 
81
  model_id = "mistralai/Magistral-Small-2509"
@@ -177,18 +178,6 @@ def llm_stream_image_text(image_bytes: bytes):
177
  yield f"[Error] {e}"
178
 
179
 
180
- def zones_get() -> dict:
181
- return zones
182
-
183
-
184
- def seconds_until_midnight_utc() -> int:
185
- now = datetime.now(timezone.utc)
186
- tomorrow = (now + timedelta(days=1)).date()
187
- midnight = datetime.combine(tomorrow, datetime.min.time(), tzinfo=timezone.utc)
188
- return max(0, int((midnight - now).total_seconds()))
189
-
190
-
191
-
192
  def pick_random_location(difficulty: str) -> Dict[str, float]:
193
  candidates = zones.get(difficulty, [])
194
  if candidates:
@@ -387,7 +376,7 @@ def gr_submit_guess(round_id: str, lat: float, lng: float, username: str, reques
387
  <button id=\"popup-close-next\" style=\"position:absolute;top:16px;right:18px;padding:10px 18px;border-radius:999px;border:1px solid rgba(96,165,250,0.4);background:linear-gradient(135deg,#1d4ed8,#2563eb);color:#f8fafc;font-weight:600;cursor:pointer;box-shadow:0 8px 18px rgba(37,99,235,0.45);\">Close & Next</button>
388
  <h3 style=\"margin:0 0 20px;color:#f8fafc;text-shadow:0 0 14px rgba(37,99,235,0.35);\">Round Results</h3>
389
  __SCOREBOARD__
390
- <div id=\"popup-map\" data-rnd-lat=\"__RND_LAT__\" data-rnd-lng=\"__RND_LNG__\" data-h-lat=\"__H_LAT__\" data-h-lng=\"__H_LNG__\" data-ai-lat=\"\" data-ai-lng=\"\" style=\"width:100%;height:440px;border-radius:16px;overflow:hidden;border:1px solid rgba(148,163,184,0.35);box-shadow:0 16px 40px rgba(4,7,15,0.72);\"></div>
391
  <div style=\"display:flex;justify-content:space-between;align-items:center;margin-top:24px;font-size:0.98rem;color:#e2e8f0;flex-wrap:wrap;gap:14px;\">
392
  <div style=\"display:flex;gap:16px;align-items:center;flex-wrap:wrap;\">
393
  <span style=\"display:flex;align-items:center;gap:8px;\"><span style=\"display:inline-flex;width:13px;height:13px;border-radius:50%;background:#22c55e;box-shadow:0 0 8px rgba(34,197,94,0.6);\"></span>G = Ground Truth</span>
@@ -417,6 +406,8 @@ def gr_submit_guess(round_id: str, lat: float, lng: float, username: str, reques
417
  .replace('__RND_LNG__', str(rnd['lng']))\
418
  .replace('__H_LAT__', str(float(lat)))\
419
  .replace('__H_LNG__', str(float(lng)))\
 
 
420
  .replace('__GMAPS_KEY__', GOOGLE_MAPS_API_KEY or '')
421
  return popup_html, result_text, rnd['lat'], rnd['lng'], score
422
 
@@ -446,34 +437,6 @@ def geocode_text_to_coords(query: str) -> Optional[Dict[str, float]]:
446
  return None
447
 
448
 
449
- def gr_ai_analyze(round_id: str, request: gr.Request):
450
- username = DEFAULT_USERNAME
451
- rnd = get_round(username, round_id)
452
- if not rnd:
453
- return "Round not found", gr.update()
454
- try:
455
- img_resp = requests.get(rnd['image_url'])
456
- img_resp.raise_for_status()
457
- full_text = llm_decode_image_return_text(img_resp.content)
458
- except Exception as e:
459
- return f"[Error] {e}", gr.update()
460
- ai_coords = extract_coords_from_text(full_text)
461
- ai_marker = None
462
- if ai_coords:
463
- rnd['ai_guess'] = ai_coords
464
- distance_km = haversine_km(rnd['lat'], rnd['lng'], ai_coords['lat'], ai_coords['lng'])
465
- rnd['ai_score'] = score_from_distance_km(distance_km)
466
- ai_marker = ai_coords
467
- return full_text, ai_marker
468
-
469
-
470
- def gr_session_summary(username: str, request: gr.Request):
471
- sess = user_sessions.get(username)
472
- if not sess:
473
- return "No active session"
474
- total = sum(float(r.get('human_score', 0.0)) for r in sess['rounds'])
475
- return f"Your total score: {total:.0f} / 15000"
476
-
477
  load_zones_from_file()
478
 
479
  def _read_text(path: str) -> str:
@@ -571,16 +534,16 @@ APP_BOOT_JS = """
571
  bounds.extend(gMk.getPosition());
572
  if (Number.isFinite(ai.lat) && Number.isFinite(ai.lng)) {
573
  log("AI coordinates are valid, creating marker.");
574
- const aMk = new google.maps.Marker({ position: ai, map: m, label: markerLabel('A'), icon: markerIcon('#2563EB', '#1e3a8a') });
575
  bounds.extend(aMk.getPosition());
576
- new google.maps.Polyline({ path: [rnd, ai], geodesic: true, strokeColor: '#2563EB', strokeOpacity: 1.0, strokeWeight: 2, map: m });
577
  } else {
578
  log("AI coordinates are NOT valid, skipping marker creation.");
579
  }
580
  if (Number.isFinite(human.lat) && Number.isFinite(human.lng)) {
581
- const hMk = new google.maps.Marker({ position: human, map: m, label: markerLabel('H'), icon: markerIcon('#f97316', '#c2410c') });
582
  bounds.extend(hMk.getPosition());
583
- new google.maps.Polyline({ path: [rnd, human], geodesic: true, strokeColor: '#f97316', strokeOpacity: 1.0, strokeWeight: 2, map: m });
584
  }
585
  const ne = bounds.getNorthEast();
586
  const sw = bounds.getSouthWest();
@@ -688,9 +651,7 @@ with gr.Blocks(css=APP_CSS, title="LLM GeoGuessr") as demo:
688
  logged_in_md = gr.Markdown(visible=False)
689
 
690
  with gr.Group(visible=False, elem_id="lobby_group") as lobby_group:
691
- with gr.Row():
692
- difficulty = gr.Dropdown(choices=["easy", "medium", "hard"], value="easy", label="Difficulty", elem_id="difficulty_select")
693
- start_btn = gr.Button("Start Game", variant="primary", elem_id="start_btn")
694
  limit_msg = gr.Markdown(visible=False)
695
 
696
  with gr.Group(visible=False, elem_id="game_group") as game_group:
@@ -704,8 +665,8 @@ with gr.Blocks(css=APP_CSS, title="LLM GeoGuessr") as demo:
704
  validate_btn = gr.Button("Validate Guess", visible=True)
705
  result_md = gr.Markdown()
706
  popup_html = gr.HTML()
707
- ai_chat = gr.Textbox(label="AI Analysis", interactive=False, elem_id="ai_chat")
708
- next_btn = gr.Button("Next", visible=True, elem_id="next_btn")
709
  final_md = gr.Markdown(visible=True)
710
 
711
  def on_login(token: gr.OAuthToken | None):
@@ -790,13 +751,13 @@ with gr.Blocks(css=APP_CSS, title="LLM GeoGuessr") as demo:
790
  ],
791
  )
792
 
793
- def start_click(difficulty: str, profile: dict, request: gr.Request):
794
  if not profile:
795
  gr.Warning("Please log in before starting the game.")
796
  # Return no-ops for all outputs to prevent errors
797
  return None, 0, "", "", "", "", gr.update(), gr.update(), gr.update()
798
 
799
- r, idx, rid, s_html, m_html, err = gr_start_game(difficulty, profile["name"], request)
800
  return (
801
  r,
802
  idx,
@@ -811,7 +772,7 @@ with gr.Blocks(css=APP_CSS, title="LLM GeoGuessr") as demo:
811
 
812
  start_btn.click(
813
  start_click,
814
- inputs=[difficulty, user_profile],
815
  outputs=[rounds_state, idx_state, round_id_box, street_html, map_html, result_md, game_group, lobby_group, limit_msg]
816
  )
817
 
@@ -887,8 +848,8 @@ with gr.Blocks(css=APP_CSS, title="LLM GeoGuessr") as demo:
887
  <div style="display:flex;justify-content:space-between;align-items:center;margin-top:24px;font-size:0.98rem;color:#e2e8f0;flex-wrap:wrap;gap:14px;">
888
  <div style="display:flex;gap:16px;align-items:center;flex-wrap:wrap;">
889
  <span style="display:flex;align-items:center;gap:8px;"><span style="display:inline-flex;width:13px;height:13px;border-radius:50%;background:#22c55e;box-shadow:0 0 8px rgba(34,197,94,0.6);"></span>G = Ground Truth</span>
890
- <span style="display:flex;align-items:center;gap:8px;"><span style="display:inline-flex;width:13px;height:13px;border-radius:50%;background:#f97316;box-shadow:0 0 8px rgba(249,115,22,0.55);"></span>H = Human</span>
891
- <span style="display:flex;align-items:center;gap:8px;"><span style="display:inline-flex;width:13px;height:13px;border-radius:50%;background:#2563EB;box-shadow:0 0 8px rgba(37,99,235,0.6);"></span>A = AI</span>
892
  </div>
893
  <button id="popup-close-next-footer" style="padding:12px 22px;border-radius:12px;border:1px solid rgba(96,165,250,0.4);background:linear-gradient(135deg,#1d4ed8,#2563eb);color:#f8fafc;font-weight:600;cursor:pointer;box-shadow:0 10px 22px rgba(37,99,235,0.48);">Next Round</button>
894
  </div>
 
76
  HF_DATASET_REPO = 'jofthomas/geoguessr_game_of_the_day'
77
 
78
  GOOGLE_MAPS_API_KEY = os.getenv('GOOGLE_MAPS_API_KEY')
79
+
80
  SERVER_HF_TOKEN = os.getenv('HF_TOKEN', '')
81
 
82
  model_id = "mistralai/Magistral-Small-2509"
 
178
  yield f"[Error] {e}"
179
 
180
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  def pick_random_location(difficulty: str) -> Dict[str, float]:
182
  candidates = zones.get(difficulty, [])
183
  if candidates:
 
376
  <button id=\"popup-close-next\" style=\"position:absolute;top:16px;right:18px;padding:10px 18px;border-radius:999px;border:1px solid rgba(96,165,250,0.4);background:linear-gradient(135deg,#1d4ed8,#2563eb);color:#f8fafc;font-weight:600;cursor:pointer;box-shadow:0 8px 18px rgba(37,99,235,0.45);\">Close & Next</button>
377
  <h3 style=\"margin:0 0 20px;color:#f8fafc;text-shadow:0 0 14px rgba(37,99,235,0.35);\">Round Results</h3>
378
  __SCOREBOARD__
379
+ <div id=\"popup-map\" data-rnd-lat=\"__RND_LAT__\" data-rnd-lng=\"__RND_LNG__\" data-h-lat=\"__H_LAT__\" data-h-lng=\"__H_LNG__\" data-ai-lat=\"__AI_LAT__\" data-ai-lng=\"__AI_LNG__\" style=\"width:100%;height:440px;border-radius:16px;overflow:hidden;border:1px solid rgba(148,163,184,0.35);box-shadow:0 16px 40px rgba(4,7,15,0.72);\"></div>
380
  <div style=\"display:flex;justify-content:space-between;align-items:center;margin-top:24px;font-size:0.98rem;color:#e2e8f0;flex-wrap:wrap;gap:14px;\">
381
  <div style=\"display:flex;gap:16px;align-items:center;flex-wrap:wrap;\">
382
  <span style=\"display:flex;align-items:center;gap:8px;\"><span style=\"display:inline-flex;width:13px;height:13px;border-radius:50%;background:#22c55e;box-shadow:0 0 8px rgba(34,197,94,0.6);\"></span>G = Ground Truth</span>
 
406
  .replace('__RND_LNG__', str(rnd['lng']))\
407
  .replace('__H_LAT__', str(float(lat)))\
408
  .replace('__H_LNG__', str(float(lng)))\
409
+ .replace('__AI_LAT__', str(float(lat)))\
410
+ .replace('__AI_LNG__', str(float(lng)))\
411
  .replace('__GMAPS_KEY__', GOOGLE_MAPS_API_KEY or '')
412
  return popup_html, result_text, rnd['lat'], rnd['lng'], score
413
 
 
437
  return None
438
 
439
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
440
  load_zones_from_file()
441
 
442
  def _read_text(path: str) -> str:
 
534
  bounds.extend(gMk.getPosition());
535
  if (Number.isFinite(ai.lat) && Number.isFinite(ai.lng)) {
536
  log("AI coordinates are valid, creating marker.");
537
+ const aMk = new google.maps.Marker({ position: ai, map: m, label: markerLabel('M'), icon: markerIcon('#f97316', '#c2410c') });
538
  bounds.extend(aMk.getPosition());
539
+ new google.maps.Polyline({ path: [rnd, ai], geodesic: true, strokeColor: '#f97316', strokeOpacity: 1.0, strokeWeight: 2, map: m });
540
  } else {
541
  log("AI coordinates are NOT valid, skipping marker creation.");
542
  }
543
  if (Number.isFinite(human.lat) && Number.isFinite(human.lng)) {
544
+ const hMk = new google.maps.Marker({ position: human, map: m, label: markerLabel('H'), icon: markerIcon('#2563EB', '#1e3a8a') });
545
  bounds.extend(hMk.getPosition());
546
+ new google.maps.Polyline({ path: [rnd, human], geodesic: true, strokeColor: '#2563EB', strokeOpacity: 1.0, strokeWeight: 2, map: m });
547
  }
548
  const ne = bounds.getNorthEast();
549
  const sw = bounds.getSouthWest();
 
651
  logged_in_md = gr.Markdown(visible=False)
652
 
653
  with gr.Group(visible=False, elem_id="lobby_group") as lobby_group:
654
+ start_btn = gr.Button("Start Game", variant="primary", elem_id="start_btn")
 
 
655
  limit_msg = gr.Markdown(visible=False)
656
 
657
  with gr.Group(visible=False, elem_id="game_group") as game_group:
 
665
  validate_btn = gr.Button("Validate Guess", visible=True)
666
  result_md = gr.Markdown()
667
  popup_html = gr.HTML()
668
+ ai_chat = gr.Textbox(label="AI Analysis", interactive=False, elem_id="ai_chat", lines=15)
669
+ next_btn = gr.Button("Next", visible=False, elem_id="next_btn")
670
  final_md = gr.Markdown(visible=True)
671
 
672
  def on_login(token: gr.OAuthToken | None):
 
751
  ],
752
  )
753
 
754
+ def start_click(profile: dict, request: gr.Request):
755
  if not profile:
756
  gr.Warning("Please log in before starting the game.")
757
  # Return no-ops for all outputs to prevent errors
758
  return None, 0, "", "", "", "", gr.update(), gr.update(), gr.update()
759
 
760
+ r, idx, rid, s_html, m_html, err = gr_start_game("easy", profile["name"], request)
761
  return (
762
  r,
763
  idx,
 
772
 
773
  start_btn.click(
774
  start_click,
775
+ inputs=[user_profile],
776
  outputs=[rounds_state, idx_state, round_id_box, street_html, map_html, result_md, game_group, lobby_group, limit_msg]
777
  )
778
 
 
848
  <div style="display:flex;justify-content:space-between;align-items:center;margin-top:24px;font-size:0.98rem;color:#e2e8f0;flex-wrap:wrap;gap:14px;">
849
  <div style="display:flex;gap:16px;align-items:center;flex-wrap:wrap;">
850
  <span style="display:flex;align-items:center;gap:8px;"><span style="display:inline-flex;width:13px;height:13px;border-radius:50%;background:#22c55e;box-shadow:0 0 8px rgba(34,197,94,0.6);"></span>G = Ground Truth</span>
851
+ <span style="display:flex;align-items:center;gap:8px;"><span style="display:inline-flex;width:13px;height:13px;border-radius:50%;background:#2563EB;box-shadow:0 0 8px rgba(37,99,235,0.6);"></span>H = Human</span>
852
+ <span style="display:flex;align-items:center;gap:8px;"><span style="display:inline-flex;width:13px;height:13px;border-radius:50%;background:#f97316;box-shadow:0 0 8px rgba(249,115,22,0.55);"></span>M = Magistral</span>
853
  </div>
854
  <button id="popup-close-next-footer" style="padding:12px 22px;border-radius:12px;border:1px solid rgba(96,165,250,0.4);background:linear-gradient(135deg,#1d4ed8,#2563eb);color:#f8fafc;font-weight:600;cursor:pointer;box-shadow:0 10px 22px rgba(37,99,235,0.48);">Next Round</button>
855
  </div>