CatoG commited on
Commit
788f59d
·
1 Parent(s): 35b0f08

more precise geoloc

Browse files
Files changed (1) hide show
  1. app.py +68 -12
app.py CHANGED
@@ -407,8 +407,49 @@ def generate_uuid(_: str = "") -> str:
407
 
408
  @tool
409
  def get_user_location(_: str = "") -> str:
410
- """Determine the user's approximate physical location based on their public IP address."""
411
- client_ip = getattr(_request_context, "client_ip", "") or ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
412
  url = f"http://ip-api.com/json/{client_ip}" if client_ip else "http://ip-api.com/json/"
413
  try:
414
  response = requests.get(url, timeout=5)
@@ -423,7 +464,8 @@ def get_user_location(_: str = "") -> str:
423
  f"Latitude: {data.get('lat', 'N/A')}\n"
424
  f"Longitude: {data.get('lon', 'N/A')}\n"
425
  f"Timezone: {data.get('timezone', 'N/A')}\n"
426
- f"ISP: {data.get('isp', 'N/A')}"
 
427
  )
428
  except requests.RequestException as exc:
429
  return f"Location lookup failed: {exc}"
@@ -587,7 +629,7 @@ def build_debug_report(
587
  def run_agent(message, history, selected_tools, model_id, client_ip: str = ""):
588
  history = history or []
589
 
590
- # Store client IP in thread-local so get_user_location can read it
591
  _request_context.client_ip = client_ip.strip() if client_ip else ""
592
 
593
  if not message or not str(message).strip():
@@ -733,7 +775,8 @@ with gr.Blocks(title="Provider Multi-Model Agent", theme=gr.themes.Soft()) as de
733
  interactive=False,
734
  )
735
 
736
- # Populated by JavaScript on page load with the browser's real public IP
 
737
  client_ip_box = gr.Textbox(visible=False, value="")
738
 
739
  demo.load(
@@ -741,13 +784,26 @@ with gr.Blocks(title="Provider Multi-Model Agent", theme=gr.themes.Soft()) as de
741
  inputs=None,
742
  outputs=[client_ip_box],
743
  js="""async () => {
744
- try {
745
- const r = await fetch('https://api.ipify.org?format=json');
746
- const d = await r.json();
747
- return d.ip;
748
- } catch(e) {
749
- return '';
750
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
751
  }""",
752
  )
753
 
 
407
 
408
  @tool
409
  def get_user_location(_: str = "") -> str:
410
+ """Determine the user's precise physical location using browser GPS/WiFi coordinates or IP fallback."""
411
+ location_data = getattr(_request_context, "client_ip", "") or ""
412
+
413
+ # Precise coordinates from browser geolocation API
414
+ if location_data and not location_data.startswith("ip:"):
415
+ try:
416
+ lat_str, lon_str = location_data.split(",", 1)
417
+ lat, lon = float(lat_str), float(lon_str)
418
+ except ValueError:
419
+ return "Location lookup failed: invalid coordinate data."
420
+ try:
421
+ headers = {"User-Agent": "HFAgent/1.0 (location lookup)"}
422
+ resp = requests.get(
423
+ "https://nominatim.openstreetmap.org/reverse",
424
+ params={"lat": lat, "lon": lon, "format": "json", "addressdetails": 1},
425
+ headers=headers,
426
+ timeout=8,
427
+ )
428
+ resp.raise_for_status()
429
+ data = resp.json()
430
+ addr = data.get("address", {})
431
+ city = (
432
+ addr.get("city")
433
+ or addr.get("town")
434
+ or addr.get("village")
435
+ or addr.get("municipality")
436
+ or addr.get("county")
437
+ or "N/A"
438
+ )
439
+ return (
440
+ f"City: {city}\n"
441
+ f"County: {addr.get('county', 'N/A')}\n"
442
+ f"Region: {addr.get('state', 'N/A')}\n"
443
+ f"Country: {addr.get('country', 'N/A')} ({addr.get('country_code', 'N/A').upper()})\n"
444
+ f"Latitude: {lat}\n"
445
+ f"Longitude: {lon}\n"
446
+ f"Source: Browser GPS/WiFi (precise)"
447
+ )
448
+ except requests.RequestException as exc:
449
+ return f"Reverse geocoding failed: {exc}"
450
+
451
+ # IP-based fallback
452
+ client_ip = location_data[3:] if location_data.startswith("ip:") else ""
453
  url = f"http://ip-api.com/json/{client_ip}" if client_ip else "http://ip-api.com/json/"
454
  try:
455
  response = requests.get(url, timeout=5)
 
464
  f"Latitude: {data.get('lat', 'N/A')}\n"
465
  f"Longitude: {data.get('lon', 'N/A')}\n"
466
  f"Timezone: {data.get('timezone', 'N/A')}\n"
467
+ f"ISP: {data.get('isp', 'N/A')}\n"
468
+ f"Source: IP geolocation (approximate)"
469
  )
470
  except requests.RequestException as exc:
471
  return f"Location lookup failed: {exc}"
 
629
  def run_agent(message, history, selected_tools, model_id, client_ip: str = ""):
630
  history = history or []
631
 
632
+ # Store location data in thread-local so get_user_location can read it
633
  _request_context.client_ip = client_ip.strip() if client_ip else ""
634
 
635
  if not message or not str(message).strip():
 
775
  interactive=False,
776
  )
777
 
778
+ # Populated by JavaScript on page load with precise browser coordinates (GPS/WiFi),
779
+ # stored as "lat,lon". Falls back to the public IP via ipify if geolocation is denied.
780
  client_ip_box = gr.Textbox(visible=False, value="")
781
 
782
  demo.load(
 
784
  inputs=None,
785
  outputs=[client_ip_box],
786
  js="""async () => {
787
+ return new Promise((resolve) => {
788
+ if (navigator.geolocation) {
789
+ navigator.geolocation.getCurrentPosition(
790
+ (pos) => resolve(pos.coords.latitude + ',' + pos.coords.longitude),
791
+ async () => {
792
+ try {
793
+ const r = await fetch('https://api.ipify.org?format=json');
794
+ const d = await r.json();
795
+ resolve('ip:' + d.ip);
796
+ } catch(e) { resolve(''); }
797
+ },
798
+ {timeout: 8000, maximumAge: 60000}
799
+ );
800
+ } else {
801
+ fetch('https://api.ipify.org?format=json')
802
+ .then(r => r.json())
803
+ .then(d => resolve('ip:' + d.ip))
804
+ .catch(() => resolve(''));
805
+ }
806
+ });
807
  }""",
808
  )
809