"""Creative/Design Domain Plugin Scores creative competency based on: - Portfolio links (Behance, Dribbble, personal site) - Project diversity and quality - Design tool proficiency - Visual content analysis """ import re import time import logging import requests from typing import Dict, List from .base_plugin import BaseDomainPlugin, DomainScore from .plugin_factory import register_plugin logger = logging.getLogger(__name__) @register_plugin('creative') class CreativePlugin(BaseDomainPlugin): """Creative/Design domain scoring plugin""" def __init__(self): super().__init__() # Design tools and platforms self.design_tools = [ 'figma', 'sketch', 'adobe xd', 'photoshop', 'illustrator', 'after effects', 'premiere pro', 'blender', 'cinema 4d' ] self.portfolio_platforms = ['behance', 'dribbble', 'artstation', 'deviantart'] def _get_domain_type(self) -> str: return 'creative' def _get_feature_weights(self) -> Dict[str, float]: return { 'portfolio_quality': 0.35, 'project_diversity': 0.25, 'tool_proficiency': 0.20, 'platform_presence': 0.15, 'description_depth': 0.05 } def get_required_fields(self) -> List[str]: return ['portfolio_url'] def get_optional_fields(self) -> List[str]: return ['behance_url', 'dribbble_url', 'design_tools_text', 'project_description'] def score(self, evidence_data: Dict) -> DomainScore: """Calculate creative domain score""" start_time = time.time() features = {} # Portfolio analysis portfolio_url = evidence_data.get('portfolio_url', '') if portfolio_url: features['portfolio_quality'] = self._analyze_portfolio_quality(portfolio_url) else: features['portfolio_quality'] = 0.0 # Platform presence behance_url = evidence_data.get('behance_url', '') dribbble_url = evidence_data.get('dribbble_url', '') features['platform_presence'] = self._check_platform_presence(behance_url, dribbble_url) # Tool proficiency tools_text = evidence_data.get('design_tools_text', '') features['tool_proficiency'] = self._assess_tool_proficiency(tools_text) # Project diversity and description project_desc = evidence_data.get('project_description', '') features['project_diversity'] = self._assess_project_diversity(project_desc) features['description_depth'] = self._assess_description_depth(project_desc) # Calculate weighted score score = sum(features[k] * self.feature_weights[k] for k in features.keys()) # Calculate confidence confidence = self.calculate_confidence(evidence_data) processing_time = (time.time() - start_time) * 1000 return DomainScore( domain_type='creative', score=min(score, 1.0), confidence=confidence, raw_features=features, processing_time_ms=processing_time ) def _analyze_portfolio_quality(self, portfolio_url: str) -> float: """ Analyze portfolio website quality Returns: 0-1 score based on accessibility and professionalism """ try: if not portfolio_url.startswith(('http://', 'https://')): portfolio_url = 'https://' + portfolio_url response = requests.head(portfolio_url, timeout=5, allow_redirects=True) if response.status_code == 200: score = 0.6 # Base score for accessible portfolio # Bonus for professional platforms if any(platform in portfolio_url for platform in self.portfolio_platforms): score += 0.2 # Bonus for custom domain if not any(free in portfolio_url for free in ['github.io', 'wixsite', 'wordpress.com']): score += 0.2 logger.info(f"Portfolio quality: {score:.2f}") return min(score, 1.0) else: return 0.2 except Exception as e: logger.error(f"Error analyzing portfolio: {e}") return 0.2 def _check_platform_presence(self, behance_url: str, dribbble_url: str) -> float: """ Check presence on design platforms Returns: 0-1 score based on platform profiles """ score = 0.0 # Behance presence if behance_url and 'behance.net' in behance_url: try: response = requests.head(behance_url, timeout=5, allow_redirects=True) if response.status_code == 200: score += 0.5 except: score += 0.2 # Partial credit for providing URL # Dribbble presence if dribbble_url and 'dribbble.com' in dribbble_url: try: response = requests.head(dribbble_url, timeout=5, allow_redirects=True) if response.status_code == 200: score += 0.5 except: score += 0.2 logger.info(f"Platform presence: {score:.2f}") return min(score, 1.0) def _assess_tool_proficiency(self, tools_text: str) -> float: """ Assess design tool proficiency Returns: 0-1 score based on tool mentions """ if not tools_text: return 0.0 text_lower = tools_text.lower() # Count tool mentions tool_count = sum(1 for tool in self.design_tools if tool in text_lower) # Score based on tool diversity score = min(tool_count / 5, 1.0) # 5+ tools = max # Bonus for professional tools (Adobe, Figma) pro_tools = ['figma', 'adobe', 'sketch'] if any(tool in text_lower for tool in pro_tools): score = min(score + 0.2, 1.0) logger.info(f"Tool proficiency: {score:.2f} ({tool_count} tools)") return score def _assess_project_diversity(self, project_desc: str) -> float: """ Assess project type diversity Returns: 0-1 score based on project variety """ if not project_desc: return 0.0 text_lower = project_desc.lower() # Project type categories project_types = [ 'ui design', 'ux design', 'branding', 'logo', 'illustration', 'animation', '3d', 'web design', 'mobile app', 'poster', 'packaging', 'typography', 'infographic', 'video editing' ] type_count = sum(1 for ptype in project_types if ptype in text_lower) score = min(type_count / 6, 1.0) # 6+ types = max logger.info(f"Project diversity: {score:.2f} ({type_count} types)") return score def _assess_description_depth(self, project_desc: str) -> float: """ Assess depth of project descriptions Returns: 0-1 score based on detail level """ if not project_desc or len(project_desc) < 50: return 0.0 score = min(len(project_desc) / 1000, 1.0) # 1000+ chars = max logger.info(f"Description depth: {score:.2f}") return score