Bug fixes, profile updates, report updates

This commit is contained in:
nickviljoen 2025-08-23 14:44:17 +02:00
parent 56ecf9218c
commit 355be50b23
39 changed files with 14595 additions and 440 deletions

View file

@ -4,14 +4,14 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Project Overview
Visual AI QC is a Python Flask-based AI-powered quality control platform for analyzing marketing materials and design assets using OpenAI GPT-4 and Google Gemini models. It evaluates visual content against brand guidelines and design best practices through 34+ specialized QC checks.
Visual AI QC is a Python Flask-based AI-powered quality control platform for analyzing marketing materials and design assets using OpenAI GPT-4 and Google Gemini models. It evaluates visual content against brand guidelines and design best practices through 33 specialized QC checks across 6 focused profiles.
## Core Architecture
### Main Components
- **`api_server.py`** - Main Flask server with async processing and parallel execution
- **`visual_qc_apps/`** - Modular QC check system with 34+ individual check modules
- **`visual_qc_apps/`** - Modular QC check system with 33 individual check modules
- **`profiles/`** - JSON configuration files defining QC check combinations and weights
- **`brand_guidelines/`** - Reference asset storage and brand guideline database
- **`llm_config.py`** - Centralized LLM configuration and API interaction
@ -69,9 +69,13 @@ python -c "import api_server, llm_config, profile_config"
│ ├── utils.py # Shared utilities
│ ├── flask_app_template.py # Template for new checks
│ └── {check_name}/app.py # Individual QC checks
├── profiles/ # QC profile configurations
│ ├── default.json # All checks profile
│ └── {brand_name}.json # Brand-specific profiles
├── profiles/ # QC profile configurations (6 total)
│ ├── general_check.json # General purpose profile (10 checks)
│ ├── unilever_key_visual.json # Unilever key visual profile (15 checks)
│ ├── unilever_packaging.json # Unilever packaging profile (17 checks)
│ ├── diageo_key_visual.json # Diageo key visual profile (11 checks)
│ ├── diageo_packaging.json # Diageo packaging profile (13 checks)
│ └── inclusive_accessibility.json # Accessibility profile (2 checks)
├── brand_guidelines/ # Reference assets
│ └── guidelines_db.json # Asset metadata
├── uploads/ # Temporary file uploads
@ -159,6 +163,49 @@ The following API endpoints require authentication:
- **Secure Headers**: Cookies use Secure, SameSite=Lax flags
- **Server-side Validation**: No client-side security dependencies
## QC Profile System
### Available Profiles
The system includes 6 focused QC profiles designed for different use cases:
1. **General Check** (10 checks, 100-point scale)
- Purpose: Streamlined general-purpose QC analysis
- Checks: Essential design and technical standards
- Weighting: Even distribution (10% each)
- Requirements: No reference assets needed
- Scoring: Individual scores 1-10, final score 0-100
2. **Unilever Key Visual** (15 checks, 120-point scale)
- Purpose: Unilever brand guidelines for key visual materials
- Special Logic: Bonus checks with zero-scoring for missing elements
- Requirements: Brand guidelines recommended
- Scoring: Weighted distribution, 120-point maximum
3. **Unilever Packaging** (17 checks)
- Purpose: Unilever packaging design standards
- Requirements: Brand guidelines recommended
4. **Diageo Key Visual** (11 checks)
- Purpose: Diageo brand guidelines for key visuals
- Requirements: Brand guidelines recommended
5. **Diageo Packaging** (13 checks)
- Purpose: Diageo packaging design standards
- Requirements: Brand guidelines recommended
6. **Inclusive Accessibility** (2 checks)
- Purpose: Focused accessibility compliance
- Checks: Accessibility and inclusive design
- Requirements: No reference assets needed
### Profile Selection Guidelines
- **General content analysis**: Use General Check
- **Brand-specific analysis**: Use appropriate brand profile
- **Accessibility focus**: Use Inclusive Accessibility
- **Mixed requirements**: Profiles can be combined in multi-profile analysis
## Recent System Enhancements
### Unilever Profile-Specific Scoring Logic
@ -186,6 +233,29 @@ if (profile_config and profile_config.get('name') == 'Unilever Key Visual' and
This ensures that missing critical elements (faces, "new" text) result in zero scores, providing more stringent quality control for Unilever key visual assets.
### Scoring System Enhancements
The scoring calculation system has been improved to handle different profile weight structures correctly:
#### Multi-Scale Scoring Support
- **100-Point Scale**: General Check profile with total weight 10.0 uses direct weighted scores
- **Other Scales**: Profiles with lower total weights use scaled scoring (weighted_score × 10)
- **Brand-Specific Scales**: Unilever Key Visual uses 120-point maximum scale
#### Fixed Calculation Logic (`api_server.py`)
```python
# Smart scoring calculation based on profile weight structure
if total_weight >= 10.0:
overall_score = total_weighted_score # Direct score for high-weight profiles
else:
overall_score = total_weighted_score * 10 # Scale up for traditional profiles
```
#### JSON Response Merging
Enhanced JSON extraction to merge multiple JSON blocks from LLM responses:
- Combines metadata (face_present, new_present) with scoring data
- Enables proper bonus check logic for Unilever profiles
- Maintains backward compatibility with single JSON responses
### Enhanced Saved Files Management
The output file system has been significantly improved for better user experience:
@ -242,7 +312,19 @@ Before ending any session, ALWAYS run these Python syntax and import checks:
2. **Import Check**: Run `python -c "import api_server, llm_config, profile_config"` to verify core modules import successfully
3. **Authentication Check**: Run `python -c "import jwt_validator, auth_middleware; print('Authentication modules imported successfully')"` to verify authentication system
4. **QC Module Check**: Test import of any modified QC modules in `visual_qc_apps/`
5. **Enhanced System Check**: Verify recent enhancements work correctly:
5. **Profile System Check**: Verify all 6 profiles load correctly:
```bash
python -c "
from profile_config import get_profile
profiles = ['general_check', 'unilever_key_visual', 'unilever_packaging', 'diageo_key_visual', 'diageo_packaging', 'inclusive_accessibility']
for p in profiles:
profile = get_profile(p)
print(f'✅ {profile.name} ({len(profile.get_enabled_checks())} checks)')
"
```
6. **Enhanced System Check**: Verify recent enhancements work correctly:
- Test General Check profile 100-point scoring system
- Test Unilever profile zero-scoring logic with face/new visibility checks
- Test saved files auto-refresh and date sorting functionality
- Test MSAL authentication initialization and error handling
- Test MSAL authentication initialization and error handling
- Verify scoring calculation handles different weight structures correctly

View file

@ -4,7 +4,7 @@
## 🚀 Overview
Visual AI QC is an intelligent quality control platform that uses advanced AI (OpenAI GPT-4 and Google Gemini) to automatically analyze visual content against brand guidelines, technical specifications, and design best practices. The system provides comprehensive feedback, scoring, and recommendations for improving visual assets.
Visual AI QC is an intelligent quality control platform that uses advanced AI (OpenAI GPT-4 and Google Gemini) to automatically analyze visual content against brand guidelines, technical specifications, and design best practices. The system provides comprehensive feedback, scoring, and recommendations for improving visual assets across 33 specialized QC checks and 6 focused profiles.
## ✨ Key Features
@ -24,7 +24,27 @@ Visual AI QC is an intelligent quality control platform that uses advanced AI (O
## 🆕 Recent Improvements
### **December 2024 - Latest Enhancements** 🚀
### **August 2025 - Major System Overhaul** 🚀
#### **Streamlined Profile System** 📊
- **Consolidated Profiles**: Reduced from 8+ profiles to 6 focused, purpose-built profiles
- **General Check Profile**: New streamlined 10-check profile for general-purpose analysis
- **100-Point Scoring**: Clean scoring system with even weighting (10% per check)
- **Essential Checks Only**: Covers technical compliance, visual design, content, and marketing effectiveness
- **No Reference Assets Required**: Works independently for quick analysis
- **Brand-Specific Optimization**: Maintained Unilever and Diageo profiles with specialized scoring logic
- **Profile Cleanup**: Removed redundant "All Checks", "General Key Visual", and "General Packaging" profiles
#### **Fixed Scoring System** 🧮
- **Corrected 100-Point Scale**: Fixed calculation bug where General Check profile showed 490/100 instead of correct scores
- **Multi-Scale Support**: System now handles different profile weight structures correctly
- General Check (10.0 total weight) → Direct scoring for 100-point scale
- Other profiles (1.0-1.2 total weight) → Scaled scoring for traditional systems
- **Enhanced JSON Merging**: Improved extraction of multiple JSON blocks from LLM responses
- Combines metadata (face_present, new_present) with scoring data
- Enables proper bonus check logic for brand profiles
### **December 2024 - Authentication & UX Enhancements** 🚀
#### **Enhanced Profile-Specific Scoring** 📊
- **Unilever Key Visual Profile**: Implemented stringent zero-score logic for critical elements
@ -188,17 +208,51 @@ When you start an analysis, the system performs these streamlined steps:
## 🎯 Available QC Profiles
### Brand-Specific Profiles
- **Diageo Key Visual**: Optimized for Diageo brand guidelines and key visual requirements
- **Diageo Packaging**: Tailored for Diageo packaging design requirements
- **Unilever Key Visual**: Focused on Unilever brand standards and visual hierarchy
- **Unilever Packaging**: Specialized for Unilever packaging compliance
The system includes 6 focused QC profiles designed for different use cases:
### General Profiles
- **All Checks**: Comprehensive analysis using all available QC checks
- **General Key Visual**: Standard checks for key visual/hero image analysis
- **General Packaging**: Technical checks for packaging design compliance
- **Inclusive Accessibility**: Focuses on accessibility and inclusive design practices
### **1. General Check** (10 checks, 100-point scale) 🎯
- **Purpose**: Streamlined general-purpose QC analysis
- **Checks**: aspect_ratio, background_contrast, call_to_action, curved_edges_digital, curved_edges_print, element_alignment, product_visibility, safety_area, text_readability, visual_elements_count
- **Weighting**: Even distribution (10% each)
- **Requirements**: No reference assets needed
- **Best For**: Quick comprehensive analysis of any visual content
### **Brand-Specific Profiles** 🏢
#### **2. Unilever Key Visual** (15 checks, 120-point scale)
- **Purpose**: Unilever brand guidelines for key visual materials
- **Special Logic**: Bonus checks with zero-scoring for missing elements (face_visibility, new_visibility, face_gaze_direction)
- **Requirements**: Brand guidelines recommended
- **Best For**: Unilever marketing materials and key visuals
#### **3. Unilever Packaging** (17 checks)
- **Purpose**: Unilever packaging design standards
- **Requirements**: Brand guidelines recommended
- **Best For**: Unilever product packaging designs
#### **4. Diageo Key Visual** (11 checks)
- **Purpose**: Diageo brand guidelines for key visuals
- **Requirements**: Brand guidelines recommended
- **Best For**: Diageo advertising and marketing materials
#### **5. Diageo Packaging** (13 checks)
- **Purpose**: Diageo packaging design standards
- **Requirements**: Brand guidelines recommended
- **Best For**: Diageo product packaging and labeling
### **Specialized Profiles**
#### **6. Inclusive Accessibility** (2 checks)
- **Purpose**: Focused accessibility compliance
- **Checks**: accessibility, inclusive design
- **Requirements**: No reference assets needed
- **Best For**: Accessibility audits and inclusive design validation
### **Profile Selection Guidelines**
- **🎯 General content analysis**: Use General Check
- **🏢 Brand-specific analysis**: Use appropriate brand profile (Unilever/Diageo)
- **♿ Accessibility focus**: Use Inclusive Accessibility
- **🔄 Mixed requirements**: Profiles can be combined in multi-profile analysis
### 🎨 Consumer-Focused Analysis
@ -250,7 +304,7 @@ The system now uses **batch-based parallel processing** to dramatically improve
## 🔍 Quality Control Checks
The system includes 34+ specialized QC checks organized into categories:
The system includes 33 specialized QC checks organized into categories:
### Visual Design Checks
- **Logo Visibility**: Ensures brand logo is clearly visible and prominent

View file

@ -80,11 +80,14 @@ def extract_json_from_response(response_text):
except Exception as e:
print(f"Could not parse JSON block: {e}")
# If we found multiple JSON blocks, use the last one that's not empty
# If we found multiple JSON blocks, merge them (later blocks override earlier blocks)
if json_objects:
for json_obj in reversed(json_objects):
merged_json = {}
for json_obj in json_objects:
if json_obj: # If not empty
return json_obj
merged_json.update(json_obj)
if merged_json:
return merged_json
# If we couldn't extract JSON blocks or they were empty, look for JSON directly
try:
@ -206,7 +209,9 @@ def extract_score_from_result(result, profile_config=None, check_name=None):
json_data = extract_json_from_response(result['response'])
# Unilever Key Visual profile specific logic
if (profile_config and profile_config.get('name') == 'Unilever Key Visual' and
if (profile_config and
((hasattr(profile_config, 'name') and profile_config.name == 'Unilever Key Visual') or
(hasattr(profile_config, 'get') and profile_config.get('name') == 'Unilever Key Visual')) and
check_name in ['face_visibility', 'new_visibility', 'face_gaze_direction']):
# Check for zero score conditions based on missing elements
@ -784,7 +789,8 @@ def generate_html_content(report_data, filename, file_path=None):
</div>
<div class="expandable-content" id="content-{check_name}">
<div class="check-metadata">
<p><strong>Weight:</strong> {weight:.3f} | <strong>Weighted Score:</strong> {weighted_score:.2f}</p>
<p><strong>Score:</strong> {score}/10 | <strong>Weight:</strong> {weight:.1%} | <strong>Weighted Score:</strong> {weighted_score:.2f}</p>
{'<p><strong>⭐ Bonus Check:</strong> If missing required element, this scores 0</p>' if check_name in ['face_gaze_direction', 'face_visibility', 'new_visibility'] else ''}
<p><strong>Reference Asset:</strong> {'✅ Used' if check_name in REFERENCE_ASSET_REQUIRED_CHECKS and reference_asset_used else ('🚨 Required but missing' if check_name in REFERENCE_ASSET_REQUIRED_CHECKS else ' Not required')}</p>
{f'<p><strong>Reference Asset Details:</strong> {reference_asset}</p>' if check_name in REFERENCE_ASSET_REQUIRED_CHECKS and reference_asset_used and reference_asset else ''}
</div>
@ -981,7 +987,8 @@ def generate_comprehensive_html_report(analysis_result, filename, file_path=None
</div>
<div class="expandable-content" id="content-{check_name}">
<div class="check-metadata">
<p><strong>Weight:</strong> {result.get('weight', 0)} | <strong>Weighted Score:</strong> {result.get('weighted_score', 0)}</p>
<p><strong>Score:</strong> {score}/10 | <strong>Weight:</strong> {result.get('weight', 0):.1%} | <strong>Weighted Score:</strong> {result.get('weighted_score', 0):.2f}</p>
{'<p><strong>⭐ Bonus Check:</strong> If missing required element, this scores 0</p>' if check_name in ['face_gaze_direction', 'face_visibility', 'new_visibility'] else ''}
<p><strong>Reference Asset:</strong> {'✅ Used' if check_name in REFERENCE_ASSET_REQUIRED_CHECKS and reference_asset_used else ('🚨 Required but missing' if check_name in REFERENCE_ASSET_REQUIRED_CHECKS else ' Not required')}</p>
{f'<p><strong>Reference Asset Details:</strong> {reference_asset}</p>' if check_name in REFERENCE_ASSET_REQUIRED_CHECKS and reference_asset_used and reference_asset else ''}
</div>
@ -1438,7 +1445,12 @@ def start_analysis():
failed_checks += 1
# Calculate overall score
overall_score = (total_weighted_score * 10) if total_weight > 0 else 0
# For profiles with total_weight = 10.0 (like General Check), use direct weighted score
# For profiles with total_weight = 1.0, multiply by 10 to scale to 100
if total_weight >= 10.0:
overall_score = total_weighted_score # Already scaled correctly
else:
overall_score = (total_weighted_score * 10) # Scale to 100-point system
# STEP 5: Prepare Combined Response
print(f"Step 5: Preparing response")
@ -1895,7 +1907,7 @@ def api_process_triaged_file():
)
# Extract score from result
score = extract_score_from_result(result, profile.config, check_name)
score = extract_score_from_result(result, profile, check_name)
result['score'] = score
# Process result for JSON mode
@ -2635,7 +2647,14 @@ def api_analyze_with_triage():
failed_checks += 1
# Calculate overall score - sum of weighted scores scaled to 100
overall_score = (total_weighted_score * 10) if total_weight > 0 else 0
# For profiles with total_weight = 10.0 (like General Check), use direct weighted score
# For profiles with total_weight = 1.0, multiply by 10 to scale to 100
if total_weight >= 10.0:
overall_score = total_weighted_score # Already scaled correctly
elif total_weight > 0:
overall_score = (total_weighted_score * 10) # Scale to 100-point system
else:
overall_score = 0
# STEP 5: Prepare Combined Response
print(f"Step 5: Preparing response")
@ -3319,30 +3338,8 @@ def auth_login():
token = data['token']
# Validate and set authentication token
success, message = auth.set_auth_token(token)
if success:
# Get user information
auth_status = auth.get_auth_status()
response_data = {
'success': True,
'message': message,
'authenticated': True,
'user': auth_status.get('user')
}
# Create response with httpOnly cookie
response = make_response(jsonify(response_data))
# The cookie is already set in set_auth_token, but we need to return the response
return response
else:
return jsonify({
'success': False,
'error': message,
'authenticated': False
}), 401
# Validate and set authentication token - returns response with cookie set
return auth.set_auth_token(token)
except Exception as e:
return jsonify({

View file

@ -104,10 +104,10 @@ class AuthMiddleware:
'payload': None
}
def set_auth_token(self, token: str) -> Tuple[bool, str]:
def set_auth_token(self, token: str):
"""
Validate and store authentication token in httpOnly cookie.
Returns (success, message).
Returns Flask response with cookie set.
"""
try:
# Validate token before storing
@ -117,16 +117,21 @@ class AuthMiddleware:
response = make_response(jsonify({
'success': True,
'message': 'Authentication successful',
'authenticated': True,
'user': self.jwt_validator.get_user_info(payload)
}))
# Set httpOnly cookie with security flags
self._set_secure_cookie(response, token, payload)
return True, 'Authentication token set successfully'
return response
except Exception as e:
return False, f'Token validation failed: {str(e)}'
return make_response(jsonify({
'success': False,
'error': f'Token validation failed: {str(e)}',
'authenticated': False
}), 401)
def clear_auth_token(self):
"""Clear authentication cookie and return response."""

Binary file not shown.

View file

@ -16,6 +16,14 @@
"guidelines": [
"Hellmanns_20250805_113413"
]
},
"Dove": {
"name": "Dove",
"created_at": "2025-08-23T13:05:33.656313",
"file_count": 1,
"guidelines": [
"Dove_20250823_130533"
]
}
},
"files": {
@ -54,8 +62,20 @@
"tags": [],
"upload_date": "2025-08-05T11:34:13.372342",
"file_type": ".png"
},
"Dove_20250823_130533": {
"id": "Dove_20250823_130533",
"brand_name": "Dove",
"original_filename": "temp_20250823_130533_- Dove Brand Book.pdf",
"stored_filename": "Dove_20250823_130533.pdf",
"stored_path": "brand_guidelines/files/Dove_20250823_130533.pdf",
"file_size": 5328348,
"description": "",
"tags": [],
"upload_date": "2025-08-23T13:05:33.656294",
"file_type": ".pdf"
}
},
"created_at": "2025-07-27T20:52:56.220914",
"last_updated": "2025-08-05T11:34:13.372400"
"last_updated": "2025-08-23T13:05:33.656319"
}

View file

@ -12,3 +12,16 @@ Session 20250807_202433: analysis_mode = 'html'
Session 20250807_203144: analysis_mode = 'html'
Session 20250807_203255: analysis_mode = 'html'
Session 20250807_203434: analysis_mode = 'html'
Session 20250823_121621: analysis_mode = 'html'
Session 20250823_124659: analysis_mode = 'html'
Session 20250823_130057: analysis_mode = 'html'
Session 20250823_130328: analysis_mode = 'html'
Session 20250823_130604: analysis_mode = 'html'
Session 20250823_131749: analysis_mode = 'html'
Session 20250823_133626: analysis_mode = 'html'
Session 20250823_133902: analysis_mode = 'html'
Session 20250823_135013: analysis_mode = 'html'
Session 20250823_142149: analysis_mode = 'html'
Session 20250823_142644: analysis_mode = 'html'
Session 20250823_143535: analysis_mode = 'html'
Session 20250823_143740: analysis_mode = 'html'

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,152 +0,0 @@
{
"name": "All Checks",
"description": "Run all available QC checks",
"pre_analysis_instructions": "Before assessment: Users often upload complex print production files with multiple panels, cut lines, and technical markings.\n\nYour task: Focus ONLY on the primary consumer-facing visual - what the end customer would actually see after production.\n\nKey instructions:\n• Ignore cut lines, registration marks, and production guides\n• If multiple panels exist, assess the main/largest consumer-facing design\n• Disregard technical text, color bars, or printer information\n• Focus on the final visual as it would appear on shelf/in-market\n• Treat folded/die-cut layouts as the assembled final product\n\nSTEPS TO EVALUATE:\n1. Examine the design components (logos, pack shots, icons, images, text blocks, promotion badges, etc.). Each distinct object or text grouping counts as one visual element that the viewer must actively notice.\n2. Count the total number of these distinct visual elements.\n3. If the count is more than 4, the design fails this checkpoint, as it may be too cluttered or complex.",
"checks": {
"logo_visibility": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"brand_assets_visibility": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"visual_elements_count": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"background_contrast": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"face_visibility": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"new_visibility": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"visual_hierarchy": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"supporting_images": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"curved_edges": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"visuals_left_text_right": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"face_gaze_direction": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"lowercase_text": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"call_to_action": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"word_count": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"imperative_verb": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"file_naming": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"layer_organization": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"color_format": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"image_resolution": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"safety_area": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"element_alignment": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"animation_transitions": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"aspect_ratio": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"responsiveness": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"dark_mode_legibility": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"print_bleed": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"crop_marks": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"text_readability": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
},
"product_visibility": {
"weight": 0.0,
"llm": "Gemini",
"enabled": true
}
}
}

View file

@ -0,0 +1,67 @@
{
"name": "General Check",
"description": "Streamlined QC profile with 10 essential checks that don't require reference assets - Even weighting with 100-point total, each tool scores out of 10",
"pre_analysis_instructions": "This is a focused quality control analysis that evaluates the most essential design and content criteria without requiring reference assets. Each check is equally weighted (10% each) to provide a balanced overall assessment.\n\nFocus areas:\n• Technical compliance (aspect ratio, resolution standards)\n• Visual design (contrast, alignment, readability)\n• Content structure (visual elements count, text readability)\n• Production requirements (curved edges, safety areas)\n• Marketing effectiveness (call to action, product visibility)\n\nEach of the 10 checks contributes 10% to the final score out of 100.",
"checks": {
"aspect_ratio": {
"weight": 1.0,
"llm": "Gemini",
"enabled": true,
"notes": "Individual score out of 10 - 10% of total"
},
"background_contrast": {
"weight": 1.0,
"llm": "Gemini",
"enabled": true,
"notes": "Individual score out of 10 - 10% of total"
},
"call_to_action": {
"weight": 1.0,
"llm": "Gemini",
"enabled": true,
"notes": "Individual score out of 10 - 10% of total"
},
"curved_edges_digital": {
"weight": 1.0,
"llm": "Gemini",
"enabled": true,
"notes": "Individual score out of 10 - 10% of total"
},
"curved_edges_print": {
"weight": 1.0,
"llm": "Gemini",
"enabled": true,
"notes": "Individual score out of 10 - 10% of total"
},
"element_alignment": {
"weight": 1.0,
"llm": "Gemini",
"enabled": true,
"notes": "Individual score out of 10 - 10% of total"
},
"product_visibility": {
"weight": 1.0,
"llm": "Gemini",
"enabled": true,
"notes": "Individual score out of 10 - 10% of total"
},
"safety_area": {
"weight": 1.0,
"llm": "Gemini",
"enabled": true,
"notes": "Individual score out of 10 - 10% of total"
},
"text_readability": {
"weight": 1.0,
"llm": "Gemini",
"enabled": true,
"notes": "Individual score out of 10 - 10% of total"
},
"visual_elements_count": {
"weight": 1.0,
"llm": "Gemini",
"enabled": true,
"notes": "Individual score out of 10 - 10% of total"
}
}
}

View file

@ -1,132 +0,0 @@
{
"name": "General Key Visual",
"description": "General QC profile for key visual materials (single key visual, multiple key visuals on a single page, or packaging) - combines digital, print, and OOH standards",
"pre_analysis_instructions": "Before assessment: Users often upload complex print production files with multiple panels, cut lines, and technical markings.\n\nYour task: Focus ONLY on the primary consumer-facing visual - what the end customer would actually see after production.\n\nKey instructions:\n• Ignore cut lines, registration marks, and production guides\n• If multiple panels exist, assess the main/largest consumer-facing design\n• Disregard technical text, color bars, or printer information\n• Focus on the final visual as it would appear on shelf/in-market\n• Treat folded/die-cut layouts as the assembled final product\n\nSTEPS TO EVALUATE:\n1. Examine the design components (logos, pack shots, icons, images, text blocks, promotion badges, etc.). Each distinct object or text grouping counts as one visual element that the viewer must actively notice.\n2. Count the total number of these distinct visual elements.\n3. If the count is more than 4, the design fails this checkpoint, as it may be too cluttered or complex.",
"checks": {
"background_contrast": {
"weight": 0.12,
"llm": "Gemini",
"enabled": true
},
"brand_assets_visibility": {
"weight": 0.08,
"llm": "Gemini",
"enabled": true
},
"call_to_action": {
"weight": 0.12,
"llm": "Gemini",
"enabled": true
},
"curved_edges": {
"weight": 0.03,
"llm": "Gemini",
"enabled": true
},
"curved_edges_digital": {
"weight": 0.03,
"llm": "Gemini",
"enabled": true
},
"curved_edges_print": {
"weight": 0.03,
"llm": "Gemini",
"enabled": true
},
"element_alignment": {
"weight": 0.06,
"llm": "Gemini",
"enabled": true
},
"face_gaze_direction": {
"weight": 0.04,
"llm": "Gemini",
"enabled": true
},
"face_visibility": {
"weight": 0.08,
"llm": "Gemini",
"enabled": true
},
"imperative_verb": {
"weight": 0.08,
"llm": "Gemini",
"enabled": true
},
"logo_visibility": {
"weight": 0.12,
"llm": "Gemini",
"enabled": true
},
"lowercase_text": {
"weight": 0.05,
"llm": "Gemini",
"enabled": true
},
"new_visibility": {
"weight": 0.05,
"llm": "Gemini",
"enabled": true
},
"product_visibility": {
"weight": 0.04,
"llm": "Gemini",
"enabled": true
},
"supporting_images": {
"weight": 0.05,
"llm": "Gemini",
"enabled": true
},
"text_readability": {
"weight": 0.12,
"llm": "Gemini",
"enabled": true
},
"visual_elements_count": {
"weight": 0.08,
"llm": "Gemini",
"enabled": true
},
"visual_hierarchy": {
"weight": 0.12,
"llm": "Gemini",
"enabled": true
},
"visuals_left_text_right": {
"weight": 0.06,
"llm": "Gemini",
"enabled": true
},
"word_count": {
"weight": 0.06,
"llm": "Gemini",
"enabled": true
},
"responsiveness": {
"weight": 0.03,
"llm": "Gemini",
"enabled": true
},
"dark_mode_legibility": {
"weight": 0.03,
"llm": "Gemini",
"enabled": true
},
"file_naming": {
"weight": 0.03,
"llm": "Gemini",
"enabled": true
},
"print_bleed": {
"weight": 0.03,
"llm": "Gemini",
"enabled": true
},
"crop_marks": {
"weight": 0.02,
"llm": "Gemini",
"enabled": true
}
}
}

View file

@ -1,72 +0,0 @@
{
"name": "General Packaging",
"description": "General QC profile for packaging materials (product packaging, labels, POS displays, gift cards)",
"pre_analysis_instructions": "Before assessment: Users often upload complex print production files with multiple panels, cut lines, and technical markings.\n\nYour task: Focus ONLY on the primary consumer-facing visual - what the end customer would actually see after production.\n\nKey instructions:\n• Ignore cut lines, registration marks, and production guides\n• If multiple panels exist, assess the main/largest consumer-facing design\n• Disregard technical text, color bars, or printer information\n• Focus on the final visual as it would appear on shelf/in-market\n• Treat folded/die-cut layouts as the assembled final product\n\nSTEPS TO EVALUATE:\n1. Examine the design components (logos, pack shots, icons, images, text blocks, promotion badges, etc.). Each distinct object or text grouping counts as one visual element that the viewer must actively notice.\n2. Count the total number of these distinct visual elements.\n3. If the count is more than 4, the design fails this checkpoint, as it may be too cluttered or complex.",
"checks": {
"background_contrast": {
"weight": 0.10,
"llm": "Gemini",
"enabled": true
},
"brand_assets_visibility": {
"weight": 0.15,
"llm": "Gemini",
"enabled": true
},
"call_to_action": {
"weight": 0.05,
"llm": "Gemini",
"enabled": true
},
"curved_edges": {
"weight": 0.10,
"llm": "Gemini",
"enabled": true
},
"face_gaze_direction": {
"weight": 0.05,
"llm": "Gemini",
"enabled": true
},
"face_visibility": {
"weight": 0.05,
"llm": "Gemini",
"enabled": true
},
"logo_visibility": {
"weight": 0.15,
"llm": "Gemini",
"enabled": true
},
"lowercase_text": {
"weight": 0.05,
"llm": "Gemini",
"enabled": true
},
"new_visibility": {
"weight": 0.10,
"llm": "Gemini",
"enabled": true
},
"product_visibility": {
"weight": 0.15,
"llm": "Gemini",
"enabled": true
},
"visual_elements_count": {
"weight": 0.05,
"llm": "Gemini",
"enabled": true
},
"text_readability": {
"weight": 0.10,
"llm": "Gemini",
"enabled": true
},
"color_format": {
"weight": 0.05,
"llm": "Gemini",
"enabled": true
}
}
}

View file

@ -6,77 +6,98 @@
"background_contrast": {
"weight": 0.10,
"llm": "Gemini",
"enabled": true
"enabled": true,
"notes": "Individual score out of 10"
},
"brand_assets_visibility": {
"weight": 0.12,
"llm": "Gemini",
"enabled": true
"enabled": true,
"notes": "Individual score out of 10"
},
"call_to_action": {
"weight": 0.03,
"llm": "Gemini",
"enabled": true
"enabled": true,
"notes": "Individual score out of 10"
},
"curved_edges": {
"weight": 0.04,
"llm": "Gemini",
"enabled": true
"enabled": true,
"notes": "Individual score out of 10"
},
"face_gaze_direction": {
"weight": 0.06,
"llm": "Gemini",
"enabled": true
"enabled": true,
"notes": "Bonus check - Individual score out of 10",
"additional_notes": "If there is no face then score this a 0",
"bonus_check": true
},
"face_visibility": {
"weight": 0.07,
"llm": "Gemini",
"enabled": true
"enabled": true,
"notes": "Bonus check - Individual score out of 10",
"additional_notes": "If there is no face then score this a 0",
"bonus_check": true
},
"imperative_verb": {
"weight": 0.02,
"llm": "Gemini",
"enabled": true
"enabled": true,
"notes": "Individual score out of 10"
},
"logo_visibility": {
"weight": 0.14,
"llm": "Gemini",
"enabled": true
"enabled": true,
"notes": "Individual score out of 10"
},
"lowercase_text": {
"weight": 0.10,
"llm": "Gemini",
"enabled": true
"enabled": true,
"notes": "Individual score out of 10"
},
"new_visibility": {
"weight": 0.07,
"llm": "Gemini",
"enabled": true
"enabled": true,
"notes": "Bonus check - Individual score out of 10",
"additional_notes": "If there is no New text visible then score this a 0",
"bonus_check": true
},
"supporting_images": {
"weight": 0.10,
"llm": "Gemini",
"enabled": true
"enabled": true,
"notes": "Individual score out of 10"
},
"visual_elements_count": {
"weight": 0.14,
"llm": "Gemini",
"enabled": true
"enabled": true,
"notes": "Individual score out of 10"
},
"visual_hierarchy": {
"weight": 0.10,
"llm": "Gemini",
"enabled": true
"enabled": true,
"notes": "Individual score out of 10"
},
"visuals_left_text_right": {
"weight": 0.06,
"llm": "Gemini",
"enabled": true
"enabled": true,
"notes": "Individual score out of 10"
},
"word_count": {
"weight": 0.05,
"llm": "Gemini",
"enabled": true
"enabled": true,
"notes": "Individual score out of 10"
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 KiB

View file

@ -670,7 +670,9 @@
console.log('Current URL:', window.location.href);
console.log(`Attempting to fetch: ${BASE_PATH}api/profiles`);
const response = await fetch(`${BASE_PATH}api/profiles`);
const response = await fetch(`${BASE_PATH}api/profiles`, {
credentials: 'include'
});
console.log('Response received:', response);
console.log('Response status:', response.status);
console.log('Response ok:', response.ok);
@ -753,7 +755,9 @@
async function loadSavedFiles(retryAttempts = 0, maxRetries = 3) {
try {
console.log(`Loading saved files... (attempt ${retryAttempts + 1}/${maxRetries + 1})`);
const response = await fetch(`${BASE_PATH}api/output_files`);
const response = await fetch(`${BASE_PATH}api/output_files`, {
credentials: 'include'
});
const data = await response.json();
if (data.files && data.files.length > 0) {
@ -787,7 +791,9 @@
// Store the current number of files for comparison
let previousFileCount = 0;
try {
const response = await fetch(`${BASE_PATH}api/output_files`);
const response = await fetch(`${BASE_PATH}api/output_files`, {
credentials: 'include'
});
const data = await response.json();
previousFileCount = data.files ? data.files.length : 0;
console.log(`Current file count: ${previousFileCount}`);
@ -803,7 +809,9 @@
try {
console.log(`Refresh attempt ${i + 1} after ${refreshAttempts[i]}ms delay`);
const response = await fetch(`${BASE_PATH}api/output_files`);
const response = await fetch(`${BASE_PATH}api/output_files`, {
credentials: 'include'
});
const data = await response.json();
if (data.files && data.files.length > 0) {
@ -1165,7 +1173,8 @@
const response = await fetch(`${BASE_PATH}api/start_analysis`, {
method: 'POST',
body: formData
body: formData,
credentials: 'include'
});
console.log('Analysis response status:', response.status);
@ -1227,7 +1236,9 @@
const pollProgress = async () => {
try {
console.log(`Polling progress for session: ${sessionId}`);
const response = await fetch(`${BASE_PATH}api/progress/${sessionId}`);
const response = await fetch(`${BASE_PATH}api/progress/${sessionId}`, {
credentials: 'include'
});
console.log('Progress API response status:', response.status);
if (!response.ok) {
console.error(`Progress check failed with status: ${response.status}`);
@ -1712,8 +1723,8 @@
try {
// Load profiles and QC apps in parallel
const [profilesResponse, qcAppsResponse] = await Promise.all([
fetch(`${BASE_PATH}api/profiles`),
fetch(`${BASE_PATH}api/qc-apps`)
fetch(`${BASE_PATH}api/profiles`, { credentials: 'include' }),
fetch(`${BASE_PATH}api/qc-apps`, { credentials: 'include' })
]);
if (!profilesResponse.ok || !qcAppsResponse.ok) {
@ -1964,7 +1975,8 @@
try {
const response = await fetch(`${BASE_PATH}api/profiles/${selectedProfileId}`, {
method: 'DELETE'
method: 'DELETE',
credentials: 'include'
});
if (!response.ok) {
@ -2014,6 +2026,7 @@
fetch(`${BASE_PATH}api/brand_guidelines`, {
method: 'POST',
credentials: 'include',
body: formData
})
.then(response => response.json())
@ -2049,7 +2062,9 @@
// Load brand guidelines for settings modal
async function loadSettingsBrandGuidelines() {
try {
const response = await fetch(`${BASE_PATH}api/brand_guidelines`);
const response = await fetch(`${BASE_PATH}api/brand_guidelines`, {
credentials: 'include'
});
const data = await response.json();
console.log('Settings brand guidelines loaded:', data);
@ -2105,7 +2120,9 @@
if (!referenceAssetSelect) return;
try {
const response = await fetch(`${BASE_PATH}api/brand_guidelines`);
const response = await fetch(`${BASE_PATH}api/brand_guidelines`, {
credentials: 'include'
});
const data = await response.json();
referenceAssetSelect.innerHTML = '<option value="">No reference asset selected</option>';