| import os |
| import urllib.request |
| import json |
| import ssl |
|
|
| |
| def load_env_variables(): |
| |
| try: |
| from dotenv import load_dotenv |
| load_dotenv('.env') |
| except ImportError: |
| pass |
| |
| |
| 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 檔案設定。") |
|
|
| |
| model_name = "gemini-2.5-flash" |
| url = f"https://generativelanguage.googleapis.com/v1beta/models/{model_name}:generateContent?key={GEMINI_KEY}" |
| |
| |
| |
| 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" |
| ) |
| |
| |
| 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() |
|
|