diff --git a/modules/video_qc/executor.py b/modules/video_qc/executor.py index 11ecc03..88583a3 100644 --- a/modules/video_qc/executor.py +++ b/modules/video_qc/executor.py @@ -44,6 +44,83 @@ def _language_display(lang_code: str) -> str: return _LANG_NAMES.get(lang_code.lower(), f"language code '{lang_code}'") +# Platform UI overlay zones for `title_safe` check. Each entry describes the +# regions of the frame that the platform's UI obscures (profile pills, captions, +# action icons). Used to flag when price or garment-name text lands inside. +# Percentages are conservative — tuned against IG/TikTok screenshots circa 2026. +_PLATFORM_ZONES = { + 'tiktok': { + 'description': "TikTok feed: top ~10% (profile/handle bar), bottom ~25% " + "(caption + UI action rail).", + 'zones': [ + {'edge': 'top', 'percent': 10}, + {'edge': 'bottom', 'percent': 25}, + ], + }, + 'ig_stories': { + 'description': "Instagram Stories: top ~12% (profile pill + reactions), " + "bottom ~18% (swipe-up / reply bar).", + 'zones': [ + {'edge': 'top', 'percent': 12}, + {'edge': 'bottom', 'percent': 18}, + ], + }, + 'ig_reels': { + 'description': "Instagram Reels: bottom ~25% (caption + icons), " + "right edge ~10% (action rail).", + 'zones': [ + {'edge': 'bottom', 'percent': 25}, + {'edge': 'right', 'percent': 10}, + ], + }, + 'vertical_generic': { + 'description': "Generic vertical (9x16) social: top ~10%, bottom ~20%.", + 'zones': [ + {'edge': 'top', 'percent': 10}, + {'edge': 'bottom', 'percent': 20}, + ], + }, +} + + +def _infer_platform_zones(filename: str) -> dict | None: + """Infer platform UI overlay zones from filename tokens. + + Returns a dict {'platform': str, 'description': str, 'zones': [...]} + or None when the format has no known overlay zones (feed formats like + 1x1 / 4x5, or unrecognised). + + The returned dict is freshly built (deep-copied zones list) so callers + can mutate it without corrupting the module-level _PLATFORM_ZONES. + """ + if not filename: + return None + upper = filename.upper() + + def _build(key: str) -> dict: + base = _PLATFORM_ZONES[key] + return { + 'platform': key, + 'description': base['description'], + 'zones': [dict(z) for z in base['zones']], + } + + # Most specific first: explicit platform + format combos. + if 'TK_STORIES' in upper or '_TK_' in upper or 'TT_9X16' in upper: + return _build('tiktok') + if 'IG_STORIES' in upper or 'STORIES_9X16' in upper: + return _build('ig_stories') + if 'IG_REELS' in upper or 'REELS_9X16' in upper: + return _build('ig_reels') + + # Fallback: any 9x16 with no platform hint -> generic vertical. + if '9X16' in upper: + return _build('vertical_generic') + + # Feed formats (1x1, 4x5) and anything else -> no overlay zones. + return None + + class VideoQCExecutor: """Execute video QC checks with frame extraction and AI analysis."""