Spaces:
Running
on
Zero
Running
on
Zero
Update models.py
Browse files
models.py
CHANGED
@@ -19,7 +19,8 @@ from utils import clean_memory, safe_execute
|
|
19 |
from professional_photography import (
|
20 |
ProfessionalPhotoAnalyzer,
|
21 |
enhance_flux_prompt_with_professional_knowledge,
|
22 |
-
professional_analyzer
|
|
|
23 |
)
|
24 |
|
25 |
logger = logging.getLogger(__name__)
|
@@ -89,183 +90,43 @@ class BagelAPIAnalyzer(BaseImageAnalyzer):
|
|
89 |
logger.error(f"Fallback initialization failed: {e2}")
|
90 |
return False
|
91 |
|
92 |
-
def
|
93 |
-
"""
|
94 |
-
|
95 |
-
if analysis_type == "cinematic":
|
96 |
-
return """You are a master cinematographer with 30+ years of experience. Analyze this image with complete professional cinematography knowledge and provide exactly two sections:
|
97 |
-
|
98 |
-
1. DESCRIPTION: Analyze what you see using professional cinematography terminology:
|
99 |
-
|
100 |
-
First, identify the PHOTOGRAPHIC PLANE:
|
101 |
-
- EXTREME WIDE SHOT: Subject very small in environment (establishes location)
|
102 |
-
- WIDE SHOT: Full body visible with environment (subject in context)
|
103 |
-
- MEDIUM SHOT: From waist up (balance subject/environment)
|
104 |
-
- CLOSE-UP: Head and shoulders (emotion and expression)
|
105 |
-
- EXTREME CLOSE-UP: Part of face or detail (intense emotion)
|
106 |
-
- DETAIL SHOT: Specific small element (highlight aspect)
|
107 |
-
|
108 |
-
Second, identify the CAMERA ANGLE:
|
109 |
-
- EYE LEVEL: Camera at subject's eye level (neutral, natural perspective)
|
110 |
-
- LOW ANGLE: Camera below looking up (subject appears powerful, heroic)
|
111 |
-
- HIGH ANGLE: Camera above looking down (subject appears vulnerable, shows context)
|
112 |
-
- DUTCH ANGLE: Camera tilted (dynamic tension, instability)
|
113 |
-
|
114 |
-
Third, analyze the LIGHTING:
|
115 |
-
- GOLDEN HOUR: Warm, soft, directional light (first/last hour of sun)
|
116 |
-
- BLUE HOUR: Even blue light, dramatic mood (20-30 min after sunset)
|
117 |
-
- NATURAL DAYLIGHT: Bright sunny conditions
|
118 |
-
- SOFT NATURAL: Overcast, diffused, even light
|
119 |
-
- DRAMATIC: High contrast, moody shadows
|
120 |
-
- STUDIO: Controlled professional lighting
|
121 |
-
|
122 |
-
Fourth, identify COMPOSITION:
|
123 |
-
- RULE OF THIRDS: Key elements on intersection points
|
124 |
-
- LEADING LINES: Lines guide viewer's eye to subject
|
125 |
-
- SYMMETRICAL: Mirror-like balance
|
126 |
-
- CENTERED: Subject in middle for impact
|
127 |
-
- DEPTH LAYERS: Foreground, middle ground, background separation
|
128 |
-
|
129 |
-
Now describe the scene combining all these professional elements in flowing descriptive language.
|
130 |
-
|
131 |
-
2. CAMERA_SETUP: Recommend specific professional equipment based on your analysis:
|
132 |
-
|
133 |
-
For PORTRAIT scenes: Canon EOS R5, 85mm f/1.4 lens, f/2.8, ISO 200, single point AF on eyes
|
134 |
-
For LANDSCAPE scenes: Phase One XT, 24-70mm f/4 lens, f/8-f/11, ISO 100, hyperfocal distance
|
135 |
-
For STREET scenes: Leica M11, 35mm f/1.4 lens, f/5.6-f/8, ISO 400-1600, zone focusing
|
136 |
-
For ARCHITECTURE: Canon EOS R5, 24-70mm f/2.8 lens, f/8-f/11, ISO 100, tilt-shift correction
|
137 |
-
For ACTION: Sony A1, 70-200mm f/2.8 lens, f/2.8-f/4, ISO 800-3200, continuous AF tracking
|
138 |
-
|
139 |
-
Apply your complete professional cinematography knowledge to see this image as a master would."""
|
140 |
-
|
141 |
-
elif analysis_type == "flux_optimized":
|
142 |
-
return """You are a professional cinematographer analyzing this image for photorealistic prompt generation. Use complete technical knowledge and provide exactly two sections:
|
143 |
-
|
144 |
-
1. DESCRIPTION: Technical cinematographic analysis:
|
145 |
-
|
146 |
-
PHOTOGRAPHIC PLANE (choose one):
|
147 |
-
- Wide shot: Full subject visible with environment
|
148 |
-
- Medium shot: Waist up, balanced composition
|
149 |
-
- Close-up: Head and shoulders, tight framing
|
150 |
-
- Extreme close-up: Facial details or specific elements
|
151 |
-
- Detail shot: Small specific elements highlighted
|
152 |
-
|
153 |
-
CAMERA ANGLE (identify):
|
154 |
-
- Eye level: Natural, relatable perspective
|
155 |
-
- Low angle: Looking up, subject appears powerful
|
156 |
-
- High angle: Looking down, shows vulnerability/context
|
157 |
-
- Dutch angle: Tilted, creates dynamic tension
|
158 |
-
|
159 |
-
LIGHTING TYPE (analyze):
|
160 |
-
- Golden hour: Warm, soft directional light
|
161 |
-
- Natural daylight: Bright outdoor conditions
|
162 |
-
- Soft natural: Overcast, even diffusion
|
163 |
-
- Dramatic: High contrast, moody shadows
|
164 |
-
- Blue hour: Even twilight, dramatic mood
|
165 |
-
|
166 |
-
COMPOSITION TECHNIQUE (apply):
|
167 |
-
- Rule of thirds: Subject on intersection points
|
168 |
-
- Leading lines: Elements guide eye to subject
|
169 |
-
- Symmetrical: Balanced mirror composition
|
170 |
-
- Centered: Subject middle for impact
|
171 |
-
- Dynamic: Diagonal elements, movement
|
172 |
-
|
173 |
-
Describe the scene using these professional cinematography elements in precise technical language.
|
174 |
-
|
175 |
-
2. CAMERA_SETUP: Professional equipment recommendation:
|
176 |
-
|
177 |
-
PORTRAIT SETUP: Canon EOS R5 with 85mm f/1.4 lens at f/2.8, ISO 200, rule of thirds composition
|
178 |
-
LANDSCAPE SETUP: Phase One XT with 24-70mm f/4 lens at f/8, ISO 100, hyperfocal distance focus
|
179 |
-
STREET SETUP: Leica M11 with 35mm f/1.4 lens at f/5.6, ISO 800, zone focusing technique
|
180 |
-
ARCHITECTURE SETUP: Canon EOS R5 with 24-70mm f/2.8 lens at f/11, ISO 100, perspective correction
|
181 |
-
ACTION SETUP: Sony A1 with 70-200mm f/2.8 lens at f/4, ISO 1600, continuous AF tracking
|
182 |
-
|
183 |
-
Choose the setup that matches your scene analysis and provide complete technical specifications."""
|
184 |
-
|
185 |
-
else: # multimodal analysis
|
186 |
-
return """You are a master cinematographer with decades of professional experience. Analyze this image using complete cinematography knowledge and provide exactly two sections:
|
187 |
-
|
188 |
-
1. DESCRIPTION: Professional cinematographic analysis combining:
|
189 |
-
|
190 |
-
PHOTOGRAPHIC PLANES: Identify if this is a wide shot (full subject with environment), medium shot (waist up), close-up (head/shoulders), extreme close-up (facial details), or detail shot (specific elements).
|
191 |
-
|
192 |
-
CAMERA ANGLES: Determine if shot from eye level (natural perspective), low angle (looking up, powerful), high angle (looking down, vulnerable), or dutch angle (tilted, dynamic).
|
193 |
-
|
194 |
-
LIGHTING ANALYSIS: Analyze if this is golden hour (warm directional), natural daylight (bright outdoor), soft natural (overcast even), dramatic (high contrast), blue hour (twilight mood), or studio (controlled).
|
195 |
-
|
196 |
-
COMPOSITION: Identify rule of thirds (key elements on intersections), leading lines (guiding elements), symmetrical (balanced), centered (middle impact), or dynamic (diagonal movement).
|
197 |
-
|
198 |
-
Describe the complete scene using professional cinematography terminology in flowing descriptive language that captures all visual and technical elements.
|
199 |
-
|
200 |
-
2. CAMERA_SETUP: Professional equipment recommendation based on scene analysis:
|
201 |
-
|
202 |
-
Choose from these professional setups:
|
203 |
-
- PORTRAIT: Canon EOS R5, 85mm f/1.4 lens, f/2.8, ISO 200
|
204 |
-
- LANDSCAPE: Phase One XT, 24-70mm f/4 lens, f/8, ISO 100
|
205 |
-
- STREET: Leica M11, 35mm f/1.4 lens, f/5.6, ISO 800
|
206 |
-
- ARCHITECTURE: Canon EOS R5, 24-70mm f/2.8 lens, f/11, ISO 100
|
207 |
-
- ACTION: Sony A1, 70-200mm f/2.8 lens, f/4, ISO 1600
|
208 |
-
|
209 |
-
Provide complete technical specifications matching your cinematographic analysis."""
|
210 |
-
|
211 |
-
def _extract_professional_camera_setup(self, description: str) -> Optional[str]:
|
212 |
-
"""Extract and enhance camera setup with professional photography knowledge"""
|
213 |
try:
|
214 |
-
|
215 |
-
|
216 |
-
# Extract BAGEL's camera recommendation
|
217 |
-
if "CAMERA_SETUP:" in description:
|
218 |
-
parts = description.split("CAMERA_SETUP:")
|
219 |
-
if len(parts) > 1:
|
220 |
-
camera_section = parts[1].strip()
|
221 |
-
# Take the first substantial line
|
222 |
-
lines = camera_section.split('\n')
|
223 |
-
for line in lines:
|
224 |
-
clean_line = line.strip()
|
225 |
-
if len(clean_line) > 20 and not clean_line.startswith('2.'):
|
226 |
-
camera_setup = clean_line
|
227 |
-
break
|
228 |
-
|
229 |
-
elif "2. CAMERA_SETUP" in description:
|
230 |
-
parts = description.split("2. CAMERA_SETUP")
|
231 |
-
if len(parts) > 1:
|
232 |
-
camera_section = parts[1].strip()
|
233 |
-
lines = camera_section.split('\n')
|
234 |
-
for line in lines:
|
235 |
-
clean_line = line.strip()
|
236 |
-
if len(clean_line) > 20:
|
237 |
-
camera_setup = clean_line
|
238 |
-
break
|
239 |
|
240 |
-
|
241 |
-
|
242 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
243 |
|
244 |
-
return
|
245 |
|
246 |
except Exception as e:
|
247 |
-
logger.warning(f"
|
248 |
-
|
|
|
249 |
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
setup = re.sub(r'^(CAMERA_SETUP:|2\.\s*CAMERA_SETUP:?)\s*', '', setup, flags=re.IGNORECASE)
|
256 |
-
|
257 |
-
# Clean up formatting
|
258 |
-
setup = re.sub(r'\s+', ' ', setup).strip()
|
259 |
-
|
260 |
-
# Ensure proper format
|
261 |
-
if setup and not setup.lower().startswith('shot on'):
|
262 |
-
setup = f"shot on {setup}"
|
263 |
-
|
264 |
-
return setup
|
265 |
-
|
266 |
-
except Exception as e:
|
267 |
-
logger.warning(f"Camera setup cleaning failed: {e}")
|
268 |
-
return raw_setup
|
269 |
|
270 |
def _save_temp_image(self, image: Image.Image) -> str:
|
271 |
"""Save image to temporary file for API call"""
|
@@ -313,29 +174,29 @@ Provide complete technical specifications matching your cinematographic analysis
|
|
313 |
}
|
314 |
|
315 |
try:
|
316 |
-
# Use professional
|
317 |
if prompt is None:
|
318 |
-
prompt = self.
|
319 |
|
320 |
# Save image to temporary file
|
321 |
temp_path = self._save_temp_image(image)
|
322 |
if not temp_path:
|
323 |
return "Image processing failed", {"error": "Could not save image"}
|
324 |
|
325 |
-
logger.info("Calling BAGEL API with
|
326 |
|
327 |
-
# Call BAGEL API with
|
328 |
result = self.client.predict(
|
329 |
image=handle_file(temp_path),
|
330 |
prompt=prompt,
|
331 |
show_thinking=False,
|
332 |
-
do_sample=
|
333 |
-
text_temperature=0.
|
334 |
-
max_new_tokens=
|
335 |
api_name=self.api_endpoint
|
336 |
)
|
337 |
|
338 |
-
# Extract
|
339 |
if isinstance(result, tuple) and len(result) >= 2:
|
340 |
description = result[1] if result[1] else result[0]
|
341 |
else:
|
@@ -344,15 +205,12 @@ Provide complete technical specifications matching your cinematographic analysis
|
|
344 |
if isinstance(description, str) and description.strip():
|
345 |
description = description.strip()
|
346 |
|
347 |
-
# Extract
|
348 |
-
|
349 |
-
if camera_setup:
|
350 |
-
metadata["camera_setup"] = camera_setup
|
351 |
metadata["has_camera_suggestion"] = True
|
352 |
-
logger.info(
|
353 |
else:
|
354 |
metadata["has_camera_suggestion"] = False
|
355 |
-
logger.info("No camera setup found in BAGEL response")
|
356 |
|
357 |
# Mark as cinematography enhanced
|
358 |
metadata["cinematography_context_applied"] = True
|
@@ -367,7 +225,7 @@ Provide complete technical specifications matching your cinematographic analysis
|
|
367 |
"analysis_type": "professional_enhanced"
|
368 |
})
|
369 |
|
370 |
-
logger.info(f"BAGEL Professional analysis complete: {len(description)} chars
|
371 |
return description, metadata
|
372 |
|
373 |
except Exception as e:
|
@@ -380,17 +238,17 @@ Provide complete technical specifications matching your cinematographic analysis
|
|
380 |
|
381 |
def analyze_for_cinematic_prompt(self, image: Image.Image) -> Tuple[str, Dict[str, Any]]:
|
382 |
"""Analyze image specifically for cinematic/MIA TV Series prompt generation"""
|
383 |
-
cinematic_prompt = self.
|
384 |
return self.analyze_image(image, cinematic_prompt)
|
385 |
|
386 |
def analyze_for_flux_with_professional_context(self, image: Image.Image) -> Tuple[str, Dict[str, Any]]:
|
387 |
"""Analyze image for FLUX with enhanced professional cinematography context"""
|
388 |
-
flux_prompt = self.
|
389 |
return self.analyze_image(image, flux_prompt)
|
390 |
|
391 |
def analyze_for_multiengine_prompt(self, image: Image.Image) -> Tuple[str, Dict[str, Any]]:
|
392 |
"""Analyze image for multi-engine compatibility (Flux, Midjourney, etc.)"""
|
393 |
-
multiengine_prompt = self.
|
394 |
return self.analyze_image(image, multiengine_prompt)
|
395 |
|
396 |
def cleanup(self) -> None:
|
@@ -405,7 +263,7 @@ Provide complete technical specifications matching your cinematographic analysis
|
|
405 |
|
406 |
|
407 |
class FallbackAnalyzer(BaseImageAnalyzer):
|
408 |
-
"""Enhanced fallback analyzer
|
409 |
|
410 |
def __init__(self):
|
411 |
super().__init__()
|
@@ -417,43 +275,45 @@ class FallbackAnalyzer(BaseImageAnalyzer):
|
|
417 |
return True
|
418 |
|
419 |
def analyze_image(self, image: Image.Image) -> Tuple[str, Dict[str, Any]]:
|
420 |
-
"""Provide enhanced image description
|
421 |
try:
|
422 |
width, height = image.size
|
423 |
-
mode = image.mode
|
424 |
aspect_ratio = width / height
|
425 |
|
426 |
-
#
|
427 |
-
|
428 |
-
orientation = "landscape"
|
429 |
-
scene_type = "landscape"
|
430 |
-
plane = "Wide shot"
|
431 |
-
camera_suggestion = "Phase One XT with 24-70mm f/4 lens, f/8, ISO 100"
|
432 |
-
elif aspect_ratio < 0.75:
|
433 |
-
orientation = "portrait"
|
434 |
-
scene_type = "portrait_studio"
|
435 |
-
plane = "Close-up"
|
436 |
-
camera_suggestion = "Canon EOS R5 with 85mm f/1.4 lens, f/2.8, ISO 200"
|
437 |
-
else:
|
438 |
-
orientation = "square"
|
439 |
-
scene_type = "general"
|
440 |
-
plane = "Medium shot"
|
441 |
-
camera_suggestion = "Canon EOS R6 with 50mm f/1.8 lens, f/4, ISO 400"
|
442 |
|
443 |
-
#
|
444 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
445 |
|
446 |
metadata = {
|
447 |
"model": "Professional-Fallback",
|
448 |
"device": "cpu",
|
449 |
"confidence": 0.7,
|
450 |
"image_size": f"{width}x{height}",
|
451 |
-
"color_mode": mode,
|
452 |
-
"orientation": orientation,
|
453 |
"aspect_ratio": round(aspect_ratio, 2),
|
454 |
-
"scene_type": scene_type,
|
455 |
"has_camera_suggestion": True,
|
456 |
-
"camera_setup":
|
457 |
"professional_enhancement": True,
|
458 |
"cinematography_context_applied": True
|
459 |
}
|
@@ -462,7 +322,7 @@ class FallbackAnalyzer(BaseImageAnalyzer):
|
|
462 |
|
463 |
except Exception as e:
|
464 |
logger.error(f"Professional fallback analysis failed: {e}")
|
465 |
-
return "Professional cinematographic analysis
|
466 |
"error": str(e),
|
467 |
"model": "Professional-Fallback"
|
468 |
}
|
@@ -511,15 +371,15 @@ class ModelManager:
|
|
511 |
if success and result[1].get("error") is None:
|
512 |
return result
|
513 |
else:
|
514 |
-
#
|
515 |
-
logger.warning(f"Primary model failed, using
|
516 |
fallback_analyzer = self.get_analyzer("fallback")
|
517 |
fallback_success, fallback_result = safe_execute(fallback_analyzer.analyze_image, image)
|
518 |
|
519 |
if fallback_success:
|
520 |
return fallback_result
|
521 |
else:
|
522 |
-
return "All
|
523 |
|
524 |
def cleanup_all(self) -> None:
|
525 |
"""Clean up all model resources"""
|
@@ -527,10 +387,10 @@ class ModelManager:
|
|
527 |
analyzer.cleanup()
|
528 |
self.analyzers.clear()
|
529 |
clean_memory()
|
530 |
-
logger.info("All
|
531 |
|
532 |
|
533 |
-
# Global model manager instance
|
534 |
model_manager = ModelManager(preferred_model="bagel-professional")
|
535 |
|
536 |
|
|
|
19 |
from professional_photography import (
|
20 |
ProfessionalPhotoAnalyzer,
|
21 |
enhance_flux_prompt_with_professional_knowledge,
|
22 |
+
professional_analyzer,
|
23 |
+
export_professional_prompt_enhancement
|
24 |
)
|
25 |
|
26 |
logger = logging.getLogger(__name__)
|
|
|
90 |
logger.error(f"Fallback initialization failed: {e2}")
|
91 |
return False
|
92 |
|
93 |
+
def _get_professional_prompt(self, analysis_type: str = "multimodal") -> str:
|
94 |
+
"""Get professional prompt created by professional_photography.py"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
try:
|
96 |
+
# Let professional_photography.py create the complete prompt with full knowledge base
|
97 |
+
enhanced_context = self.professional_analyzer.generate_enhanced_context("")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
|
99 |
+
if analysis_type == "cinematic":
|
100 |
+
# Use the professional analyzer to format cinematic prompt
|
101 |
+
prompt = self.professional_analyzer.format_bagel_enhancement_prompt(
|
102 |
+
base_prompt="Analyze this image with complete professional cinematography expertise for cinema-quality generation.",
|
103 |
+
enhanced_context=enhanced_context
|
104 |
+
)
|
105 |
+
elif analysis_type == "flux_optimized":
|
106 |
+
# Use the professional analyzer to format FLUX prompt
|
107 |
+
prompt = self.professional_analyzer.format_bagel_enhancement_prompt(
|
108 |
+
base_prompt="Analyze this image with complete professional photography knowledge for photorealistic prompt generation.",
|
109 |
+
enhanced_context=enhanced_context
|
110 |
+
)
|
111 |
+
else:
|
112 |
+
# Use the professional analyzer to format multimodal prompt
|
113 |
+
prompt = self.professional_analyzer.format_bagel_enhancement_prompt(
|
114 |
+
base_prompt="Analyze this image with complete professional cinematography knowledge for multi-engine prompt generation.",
|
115 |
+
enhanced_context=enhanced_context
|
116 |
+
)
|
117 |
|
118 |
+
return prompt
|
119 |
|
120 |
except Exception as e:
|
121 |
+
logger.warning(f"Professional prompt generation failed: {e}")
|
122 |
+
# Fallback to basic professional prompt
|
123 |
+
return """Analyze this image using complete professional cinematography expertise. Provide exactly two sections:
|
124 |
|
125 |
+
1. DESCRIPTION: Complete professional visual analysis using your full cinematography knowledge - identify the photographic plane (wide shot, close-up, medium shot), camera angle (eye level, low angle, high angle), lighting type (golden hour, natural daylight, dramatic), and composition technique (rule of thirds, leading lines, symmetrical). Describe the specific subject, action, and context in detail.
|
126 |
+
|
127 |
+
2. CAMERA_SETUP: Recommend specific professional equipment based on your scene analysis - camera body, lens specifications, aperture settings, ISO, and any special techniques.
|
128 |
+
|
129 |
+
Apply your complete professional cinematography knowledge."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
|
131 |
def _save_temp_image(self, image: Image.Image) -> str:
|
132 |
"""Save image to temporary file for API call"""
|
|
|
174 |
}
|
175 |
|
176 |
try:
|
177 |
+
# Use professional prompt created by professional_photography.py
|
178 |
if prompt is None:
|
179 |
+
prompt = self._get_professional_prompt("multimodal")
|
180 |
|
181 |
# Save image to temporary file
|
182 |
temp_path = self._save_temp_image(image)
|
183 |
if not temp_path:
|
184 |
return "Image processing failed", {"error": "Could not save image"}
|
185 |
|
186 |
+
logger.info("Calling BAGEL API with professional_photography.py prompt...")
|
187 |
|
188 |
+
# Call BAGEL API with professional prompt - let it do its work
|
189 |
result = self.client.predict(
|
190 |
image=handle_file(temp_path),
|
191 |
prompt=prompt,
|
192 |
show_thinking=False,
|
193 |
+
do_sample=True, # Allow creativity
|
194 |
+
text_temperature=0.7, # Higher temperature for richer descriptions
|
195 |
+
max_new_tokens=1024, # More tokens for detailed analysis
|
196 |
api_name=self.api_endpoint
|
197 |
)
|
198 |
|
199 |
+
# Extract response without filtering
|
200 |
if isinstance(result, tuple) and len(result) >= 2:
|
201 |
description = result[1] if result[1] else result[0]
|
202 |
else:
|
|
|
205 |
if isinstance(description, str) and description.strip():
|
206 |
description = description.strip()
|
207 |
|
208 |
+
# Extract camera setup if present
|
209 |
+
if "CAMERA_SETUP:" in description or "2. CAMERA_SETUP" in description:
|
|
|
|
|
210 |
metadata["has_camera_suggestion"] = True
|
211 |
+
logger.info("BAGEL provided camera setup recommendation")
|
212 |
else:
|
213 |
metadata["has_camera_suggestion"] = False
|
|
|
214 |
|
215 |
# Mark as cinematography enhanced
|
216 |
metadata["cinematography_context_applied"] = True
|
|
|
225 |
"analysis_type": "professional_enhanced"
|
226 |
})
|
227 |
|
228 |
+
logger.info(f"BAGEL Professional analysis complete: {len(description)} chars")
|
229 |
return description, metadata
|
230 |
|
231 |
except Exception as e:
|
|
|
238 |
|
239 |
def analyze_for_cinematic_prompt(self, image: Image.Image) -> Tuple[str, Dict[str, Any]]:
|
240 |
"""Analyze image specifically for cinematic/MIA TV Series prompt generation"""
|
241 |
+
cinematic_prompt = self._get_professional_prompt("cinematic")
|
242 |
return self.analyze_image(image, cinematic_prompt)
|
243 |
|
244 |
def analyze_for_flux_with_professional_context(self, image: Image.Image) -> Tuple[str, Dict[str, Any]]:
|
245 |
"""Analyze image for FLUX with enhanced professional cinematography context"""
|
246 |
+
flux_prompt = self._get_professional_prompt("flux_optimized")
|
247 |
return self.analyze_image(image, flux_prompt)
|
248 |
|
249 |
def analyze_for_multiengine_prompt(self, image: Image.Image) -> Tuple[str, Dict[str, Any]]:
|
250 |
"""Analyze image for multi-engine compatibility (Flux, Midjourney, etc.)"""
|
251 |
+
multiengine_prompt = self._get_professional_prompt("multimodal")
|
252 |
return self.analyze_image(image, multiengine_prompt)
|
253 |
|
254 |
def cleanup(self) -> None:
|
|
|
263 |
|
264 |
|
265 |
class FallbackAnalyzer(BaseImageAnalyzer):
|
266 |
+
"""Enhanced fallback analyzer using professional_photography.py knowledge"""
|
267 |
|
268 |
def __init__(self):
|
269 |
super().__init__()
|
|
|
275 |
return True
|
276 |
|
277 |
def analyze_image(self, image: Image.Image) -> Tuple[str, Dict[str, Any]]:
|
278 |
+
"""Provide enhanced image description using professional_photography.py"""
|
279 |
try:
|
280 |
width, height = image.size
|
|
|
281 |
aspect_ratio = width / height
|
282 |
|
283 |
+
# Use professional_photography.py to analyze basic image properties
|
284 |
+
basic_description = f"Professional photograph with {width}x{height} resolution, aspect ratio {aspect_ratio:.2f}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
285 |
|
286 |
+
# Let professional_photography.py enhance this
|
287 |
+
try:
|
288 |
+
enhancement_result = export_professional_prompt_enhancement(
|
289 |
+
bagel_output=basic_description,
|
290 |
+
bagel_metadata={"image_size": f"{width}x{height}", "aspect_ratio": aspect_ratio}
|
291 |
+
)
|
292 |
+
|
293 |
+
description = enhancement_result["enhanced_prompt"]
|
294 |
+
camera_setup = enhancement_result["metadata"].get("technical_context", "")
|
295 |
+
|
296 |
+
except Exception as e:
|
297 |
+
logger.warning(f"Professional enhancement failed in fallback: {e}")
|
298 |
+
# Basic fallback
|
299 |
+
if aspect_ratio > 1.5:
|
300 |
+
description = "Wide shot composition with natural lighting and balanced framing"
|
301 |
+
camera_setup = "shot on Phase One XT, 24-70mm f/4 lens, ISO 100"
|
302 |
+
elif aspect_ratio < 0.75:
|
303 |
+
description = "Portrait composition with professional lighting and sharp focus"
|
304 |
+
camera_setup = "shot on Canon EOS R5, 85mm f/1.4 lens, ISO 200"
|
305 |
+
else:
|
306 |
+
description = "Balanced composition with professional execution"
|
307 |
+
camera_setup = "shot on Canon EOS R6, 50mm f/1.8 lens, ISO 400"
|
308 |
|
309 |
metadata = {
|
310 |
"model": "Professional-Fallback",
|
311 |
"device": "cpu",
|
312 |
"confidence": 0.7,
|
313 |
"image_size": f"{width}x{height}",
|
|
|
|
|
314 |
"aspect_ratio": round(aspect_ratio, 2),
|
|
|
315 |
"has_camera_suggestion": True,
|
316 |
+
"camera_setup": camera_setup,
|
317 |
"professional_enhancement": True,
|
318 |
"cinematography_context_applied": True
|
319 |
}
|
|
|
322 |
|
323 |
except Exception as e:
|
324 |
logger.error(f"Professional fallback analysis failed: {e}")
|
325 |
+
return "Professional cinematographic analysis", {
|
326 |
"error": str(e),
|
327 |
"model": "Professional-Fallback"
|
328 |
}
|
|
|
371 |
if success and result[1].get("error") is None:
|
372 |
return result
|
373 |
else:
|
374 |
+
# Fallback with professional_photography.py
|
375 |
+
logger.warning(f"Primary model failed, using professional fallback")
|
376 |
fallback_analyzer = self.get_analyzer("fallback")
|
377 |
fallback_success, fallback_result = safe_execute(fallback_analyzer.analyze_image, image)
|
378 |
|
379 |
if fallback_success:
|
380 |
return fallback_result
|
381 |
else:
|
382 |
+
return "All analyzers failed", {"error": "Complete analysis failure"}
|
383 |
|
384 |
def cleanup_all(self) -> None:
|
385 |
"""Clean up all model resources"""
|
|
|
387 |
analyzer.cleanup()
|
388 |
self.analyzers.clear()
|
389 |
clean_memory()
|
390 |
+
logger.info("All analyzers cleaned up")
|
391 |
|
392 |
|
393 |
+
# Global model manager instance
|
394 |
model_manager = ModelManager(preferred_model="bagel-professional")
|
395 |
|
396 |
|