Malaji71 commited on
Commit
b65afd3
·
verified ·
1 Parent(s): 7a0ecee

Update utils.py

Browse files
Files changed (1) hide show
  1. utils.py +176 -16
utils.py CHANGED
@@ -130,14 +130,14 @@ def detect_scene_type_from_analysis(analysis_metadata: Dict[str, Any]) -> str:
130
 
131
  def apply_flux_rules(prompt: str, analysis_metadata: Optional[Dict[str, Any]] = None) -> str:
132
  """
133
- Apply enhanced prompt optimization rules for multi-engine compatibility
134
 
135
  Args:
136
  prompt: Raw prompt text from BAGEL analysis
137
  analysis_metadata: Enhanced metadata with cinematography suggestions
138
 
139
  Returns:
140
- Optimized prompt for Flux, Midjourney, and other generative engines
141
  """
142
  if not prompt or not isinstance(prompt, str):
143
  return ""
@@ -150,6 +150,11 @@ def apply_flux_rules(prompt: str, analysis_metadata: Optional[Dict[str, Any]] =
150
  # Extract description part only (remove CAMERA_SETUP section if present)
151
  description_part = _extract_description_only(cleaned_prompt)
152
 
 
 
 
 
 
153
  # Check if BAGEL provided intelligent camera setup with cinematography context
154
  camera_config = ""
155
  scene_type = "default"
@@ -172,8 +177,15 @@ def apply_flux_rules(prompt: str, analysis_metadata: Optional[Dict[str, Any]] =
172
  # Add style enhancement for multi-engine compatibility
173
  style_enhancement = _get_style_enhancement(scene_type, description_part.lower())
174
 
175
- # Build final prompt: Description + Camera + Lighting + Style
176
- final_prompt = description_part + camera_config + lighting_enhancement + style_enhancement
 
 
 
 
 
 
 
177
 
178
  # Clean up formatting
179
  final_prompt = _clean_prompt_formatting(final_prompt)
@@ -212,6 +224,116 @@ def _extract_description_only(prompt: str) -> str:
212
  return description.strip()
213
 
214
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  def _detect_scene_from_description(description_lower: str) -> str:
216
  """Enhanced scene detection from description with cinematography knowledge"""
217
  scene_keywords = PROFESSIONAL_PHOTOGRAPHY_CONFIG.get("scene_detection_keywords", {})
@@ -238,7 +360,7 @@ def _detect_scene_from_description(description_lower: str) -> str:
238
 
239
 
240
  def _format_professional_camera_suggestion(bagel_camera: str, scene_type: str) -> str:
241
- """Format BAGEL's camera suggestion with enhanced cinematography knowledge"""
242
  try:
243
  camera_text = bagel_camera.strip()
244
  camera_text = re.sub(r'^CAMERA_SETUP:\s*', '', camera_text)
@@ -246,26 +368,64 @@ def _format_professional_camera_suggestion(bagel_camera: str, scene_type: str) -
246
  # Enhanced extraction patterns for cinema equipment
247
  cinema_patterns = {
248
  'camera': r'(ARRI [^,]+|RED [^,]+|Canon EOS [^,]+|Sony A[^,]+|Leica [^,]+|Hasselblad [^,]+|Phase One [^,]+)',
249
- 'lens': r'(\d+mm[^,]*(?:anamorphic)?[^,]*|[^,]*(?:anamorphic|telephoto|wide-angle)[^,]*)',
250
- 'aperture': r'(f/[\d.]+[^,]*)'
251
  }
252
 
253
  extracted_parts = []
254
- for key, pattern in cinema_patterns.items():
255
- match = re.search(pattern, camera_text, re.IGNORECASE)
256
- if match:
257
- extracted_parts.append(match.group(1).strip())
258
 
259
- if extracted_parts:
260
- camera_info = ', '.join(extracted_parts)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
  # Add scene-specific enhancement
262
  if scene_type == "cinematic":
263
- return f", Shot on {camera_info}, cinematic photography"
264
  elif scene_type == "portrait":
265
- return f", Shot on {camera_info}, professional portrait photography"
266
  else:
267
- return f", Shot on {camera_info}, professional photography"
 
 
 
268
  else:
 
269
  return _get_enhanced_camera_config(scene_type, camera_text.lower())
270
 
271
  except Exception as e:
 
130
 
131
  def apply_flux_rules(prompt: str, analysis_metadata: Optional[Dict[str, Any]] = None) -> str:
132
  """
133
+ Apply enhanced prompt optimization rules for multi-engine compatibility with condensation
134
 
135
  Args:
136
  prompt: Raw prompt text from BAGEL analysis
137
  analysis_metadata: Enhanced metadata with cinematography suggestions
138
 
139
  Returns:
140
+ Optimized and condensed prompt for Flux, Midjourney, and other generative engines
141
  """
142
  if not prompt or not isinstance(prompt, str):
143
  return ""
 
150
  # Extract description part only (remove CAMERA_SETUP section if present)
151
  description_part = _extract_description_only(cleaned_prompt)
152
 
153
+ # NEW: Condense the description to remove redundancy
154
+ if PROFESSIONAL_PHOTOGRAPHY_CONFIG.get("prompt_condensation", True):
155
+ description_part = _condense_description(description_part)
156
+ logger.info("Applied prompt condensation")
157
+
158
  # Check if BAGEL provided intelligent camera setup with cinematography context
159
  camera_config = ""
160
  scene_type = "default"
 
177
  # Add style enhancement for multi-engine compatibility
178
  style_enhancement = _get_style_enhancement(scene_type, description_part.lower())
179
 
180
+ # NEW: Add mandatory generative keywords
181
+ mandatory_keywords = _get_mandatory_keywords(scene_type)
182
+
183
+ # Build final prompt: Description + Camera + Lighting + Style + Keywords
184
+ final_prompt = description_part + camera_config + lighting_enhancement + style_enhancement + mandatory_keywords
185
+
186
+ # NEW: Final length optimization
187
+ if PROFESSIONAL_PHOTOGRAPHY_CONFIG.get("prompt_optimization", {}).get("max_length"):
188
+ final_prompt = _optimize_prompt_length(final_prompt)
189
 
190
  # Clean up formatting
191
  final_prompt = _clean_prompt_formatting(final_prompt)
 
224
  return description.strip()
225
 
226
 
227
+ def _condense_description(description: str) -> str:
228
+ """Condense BAGEL's verbose description into concise prompt format"""
229
+ try:
230
+ condensed = description
231
+
232
+ # Remove redundant phrases
233
+ redundant_phrases = FLUX_RULES.get("condensation_patterns", {}).get("remove_redundant_phrases", [])
234
+ for phrase in redundant_phrases:
235
+ condensed = re.sub(phrase, '', condensed, flags=re.IGNORECASE)
236
+
237
+ # Simplify lighting descriptions
238
+ lighting_simplifications = FLUX_RULES.get("condensation_patterns", {}).get("simplify_lighting_descriptions", [])
239
+ for pattern, replacement in lighting_simplifications:
240
+ condensed = re.sub(pattern, replacement, condensed, flags=re.IGNORECASE)
241
+
242
+ # Condense mood descriptions
243
+ mood_condensations = FLUX_RULES.get("condensation_patterns", {}).get("condense_mood_descriptions", [])
244
+ for pattern, replacement in mood_condensations:
245
+ condensed = re.sub(pattern, replacement, condensed, flags=re.IGNORECASE)
246
+
247
+ # Remove excessive adjectives and verbose explanations
248
+ condensed = re.sub(r'\s*,\s*which\s+[^,]+,\s*', ', ', condensed)
249
+ condensed = re.sub(r'\s*\.\s*The\s+', '. ', condensed)
250
+ condensed = re.sub(r'\s+', ' ', condensed)
251
+
252
+ # Split into sentences and keep only the most essential
253
+ sentences = [s.strip() for s in condensed.split('.') if s.strip()]
254
+
255
+ # Keep first 2-3 most descriptive sentences
256
+ if len(sentences) > 3:
257
+ essential_sentences = sentences[:3]
258
+ condensed = '. '.join(essential_sentences)
259
+
260
+ logger.info(f"Condensed description from {len(description)} to {len(condensed)} characters")
261
+ return condensed.strip()
262
+
263
+ except Exception as e:
264
+ logger.warning(f"Description condensation failed: {e}")
265
+ return description
266
+
267
+
268
+ def _get_mandatory_keywords(scene_type: str) -> str:
269
+ """Get mandatory generative keywords based on scene type"""
270
+ try:
271
+ mandatory = FLUX_RULES.get("mandatory_keywords", {})
272
+
273
+ keywords = []
274
+
275
+ # Add quality keywords
276
+ quality_keywords = mandatory.get("quality", [])
277
+ keywords.extend(quality_keywords)
278
+
279
+ # Add technical keywords
280
+ technical_keywords = mandatory.get("technical", [])
281
+ keywords.extend(technical_keywords)
282
+
283
+ # Add scene-specific keywords
284
+ style_by_scene = mandatory.get("style_by_scene", {})
285
+ if scene_type in style_by_scene:
286
+ scene_keywords = style_by_scene[scene_type]
287
+ keywords.extend(scene_keywords)
288
+
289
+ if keywords:
290
+ return ", " + ", ".join(keywords)
291
+ else:
292
+ return ""
293
+
294
+ except Exception as e:
295
+ logger.warning(f"Failed to get mandatory keywords: {e}")
296
+ return ""
297
+
298
+
299
+ def _optimize_prompt_length(prompt: str) -> str:
300
+ """Optimize prompt length while preserving essential information"""
301
+ try:
302
+ max_words = PROFESSIONAL_PHOTOGRAPHY_CONFIG.get("prompt_optimization", {}).get("max_length", 150)
303
+
304
+ words = prompt.split()
305
+ if len(words) <= max_words:
306
+ return prompt
307
+
308
+ # Keep essential parts: subject, camera setup, technical specs
309
+ essential_parts = []
310
+ current_part = []
311
+
312
+ for word in words:
313
+ current_part.append(word)
314
+
315
+ # Keep camera and technical information
316
+ if any(tech in word.lower() for tech in ["shot", "lens", "f/", "iso", "mm"]):
317
+ essential_parts.extend(current_part)
318
+ current_part = []
319
+ # Keep quality keywords
320
+ elif any(qual in word.lower() for qual in ["photorealistic", "cinematic", "professional"]):
321
+ essential_parts.extend(current_part)
322
+ current_part = []
323
+
324
+ # Add remaining words if under limit
325
+ remaining_words = max_words - len(essential_parts)
326
+ if remaining_words > 0 and current_part:
327
+ essential_parts.extend(current_part[:remaining_words])
328
+
329
+ optimized = " ".join(essential_parts[:max_words])
330
+ logger.info(f"Optimized prompt length from {len(words)} to {len(essential_parts)} words")
331
+
332
+ return optimized
333
+
334
+ except Exception as e:
335
+ logger.warning(f"Prompt length optimization failed: {e}")
336
+ return prompt
337
  def _detect_scene_from_description(description_lower: str) -> str:
338
  """Enhanced scene detection from description with cinematography knowledge"""
339
  scene_keywords = PROFESSIONAL_PHOTOGRAPHY_CONFIG.get("scene_detection_keywords", {})
 
360
 
361
 
362
  def _format_professional_camera_suggestion(bagel_camera: str, scene_type: str) -> str:
363
+ """Format BAGEL's camera suggestion with enhanced cinematography knowledge and fix formatting errors"""
364
  try:
365
  camera_text = bagel_camera.strip()
366
  camera_text = re.sub(r'^CAMERA_SETUP:\s*', '', camera_text)
 
368
  # Enhanced extraction patterns for cinema equipment
369
  cinema_patterns = {
370
  'camera': r'(ARRI [^,]+|RED [^,]+|Canon EOS [^,]+|Sony A[^,]+|Leica [^,]+|Hasselblad [^,]+|Phase One [^,]+)',
371
+ 'lens': r'(\d+mm[^,]*(?:anamorphic)?[^,]*)',
372
+ 'aperture': r'(f/[\d.]+)'
373
  }
374
 
375
  extracted_parts = []
376
+ camera_model = None
377
+ lens_spec = None
378
+ aperture_spec = None
 
379
 
380
+ # Extract camera
381
+ camera_match = re.search(cinema_patterns['camera'], camera_text, re.IGNORECASE)
382
+ if camera_match:
383
+ camera_model = camera_match.group(1).strip()
384
+
385
+ # Extract lens
386
+ lens_match = re.search(cinema_patterns['lens'], camera_text, re.IGNORECASE)
387
+ if lens_match:
388
+ lens_spec = lens_match.group(1).strip()
389
+
390
+ # Extract aperture
391
+ aperture_match = re.search(cinema_patterns['aperture'], camera_text, re.IGNORECASE)
392
+ if aperture_match:
393
+ aperture_spec = aperture_match.group(1).strip()
394
+
395
+ # Build proper camera setup with all technical specs
396
+ if camera_model and lens_spec:
397
+ # Fix the "with, 35mm" error by proper formatting
398
+ camera_setup = f"{camera_model}, {lens_spec}"
399
+
400
+ # Add aperture if found
401
+ if aperture_spec:
402
+ if 'f/' not in lens_spec: # Don't duplicate aperture
403
+ camera_setup += f" at {aperture_spec}"
404
+
405
+ # Add ISO and composition based on scene type
406
+ enhanced_config = _get_enhanced_camera_config(scene_type, "")
407
+
408
+ # Extract ISO and composition from enhanced config
409
+ iso_match = re.search(r'ISO \d+', enhanced_config)
410
+ composition_match = re.search(r'(rule of thirds|leading lines|symmetrical|centered|hyperfocal distance)[^,]*', enhanced_config)
411
+
412
+ if iso_match:
413
+ camera_setup += f", {iso_match.group()}"
414
+ if composition_match:
415
+ camera_setup += f", {composition_match.group()}"
416
+
417
  # Add scene-specific enhancement
418
  if scene_type == "cinematic":
419
+ result = f", Shot on {camera_setup}, cinematic photography"
420
  elif scene_type == "portrait":
421
+ result = f", Shot on {camera_setup}, professional portrait photography"
422
  else:
423
+ result = f", Shot on {camera_setup}, professional photography"
424
+
425
+ logger.info(f"Formatted camera setup: {result}")
426
+ return result
427
  else:
428
+ # Fallback to enhanced config if parsing fails
429
  return _get_enhanced_camera_config(scene_type, camera_text.lower())
430
 
431
  except Exception as e: