| from __future__ import annotations |
|
|
| import re |
|
|
| MAX_WORDS = 12 |
|
|
| SCENE_PATTERNS = [ |
| ("variation", r"\bvari(?:ation|ations|ant|ants|ous)\b"), |
| ("set of", r"\bsets?\s+of\b"), |
| ("collection", r"\bcollections?\b"), |
| ("assorted", r"\bassorted\b"), |
| ("multiple", r"\bmultiple\b"), |
| ("pair of", r"\bpairs?\s+of\b"), |
| ("group of", r"\bgroups?\s+of\b"), |
| ("scene", r"\bscenes?\b"), |
| ("elements", r"\belements?\b"), |
| ("featuring", r"\bfeaturing\b"), |
| ("different", r"\bdifferent\b"), |
| ] |
|
|
| MODIFIERS = { |
| "black", "white", "red", "blue", "green", "yellow", "orange", "purple", |
| "pink", "brown", "gray", "grey", "gold", "golden", "silver", "bronze", |
| "copper", "beige", "tan", "teal", "cyan", "magenta", "maroon", "navy", |
| "ivory", "cream", "turquoise", "lavender", "olive", "crimson", "scarlet", |
| "dark", "light", "pale", "bright", "deep", "pastel", "neon", "striped", |
| "wooden", "wood", "metal", "metallic", "plastic", "stone", "glass", |
| "steel", "iron", "brick", "concrete", "leather", "fabric", "marble", |
| } |
|
|
| _WORD = re.compile(r"[a-z][a-z'-]*") |
| _AND = re.compile(r"\band\b") |
|
|
| def _joins_noun_phrases(text): |
| parts = _AND.split(text) |
| if len(parts) < 2: |
| return False |
| for left, right in zip(parts[:-1], parts[1:]): |
| if "," in left: |
| return True |
| lw = _WORD.findall(left) |
| rw = _WORD.findall(right) |
| if not lw or not rw: |
| return True |
| if lw[-1] in MODIFIERS and rw[0] in MODIFIERS: |
| continue |
| return True |
| return False |
|
|
| def reject_reason(caption): |
| if not caption or not caption.strip(): |
| return "empty" |
| text = caption.lower() |
| if len(caption.split()) > MAX_WORDS: |
| return "too long" |
| for name, pattern in SCENE_PATTERNS: |
| if re.search(pattern, text): |
| return name |
| if _joins_noun_phrases(text): |
| return "and" |
| return None |
|
|
| def is_single_object(caption): |
| return reject_reason(caption) is None |
|
|