SCGR commited on
Commit
1c65d0e
Β·
1 Parent(s): 01ab2a4
py_backend/app/routers/caption.py CHANGED
@@ -44,7 +44,11 @@ if settings.HF_API_KEY:
44
  try:
45
  models = crud.get_models(db)
46
  for model in models:
47
- if model.provider == "huggingface" and model.model_id and model.m_code != "STUB_MODEL":
 
 
 
 
48
  try:
49
  service = ProvidersGenericVLMService(
50
  api_key=settings.HF_API_KEY,
@@ -89,8 +93,6 @@ async def create_caption(
89
  db: Session = Depends(get_db),
90
  ):
91
  print(f"πŸ“ Caption Router: Starting caption generation for image {image_id}")
92
- print(f"πŸ“ Caption Router: Title: {title}")
93
- print(f"πŸ“ Caption Router: Prompt: {prompt}")
94
  print(f"πŸ“ Caption Router: Requested model: {model_name}")
95
 
96
  # Get the image
@@ -99,16 +101,12 @@ async def create_caption(
99
  print(f"❌ Caption Router: Image {image_id} not found")
100
  raise HTTPException(404, f"Image {image_id} not found")
101
 
102
- print(f"πŸ“ Caption Router: Image found: {img.file_key}, type: {img.image_type}")
103
-
104
  # Get the prompt object
105
  prompt_obj = crud.get_prompt(db, prompt)
106
  if not prompt_obj:
107
  print(f"❌ Caption Router: Prompt '{prompt}' not found")
108
  raise HTTPException(400, f"Prompt '{prompt}' not found")
109
 
110
- print(f"πŸ“ Caption Router: Prompt found: {prompt_obj.p_code}")
111
-
112
  # Get image bytes
113
  try:
114
  if hasattr(storage, 's3') and settings.STORAGE_PROVIDER != "local":
@@ -122,7 +120,6 @@ async def create_caption(
122
  file_path = os.path.join(settings.STORAGE_DIR, img.file_key)
123
  with open(file_path, 'rb') as f:
124
  img_bytes = f.read()
125
- print(f"πŸ“ Caption Router: Image bytes retrieved: {len(img_bytes)} bytes")
126
  except Exception as e:
127
  print(f"❌ Caption Router: Failed to get image bytes: {e}")
128
  raise HTTPException(500, f"Failed to get image: {e}")
@@ -131,76 +128,63 @@ async def create_caption(
131
  metadata_instructions = ""
132
  if img.image_type == "drone_image":
133
  metadata_instructions = f"Image type: drone image. Center coordinates: {img.center_lon}, {img.center_lat}. Altitude: {img.amsl_m}m AMSL, {img.agl_m}m AGL. Heading: {img.heading_deg}Β°, Yaw: {img.yaw_deg}Β°, Pitch: {img.pitch_deg}Β°, Roll: {img.roll_deg}Β°. RTK fix: {img.rtk_fix}. Standard deviations: H={img.std_h_m}m, V={img.std_v_m}m."
134
- print(f"πŸ“ Caption Router: Drone metadata instructions prepared")
135
  else:
136
  metadata_instructions = f"Image type: crisis map. Source: {img.source}. Event type: {img.event_type}. EPSG: {img.epsg}. Countries: {img.countries}."
137
- print(f"πŸ“ Caption Router: Crisis map metadata instructions prepared")
138
 
139
  print(f"πŸ“ Caption Router: Calling VLM manager...")
140
 
141
- metadata = {}
142
  try:
143
  result = await vlm_manager.generate_caption(
144
- image_bytes=img_bytes,
145
  prompt=prompt_obj.label,
146
  metadata_instructions=metadata_instructions,
147
  model_name=model_name,
148
  db_session=db,
149
  )
150
-
151
- print(f"πŸ“ Caption Router: VLM manager returned result")
152
- print(f"πŸ“ Caption Router: Result keys: {list(result.keys())}")
153
- print(f"πŸ“ Caption Router: Model used: {result.get('model')}")
154
- print(f"πŸ“ Caption Router: Fallback used: {result.get('fallback_used')}")
155
-
156
- # Get the raw response for validation
157
- raw = result.get("raw_response", {})
158
-
159
- # Validate and clean the data using schema validation
160
- image_type = img.image_type
161
- print(f"πŸ“ Caption Router: Validating data for image type: {image_type}")
162
- print(f"πŸ“ Caption Router: Raw data structure: {list(raw.keys()) if isinstance(raw, dict) else 'Not a dict'}")
163
-
164
- cleaned_data, is_valid, validation_error = schema_validator.clean_and_validate_data(raw, image_type)
165
-
166
- if is_valid:
167
- print(f"βœ… Caption Router: Schema validation passed for {image_type}")
168
- text = cleaned_data.get("analysis", "")
169
- metadata = cleaned_data.get("metadata", {})
170
- else:
171
- print(f"⚠️ Caption Router: Schema validation failed for {image_type}: {validation_error}")
172
- # Use fallback but log the validation error
173
- text = result.get("caption", "This is a fallback caption due to schema validation error.")
174
- metadata = result.get("metadata", {})
175
- raw["validation_error"] = validation_error
176
- raw["validation_failed"] = True
177
-
178
- # Use the actual model that was used, not the requested model_name
179
- used_model = result.get("model", model_name) or "STUB_MODEL"
180
-
181
- # Check if fallback was used
182
- fallback_used = result.get("fallback_used", False)
183
- original_model = result.get("original_model", None)
184
- fallback_reason = result.get("fallback_reason", None)
185
-
186
- if fallback_used:
187
- print(f"⚠️ Caption Router: Model fallback occurred: {original_model} -> {used_model} (reason: {fallback_reason})")
188
- # Add fallback info to raw response for frontend
189
- raw["fallback_info"] = {
190
- "original_model": original_model,
191
- "fallback_model": used_model,
192
- "reason": fallback_reason
193
- }
194
- else:
195
- print(f"βœ… Caption Router: No fallback used, primary model {used_model} succeeded")
196
-
197
  except Exception as e:
198
- print(f"❌ Caption Router: VLM error, using fallback: {e}")
199
- print(f"❌ Caption Router: Error type: {type(e).__name__}")
200
- text = "This is a fallback caption due to VLM service error."
201
- used_model = "STUB_MODEL"
202
- raw = {"error": str(e), "fallback": True}
203
- metadata = {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
 
205
  print(f"πŸ“ Caption Router: Creating caption in database...")
206
 
@@ -218,20 +202,14 @@ async def create_caption(
218
  db.refresh(c)
219
 
220
  print(f"πŸ“ Caption Router: Caption created successfully")
221
- print(f"πŸ“ Caption Router: Caption ID: {c.image_id}")
222
- print(f"πŸ“ Caption Router: Model used: {c.model}")
223
 
224
  from .upload import convert_image_to_dict
225
  try:
226
  url = storage.get_object_url(c.file_key)
227
- print(f"πŸ“ Caption Router: Generated URL: {url}")
228
  if url.startswith('/') and settings.STORAGE_PROVIDER == "local":
229
  url = f"http://localhost:8000{url}"
230
- print(f"πŸ“ Caption Router: Local URL adjusted to: {url}")
231
  except Exception as e:
232
- print(f"⚠️ Caption Router: URL generation failed: {e}")
233
  url = f"/api/images/{c.image_id}/file"
234
- print(f"πŸ“ Caption Router: Using fallback URL: {url}")
235
 
236
  img_dict = convert_image_to_dict(c, url)
237
  print(f"πŸ“ Caption Router: Caption generation completed successfully")
 
44
  try:
45
  models = crud.get_models(db)
46
  for model in models:
47
+
48
+ if (model.provider == "huggingface" and
49
+ model.model_id and
50
+ model.m_code != "STUB_MODEL" and
51
+ model.m_code not in ["GPT-4O", "GEMINI15"]):
52
  try:
53
  service = ProvidersGenericVLMService(
54
  api_key=settings.HF_API_KEY,
 
93
  db: Session = Depends(get_db),
94
  ):
95
  print(f"πŸ“ Caption Router: Starting caption generation for image {image_id}")
 
 
96
  print(f"πŸ“ Caption Router: Requested model: {model_name}")
97
 
98
  # Get the image
 
101
  print(f"❌ Caption Router: Image {image_id} not found")
102
  raise HTTPException(404, f"Image {image_id} not found")
103
 
 
 
104
  # Get the prompt object
105
  prompt_obj = crud.get_prompt(db, prompt)
106
  if not prompt_obj:
107
  print(f"❌ Caption Router: Prompt '{prompt}' not found")
108
  raise HTTPException(400, f"Prompt '{prompt}' not found")
109
 
 
 
110
  # Get image bytes
111
  try:
112
  if hasattr(storage, 's3') and settings.STORAGE_PROVIDER != "local":
 
120
  file_path = os.path.join(settings.STORAGE_DIR, img.file_key)
121
  with open(file_path, 'rb') as f:
122
  img_bytes = f.read()
 
123
  except Exception as e:
124
  print(f"❌ Caption Router: Failed to get image bytes: {e}")
125
  raise HTTPException(500, f"Failed to get image: {e}")
 
128
  metadata_instructions = ""
129
  if img.image_type == "drone_image":
130
  metadata_instructions = f"Image type: drone image. Center coordinates: {img.center_lon}, {img.center_lat}. Altitude: {img.amsl_m}m AMSL, {img.agl_m}m AGL. Heading: {img.heading_deg}Β°, Yaw: {img.yaw_deg}Β°, Pitch: {img.pitch_deg}Β°, Roll: {img.roll_deg}Β°. RTK fix: {img.rtk_fix}. Standard deviations: H={img.std_h_m}m, V={img.std_v_m}m."
 
131
  else:
132
  metadata_instructions = f"Image type: crisis map. Source: {img.source}. Event type: {img.event_type}. EPSG: {img.epsg}. Countries: {img.countries}."
 
133
 
134
  print(f"πŸ“ Caption Router: Calling VLM manager...")
135
 
136
+ # Call VLM manager
137
  try:
138
  result = await vlm_manager.generate_caption(
139
+ image_bytes=img_bytes,
140
  prompt=prompt_obj.label,
141
  metadata_instructions=metadata_instructions,
142
  model_name=model_name,
143
  db_session=db,
144
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  except Exception as e:
146
+ print(f"❌ Caption Router: VLM manager failed: {e}")
147
+ raise HTTPException(500, f"Caption generation failed: {e}")
148
+
149
+ print(f"πŸ“ Caption Router: VLM manager returned result")
150
+
151
+ # Get the raw response for validation
152
+ raw = result.get("raw_response", {})
153
+
154
+ # Validate and clean the data using schema validation
155
+ image_type = img.image_type
156
+ print(f"πŸ“ Caption Router: Validating data for image type: {image_type}")
157
+
158
+ cleaned_data, is_valid, validation_error = schema_validator.clean_and_validate_data(raw, image_type)
159
+
160
+ if is_valid:
161
+ print(f"βœ… Caption Router: Schema validation passed for {image_type}")
162
+ text = cleaned_data.get("analysis", "")
163
+ metadata = cleaned_data.get("metadata", {})
164
+ else:
165
+ print(f"⚠️ Caption Router: Schema validation failed for {image_type}: {validation_error}")
166
+ # Use fallback but log the validation error
167
+ text = result.get("caption", "This is a fallback caption due to schema validation error.")
168
+ metadata = result.get("metadata", {})
169
+ raw["validation_error"] = validation_error
170
+ raw["validation_failed"] = True
171
+
172
+ # Use the actual model that was used, not the requested model_name
173
+ used_model = result.get("model", model_name) or "STUB_MODEL"
174
+
175
+ # Check if fallback was used
176
+ fallback_used = result.get("fallback_used", False)
177
+ original_model = result.get("original_model", None)
178
+ fallback_reason = result.get("fallback_reason", None)
179
+
180
+ if fallback_used:
181
+ print(f"⚠️ Caption Router: Model fallback occurred: {original_model} -> {used_model} (reason: {fallback_reason})")
182
+ # Add fallback info to raw response for frontend
183
+ raw["fallback_info"] = {
184
+ "original_model": original_model,
185
+ "fallback_model": used_model,
186
+ "reason": fallback_reason
187
+ }
188
 
189
  print(f"πŸ“ Caption Router: Creating caption in database...")
190
 
 
202
  db.refresh(c)
203
 
204
  print(f"πŸ“ Caption Router: Caption created successfully")
 
 
205
 
206
  from .upload import convert_image_to_dict
207
  try:
208
  url = storage.get_object_url(c.file_key)
 
209
  if url.startswith('/') and settings.STORAGE_PROVIDER == "local":
210
  url = f"http://localhost:8000{url}"
 
211
  except Exception as e:
 
212
  url = f"/api/images/{c.image_id}/file"
 
213
 
214
  img_dict = convert_image_to_dict(c, url)
215
  print(f"πŸ“ Caption Router: Caption generation completed successfully")
py_backend/app/services/gemini_service.py CHANGED
@@ -84,53 +84,18 @@ class GeminiService(VLMService):
84
  print(f"❌ Gemini: Error type: {error_type}")
85
  print(f"❌ Gemini: Error message: {error_msg}")
86
 
87
- # Capture Google Gemini API specific error details
88
- provider_error_details = {}
89
-
90
- # Check for Google API specific errors
91
- if hasattr(e, 'status_code'):
92
- provider_error_details = {
93
- "provider": "google",
94
- "status_code": e.status_code,
95
- "error_type": error_type,
96
- "error_message": error_msg
97
- }
98
- print(f"❌ Gemini: Google API Error Details: {provider_error_details}")
99
- elif hasattr(e, 'details'):
100
- try:
101
- provider_error_details = {
102
- "provider": "google",
103
- "error_details": str(e.details),
104
- "error_type": error_type,
105
- "error_message": error_msg
106
- }
107
- print(f"❌ Gemini: Google API Error Details: {provider_error_details}")
108
- except Exception as parse_error:
109
- print(f"⚠️ Gemini: Could not parse error details: {parse_error}")
110
- provider_error_details = {
111
- "provider": "google",
112
- "raw_error": error_msg,
113
- "error_type": error_type
114
- }
115
- else:
116
- provider_error_details = {
117
- "provider": "google",
118
- "raw_error": error_msg,
119
- "error_type": error_type
120
- }
121
-
122
  # Check for specific error types
123
  if "quota" in error_msg.lower() or "limit" in error_msg.lower():
124
  print(f"❌ Gemini: Quota or rate limit exceeded detected")
125
- raise Exception(f"MODEL_UNAVAILABLE: GEMINI15 is currently unavailable (quota/rate limit exceeded). Switching to another model. Provider details: {provider_error_details}")
126
  elif "authentication" in error_msg.lower() or "invalid" in error_msg.lower() or "api_key" in error_msg.lower():
127
  print(f"❌ Gemini: Authentication or API key error detected")
128
- raise Exception(f"MODEL_UNAVAILABLE: GEMINI15 is currently unavailable (authentication error). Switching to another model. Provider details: {provider_error_details}")
129
  elif "timeout" in error_msg.lower() or "connection" in error_msg.lower():
130
  print(f"❌ Gemini: Network timeout or connection error detected")
131
- raise Exception(f"MODEL_UNAVAILABLE: GEMINI15 is currently unavailable (network error). Switching to another model. Provider details: {provider_error_details}")
132
  else:
133
  print(f"❌ Gemini: Generic error, converting to MODEL_UNAVAILABLE")
134
- raise Exception(f"MODEL_UNAVAILABLE: GEMINI15 is currently unavailable ({error_type}: {error_msg}). Switching to another model. Provider details: {provider_error_details}")
135
 
136
 
 
84
  print(f"❌ Gemini: Error type: {error_type}")
85
  print(f"❌ Gemini: Error message: {error_msg}")
86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  # Check for specific error types
88
  if "quota" in error_msg.lower() or "limit" in error_msg.lower():
89
  print(f"❌ Gemini: Quota or rate limit exceeded detected")
90
+ raise Exception(f"MODEL_UNAVAILABLE: GEMINI15 is currently unavailable (quota/rate limit exceeded). Switching to another model.")
91
  elif "authentication" in error_msg.lower() or "invalid" in error_msg.lower() or "api_key" in error_msg.lower():
92
  print(f"❌ Gemini: Authentication or API key error detected")
93
+ raise Exception(f"MODEL_UNAVAILABLE: GEMINI15 is currently unavailable (authentication error). Switching to another model.")
94
  elif "timeout" in error_msg.lower() or "connection" in error_msg.lower():
95
  print(f"❌ Gemini: Network timeout or connection error detected")
96
+ raise Exception(f"MODEL_UNAVAILABLE: GEMINI15 is currently unavailable (network error). Switching to another model.")
97
  else:
98
  print(f"❌ Gemini: Generic error, converting to MODEL_UNAVAILABLE")
99
+ raise Exception(f"MODEL_UNAVAILABLE: GEMINI15 is currently unavailable ({error_type}: {error_msg}). Switching to another model.")
100
 
101
 
py_backend/app/services/gpt4v_service.py CHANGED
@@ -102,41 +102,16 @@ class GPT4VService(VLMService):
102
  print(f"❌ GPT-4V: Error type: {error_type}")
103
  print(f"❌ GPT-4V: Error message: {error_msg}")
104
 
105
- # Capture OpenAI API specific error details
106
- provider_error_details = {}
107
-
108
- # Check for OpenAI API specific errors
109
- if hasattr(e, 'response') and e.response:
110
- try:
111
- error_response = e.response.json()
112
- print(f"❌ GPT-4V: OpenAI API Error Response: {error_response}")
113
- provider_error_details = {
114
- "provider": "openai",
115
- "error_code": error_response.get("error", {}).get("code"),
116
- "error_type": error_response.get("error", {}).get("type"),
117
- "error_message": error_response.get("error", {}).get("message"),
118
- "error_param": error_response.get("error", {}).get("param"),
119
- "status_code": e.response.status_code
120
- }
121
- print(f"❌ GPT-4V: Parsed Error Details: {provider_error_details}")
122
- except Exception as parse_error:
123
- print(f"⚠️ GPT-4V: Could not parse error response: {parse_error}")
124
- provider_error_details = {
125
- "provider": "openai",
126
- "raw_error": error_msg,
127
- "status_code": getattr(e.response, 'status_code', None) if hasattr(e, 'response') else None
128
- }
129
-
130
  # Check for specific error types
131
  if "rate_limit" in error_msg.lower() or "quota" in error_msg.lower():
132
  print(f"❌ GPT-4V: Rate limit or quota exceeded detected")
133
- raise Exception(f"MODEL_UNAVAILABLE: GPT-4O is currently unavailable (rate limit/quota exceeded). Switching to another model. Provider details: {provider_error_details}")
134
  elif "authentication" in error_msg.lower() or "invalid" in error_msg.lower() or "api_key" in error_msg.lower():
135
  print(f"❌ GPT-4V: Authentication or API key error detected")
136
- raise Exception(f"MODEL_UNAVAILABLE: GPT-4O is currently unavailable (authentication error). Switching to another model. Provider details: {provider_error_details}")
137
  elif "timeout" in error_msg.lower() or "connection" in error_msg.lower():
138
  print(f"❌ GPT-4V: Network timeout or connection error detected")
139
- raise Exception(f"MODEL_UNAVAILABLE: GPT-4O is currently unavailable (network error). Switching to another model. Provider details: {provider_error_details}")
140
  else:
141
  print(f"❌ GPT-4V: Generic error, converting to MODEL_UNAVAILABLE")
142
- raise Exception(f"MODEL_UNAVAILABLE: GPT-4O is currently unavailable ({error_type}: {error_msg}). Switching to another model. Provider details: {provider_error_details}")
 
102
  print(f"❌ GPT-4V: Error type: {error_type}")
103
  print(f"❌ GPT-4V: Error message: {error_msg}")
104
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  # Check for specific error types
106
  if "rate_limit" in error_msg.lower() or "quota" in error_msg.lower():
107
  print(f"❌ GPT-4V: Rate limit or quota exceeded detected")
108
+ raise Exception(f"MODEL_UNAVAILABLE: GPT-4O is currently unavailable (rate limit/quota exceeded). Switching to another model.")
109
  elif "authentication" in error_msg.lower() or "invalid" in error_msg.lower() or "api_key" in error_msg.lower():
110
  print(f"❌ GPT-4V: Authentication or API key error detected")
111
+ raise Exception(f"MODEL_UNAVAILABLE: GPT-4O is currently unavailable (authentication error). Switching to another model.")
112
  elif "timeout" in error_msg.lower() or "connection" in error_msg.lower():
113
  print(f"❌ GPT-4V: Network timeout or connection error detected")
114
+ raise Exception(f"MODEL_UNAVAILABLE: GPT-4O is currently unavailable (network error). Switching to another model.")
115
  else:
116
  print(f"❌ GPT-4V: Generic error, converting to MODEL_UNAVAILABLE")
117
+ raise Exception(f"MODEL_UNAVAILABLE: GPT-4O is currently unavailable ({error_type}: {error_msg}). Switching to another model.")
py_backend/app/services/huggingface_service.py CHANGED
@@ -81,43 +81,8 @@ class HuggingFaceService(VLMService):
81
  ) as resp:
82
  raw_text = await resp.text()
83
  if resp.status != 200:
84
- # Capture the actual error response from HuggingFace
85
- try:
86
- error_response = await resp.json()
87
- print(f"❌ HuggingFace: API Error Response (HTTP {resp.status}): {error_response}")
88
-
89
- # Extract specific error details
90
- provider_error_details = {
91
- "provider": "huggingface",
92
- "status_code": resp.status,
93
- "error_response": error_response,
94
- "model_id": self.model_id,
95
- "model_name": self.model_name
96
- }
97
-
98
- # Check for specific error types
99
- if "error" in error_response:
100
- error_info = error_response["error"]
101
- provider_error_details.update({
102
- "error_type": error_info.get("type"),
103
- "error_message": error_info.get("message"),
104
- "error_code": error_info.get("code")
105
- })
106
-
107
- print(f"❌ HuggingFace: Parsed Error Details: {provider_error_details}")
108
-
109
- # Any non-200 status - throw generic error for fallback handling
110
- raise Exception(f"MODEL_UNAVAILABLE: {self.model_name} is currently unavailable (HTTP {resp.status}). Switching to another model. Provider details: {provider_error_details}")
111
- except Exception as parse_error:
112
- print(f"⚠️ HuggingFace: Could not parse error response: {parse_error}")
113
- provider_error_details = {
114
- "provider": "huggingface",
115
- "status_code": resp.status,
116
- "raw_response": raw_text,
117
- "model_id": self.model_id,
118
- "model_name": self.model_name
119
- }
120
- raise Exception(f"MODEL_UNAVAILABLE: {self.model_name} is currently unavailable (HTTP {resp.status}). Switching to another model. Provider details: {provider_error_details}")
121
  result = await resp.json()
122
  except Exception as e:
123
  if "MODEL_UNAVAILABLE" in str(e):
 
81
  ) as resp:
82
  raw_text = await resp.text()
83
  if resp.status != 200:
84
+ # Any non-200 status - throw generic error for fallback handling
85
+ raise Exception(f"MODEL_UNAVAILABLE: {self.model_name} is currently unavailable (HTTP {resp.status}). Switching to another model.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  result = await resp.json()
87
  except Exception as e:
88
  if "MODEL_UNAVAILABLE" in str(e):
py_backend/app/services/vlm_service.py CHANGED
@@ -66,27 +66,20 @@ class VLMServiceManager:
66
  """Generate caption using available VLM services with fallback"""
67
  print(f"πŸš€ VLM Manager: Starting caption generation")
68
  print(f"πŸš€ VLM Manager: Requested model: {model_name}")
69
- print(f"πŸš€ VLM Manager: Available services: {[s.model_name for s in self.services.values()]}")
70
- print(f"πŸš€ VLM Manager: Total services: {len(self.services)}")
71
 
72
  # Select initial service
73
  service = None
74
  if model_name:
75
- print(f"πŸš€ VLM Manager: Looking for requested model: {model_name}")
76
  service = self.services.get(model_name)
77
- if service:
78
- print(f"πŸš€ VLM Manager: Found requested model: {service.model_name}")
79
- else:
80
  print(f"⚠️ VLM Manager: Requested model {model_name} not found in services")
81
 
82
  if not service:
83
- print(f"πŸš€ VLM Manager: No specific model requested, selecting from available services")
84
  if db_session:
85
  try:
86
  from .. import crud
87
  available_models = crud.get_models(db_session)
88
  available_model_codes = [m.m_code for m in available_models if m.is_available]
89
- print(f"πŸš€ VLM Manager: Available models from DB: {available_model_codes}")
90
 
91
  available_services = [s for s in self.services.values() if s.model_name in available_model_codes]
92
  if available_services:
@@ -94,34 +87,22 @@ class VLMServiceManager:
94
  shuffled_services = available_services.copy()
95
  random.shuffle(shuffled_services)
96
  service = shuffled_services[0]
97
- print(f"πŸš€ VLM Manager: Randomly selected service: {service.model_name} (from {len(available_services)} available)")
98
- print(f"πŸš€ VLM Manager: All available services were: {[s.model_name for s in available_services]}")
99
- print(f"πŸš€ VLM Manager: Shuffled order: {[s.model_name for s in shuffled_services]}")
100
  else:
101
- print(f"⚠️ VLM Manager: No available services from DB, using fallback")
102
  service = next(iter(self.services.values()))
103
- print(f"πŸš€ VLM Manager: Using fallback service: {service.model_name}")
104
  except Exception as e:
105
  print(f"❌ VLM Manager: Error checking database availability: {e}, using fallback")
106
  service = next(iter(self.services.values()))
107
- print(f"πŸš€ VLM Manager: Using fallback service: {service.model_name}")
108
  else:
109
- print(f"πŸš€ VLM Manager: No database session, using service property")
110
  available_services = [s for s in self.services.values() if s.is_available]
111
  if available_services:
112
  import random
113
  service = random.choice(available_services)
114
- print(f"πŸš€ VLM Manager: Randomly selected service: {service.model_name}")
115
  else:
116
- print(f"⚠️ VLM Manager: No available services, using fallback")
117
  service = next(iter(self.services.values()))
118
- print(f"πŸš€ VLM Manager: Using fallback service: {service.model_name}")
119
 
120
  if not service:
121
  raise ValueError("No VLM services available")
122
 
123
- print(f"πŸš€ VLM Manager: Initial service selected: {service.model_name}")
124
-
125
  # Track attempts to avoid infinite loops
126
  attempted_services = set()
127
  max_attempts = len(self.services)
@@ -129,7 +110,6 @@ class VLMServiceManager:
129
  while len(attempted_services) < max_attempts:
130
  try:
131
  print(f"πŸš€ VLM Manager: Attempting with service: {service.model_name}")
132
- print(f"πŸš€ VLM Manager: Attempt #{len(attempted_services) + 1}/{max_attempts}")
133
 
134
  result = await service.generate_caption(image_bytes, prompt, metadata_instructions)
135
  if isinstance(result, dict):
@@ -150,45 +130,6 @@ class VLMServiceManager:
150
  if "MODEL_UNAVAILABLE" in error_str:
151
  attempted_services.add(service.model_name)
152
  print(f"πŸ”„ VLM Manager: Model {service.model_name} is unavailable, trying another service...")
153
- print(f"πŸ”„ VLM Manager: Attempted services so far: {attempted_services}")
154
-
155
- # Extract provider error details if available
156
- provider_error_details = {}
157
- if "Provider details:" in error_str:
158
- try:
159
- # Extract the provider details section
160
- details_start = error_str.find("Provider details:") + len("Provider details:")
161
- details_str = error_str[details_start:].strip()
162
- if details_str.startswith("{") and details_str.endswith("}"):
163
- import json
164
- provider_error_details = json.loads(details_str)
165
- print(f"πŸ” VLM Manager: Provider Error Details: {provider_error_details}")
166
- except Exception as parse_error:
167
- print(f"⚠️ VLM Manager: Could not parse provider error details: {parse_error}")
168
-
169
- # Log specific error information
170
- if provider_error_details:
171
- provider = provider_error_details.get("provider", "unknown")
172
- status_code = provider_error_details.get("status_code")
173
- error_type = provider_error_details.get("error_type")
174
- error_message = provider_error_details.get("error_message")
175
-
176
- print(f"πŸ” VLM Manager: {service.model_name} failed with {provider} error:")
177
- print(f" Status Code: {status_code}")
178
- print(f" Error Type: {error_type}")
179
- print(f" Error Message: {error_message}")
180
-
181
- # Log specific error patterns
182
- if status_code == 400:
183
- print(f"πŸ” VLM Manager: HTTP 400 detected - likely request format issue")
184
- elif status_code == 401:
185
- print(f"πŸ” VLM Manager: HTTP 401 detected - authentication issue")
186
- elif status_code == 403:
187
- print(f"πŸ” VLM Manager: HTTP 403 detected - access forbidden")
188
- elif status_code == 429:
189
- print(f"πŸ” VLM Manager: HTTP 429 detected - rate limit exceeded")
190
- elif status_code == 500:
191
- print(f"πŸ” VLM Manager: HTTP 500 detected - server error")
192
 
193
  # Try to find another available service
194
  if db_session:
@@ -196,7 +137,6 @@ class VLMServiceManager:
196
  from .. import crud
197
  available_models = crud.get_models(db_session)
198
  available_model_codes = [m.m_code for m in available_models if m.is_available]
199
- print(f"πŸ”„ VLM Manager: Available models from DB: {available_model_codes}")
200
 
201
  # Find next available service that hasn't been attempted
202
  for next_service in self.services.values():
@@ -206,12 +146,10 @@ class VLMServiceManager:
206
  print(f"πŸ”„ VLM Manager: Switching to fallback service: {service.model_name}")
207
  break
208
  else:
209
- print(f"⚠️ VLM Manager: No more available services from DB, using any untried service")
210
  # No more available services, use any untried service
211
  for next_service in self.services.values():
212
  if next_service.model_name not in attempted_services:
213
  service = next_service
214
- print(f"πŸ”„ VLM Manager: Using untried service as fallback: {service.model_name}")
215
  break
216
  except Exception as db_error:
217
  print(f"❌ VLM Manager: Error checking database availability: {db_error}")
@@ -219,15 +157,12 @@ class VLMServiceManager:
219
  for next_service in self.services.values():
220
  if next_service.model_name not in attempted_services:
221
  service = next_service
222
- print(f"πŸ”„ VLM Manager: Using untried service as fallback: {service.model_name}")
223
  break
224
  else:
225
- print(f"πŸ”„ VLM Manager: No database session, using any untried service")
226
  # No database session, use any untried service
227
  for next_service in self.services.values():
228
  if next_service.model_name not in attempted_services:
229
  service = next_service
230
- print(f"πŸ”„ VLM Manager: Using untried service as fallback: {service.model_name}")
231
  break
232
 
233
  if not service:
@@ -242,7 +177,6 @@ class VLMServiceManager:
242
 
243
  # If we get here, we've tried all services
244
  print(f"❌ VLM Manager: All VLM services failed due to model unavailability")
245
- print(f"❌ VLM Manager: Attempted services: {attempted_services}")
246
  raise ValueError("All VLM services failed due to model unavailability")
247
 
248
  vlm_manager = VLMServiceManager()
 
66
  """Generate caption using available VLM services with fallback"""
67
  print(f"πŸš€ VLM Manager: Starting caption generation")
68
  print(f"πŸš€ VLM Manager: Requested model: {model_name}")
 
 
69
 
70
  # Select initial service
71
  service = None
72
  if model_name:
 
73
  service = self.services.get(model_name)
74
+ if not service:
 
 
75
  print(f"⚠️ VLM Manager: Requested model {model_name} not found in services")
76
 
77
  if not service:
 
78
  if db_session:
79
  try:
80
  from .. import crud
81
  available_models = crud.get_models(db_session)
82
  available_model_codes = [m.m_code for m in available_models if m.is_available]
 
83
 
84
  available_services = [s for s in self.services.values() if s.model_name in available_model_codes]
85
  if available_services:
 
87
  shuffled_services = available_services.copy()
88
  random.shuffle(shuffled_services)
89
  service = shuffled_services[0]
 
 
 
90
  else:
 
91
  service = next(iter(self.services.values()))
 
92
  except Exception as e:
93
  print(f"❌ VLM Manager: Error checking database availability: {e}, using fallback")
94
  service = next(iter(self.services.values()))
 
95
  else:
 
96
  available_services = [s for s in self.services.values() if s.is_available]
97
  if available_services:
98
  import random
99
  service = random.choice(available_services)
 
100
  else:
 
101
  service = next(iter(self.services.values()))
 
102
 
103
  if not service:
104
  raise ValueError("No VLM services available")
105
 
 
 
106
  # Track attempts to avoid infinite loops
107
  attempted_services = set()
108
  max_attempts = len(self.services)
 
110
  while len(attempted_services) < max_attempts:
111
  try:
112
  print(f"πŸš€ VLM Manager: Attempting with service: {service.model_name}")
 
113
 
114
  result = await service.generate_caption(image_bytes, prompt, metadata_instructions)
115
  if isinstance(result, dict):
 
130
  if "MODEL_UNAVAILABLE" in error_str:
131
  attempted_services.add(service.model_name)
132
  print(f"πŸ”„ VLM Manager: Model {service.model_name} is unavailable, trying another service...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
  # Try to find another available service
135
  if db_session:
 
137
  from .. import crud
138
  available_models = crud.get_models(db_session)
139
  available_model_codes = [m.m_code for m in available_models if m.is_available]
 
140
 
141
  # Find next available service that hasn't been attempted
142
  for next_service in self.services.values():
 
146
  print(f"πŸ”„ VLM Manager: Switching to fallback service: {service.model_name}")
147
  break
148
  else:
 
149
  # No more available services, use any untried service
150
  for next_service in self.services.values():
151
  if next_service.model_name not in attempted_services:
152
  service = next_service
 
153
  break
154
  except Exception as db_error:
155
  print(f"❌ VLM Manager: Error checking database availability: {db_error}")
 
157
  for next_service in self.services.values():
158
  if next_service.model_name not in attempted_services:
159
  service = next_service
 
160
  break
161
  else:
 
162
  # No database session, use any untried service
163
  for next_service in self.services.values():
164
  if next_service.model_name not in attempted_services:
165
  service = next_service
 
166
  break
167
 
168
  if not service:
 
177
 
178
  # If we get here, we've tried all services
179
  print(f"❌ VLM Manager: All VLM services failed due to model unavailability")
 
180
  raise ValueError("All VLM services failed due to model unavailability")
181
 
182
  vlm_manager = VLMServiceManager()