dev.altai / src /analyzer.py
prince1604
Merged short alt detection back into main 'poor quality' report and removed separate 'short_alt' counts as requested
14aaae8
Raw
History Blame Contribute Delete
5.29 kB
class ImageAnalyzer:
def analyze_site(self, site_data):
"""
Analyzes the crawled site data for missing ALT text.
:param site_data: Dict { page_url: [image_dicts] }
:return: Dict containing summary and detailed report.
"""
total_images = 0
total_missing_alt = 0
total_poor_quality = 0 # Track all poor quality images
total_short_alt_legacy = 0 # Track only strictly short ones
pages_report = []
# Compile regex for filename patterns
import re
# Pattern 1: Common Camera Prefixes (e.g., DSC_001, IMG_1234, Screenshot-1)
prefix_pattern = re.compile(r'^(dsc|img|pic|screenshot|photo)[\-_]?\d+', re.IGNORECASE)
# Pattern 2: General Slug + Number (e.g., product-12345, item_01) - enforces no spaces
slug_pattern = re.compile(r'^[a-z0-9\-_]+[-_]\d+$', re.IGNORECASE)
for page_url, images in site_data.items():
missing_images = []
poor_quality_images = []
for img in images:
total_images += 1
alt_text = img.get('alt')
# 1. Strictly Missing
if not alt_text or alt_text.strip() == "":
missing_images.append(img['src'])
total_missing_alt += 1
continue # Skip further checks if missing
cleaned_alt = alt_text.strip()
lower_alt = cleaned_alt.lower()
word_count = len(cleaned_alt.split())
is_poor = False
reason = ""
# 2. Advanced Poor Quality Checks
# A) File Name / Extension Check (Highest Priority)
if any(lower_alt.endswith(ext) for ext in ['.jpg', '.png', '.jpeg', '.webp', '.gif', '.svg']):
is_poor = True
reason = "Filename extension detected"
elif prefix_pattern.search(cleaned_alt):
is_poor = True
reason = "Filename pattern detected (prefix)"
elif slug_pattern.match(cleaned_alt):
is_poor = True
reason = "Filename pattern detected (slug)"
# B) Generic / Filler Text (Smart check)
# Flag if alt equals or contains generic terms.
# Exception: "Brand Name Logo" (usually > 2 words or specific)
# If word count is low (< 3) AND contains a generic term, it's likely poor.
# If it is EXACTLY a generic term, it is definitely poor.
generic_terms = {'image', 'photo', 'picture', 'logo', 'banner', 'icon', 'thumbnail', 'placeholder', 'img', 'spacer'}
if not is_poor:
if lower_alt in generic_terms:
# Exact match found (e.g., "logo", "image") -> Bad
is_poor = True
reason = "Generic filler text"
else:
# Check partial match for short phrases (likely "My Logo", "Chart Image")
# If phrase is long (>= 3 words), it might be descriptive enough (e.g., "Eminent Tactiles Logo")
# So we only flag partial generic matches if word count is small (< 3)
has_generic = any(term in lower_alt.split() for term in generic_terms)
if has_generic and word_count < 3:
is_poor = True
reason = "Generic filler text (partial match)"
# C) Too Short / Sparse (Lowest Priority)
if not is_poor:
if len(cleaned_alt) < 5:
is_poor = True
reason = "Too short (< 5 chars)"
elif word_count < 2:
# Single word check
is_poor = True
reason = "Too few words (needs >= 2)"
if is_poor:
# Store with reason
poor_quality_images.append({'src': img['src'], 'alt': alt_text, 'reason': reason})
total_poor_quality += 1
# User Intent: "short alt list and that count are add in poor not it show separately"
# Action: Consolidate everything into 'poor_quality' and remove specific 'short_alt' reporting.
pages_report.append({
"page_url": page_url,
"missing_alt_count": len(missing_images),
"poor_quality_count": len(poor_quality_images), # Contains ALL poor images (Generic, Filename, Short)
"images_without_alt": list(set(missing_images)),
"images_with_poor_alt": poor_quality_images
})
return {
"summary": {
"total_pages_scanned": len(site_data),
"total_images_found": total_images,
"total_images_missing_alt": total_missing_alt,
"total_images_poor_quality": total_poor_quality
},
"details": pages_report
}