modcomms/backend/app/agents/channel_tech_specs_agent.py
Vadym Samoilenko efa6e772e0 Add toast notification when primary Gemini model falls back to backup
Backend: thread on_fallback callback through analysis chain
(gemini_service → agents → analysis_service → handlers). The handler
sends a 'model_fallback' WebSocket message exactly once per analysis
when the primary model is unavailable.

Frontend: handle 'model_fallback' WS message and show a dismissible
yellow toast at the bottom of the screen with an 8-second auto-dismiss.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 13:00:12 +00:00

179 lines
9.5 KiB
Python

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 ChannelTechSpecsAgent(BaseAgent):
"""Channel Tech Specs Agent - analyzes proofs for technical specifications and format requirements using Gemini."""
name = "Channel Tech Specs Agent"
def __init__(self, gemini_service: GeminiService, reference_docs: ReferenceDocsService):
"""
Initialize the Channel Tech Specs 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 _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 channel tech specs 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,
channel: Optional[str] = None,
sub_channel: Optional[str] = None,
proof_type: Optional[str] = None,
on_fallback=None,
) -> SubReview:
"""
Analyze the proof for technical specifications compliance.
Args:
images: List of (file_data, mime_type) tuples representing the proof
previous_review: Optional context from previous version for revision-aware analysis
channel: Target channel (e.g. "Social", "Digital")
sub_channel: Target sub-channel (e.g. "Meta", "Google")
proof_type: Proof format type (e.g. "In-feed 1x1", "Banner")
Returns:
SubReview with technical specifications assessment
"""
# Get the channel tech specs specification
tech_specs_context = self.reference_docs.get_channel_tech_specs_spec()
# Build revision context if available
revision_context = ""
if previous_review:
revision_context = self._build_revision_context(previous_review)
prompt = f"""You are a digital channel technical specifications specialist for Barclays Bank. Your role is to analyze marketing proofs for technical compliance with platform specifications, dimensions, file formats, and character limits.
Here are the channel technical specifications to use for your analysis:
{tech_specs_context}
{revision_context}
---
**PROOF METADATA**
- Channel: {channel or "Not specified"}
- Sub-Channel: {sub_channel or "Not specified"}
- Proof Type: {proof_type or "Not specified"}
Use this metadata to focus your analysis on the specific technical specifications for this channel and format.
---
Analyze the uploaded proof for technical specification compliance, checking:
1. **Dimensions & Resolution**:
- Does the asset meet the required dimensions for the target platform?
- Is the resolution appropriate (DPI/PPI requirements)?
- Are aspect ratios correct for the intended placement?
2. **File Format Requirements**:
- Is the file format suitable for the platform?
- Are file size limits being respected?
- Is compression appropriate for quality vs. performance?
3. **Typography Specifications**:
- Are minimum font sizes met for the platform?
- Character counts within platform limits (headlines, body, etc.)?
- Is text readable at the intended display size?
4. **Digital Grid System**:
- Desktop: 12-column grid compliance
- Tablet: 12-column grid compliance
- Mobile: 6-column grid compliance
- 8px baseline grid adherence
5. **Accessibility Requirements**:
- Color contrast meets WCAG requirements?
- Only documented color pairings are used?
- Text is legible at intended display sizes?
6. **Platform-Specific Technical Requirements**:
- Safe zone compliance for interactive elements
- Video/animation format requirements (if applicable)
- Frame rate and duration limits (if applicable)
Provide your analysis as a JSON object. Be specific about any technical issues found.
IMPORTANT: Do NOT include page numbers, document names, or source citations in your feedback (e.g., no "Page 10", "per Page 12", "Digital Guidelines Page 8"). All feedback must be self-contained and directly actionable without requiring users to look up external references.
RAG Status Guidelines:
- **Green**: Fully compliant with all technical specifications
- **Amber**: Minor technical adjustments needed but content is deployable
- **Red**: Significant technical issues that will prevent proper display or deployment
If the proof is nonsensical, not a marketing material, or cannot be analyzed, set analysisStatus to 'low_confidence'.
**Response Format:**
- Begin the feedback with a single line: "Specifications checked: [Channel] > [Sub-Channel] > [Proof Type]" using the actual metadata values supplied above (omit any that are "Not specified")
- Then provide your analysis findings below
- Keep feedback brief and scannable
- Use bullet points for each finding
- Structure each feedback bullet as two clearly labelled parts separated by a line break:
**Issue:** [Clear description of what's wrong]
**Recommendation:** [Actionable fix — what to do and how]
- Always capitalise "Issue:" and "Recommendation:" and bold them with double asterisks (**)
- Always place the Recommendation on a new line after the Issue (not on the same line)
- Example:
"• **Issue:** The image resolution is 72 DPI (dots per inch), which is below the minimum for this format.
**Recommendation:** Increase the resolution to at least 150 DPI to meet the platform's quality requirements."
- IMPORTANT: Use British English spelling throughout all output (e.g. "authorised" not "authorized", "colour" not "color", "capitalise" not "capitalize", "organised" not "organized", "centre" not "center", "analysed" not "analyzed").
- IMPORTANT: Never use the words "violation", "violates", or "violated" in your output. Use constructive alternatives such as "issue", "doesn't align with", "doesn't meet", or "conflicts with".
- IMPORTANT: Use Plain English throughout. Choose simple, clear words over complex vocabulary. Prefer: "add" over "incorporate/integrate", "about" over "regarding", "qualifies as" over "constitutes", "use" over "utilise", "before" over "prior to", "to" over "in order to", "try" over "endeavour", "then" over "subsequently", "put in place" over "implement", "keep/contain" over "constrain", "standard interest rate" over "reversion rate". Avoid unnecessary jargon (e.g. use "exaggerated claim" instead of "puffery"). Feedback should be easy to understand for all users.
- IMPORTANT: Apply consistent punctuation and capitalisation throughout:
(a) Always capitalise the first word after a full stop, including labels like "Recommendation:" and "Issue:".
(b) End every bullet point with a full stop if it is a complete sentence. If bullets are short fragments, omit the full stop — but be consistent within the same output.
(c) Write "e.g." with no comma after it (e.g. "Apply rotation" not "e.g., Apply rotation").
- IMPORTANT: When providing example corrections in recommendations, always show the example in the format you are recommending. If recommending sentence case, write the example in sentence case (e.g. "Apply now" not "Apply Now"). If quoting the user's original error, show it first, then the corrected version: "Change 'Apply Now' to 'Apply now' (sentence case)."
- IMPORTANT: Always spell out acronyms in full on first use, with the abbreviation in parentheses. Use the short form only for subsequent mentions within the same output. Common acronyms to expand include: WCAG (Web Content Accessibility Guidelines), FSCS (Financial Services Compensation Scheme), GDE (Global Digital Expression), APR (Annual Percentage Rate), CTA (Call-to-Action), FCA (Financial Conduct Authority), PRA (Prudential Regulation Authority), T&Cs (Terms and Conditions). Apply this rule to any acronym, not only those listed here.
"""
# 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, on_fallback=on_fallback
)
else:
return await self.gemini.analyze_with_images(
prompt, images, include_revision_fields=include_revision_fields, on_fallback=on_fallback
)