import os import urllib.request import json import ssl # 1. 讀取 .env 檔案中的金鑰 def load_env_variables(): # 優先嘗試使用 python-dotenv try: from dotenv import load_dotenv load_dotenv('.env') except ImportError: pass # 手動備用解析 .env,確保在任何環境下都能正常讀取 env_path = '.env' if os.path.exists(env_path): with open(env_path, 'r', encoding='utf-8') as f: for line in f: line = line.strip() if line and not line.startswith('#') and '=' in line: parts = line.split('=', 1) key = parts[0].strip() val = parts[1].strip().strip('\'"') os.environ[key] = val load_env_variables() GEMINI_KEY = os.getenv("GEMINI_KEY") or os.getenv("GEMINI_API_KEY") def query_gemini_with_search(prompt: str) -> dict: """ 使用 Python 標準庫 urllib 呼叫 Gemini API,並開啟 Google Search Grounding 工具來進行實時/地圖查詢。 """ if not GEMINI_KEY: raise ValueError("❌ 錯誤:找不到 GEMINI_KEY 或 GEMINI_API_KEY,請確認您的 .env 檔案設定。") # 使用支援 Google 搜尋 Grounding 的主流模型 model_name = "gemini-2.5-flash" url = f"https://generativelanguage.googleapis.com/v1beta/models/{model_name}:generateContent?key={GEMINI_KEY}" # 準備 Payload,啟用 Google 搜尋工具 # print('prompt', prompt) prompt += '\n回覆請用 2 句話簡短的話回覆。' print('prompt', prompt) payload = { "contents": [{ "parts": [{"text": prompt}] }], "tools": [{ "google_search": {} }] } data = json.dumps(payload).encode('utf-8') req = urllib.request.Request( url, data=data, headers={"Content-Type": "application/json"}, method="POST" ) # 忽略 SSL 憑證警告 (防止特定本機網路環境異常) ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE try: with urllib.request.urlopen(req, context=ctx, timeout=30) as response: res_data = response.read().decode('utf-8') return json.loads(res_data) except urllib.error.HTTPError as e: error_msg = e.read().decode('utf-8') print(f"\n❌ API 請求失敗:{e.code} {e.reason}") print(f"詳細錯誤資訊:{error_msg}") return {} except Exception as e: print(f"\n❌ 連線失敗:{e}") return {} def main(): print("=" * 60) print("🗺️ Gemini 地圖/實時地理資訊查詢工具") print("=" * 60) if not GEMINI_KEY: print("❌ 未在環境變數或 .env 中偵測到 API 金鑰。") print("請在專案目錄下的 .env 檔案中加入:") print("GEMINI_API_KEY=您的_API_金鑰") return masked_key = f"{GEMINI_KEY[:6]}...{GEMINI_KEY[-6:]}" if len(GEMINI_KEY) > 12 else "已讀取" print(f"🔑 已載入 API 金鑰:{masked_key}") print("💡 輸入 'exit' 或 'quit' 即可退出。") print("-" * 60) while True: try: prompt = input("\n💬 請輸入您的問題(如:尋找台北車站附近的露營用品店、大直捷運站附近的餐廳):\n👉 ").strip() if not prompt: continue if prompt.lower() in ['exit', 'quit']: print("\n👋 感謝使用,再見!") break print("⏳ 正在由 Gemini 查詢並搜尋地圖/網路資訊...") result = query_gemini_with_search(prompt) if not result: continue try: candidate = result['candidates'][0] text = candidate['content']['parts'][0]['text'] print("\n🤖 Gemini 回覆:") print(text) except (KeyError, IndexError) as e: print(f"\n❌ 解析 API 回傳資料時發生錯誤:{e}") print("原始回傳內容:", json.dumps(result, ensure_ascii=False, indent=2)) except KeyboardInterrupt: print("\n\n👋 偵測到中斷指令,結束程式。") break except Exception as e: print(f"\n❌ 發生未預期的錯誤:{e}") if __name__ == "__main__": main()