mirror of
https://github.com/furyhawk/agent_alpha.git
synced 2026-07-21 02:25:34 +00:00
326 lines
10 KiB
Python
326 lines
10 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Brand Validation Script
|
|
Validates content against brand guidelines including colors, fonts, tone, and messaging.
|
|
"""
|
|
|
|
import json
|
|
import re
|
|
from dataclasses import asdict, dataclass
|
|
|
|
|
|
@dataclass
|
|
class BrandGuidelines:
|
|
"""Brand guidelines configuration"""
|
|
|
|
brand_name: str
|
|
primary_colors: list[str]
|
|
secondary_colors: list[str]
|
|
fonts: list[str]
|
|
tone_keywords: list[str]
|
|
prohibited_words: list[str]
|
|
tagline: str | None = None
|
|
logo_usage_rules: dict | None = None
|
|
|
|
|
|
@dataclass
|
|
class ValidationResult:
|
|
"""Result of brand validation"""
|
|
|
|
passed: bool
|
|
score: float
|
|
violations: list[str]
|
|
warnings: list[str]
|
|
suggestions: list[str]
|
|
|
|
|
|
class BrandValidator:
|
|
"""Validates content against brand guidelines"""
|
|
|
|
def __init__(self, guidelines: BrandGuidelines):
|
|
self.guidelines = guidelines
|
|
|
|
def validate_colors(self, content: str) -> tuple[list[str], list[str]]:
|
|
"""
|
|
Validate color usage in content (hex codes, RGB, color names)
|
|
Returns: (violations, warnings)
|
|
"""
|
|
violations = []
|
|
warnings = []
|
|
|
|
# Find hex colors
|
|
hex_pattern = r"#[0-9A-Fa-f]{6}|#[0-9A-Fa-f]{3}"
|
|
found_colors = re.findall(hex_pattern, content)
|
|
|
|
# Find RGB colors
|
|
rgb_pattern = r"rgb\s*\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*\)"
|
|
found_colors.extend(re.findall(rgb_pattern, content, re.IGNORECASE))
|
|
|
|
approved_colors = self.guidelines.primary_colors + self.guidelines.secondary_colors
|
|
|
|
for color in found_colors:
|
|
if color.upper() not in [c.upper() for c in approved_colors]:
|
|
violations.append(f"Unapproved color used: {color}")
|
|
|
|
return violations, warnings
|
|
|
|
def validate_fonts(self, content: str) -> tuple[list[str], list[str]]:
|
|
"""
|
|
Validate font usage in content
|
|
Returns: (violations, warnings)
|
|
"""
|
|
violations = []
|
|
warnings = []
|
|
|
|
# Common font specification patterns
|
|
font_patterns = [
|
|
r'font-family\s*:\s*["\']?([^;"\']+)["\']?',
|
|
r"font:\s*[^;]*\s+([A-Za-z][A-Za-z\s]+)(?:,|;|\s+\d)",
|
|
]
|
|
|
|
found_fonts = []
|
|
for pattern in font_patterns:
|
|
matches = re.findall(pattern, content, re.IGNORECASE)
|
|
found_fonts.extend(matches)
|
|
|
|
for font in found_fonts:
|
|
font_clean = font.strip().lower()
|
|
# Check if any approved font is in the found font string
|
|
if not any(approved.lower() in font_clean for approved in self.guidelines.fonts):
|
|
violations.append(f"Unapproved font used: {font}")
|
|
|
|
return violations, warnings
|
|
|
|
def validate_tone(self, content: str) -> tuple[list[str], list[str]]:
|
|
"""
|
|
Validate tone and messaging
|
|
Returns: (violations, warnings)
|
|
"""
|
|
violations = []
|
|
warnings = []
|
|
|
|
# Check for prohibited words
|
|
content_lower = content.lower()
|
|
for word in self.guidelines.prohibited_words:
|
|
if word.lower() in content_lower:
|
|
violations.append(f"Prohibited word/phrase used: '{word}'")
|
|
|
|
# Check for tone keywords (should have at least some)
|
|
tone_matches = sum(
|
|
1 for keyword in self.guidelines.tone_keywords if keyword.lower() in content_lower
|
|
)
|
|
|
|
if tone_matches == 0 and len(content) > 100:
|
|
warnings.append(
|
|
f"Content may not align with brand tone. "
|
|
f"Consider using terms like: {', '.join(self.guidelines.tone_keywords[:5])}"
|
|
)
|
|
|
|
return violations, warnings
|
|
|
|
def validate_brand_name(self, content: str) -> tuple[list[str], list[str]]:
|
|
"""
|
|
Validate brand name usage and capitalization
|
|
Returns: (violations, warnings)
|
|
"""
|
|
violations = []
|
|
warnings = []
|
|
|
|
# Find all variations of the brand name
|
|
brand_pattern = re.compile(re.escape(self.guidelines.brand_name), re.IGNORECASE)
|
|
matches = brand_pattern.findall(content)
|
|
|
|
for match in matches:
|
|
if match != self.guidelines.brand_name:
|
|
violations.append(
|
|
f"Incorrect brand name capitalization: '{match}' "
|
|
f"should be '{self.guidelines.brand_name}'"
|
|
)
|
|
|
|
return violations, warnings
|
|
|
|
def calculate_score(self, violations: list[str], warnings: list[str]) -> float:
|
|
"""Calculate compliance score (0-100)"""
|
|
violation_penalty = len(violations) * 10
|
|
warning_penalty = len(warnings) * 3
|
|
|
|
score = max(0, 100 - violation_penalty - warning_penalty)
|
|
return round(score, 2)
|
|
|
|
def generate_suggestions(self, violations: list[str], warnings: list[str]) -> list[str]:
|
|
"""Generate helpful suggestions based on violations and warnings"""
|
|
suggestions = []
|
|
|
|
if any("color" in v.lower() for v in violations):
|
|
suggestions.append(
|
|
f"Use approved colors: Primary: {', '.join(self.guidelines.primary_colors[:3])}"
|
|
)
|
|
|
|
if any("font" in v.lower() for v in violations):
|
|
suggestions.append(f"Use approved fonts: {', '.join(self.guidelines.fonts)}")
|
|
|
|
if any("tone" in w.lower() for w in warnings):
|
|
suggestions.append(
|
|
f"Incorporate brand tone keywords: {', '.join(self.guidelines.tone_keywords[:5])}"
|
|
)
|
|
|
|
if any("brand name" in v.lower() for v in violations):
|
|
suggestions.append(f"Always capitalize brand name as: {self.guidelines.brand_name}")
|
|
|
|
return suggestions
|
|
|
|
def validate(self, content: str) -> ValidationResult:
|
|
"""
|
|
Perform complete brand validation
|
|
Returns: ValidationResult
|
|
"""
|
|
all_violations = []
|
|
all_warnings = []
|
|
|
|
# Run all validation checks
|
|
color_v, color_w = self.validate_colors(content)
|
|
all_violations.extend(color_v)
|
|
all_warnings.extend(color_w)
|
|
|
|
font_v, font_w = self.validate_fonts(content)
|
|
all_violations.extend(font_v)
|
|
all_warnings.extend(font_w)
|
|
|
|
tone_v, tone_w = self.validate_tone(content)
|
|
all_violations.extend(tone_v)
|
|
all_warnings.extend(tone_w)
|
|
|
|
brand_v, brand_w = self.validate_brand_name(content)
|
|
all_violations.extend(brand_v)
|
|
all_warnings.extend(brand_w)
|
|
|
|
# Calculate score and generate suggestions
|
|
score = self.calculate_score(all_violations, all_warnings)
|
|
suggestions = self.generate_suggestions(all_violations, all_warnings)
|
|
|
|
return ValidationResult(
|
|
passed=len(all_violations) == 0,
|
|
score=score,
|
|
violations=all_violations,
|
|
warnings=all_warnings,
|
|
suggestions=suggestions,
|
|
)
|
|
|
|
|
|
def load_guidelines_from_json(filepath: str) -> BrandGuidelines:
|
|
"""
|
|
Load brand guidelines from JSON file
|
|
|
|
Args:
|
|
filepath: Path to JSON file containing brand guidelines
|
|
|
|
Returns:
|
|
BrandGuidelines object
|
|
|
|
Raises:
|
|
FileNotFoundError: If the file doesn't exist
|
|
json.JSONDecodeError: If the file contains invalid JSON
|
|
TypeError: If required fields are missing
|
|
"""
|
|
try:
|
|
with open(filepath) as f:
|
|
data = json.load(f)
|
|
return BrandGuidelines(**data)
|
|
except FileNotFoundError as e:
|
|
raise FileNotFoundError(f"Brand guidelines file not found: {filepath}") from e
|
|
except json.JSONDecodeError as e:
|
|
raise json.JSONDecodeError(
|
|
f"Invalid JSON in brand guidelines file: {e.msg}", e.doc, e.pos
|
|
) from e
|
|
except TypeError as e:
|
|
raise TypeError(f"Missing required fields in brand guidelines: {e}") from e
|
|
|
|
|
|
def get_acme_corporation_guidelines() -> BrandGuidelines:
|
|
"""
|
|
Get default Acme Corporation brand guidelines.
|
|
|
|
These guidelines match the standards defined in the SKILL.md reference.
|
|
Users should customize these for their own organization.
|
|
|
|
Returns:
|
|
BrandGuidelines object with Acme Corporation standards
|
|
"""
|
|
return BrandGuidelines(
|
|
brand_name="Acme Corporation",
|
|
primary_colors=["#0066CC", "#003366", "#FFFFFF"], # Acme Blue, Acme Navy, White
|
|
secondary_colors=[
|
|
"#28A745",
|
|
"#FFC107",
|
|
"#DC3545",
|
|
"#6C757D",
|
|
"#F8F9FA",
|
|
], # Success Green, Warning Amber, Error Red, Neutral Gray, Light Gray
|
|
fonts=["Segoe UI", "system-ui", "-apple-system", "sans-serif"],
|
|
tone_keywords=[
|
|
"innovation",
|
|
"excellence",
|
|
"professional",
|
|
"solutions",
|
|
"trusted",
|
|
"reliable",
|
|
],
|
|
prohibited_words=["cheap", "outdated", "inferior", "unprofessional", "sloppy"],
|
|
tagline="Innovation Through Excellence",
|
|
)
|
|
|
|
|
|
def main():
|
|
"""Example usage demonstrating brand validation"""
|
|
# Load Acme Corporation brand guidelines
|
|
# Users should customize this for their own organization
|
|
guidelines = get_acme_corporation_guidelines()
|
|
|
|
# Example content to validate (intentionally contains violations for demonstration)
|
|
test_content = """
|
|
Welcome to acme corporation!
|
|
|
|
We are a cheap solution provider with outdated technology.
|
|
|
|
Our innovation and excellence in professional solutions are trusted by many.
|
|
|
|
Contact us at: font-family: 'Comic Sans MS'
|
|
Color scheme: #FF0000
|
|
Background: rgb(255, 0, 0)
|
|
"""
|
|
|
|
# Validate
|
|
validator = BrandValidator(guidelines)
|
|
result = validator.validate(test_content)
|
|
|
|
# Print results
|
|
print("=" * 60)
|
|
print("BRAND VALIDATION REPORT")
|
|
print("=" * 60)
|
|
print(f"\nOverall Status: {'✓ PASSED' if result.passed else '✗ FAILED'}")
|
|
print(f"Compliance Score: {result.score}/100")
|
|
|
|
if result.violations:
|
|
print(f"\n❌ VIOLATIONS ({len(result.violations)}):")
|
|
for i, violation in enumerate(result.violations, 1):
|
|
print(f" {i}. {violation}")
|
|
|
|
if result.warnings:
|
|
print(f"\n⚠️ WARNINGS ({len(result.warnings)}):")
|
|
for i, warning in enumerate(result.warnings, 1):
|
|
print(f" {i}. {warning}")
|
|
|
|
if result.suggestions:
|
|
print("\n💡 SUGGESTIONS:")
|
|
for i, suggestion in enumerate(result.suggestions, 1):
|
|
print(f" {i}. {suggestion}")
|
|
|
|
print("\n" + "=" * 60)
|
|
|
|
# Return JSON for programmatic use
|
|
return asdict(result)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|