import gradio as gr import math treasures = [ {"name": "寶藏第1個", "lat": 24.985703, "lon": 121.288680}, {"name": "寶藏第2個", "lat": 24.985900, "lon": 121.289000}, {"name": "寶藏第3個", "lat": 24.956398, "lon": 121.297729}, ] def haversine(lat1, lon1, lat2, lon2): R = 6371000 phi1, phi2 = math.radians(lat1), math.radians(lat2) d_phi = math.radians(lat2 - lat1) d_lambda = math.radians(lon2 - lon1) a = math.sin(d_phi/2)**2 + math.cos(phi1)*math.cos(phi2)*math.sin(d_lambda/2)**2 c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a)) return R * c def check_nearest(lat, lon, found): if not lat or not lon: return "❌ 請先取得 GPS", "", "", found try: lat = float(lat) lon = float(lon) except: return "❌ 座標格式錯誤", "", "", found nearest = None nearest_idx = None min_distance = float("inf") for idx, treasure in enumerate(treasures): dist = haversine(lat, lon, treasure["lat"], treasure["lon"]) if dist < min_distance: min_distance = dist nearest = treasure nearest_idx = idx dist = haversine(lat, lon, nearest["lat"], nearest["lon"]) gmap = f"https://www.google.com/maps/dir/{lat},{lon}/{nearest['lat']},{nearest['lon']}" if dist <= 30 and nearest_idx not in found: found.append(nearest_idx) status = f"🎯 找到 {nearest['name']}!距離:{dist:.2f} 公尺 ✅" html = f"""
"""
elif nearest_idx in found:
status = f"✅ {nearest['name']} 已找到!目前距離:{dist:.2f} 公尺"
html = f'➡️ 再次導航至 {nearest["name"]}'
else:
status = f"📍 距離 {nearest['name']}:{dist:.2f} 公尺,請再靠近一些"
html = f'➡️ 點我導航至 {nearest["name"]}'
if len(found) == len(treasures):
html += """
"""
progress = f"✅ 已找到:{', '.join([treasures[i]['name'] for i in sorted(found)])}" if found else ""
return status, html, progress, found
with gr.Blocks() as demo:
gr.Markdown("# 🗺️ GPS 尋寶遊戲")
gr.Markdown("📍 自動找最近寶藏,進入 30 公尺範圍內顯示動畫 🎉")
gr.HTML("""
""")
with gr.Row():
lat = gr.Textbox(label="Latitude")
lon = gr.Textbox(label="Longitude")
status = gr.Markdown()
link = gr.HTML()
progress = gr.Markdown()
found_state = gr.State([])
btn = gr.Button("🔍 檢查距離 + 導航")
btn.click(fn=check_nearest, inputs=[lat, lon, found_state],
outputs=[status, link, progress, found_state])
demo.launch()