Update planmate/config.py

#1
by Memoona648 - opened
Files changed (1) hide show
  1. planmate/config.py +87 -11
planmate/config.py CHANGED
@@ -1,8 +1,27 @@
1
  import os
2
- from dotenv import load_dotenv
 
 
3
 
4
- # Load .env if present (local dev convenience)
5
- load_dotenv()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
  APP_TITLE = "PlanMate"
8
  APP_TAGLINE = "AI Powered smart trip planner"
@@ -26,18 +45,17 @@ OPENTRIPMAP_BASE = "https://api.opentripmap.com/0.1/en"
26
  # ---------- Hugging Face Secrets Configuration ----------
27
  def get_secret(key, default=None):
28
  """
29
- Get secret from Hugging Face Spaces environment or fallback to local .env
 
30
  """
31
- # Try to get from environment first (Hugging Face Spaces)
32
  value = os.getenv(key)
33
-
34
  if value is None and default is not None:
35
  return default
36
  elif value is None:
37
- st.error(f"Missing required secret: {key}")
38
- st.info("Please add this secret in your Hugging Face Space settings.")
39
- st.stop()
40
-
41
  return value
42
 
43
  def get_env(key: str) -> str:
@@ -46,9 +64,67 @@ def get_env(key: str) -> str:
46
  raise RuntimeError(f"Missing required environment variable: {key}")
47
  return val
48
 
 
 
 
 
 
 
 
 
 
 
49
  def get_gemini_key():
50
- return get_secret("GEMINI_API_KEY")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
 
52
  def get_amadeus_credentials():
53
  return get_secret("AMADEUS_CLIENT_ID"), get_secret("AMADEUS_CLIENT_SECRET")
54
 
 
1
  import os
2
+ import time
3
+ import requests
4
+ from itertools import cycle
5
 
6
+ # Try to load .env (local dev only, ignored in production)
7
+ try:
8
+ from dotenv import load_dotenv
9
+ load_dotenv()
10
+ except ImportError:
11
+ pass
12
+
13
+ # Streamlit-safe logging
14
+ def log_message(msg, level="info"):
15
+ try:
16
+ import streamlit as st
17
+ if level == "error":
18
+ st.error(msg)
19
+ elif level == "warning":
20
+ st.warning(msg)
21
+ else:
22
+ st.info(msg)
23
+ except ImportError:
24
+ print(f"[{level.upper()}] {msg}")
25
 
26
  APP_TITLE = "PlanMate"
27
  APP_TAGLINE = "AI Powered smart trip planner"
 
45
  # ---------- Hugging Face Secrets Configuration ----------
46
  def get_secret(key, default=None):
47
  """
48
+ Get secret from environment first (production),
49
+ fallback to .env for local dev.
50
  """
 
51
  value = os.getenv(key)
52
+
53
  if value is None and default is not None:
54
  return default
55
  elif value is None:
56
+ log_message(f"Missing required secret: {key}", level="error")
57
+ raise RuntimeError(f"Missing required secret: {key}")
58
+
 
59
  return value
60
 
61
  def get_env(key: str) -> str:
 
64
  raise RuntimeError(f"Missing required environment variable: {key}")
65
  return val
66
 
67
+ # ---------- Gemini Key Rotation ----------
68
+ gemini_keys = os.getenv("GEMINI_API_KEYS", "").split(",")
69
+ gemini_keys = [k.strip() for k in gemini_keys if k.strip()]
70
+
71
+ if not gemini_keys:
72
+ raise RuntimeError("No GEMINI_API_KEYS found in environment!")
73
+
74
+ gemini_cycle = cycle(gemini_keys)
75
+ _current_gemini_key = next(gemini_cycle)
76
+
77
  def get_gemini_key():
78
+ """Get the current Gemini API key"""
79
+ return _current_gemini_key
80
+
81
+ def rotate_gemini_key():
82
+ """Rotate to the next Gemini API key (when quota exceeded)"""
83
+ global _current_gemini_key
84
+ _current_gemini_key = next(gemini_cycle)
85
+ log_message(f"Rotated to new Gemini API key: {_current_gemini_key}", level="warning")
86
+ return _current_gemini_key
87
+
88
+ # ---------- Gemini Helper Function ----------
89
+ def make_gemini_request(prompt, model="gemini-2.0-flash-lite", max_retries=3):
90
+ """
91
+ Make a Gemini API request with automatic key rotation on quota errors.
92
+ """
93
+ import google.generativeai as genai
94
+
95
+ for attempt in range(max_retries):
96
+ try:
97
+ # Configure SDK with current key
98
+ genai.configure(api_key=get_gemini_key())
99
+
100
+ # Create the model
101
+ model_instance = genai.GenerativeModel(model)
102
+
103
+ # Generate response
104
+ response = model_instance.generate_content(prompt)
105
+ return response.text # or response.candidates, depending on usage
106
+
107
+ except Exception as e:
108
+ error_message = str(e)
109
+
110
+ # Case 1: Quota exceeded (429)
111
+ if "429" in error_message or "quota" in error_message.lower():
112
+ rotate_gemini_key()
113
+ time.sleep(2) # short delay before retry
114
+ continue
115
+
116
+ # Case 2: Network/HTTP error
117
+ elif isinstance(e, requests.exceptions.RequestException):
118
+ log_message(f"Network issue: {e}. Retrying...", level="warning")
119
+ time.sleep(2)
120
+ continue
121
+
122
+ # Any other error → stop immediately
123
+ raise e
124
+
125
+ raise RuntimeError("Gemini request failed after rotating all keys")
126
 
127
+ # ---------- Other API Keys ----------
128
  def get_amadeus_credentials():
129
  return get_secret("AMADEUS_CLIENT_ID"), get_secret("AMADEUS_CLIENT_SECRET")
130