import gradio as gr import math treasures = [ {"name": "寶藏第1個", "lat": 24.985703, "lon": 121.288680, "question": "請問喬一老師叫什麼課?", "answer": "STEAM"}, {"name": "寶藏第2個", "lat": 24.985900, "lon": 121.289000, "question": "請問今年是何年?", "answer": "2025"}, {"name": "寶藏第3個", "lat": 24.956398, "lon": 121.297729, "question": "請問熊熊老師叫什麼課?", "answer": "balloon"}, ] 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 find_nearest(lat, lon, found): nearest = None nearest_idx = None min_distance = float("inf") for idx, treasure in enumerate(treasures): if idx in found: continue dist = haversine(lat, lon, treasure["lat"], treasure["lon"]) if dist < min_distance: min_distance = dist nearest = treasure nearest_idx = idx return nearest, nearest_idx, min_distance def update_position(lat, lon, found): if not lat or not lon: return "❌ 請先取得 GPS", gr.update(visible=False), "", "", found try: lat = float(lat) lon = float(lon) except: return "❌ 座標格式錯誤", gr.update(visible=False), "", "", found nearest, nearest_idx, dist = find_nearest(lat, lon, found) if nearest is None: return "🎉 所有寶藏已完成!", gr.update(visible=False), "", "", found if dist <= 200: return f"📍 距離 {nearest['name']}:{dist:.2f} 公尺 ✅ 請回答問題:", gr.update(visible=True), nearest["question"], nearest_idx, found else: return f"📍 距離 {nearest['name']}:{dist:.2f} 公尺,請再靠近一些", gr.update(visible=False), "", "", found def check_answer(user_answer, nearest_idx, found): correct = treasures[nearest_idx]["answer"] if user_answer.strip().lower() == correct.strip().lower(): return "✅ 答對了!請上傳一張照片作為紀念!", gr.update(visible=True), nearest_idx, found else: return "❌ 答錯了,請再試一次。", gr.update(visible=False), None, found def complete_mission(photo, nearest_idx, found): if photo is not None: found.append(nearest_idx) if len(found) == len(treasures): return "🎉 所有寶藏完成!", """

🎉 恭喜完成全部探索任務!

""", found else: return "✅ 照片上傳成功!繼續尋找下一個寶藏~", "", found else: return "❌ 請上傳照片!", "", found with gr.Blocks() as demo: gr.Markdown("# 🗺️ GPS 探索互動尋寶遊戲") gr.Markdown("📍 自動定位,靠近寶藏觸發題目任務") with gr.Row(): lat = gr.Textbox(label="Latitude") lon = gr.Textbox(label="Longitude") found_state = gr.State([]) status = gr.Markdown() question_box = gr.Textbox(label="回答問題", visible=False) question_text = gr.Textbox(visible=False) nearest_idx_state = gr.State() photo_upload = gr.Image(type="filepath", label="上傳紀念照片", visible=False) final_message = gr.Markdown() final_celebration = gr.HTML() btn_check = gr.Button("🔍 刷新位置") btn_check.click(update_position, inputs=[lat, lon, found_state], outputs=[status, question_box, question_text, nearest_idx_state, found_state]) btn_submit_answer = gr.Button("✅ 提交回答") btn_submit_answer.click(check_answer, inputs=[question_box, nearest_idx_state, found_state], outputs=[status, photo_upload, nearest_idx_state, found_state]) btn_upload_photo = gr.Button("📸 上傳完成") btn_upload_photo.click(complete_mission, inputs=[photo_upload, nearest_idx_state, found_state], outputs=[status, final_celebration, found_state]) gr.HTML(""" """) demo.launch()