When a subsequent revision of a proof is uploaded, the analysis now takes place in context of the previous version's results. The system identifies: - Resolved issues: fixed in the new revision - Outstanding issues: still present from previous version - New issues: introduced in the new revision Key changes: - Add resolvedIssues, outstandingIssues, newIssues fields to SubReview - Add PreviousReviewContext model for passing previous review data - Update all specialist agents to accept previous_review context - Extend GeminiService with include_revision_fields parameter - Add get_latest_version_review() repository method - Update LeadAgent to synthesize cross-version context in summary - Fetch previous analysis in WebSocket handler for revisions First version analysis continues to work exactly as before with revision fields set to null. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
147 lines
6 KiB
Python
Executable file
147 lines
6 KiB
Python
Executable file
from typing import List, Optional, Tuple
|
|
|
|
from app.agents.base_agent import BaseAgent
|
|
from app.models.schemas import PreviousReviewContext, SubReview
|
|
from app.services.gemini_service import GeminiService
|
|
from app.services.reference_docs import ReferenceDocsService
|
|
|
|
|
|
class BrandAgent(BaseAgent):
|
|
"""Brand Agent - analyzes proofs against Barclays brand guidelines using Gemini."""
|
|
|
|
name = "Brand Agent"
|
|
|
|
def __init__(self, gemini_service: GeminiService, reference_docs: ReferenceDocsService):
|
|
"""
|
|
Initialize the Brand Agent.
|
|
|
|
Args:
|
|
gemini_service: Service for making Gemini API calls
|
|
reference_docs: Service for loading reference documents
|
|
"""
|
|
self.gemini = gemini_service
|
|
self.reference_docs = reference_docs
|
|
|
|
def _get_brand_context(self, brand: str) -> str:
|
|
"""
|
|
Get the appropriate brand specification based on the brand selection.
|
|
|
|
Args:
|
|
brand: Brand name ('Barclays' or 'Barclaycard')
|
|
|
|
Returns:
|
|
Brand specification content
|
|
"""
|
|
if brand == "Barclays":
|
|
return self.reference_docs.get_barclays_brand_spec()
|
|
else:
|
|
# Default to Barclaycard
|
|
return self.reference_docs.get_barclaycard_brand_spec()
|
|
|
|
def _build_revision_context(self, previous_review: PreviousReviewContext) -> str:
|
|
"""Build prompt section for revision-aware analysis."""
|
|
issues_list = "\n".join(f" - {issue}" for issue in previous_review.issues) if previous_review.issues else " (No issues)"
|
|
return f"""
|
|
---
|
|
|
|
**REVISION CONTEXT**
|
|
|
|
This is a revision of a previously reviewed proof. The previous version (Version {previous_review.version}) had the following brand review:
|
|
|
|
- RAG Status: {previous_review.ragStatus}
|
|
- Feedback: {previous_review.feedback}
|
|
- Issues identified:
|
|
{issues_list}
|
|
|
|
When analyzing this revision, you MUST:
|
|
1. Compare against the previous issues and determine which have been RESOLVED
|
|
2. Identify which previous issues are still OUTSTANDING (not fixed)
|
|
3. Identify any NEW issues introduced in this revision
|
|
|
|
Your response MUST include:
|
|
- resolvedIssues: Array of issues from the previous version that have been fixed
|
|
- outstandingIssues: Array of issues from the previous version that remain unfixed
|
|
- newIssues: Array of new issues not present in the previous version
|
|
|
|
---
|
|
"""
|
|
|
|
async def analyze(
|
|
self,
|
|
images: List[Tuple[bytes, str]],
|
|
previous_review: Optional[PreviousReviewContext] = None,
|
|
brand: str = "Barclaycard",
|
|
) -> SubReview:
|
|
"""
|
|
Analyze the proof for brand guideline adherence.
|
|
|
|
Args:
|
|
images: List of (file_data, mime_type) tuples representing the proof
|
|
previous_review: Optional context from previous version for revision-aware analysis
|
|
brand: Brand to analyze against ('Barclays' or 'Barclaycard')
|
|
|
|
Returns:
|
|
SubReview with brand compliance assessment
|
|
"""
|
|
# Get the appropriate brand specification
|
|
brand_context = self._get_brand_context(brand)
|
|
|
|
# Build revision context if available
|
|
revision_context = ""
|
|
if previous_review:
|
|
revision_context = self._build_revision_context(previous_review)
|
|
|
|
prompt = f"""You are a brand expert for {brand}. Your role is to analyze marketing proofs for adherence to {brand} brand guidelines.
|
|
|
|
Here is the {brand} brand specification to use for your analysis:
|
|
|
|
{brand_context}
|
|
{revision_context}
|
|
---
|
|
|
|
Analyze the uploaded proof against the {brand} brand specification above, checking for:
|
|
|
|
1. **Logo Usage**: Is the {brand} logo used correctly? Check minimum size, clear space, placement, and that it hasn't been altered. Verify correct logo colors per guidelines.
|
|
|
|
2. **Card Portal** (if applicable for {brand}): If the Card Portal asset is present, verify it follows sizing rules (stroke weight and corner radius based on shortest side), proper border color, rotation limits, and that the logo is not placed outside it.
|
|
|
|
3. **Color Palette**: Are only approved {brand} masterbrand colors used? Check for proper WCAG-compliant color pairings and that sacred/primary colors are used appropriately.
|
|
|
|
4. **Typography**: Is Barclays Effra (or Arial fallback) used correctly? Check font weights (Medium/Bold for headings, Regular/Medium for body), sizes per type scale, and line spacing.
|
|
|
|
5. **Design Principles**: Does the overall design reflect the brand principles defined in the specification?
|
|
|
|
6. **Sacred Assets**: Verify that sacred/primary brand assets are present and not altered or misused.
|
|
|
|
7. **Accessibility**: Check for legible font sizes, proper contrast, and appropriate use of special typography elements per guidelines.
|
|
|
|
Provide your analysis as a JSON object. Be specific about any issues found and reference the relevant guideline sections.
|
|
|
|
RAG Status Guidelines:
|
|
- **Green**: Fully compliant with brand guidelines, no issues
|
|
- **Amber**: Minor deviations that should be addressed but don't severely impact brand integrity
|
|
- **Red**: Significant brand guideline violations that must be fixed before use
|
|
|
|
If the proof is nonsensical, not a marketing material, or cannot be analyzed, set analysisStatus to 'low_confidence'.
|
|
|
|
**Response Format:**
|
|
- Keep feedback brief and scannable
|
|
- Use bullet points for each finding
|
|
- Each bullet should be one actionable sentence
|
|
- Start with the issue, then the recommendation
|
|
- Example: "Logo placement incorrect (bottom-left) - move to top-right corner per guidelines"
|
|
"""
|
|
|
|
# Determine if revision fields should be included
|
|
include_revision_fields = previous_review is not None
|
|
|
|
# Use single-image or multi-image analysis depending on input
|
|
if len(images) == 1:
|
|
file_data, file_type = images[0]
|
|
return await self.gemini.analyze_with_image(
|
|
prompt, file_data, file_type, include_revision_fields=include_revision_fields
|
|
)
|
|
else:
|
|
return await self.gemini.analyze_with_images(
|
|
prompt, images, include_revision_fields=include_revision_fields
|
|
)
|