Spaces:
Sleeping
Sleeping
| """ | |
| Agent 5: AI Analyzer | |
| Uses HuggingFace models for intelligent analysis of UI differences. | |
| Synthesizes findings from visual comparison and element matching. | |
| """ | |
| from typing import Dict, Any, List | |
| import sys | |
| import os | |
| sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
| from utils.hf_models import analyze_with_ai, HFModelClient | |
| def agent_5_node(state: Dict[str, Any]) -> Dict[str, Any]: | |
| """ | |
| Agent 5: AI-powered analysis and synthesis. | |
| Uses multiple HF models to: | |
| 1. Analyze visual differences in screenshots | |
| 2. Generate insights from element comparisons | |
| 3. Synthesize findings into actionable report | |
| """ | |
| print("\n" + "="*60) | |
| print("🤖 Agent 5: AI Analyzer - Intelligent Analysis") | |
| print("="*60) | |
| hf_token = state.get("hf_token", "") | |
| logs = state.get("logs", []) | |
| # Get data from previous agents | |
| figma_screenshots = state.get("figma_screenshots", {}) | |
| website_screenshots = state.get("website_screenshots", {}) | |
| comparison_images = state.get("comparison_images", {}) | |
| element_matches = state.get("element_matches", {}) | |
| element_differences = state.get("element_differences", []) | |
| similarity_scores = state.get("similarity_scores", {}) | |
| overall_score = state.get("overall_score", 0) | |
| # Build elements summary | |
| elements_summary = { | |
| "figma": {}, | |
| "website": {}, | |
| "matched": 0 | |
| } | |
| for viewport, data in element_matches.items(): | |
| if isinstance(data, dict) and "statistics" in data: | |
| stats = data["statistics"] | |
| elements_summary["figma"][viewport] = stats.get("total_figma", 0) | |
| elements_summary["website"][viewport] = stats.get("total_website", 0) | |
| elements_summary["matched"] += stats.get("matched", 0) | |
| # Check if AI is available | |
| if not hf_token: | |
| print(" ℹ️ No HF token provided - using rule-based synthesis") | |
| logs.append("ℹ️ AI analysis skipped (no HF token)") | |
| # Fallback synthesis | |
| result = _fallback_analysis(element_differences, similarity_scores, overall_score) | |
| return { | |
| "ai_analysis": result, | |
| "status": "analysis_complete", | |
| "logs": logs | |
| } | |
| print(" 🔑 HF token provided - running AI analysis") | |
| logs.append("🤖 Running AI-powered analysis...") | |
| try: | |
| # Get images for analysis (prefer desktop) | |
| figma_img = figma_screenshots.get("desktop", "") | |
| website_img = website_screenshots.get("desktop", "") | |
| diff_img = comparison_images.get("desktop", "") | |
| scores = { | |
| "overall": overall_score, | |
| "desktop": similarity_scores.get("desktop", 0), | |
| "mobile": similarity_scores.get("mobile", 0) | |
| } | |
| # Run AI analysis | |
| result = analyze_with_ai( | |
| hf_token=hf_token, | |
| figma_image=figma_img, | |
| website_image=website_img, | |
| diff_image=diff_img, | |
| elements_summary=elements_summary, | |
| differences=element_differences, | |
| scores=scores | |
| ) | |
| if result.get("ai_enhanced"): | |
| print(" ✅ AI analysis complete") | |
| logs.append("✅ AI analysis successful") | |
| else: | |
| print(" ⚠️ AI analysis fell back to rule-based") | |
| logs.append("⚠️ AI unavailable, used rule-based analysis") | |
| # Add priority issues to logs | |
| for i, issue in enumerate(result.get("priority_issues", [])[:3], 1): | |
| print(f" {i}. {issue[:60]}...") | |
| return { | |
| "ai_analysis": result, | |
| "status": "analysis_complete", | |
| "logs": logs | |
| } | |
| except Exception as e: | |
| print(f" ❌ AI analysis failed: {str(e)}") | |
| logs.append(f"❌ AI error: {str(e)}") | |
| # Fallback | |
| result = _fallback_analysis(element_differences, similarity_scores, overall_score) | |
| return { | |
| "ai_analysis": result, | |
| "status": "analysis_complete", | |
| "logs": logs | |
| } | |
| def _fallback_analysis( | |
| differences: List[Dict], | |
| scores: Dict[str, float], | |
| overall_score: float | |
| ) -> Dict[str, Any]: | |
| """Generate analysis without AI.""" | |
| # Count by severity | |
| high = len([d for d in differences if d.get("severity") == "high"]) | |
| medium = len([d for d in differences if d.get("severity") == "medium"]) | |
| low = len([d for d in differences if d.get("severity") == "low"]) | |
| # Count by category | |
| categories = {} | |
| for d in differences: | |
| cat = d.get("category", "unknown") | |
| categories[cat] = categories.get(cat, 0) + 1 | |
| # Generate summary | |
| if overall_score >= 90: | |
| summary = f"Excellent match! The website closely follows the Figma design with {overall_score:.0f}% similarity." | |
| elif overall_score >= 75: | |
| summary = f"Good match with {overall_score:.0f}% similarity. {high} high-priority issues need attention." | |
| elif overall_score >= 50: | |
| summary = f"Moderate match at {overall_score:.0f}% similarity. {high + medium} issues detected that require fixes." | |
| else: | |
| summary = f"Significant differences found ({overall_score:.0f}% similarity). Major review needed." | |
| # Priority issues from high severity | |
| priority_issues = [] | |
| # Missing elements are highest priority | |
| missing = [d for d in differences if d.get("category") == "missing"] | |
| for m in missing[:2]: | |
| priority_issues.append(f"Missing element: {m.get('element_name', 'Unknown')} not found in website") | |
| # Then high severity issues | |
| high_issues = [d for d in differences if d.get("severity") == "high" and d.get("category") != "missing"] | |
| for h in high_issues[:3]: | |
| priority_issues.append(f"{h.get('category', '').title()}: {h.get('description', 'Check this element')}") | |
| # Fill remaining with medium issues | |
| if len(priority_issues) < 5: | |
| medium_issues = [d for d in differences if d.get("severity") == "medium"] | |
| for m in medium_issues[:5 - len(priority_issues)]: | |
| priority_issues.append(f"{m.get('category', '').title()}: {m.get('description', '')}") | |
| if not priority_issues: | |
| priority_issues = ["No critical issues found. Review minor differences for polish."] | |
| return { | |
| "summary": summary, | |
| "priority_issues": priority_issues, | |
| "ai_enhanced": False, | |
| "statistics": { | |
| "high_severity": high, | |
| "medium_severity": medium, | |
| "low_severity": low, | |
| "by_category": categories | |
| }, | |
| "scores": { | |
| "overall": overall_score, | |
| **scores | |
| } | |
| } | |