CodeCommunity commited on
Commit
33c1793
·
verified ·
1 Parent(s): a9724d2

Update app/core/model_loader.py

Browse files
Files changed (1) hide show
  1. app/core/model_loader.py +35 -7
app/core/model_loader.py CHANGED
@@ -13,6 +13,11 @@ load_dotenv()
13
  logger = logging.getLogger(__name__)
14
  STATS_FILE = "usage_stats.json"
15
 
 
 
 
 
 
16
  class LLMSingleton:
17
  _instance = None
18
  _instance_lock = threading.Lock()
@@ -29,21 +34,26 @@ class LLMSingleton:
29
  if self._instance is not None:
30
  raise Exception("Singleton instance already exists!")
31
 
32
- self.api_key = os.getenv("GROQ_API_KEY")
 
 
 
33
  if not self.api_key:
34
- logger.warning("⚠️ GROQ_API_KEY not found in environment variables. AI features will fail.")
35
  self.client = None
36
  else:
37
  self.client = Groq(api_key=self.api_key)
38
 
39
- # Sanitize model string to strip hidden whitespace, newlines, or quotes injected by HF UI
40
- raw_model = os.getenv("GROQ_MODEL", "llama-3.1-8b-instant")
41
  clean_model = raw_model.strip().strip('"').strip("'") if raw_model else ""
42
- self.model_name = clean_model if clean_model else "llama-3.1-8b-instant"
43
 
 
 
 
44
  self._stats_lock = threading.Lock()
45
  self._rpm_lock = threading.Lock()
46
-
47
  self.stats = self._load_stats()
48
  self._check_daily_reset()
49
 
@@ -125,6 +135,7 @@ class LLMSingleton:
125
  self.stats["total_requests"] += 1
126
  self.stats["daily_requests_count"] += 1
127
  self._save_stats()
 
128
  with self._rpm_lock:
129
  self.requests_this_minute += 1
130
  return True
@@ -146,6 +157,7 @@ class LLMSingleton:
146
  retries = 0
147
  max_retries = 3
148
  base_delay = 2
 
149
 
150
  while retries <= max_retries:
151
  try:
@@ -154,7 +166,7 @@ class LLMSingleton:
154
  self._save_stats()
155
 
156
  chat_completion = self.client.chat.completions.create(
157
- model=self.model_name,
158
  messages=[
159
  {
160
  "role": "system",
@@ -179,10 +191,22 @@ class LLMSingleton:
179
 
180
  except Exception as e:
181
  error_str = str(e)
 
 
 
 
 
 
 
 
 
 
 
182
  if "429" in error_str or "rate_limit_exceeded" in error_str.lower():
183
  with self._stats_lock:
184
  self.stats["rate_limit_hits"] += 1
185
  self._save_stats()
 
186
  wait_time = (base_delay * (2**retries)) + random.uniform(0.5, 1.5)
187
  logger.warning(
188
  f"⚠️ Groq rate limit hit. Retrying in {wait_time:.2f}s... (Attempt {retries + 1}/{max_retries})"
@@ -199,6 +223,7 @@ class LLMSingleton:
199
  with self._stats_lock:
200
  self.stats["errors"] += 1
201
  self._save_stats()
 
202
  logger.error("❌ Max retries reached. Request failed.")
203
  raise RuntimeError("RATE_LIMIT_EXCEEDED")
204
 
@@ -238,8 +263,11 @@ class LLMSingleton:
238
  self._save_stats()
239
 
240
  return response_text
 
241
  except Exception as e:
242
  logger.error(f"Groq text generation failed: {e}")
243
  return f"Error generating content: {str(e)}"
244
 
 
 
245
  llm_engine = LLMSingleton.get_instance()
 
13
  logger = logging.getLogger(__name__)
14
  STATS_FILE = "usage_stats.json"
15
 
16
+ # Supported active Groq free-tier models (Fallback list)
17
+ DEFAULT_MODEL = "llama-3.1-8b-instant"
18
+ FALLBACK_MODEL = "llama-3.3-70b-versatile"
19
+
20
+
21
  class LLMSingleton:
22
  _instance = None
23
  _instance_lock = threading.Lock()
 
34
  if self._instance is not None:
35
  raise Exception("Singleton instance already exists!")
36
 
37
+ # 1. Load and sanitize API Key
38
+ raw_key = os.getenv("GROQ_API_KEY", "")
39
+ self.api_key = raw_key.strip().strip('"').strip("'") if raw_key else ""
40
+
41
  if not self.api_key:
42
+ logger.warning("⚠️ GROQ_API_KEY not found or empty. AI features will fail.")
43
  self.client = None
44
  else:
45
  self.client = Groq(api_key=self.api_key)
46
 
47
+ # 2. Load and sanitize Model Name
48
+ raw_model = os.getenv("GROQ_MODEL", DEFAULT_MODEL)
49
  clean_model = raw_model.strip().strip('"').strip("'") if raw_model else ""
50
+ self.model_name = clean_model if clean_model else DEFAULT_MODEL
51
 
52
+ logger.info(f"🔑 Groq Client initialized with model target: {self.model_name}")
53
+
54
+ # 3. Threading locks and usage stats setup
55
  self._stats_lock = threading.Lock()
56
  self._rpm_lock = threading.Lock()
 
57
  self.stats = self._load_stats()
58
  self._check_daily_reset()
59
 
 
135
  self.stats["total_requests"] += 1
136
  self.stats["daily_requests_count"] += 1
137
  self._save_stats()
138
+
139
  with self._rpm_lock:
140
  self.requests_this_minute += 1
141
  return True
 
157
  retries = 0
158
  max_retries = 3
159
  base_delay = 2
160
+ active_model = self.model_name
161
 
162
  while retries <= max_retries:
163
  try:
 
166
  self._save_stats()
167
 
168
  chat_completion = self.client.chat.completions.create(
169
+ model=active_model,
170
  messages=[
171
  {
172
  "role": "system",
 
191
 
192
  except Exception as e:
193
  error_str = str(e)
194
+
195
+ # Automatic Model Fallback handling if a 404/model_not_found occurs
196
+ if "404" in error_str or "model_not_found" in error_str.lower():
197
+ if active_model != FALLBACK_MODEL:
198
+ logger.warning(
199
+ f"⚠️ Model target '{active_model}' rejected (404). Falling back to '{FALLBACK_MODEL}'..."
200
+ )
201
+ active_model = FALLBACK_MODEL
202
+ continue
203
+
204
+ # Rate Limit handling (HTTP 429)
205
  if "429" in error_str or "rate_limit_exceeded" in error_str.lower():
206
  with self._stats_lock:
207
  self.stats["rate_limit_hits"] += 1
208
  self._save_stats()
209
+
210
  wait_time = (base_delay * (2**retries)) + random.uniform(0.5, 1.5)
211
  logger.warning(
212
  f"⚠️ Groq rate limit hit. Retrying in {wait_time:.2f}s... (Attempt {retries + 1}/{max_retries})"
 
223
  with self._stats_lock:
224
  self.stats["errors"] += 1
225
  self._save_stats()
226
+
227
  logger.error("❌ Max retries reached. Request failed.")
228
  raise RuntimeError("RATE_LIMIT_EXCEEDED")
229
 
 
263
  self._save_stats()
264
 
265
  return response_text
266
+
267
  except Exception as e:
268
  logger.error(f"Groq text generation failed: {e}")
269
  return f"Error generating content: {str(e)}"
270
 
271
+
272
+ # Export global instance
273
  llm_engine = LLMSingleton.get_instance()