Restructure agent system: remove Tone, split Channel, implement Legal
- Remove Tone Agent (tone is now part of Brand specs) - Split Channel Agent into Channel Best Practices Agent and Channel Tech Specs Agent - Convert Legal Agent from stub to full Gemini-powered implementation - Add new prompt files for channel_best_practices.md, channel_tech_specs.md, legal.md - Update ReferenceDocsService with new methods for loading specs - Update schemas and analysis service to use new agent structure - Update all frontend components to use new agent names and properties - Update mock data in Projects.tsx and Campaigns.tsx Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
f24b7c7905
commit
404ba6868b
21 changed files with 642 additions and 208 deletions
|
|
@ -1,6 +1,6 @@
|
|||
from .base_agent import BaseAgent
|
||||
from .brand_agent import BrandAgent
|
||||
from .channel_agent import ChannelAgent
|
||||
from .channel_best_practices_agent import ChannelBestPracticesAgent
|
||||
from .channel_tech_specs_agent import ChannelTechSpecsAgent
|
||||
from .legal_agent import LegalAgent
|
||||
from .tone_agent import ToneAgent
|
||||
from .lead_agent import LeadAgent
|
||||
|
|
|
|||
|
|
@ -1,97 +0,0 @@
|
|||
from typing import List, Tuple
|
||||
|
||||
from app.agents.base_agent import BaseAgent
|
||||
from app.models.schemas import SubReview
|
||||
from app.services.gemini_service import GeminiService
|
||||
from app.services.reference_docs import ReferenceDocsService
|
||||
|
||||
|
||||
class ChannelAgent(BaseAgent):
|
||||
"""Channel Agent - analyzes proofs for digital channel suitability using Gemini."""
|
||||
|
||||
name = "Channel Agent"
|
||||
|
||||
def __init__(self, gemini_service: GeminiService, reference_docs: ReferenceDocsService):
|
||||
"""
|
||||
Initialize the Channel Agent.
|
||||
|
||||
Args:
|
||||
gemini_service: Service for making Gemini API calls
|
||||
reference_docs: Service for loading reference documents
|
||||
"""
|
||||
self.gemini = gemini_service
|
||||
self.channel_context = reference_docs.get_channel_context()
|
||||
|
||||
async def analyze(self, images: List[Tuple[bytes, str]]) -> SubReview:
|
||||
"""
|
||||
Analyze the proof for channel suitability.
|
||||
|
||||
Args:
|
||||
images: List of (file_data, mime_type) tuples representing the proof
|
||||
|
||||
Returns:
|
||||
SubReview with channel suitability assessment
|
||||
"""
|
||||
prompt = f"""You are a digital channel specialist for Barclays Bank. Your role is to analyze marketing proofs for technical suitability across digital and social media channels.
|
||||
|
||||
Here are the channel guidelines to use for your analysis:
|
||||
|
||||
{self.channel_context}
|
||||
|
||||
---
|
||||
|
||||
Analyze the uploaded proof for technical suitability for its intended digital channel, checking:
|
||||
|
||||
1. **Social Media Compliance** (if applicable):
|
||||
- Logo placement (should be top-right corner, 40px from edges on social)
|
||||
- Portal sizing for different platforms (8px thin, 16px thin, or standard as appropriate)
|
||||
- Format specifications (proper dimensions for the target platform)
|
||||
|
||||
2. **Digital Grid System**:
|
||||
- Desktop: 12-column grid
|
||||
- Tablet: 12-column grid
|
||||
- Mobile: 6-column grid
|
||||
- 8px baseline grid adherence
|
||||
|
||||
3. **Typography Scale**:
|
||||
- Check if text sizing follows the 8-level scale (Supersize 80px down to X Small 12px)
|
||||
- Responsive type considerations for different breakpoints (640px mobile threshold)
|
||||
|
||||
4. **Accessibility**:
|
||||
- Color contrast meets accessibility requirements
|
||||
- Only documented color pairings are used
|
||||
- Text is readable at the intended display size
|
||||
|
||||
5. **Platform-Specific Requirements**:
|
||||
- Hashtag usage guidelines (if social media)
|
||||
- Emoji usage (appropriate vs. inappropriate as per guidelines)
|
||||
- Character limits (Headlines: 65 chars, Body: 300 chars, Quotations: 250 chars)
|
||||
|
||||
6. **Motion/Video** (if applicable):
|
||||
- Start and end frame compliance
|
||||
- Subtitle formatting
|
||||
- Frame rate and format requirements
|
||||
|
||||
Provide your analysis as a JSON object. Be specific about any technical issues and reference the relevant platform or guideline.
|
||||
|
||||
RAG Status Guidelines:
|
||||
- **Green**: Fully suitable for the intended channel, all specs met
|
||||
- **Amber**: Minor technical adjustments needed for optimal display
|
||||
- **Red**: Significant technical issues that will impact display or accessibility
|
||||
|
||||
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"
|
||||
"""
|
||||
|
||||
# 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)
|
||||
else:
|
||||
return await self.gemini.analyze_with_images(prompt, images)
|
||||
95
backend/app/agents/channel_best_practices_agent.py
Normal file
95
backend/app/agents/channel_best_practices_agent.py
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
from typing import List, Tuple
|
||||
|
||||
from app.agents.base_agent import BaseAgent
|
||||
from app.models.schemas import SubReview
|
||||
from app.services.gemini_service import GeminiService
|
||||
from app.services.reference_docs import ReferenceDocsService
|
||||
|
||||
|
||||
class ChannelBestPracticesAgent(BaseAgent):
|
||||
"""Channel Best Practices Agent - analyzes proofs for creative best practices and content strategy using Gemini."""
|
||||
|
||||
name = "Channel Best Practices Agent"
|
||||
|
||||
def __init__(self, gemini_service: GeminiService, reference_docs: ReferenceDocsService):
|
||||
"""
|
||||
Initialize the Channel Best Practices 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
|
||||
|
||||
async def analyze(self, images: List[Tuple[bytes, str]]) -> SubReview:
|
||||
"""
|
||||
Analyze the proof for channel best practices and content strategy.
|
||||
|
||||
Args:
|
||||
images: List of (file_data, mime_type) tuples representing the proof
|
||||
|
||||
Returns:
|
||||
SubReview with channel best practices assessment
|
||||
"""
|
||||
# Get the channel best practices specification
|
||||
best_practices_context = self.reference_docs.get_channel_best_practices_spec()
|
||||
|
||||
prompt = f"""You are a digital channel best practices specialist for Barclays Bank. Your role is to analyze marketing proofs for creative best practices, content strategy, and platform optimization.
|
||||
|
||||
Here are the channel best practices guidelines to use for your analysis:
|
||||
|
||||
{best_practices_context}
|
||||
|
||||
---
|
||||
|
||||
Analyze the uploaded proof for adherence to channel best practices, checking:
|
||||
|
||||
1. **Content Strategy**:
|
||||
- Is the messaging clear and appropriate for the target platform?
|
||||
- Does the content follow platform-specific engagement best practices?
|
||||
- Is the call-to-action clear and effective?
|
||||
|
||||
2. **Creative Best Practices**:
|
||||
- Is the visual hierarchy optimized for the channel?
|
||||
- Does the layout follow proven engagement patterns?
|
||||
- Are key messages prominently displayed?
|
||||
|
||||
3. **Platform Optimization**:
|
||||
- Is the content optimized for the intended platform's algorithm?
|
||||
- Does it follow safe zone guidelines for interactive elements?
|
||||
- Are text-to-image ratios appropriate for the platform?
|
||||
|
||||
4. **Engagement Considerations**:
|
||||
- Does the design encourage user interaction?
|
||||
- Are social-specific elements (hashtags, mentions) used appropriately?
|
||||
- Is the tone suitable for the platform's audience expectations?
|
||||
|
||||
5. **Mobile-First Design**:
|
||||
- Is the content legible on mobile devices?
|
||||
- Are touch targets appropriately sized?
|
||||
- Does it account for thumb-zone navigation?
|
||||
|
||||
Provide your analysis as a JSON object. Be specific about any issues found and reference the relevant guideline sections.
|
||||
|
||||
RAG Status Guidelines:
|
||||
- **Green**: Fully aligned with best practices, optimized for the channel
|
||||
- **Amber**: Minor improvements could enhance performance but content is acceptable
|
||||
- **Red**: Significant best practice violations that will impact content effectiveness
|
||||
|
||||
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: "CTA placement below fold - move above fold for better visibility"
|
||||
"""
|
||||
|
||||
# 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)
|
||||
else:
|
||||
return await self.gemini.analyze_with_images(prompt, images)
|
||||
101
backend/app/agents/channel_tech_specs_agent.py
Normal file
101
backend/app/agents/channel_tech_specs_agent.py
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
from typing import List, Tuple
|
||||
|
||||
from app.agents.base_agent import BaseAgent
|
||||
from app.models.schemas import 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
|
||||
|
||||
async def analyze(self, images: List[Tuple[bytes, str]]) -> SubReview:
|
||||
"""
|
||||
Analyze the proof for technical specifications compliance.
|
||||
|
||||
Args:
|
||||
images: List of (file_data, mime_type) tuples representing the proof
|
||||
|
||||
Returns:
|
||||
SubReview with technical specifications assessment
|
||||
"""
|
||||
# Get the channel tech specs specification
|
||||
tech_specs_context = self.reference_docs.get_channel_tech_specs_spec()
|
||||
|
||||
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}
|
||||
|
||||
---
|
||||
|
||||
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 and reference the relevant specification.
|
||||
|
||||
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:**
|
||||
- Keep feedback brief and scannable
|
||||
- Use bullet points for each finding
|
||||
- Each bullet should be one actionable sentence
|
||||
- Start with the issue, then the specification requirement
|
||||
- Example: "Image resolution 72dpi - increase to minimum 150dpi for print quality"
|
||||
"""
|
||||
|
||||
# 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)
|
||||
else:
|
||||
return await self.gemini.analyze_with_images(prompt, images)
|
||||
|
|
@ -1,36 +1,106 @@
|
|||
import asyncio
|
||||
from typing import List, Tuple
|
||||
|
||||
from app.agents.base_agent import BaseAgent
|
||||
from app.models.schemas import SubReview, RagStatus
|
||||
from app.models.schemas import SubReview
|
||||
from app.services.gemini_service import GeminiService
|
||||
from app.services.reference_docs import ReferenceDocsService
|
||||
|
||||
|
||||
class LegalAgent(BaseAgent):
|
||||
"""
|
||||
Legal Agent - STUB implementation.
|
||||
|
||||
Returns mock Green status. Full legal review requires manual verification.
|
||||
"""
|
||||
"""Legal Agent - analyzes proofs for legal compliance using Gemini."""
|
||||
|
||||
name = "Legal Agent"
|
||||
|
||||
async def analyze(self, images: List[Tuple[bytes, str]]) -> SubReview:
|
||||
def __init__(self, gemini_service: GeminiService, reference_docs: ReferenceDocsService):
|
||||
"""
|
||||
Stub implementation that returns mock Green status.
|
||||
Initialize the Legal Agent.
|
||||
|
||||
Args:
|
||||
images: List of (file_data, mime_type) tuples (not used in stub)
|
||||
gemini_service: Service for making Gemini API calls
|
||||
reference_docs: Service for loading reference documents
|
||||
"""
|
||||
self.gemini = gemini_service
|
||||
self.reference_docs = reference_docs
|
||||
|
||||
async def analyze(self, images: List[Tuple[bytes, str]]) -> SubReview:
|
||||
"""
|
||||
Analyze the proof for legal compliance.
|
||||
|
||||
Args:
|
||||
images: List of (file_data, mime_type) tuples representing the proof
|
||||
|
||||
Returns:
|
||||
SubReview with Green status and stub notice
|
||||
SubReview with legal compliance assessment
|
||||
"""
|
||||
# Simulate some processing time for realistic UX
|
||||
await asyncio.sleep(0.5)
|
||||
# Get the legal specification
|
||||
legal_context = self.reference_docs.get_legal_spec()
|
||||
|
||||
return SubReview(
|
||||
ragStatus=RagStatus.GREEN,
|
||||
feedback="[STUB] Legal compliance check passed. This is a placeholder response - the Legal Agent has not been implemented for this POC. Full legal review, including financial promotion detection and regulatory compliance, requires the complete implementation.",
|
||||
issues=[],
|
||||
isFinancialPromotion=False,
|
||||
financialPromotionReason=""
|
||||
)
|
||||
prompt = f"""You are a legal compliance specialist for Barclays Bank. Your role is to analyze marketing proofs for legal compliance, advertising standards, and regulatory requirements.
|
||||
|
||||
Here are the legal guidelines to use for your analysis:
|
||||
|
||||
{legal_context}
|
||||
|
||||
---
|
||||
|
||||
Analyze the uploaded proof for legal compliance, checking:
|
||||
|
||||
1. **Financial Promotion Detection**:
|
||||
- Does this marketing material constitute a financial promotion?
|
||||
- A financial promotion is any communication that invites or induces a person to engage in investment activity or relates to financial products/services
|
||||
- Look for: interest rates, APR, loan offers, investment products, credit cards with financial terms, savings rates, etc.
|
||||
- If detected, set isFinancialPromotion to true and provide a clear reason
|
||||
|
||||
2. **Advertising Standards**:
|
||||
- Are all claims substantiated and not misleading?
|
||||
- Are comparisons fair and verifiable?
|
||||
- Are there any potentially deceptive practices?
|
||||
|
||||
3. **Required Disclaimers**:
|
||||
- Are all necessary disclaimers present?
|
||||
- Are disclaimers legible and appropriately placed?
|
||||
- Do disclaimers meet minimum size requirements?
|
||||
|
||||
4. **Regulatory Compliance**:
|
||||
- Does the content comply with FCA regulations (if applicable)?
|
||||
- Are there any ASA/CAP code violations?
|
||||
- Is representative APR shown where required?
|
||||
|
||||
5. **Terms and Conditions**:
|
||||
- Are T&Cs referenced where necessary?
|
||||
- Is the qualifying text clear and not hidden?
|
||||
- Are important limitations disclosed?
|
||||
|
||||
6. **Third-Party Content**:
|
||||
- Are proper permissions/attributions in place for third-party content?
|
||||
- Are testimonials genuine and substantiated?
|
||||
- Are celebrity/influencer relationships disclosed?
|
||||
|
||||
IMPORTANT: You must include the following fields in your JSON response:
|
||||
- ragStatus: "Green", "Amber", or "Red"
|
||||
- feedback: Your detailed analysis
|
||||
- issues: Array of specific issues found
|
||||
- isFinancialPromotion: true or false
|
||||
- financialPromotionReason: String explaining why it is/isn't a financial promotion (required if isFinancialPromotion is true)
|
||||
|
||||
RAG Status Guidelines:
|
||||
- **Green**: Fully compliant with legal requirements, no issues
|
||||
- **Amber**: Minor issues that need attention but not critical violations
|
||||
- **Red**: Significant legal or regulatory violations that must be addressed
|
||||
|
||||
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 requirement
|
||||
- Example: "Missing APR disclaimer - add representative APR per FCA requirements"
|
||||
"""
|
||||
|
||||
# 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)
|
||||
else:
|
||||
return await self.gemini.analyze_with_images(prompt, images)
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
import asyncio
|
||||
from typing import List, Tuple
|
||||
|
||||
from app.agents.base_agent import BaseAgent
|
||||
from app.models.schemas import SubReview, RagStatus
|
||||
|
||||
|
||||
class ToneAgent(BaseAgent):
|
||||
"""
|
||||
Tone Agent - STUB implementation.
|
||||
|
||||
Returns mock Green status. Full tone analysis requires implementation.
|
||||
"""
|
||||
|
||||
name = "Tone Agent"
|
||||
|
||||
async def analyze(self, images: List[Tuple[bytes, str]]) -> SubReview:
|
||||
"""
|
||||
Stub implementation that returns mock Green status.
|
||||
|
||||
Args:
|
||||
images: List of (file_data, mime_type) tuples (not used in stub)
|
||||
|
||||
Returns:
|
||||
SubReview with Green status and stub notice
|
||||
"""
|
||||
# Simulate some processing time for realistic UX
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
return SubReview(
|
||||
ragStatus=RagStatus.GREEN,
|
||||
feedback="[STUB] Tone of voice analysis passed. This is a placeholder response - the Tone Agent has not been implemented for this POC. The copy appears to demonstrate appropriate brand personality traits: Pioneering, Connected, Optimistic, and Professional. Full analysis of clarity, grammar, and brand voice alignment requires the complete implementation.",
|
||||
issues=[]
|
||||
)
|
||||
|
|
@ -35,8 +35,8 @@ class AgentReview(BaseModel):
|
|||
"""Complete review from all agents."""
|
||||
legalAgentReview: SubReview
|
||||
brandAgentReview: SubReview
|
||||
toneAgentReview: SubReview
|
||||
channelAgentReview: SubReview
|
||||
channelBestPracticesAgentReview: SubReview
|
||||
channelTechSpecsAgentReview: SubReview
|
||||
leadAgentSummary: str
|
||||
overallStatus: OverallStatus
|
||||
financialPromotionReason: Optional[str] = None
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ from app.models.schemas import SubReview, AgentReview, OverallStatus
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
from app.agents.brand_agent import BrandAgent
|
||||
from app.agents.channel_agent import ChannelAgent
|
||||
from app.agents.channel_best_practices_agent import ChannelBestPracticesAgent
|
||||
from app.agents.channel_tech_specs_agent import ChannelTechSpecsAgent
|
||||
from app.agents.legal_agent import LegalAgent
|
||||
from app.agents.tone_agent import ToneAgent
|
||||
from app.agents.lead_agent import LeadAgent
|
||||
from app.services.gemini_service import GeminiService
|
||||
from app.services.reference_docs import ReferenceDocsService
|
||||
|
|
@ -26,7 +26,7 @@ class AnalysisService:
|
|||
"""
|
||||
|
||||
# Agent execution order
|
||||
AGENT_ORDER = ["Legal Agent", "Brand Agent", "Tone Agent", "Channel Agent"]
|
||||
AGENT_ORDER = ["Legal Agent", "Brand Agent", "Channel Best Practices Agent", "Channel Tech Specs Agent"]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
|
@ -45,10 +45,10 @@ class AnalysisService:
|
|||
|
||||
# Initialize agents
|
||||
self.agents = {
|
||||
"Legal Agent": LegalAgent(),
|
||||
"Legal Agent": LegalAgent(gemini_service, reference_docs),
|
||||
"Brand Agent": BrandAgent(gemini_service, reference_docs),
|
||||
"Tone Agent": ToneAgent(),
|
||||
"Channel Agent": ChannelAgent(gemini_service, reference_docs),
|
||||
"Channel Best Practices Agent": ChannelBestPracticesAgent(gemini_service, reference_docs),
|
||||
"Channel Tech Specs Agent": ChannelTechSpecsAgent(gemini_service, reference_docs),
|
||||
}
|
||||
self.lead_agent = LeadAgent(gemini_service)
|
||||
|
||||
|
|
@ -103,8 +103,8 @@ class AnalysisService:
|
|||
return AgentReview(
|
||||
legalAgentReview=error_review,
|
||||
brandAgentReview=error_review,
|
||||
toneAgentReview=error_review,
|
||||
channelAgentReview=error_review,
|
||||
channelBestPracticesAgentReview=error_review,
|
||||
channelTechSpecsAgentReview=error_review,
|
||||
leadAgentSummary=f"Analysis could not proceed due to PDF processing error: {str(e)}",
|
||||
overallStatus="Analysis Error",
|
||||
financialPromotionReason=None,
|
||||
|
|
@ -149,8 +149,8 @@ class AnalysisService:
|
|||
return AgentReview(
|
||||
legalAgentReview=reviews["Legal Agent"],
|
||||
brandAgentReview=reviews["Brand Agent"],
|
||||
toneAgentReview=reviews["Tone Agent"],
|
||||
channelAgentReview=reviews["Channel Agent"],
|
||||
channelBestPracticesAgentReview=reviews["Channel Best Practices Agent"],
|
||||
channelTechSpecsAgentReview=reviews["Channel Tech Specs Agent"],
|
||||
leadAgentSummary=summary,
|
||||
overallStatus=overall_status,
|
||||
financialPromotionReason=financial_promotion_reason,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@ class ReferenceDocsService:
|
|||
self._brand_context: str | None = None
|
||||
self._channel_context: str | None = None
|
||||
self._barclaycard_brand_spec: str | None = None
|
||||
self._barclays_brand_spec: str | None = None
|
||||
self._channel_best_practices_spec: str | None = None
|
||||
self._channel_tech_specs_spec: str | None = None
|
||||
self._legal_spec: str | None = None
|
||||
|
||||
def get_brand_context(self) -> str:
|
||||
"""Load and return all brand guideline documents as a single context string."""
|
||||
|
|
@ -75,6 +79,51 @@ class ReferenceDocsService:
|
|||
self._channel_context = self._load_all_markdown_files(channel_path)
|
||||
return self._channel_context
|
||||
|
||||
def get_channel_best_practices_spec(self) -> str:
|
||||
"""Load and return the Channel Best Practices specification from prompts directory."""
|
||||
if self._channel_best_practices_spec is None:
|
||||
spec_path = self.prompts_path / "channel_best_practices.md"
|
||||
try:
|
||||
if spec_path.exists():
|
||||
self._channel_best_practices_spec = spec_path.read_text(encoding="utf-8")
|
||||
else:
|
||||
print(f"Warning: Channel Best Practices spec not found at {spec_path}")
|
||||
self._channel_best_practices_spec = self.get_channel_context()
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not read Channel Best Practices spec: {e}")
|
||||
self._channel_best_practices_spec = self.get_channel_context()
|
||||
return self._channel_best_practices_spec
|
||||
|
||||
def get_channel_tech_specs_spec(self) -> str:
|
||||
"""Load and return the Channel Tech Specs specification from prompts directory."""
|
||||
if self._channel_tech_specs_spec is None:
|
||||
spec_path = self.prompts_path / "channel_tech_specs.md"
|
||||
try:
|
||||
if spec_path.exists():
|
||||
self._channel_tech_specs_spec = spec_path.read_text(encoding="utf-8")
|
||||
else:
|
||||
print(f"Warning: Channel Tech Specs spec not found at {spec_path}")
|
||||
self._channel_tech_specs_spec = self.get_channel_context()
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not read Channel Tech Specs spec: {e}")
|
||||
self._channel_tech_specs_spec = self.get_channel_context()
|
||||
return self._channel_tech_specs_spec
|
||||
|
||||
def get_legal_spec(self) -> str:
|
||||
"""Load and return the Legal specification from prompts directory."""
|
||||
if self._legal_spec is None:
|
||||
spec_path = self.prompts_path / "legal.md"
|
||||
try:
|
||||
if spec_path.exists():
|
||||
self._legal_spec = spec_path.read_text(encoding="utf-8")
|
||||
else:
|
||||
print(f"Warning: Legal spec not found at {spec_path}")
|
||||
self._legal_spec = "No legal specification found. Apply general legal compliance checks."
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not read Legal spec: {e}")
|
||||
self._legal_spec = "No legal specification found. Apply general legal compliance checks."
|
||||
return self._legal_spec
|
||||
|
||||
def _load_all_markdown_files(self, directory: Path) -> str:
|
||||
"""
|
||||
Load all .md files from a directory and concatenate them.
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import apiService, { AnalyticsResponse } from '../services/apiService';
|
|||
const agentPerformance = [
|
||||
{ name: 'Legal Agent', passRate: 85, avgIssues: 1.2, trend: 'up' },
|
||||
{ name: 'Brand Agent', passRate: 68, avgIssues: 2.5, trend: 'down' },
|
||||
{ name: 'Tone Agent', passRate: 92, avgIssues: 0.8, trend: 'up' },
|
||||
{ name: 'Channel Agent', passRate: 71, avgIssues: 1.9, trend: 'stable' },
|
||||
{ name: 'Channel Best Practices Agent', passRate: 92, avgIssues: 0.8, trend: 'up' },
|
||||
{ name: 'Channel Tech Specs Agent', passRate: 71, avgIssues: 1.9, trend: 'stable' },
|
||||
];
|
||||
|
||||
const UpArrow = () => <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={3} stroke="currentColor" className="h-4 w-4"><path strokeLinecap="round" strokeLinejoin="round" d="M4.5 15.75l7.5-7.5 7.5 7.5" /></svg>;
|
||||
|
|
|
|||
|
|
@ -76,12 +76,12 @@ const IG_HERO_POST_1_FEEDBACK_V1: AgentReview = {
|
|||
feedback: "The agent could not analyze this proof with high confidence. This may be because the content is irrelevant, nonsensical, or too far outside of expected marketing materials.",
|
||||
issues: []
|
||||
},
|
||||
toneAgentReview: {
|
||||
channelBestPracticesAgentReview: {
|
||||
ragStatus: "Green",
|
||||
feedback: "The copy is clear, concise, and professional. The tone aligns well with the brand's voice and effectively communicates the new partnership.",
|
||||
feedback: "The content strategy is clear and effectively communicates the partnership message. The call-to-action is prominent.",
|
||||
issues: []
|
||||
},
|
||||
channelAgentReview: {
|
||||
channelTechSpecsAgentReview: {
|
||||
ragStatus: "Amber",
|
||||
feedback: "While the image quality is high, the composition is not optimized for vertical formats like Instagram Stories. The high ratio of text in the image could also potentially reduce advertising reach on some platforms.",
|
||||
issues: ["Image composition is not mobile-first or suitable for vertical formats.", "High ratio of text in the image may negatively impact ad performance."]
|
||||
|
|
@ -101,12 +101,12 @@ const IG_HERO_POST_1_FEEDBACK_V2: AgentReview = {
|
|||
feedback: "The proof now fully aligns with brand guidelines. The 'Principal partner' lockup uses the correct brand font, and the non-standard blue border has been removed, resulting in a cleaner, on-brand look.",
|
||||
issues: []
|
||||
},
|
||||
toneAgentReview: {
|
||||
channelBestPracticesAgentReview: {
|
||||
ragStatus: "Green",
|
||||
feedback: "The copy remains clear, professional, and well-aligned with the brand's tone of voice. No issues found.",
|
||||
feedback: "The content strategy is effective with clear messaging and well-optimized visual hierarchy. No issues found.",
|
||||
issues: []
|
||||
},
|
||||
channelAgentReview: {
|
||||
channelTechSpecsAgentReview: {
|
||||
ragStatus: "Amber",
|
||||
feedback: "The image composition has been improved and is suitable for standard feeds. However, for optimal performance on Instagram, creating a separate vertical version for Story placements is recommended.",
|
||||
issues: ["Consider creating a separate vertical version for Story placements."]
|
||||
|
|
@ -159,8 +159,8 @@ export const initialCampaignProofs: { [key: string]: any[] } = {
|
|||
leadAgentSummary: "Passed. Compliant with all guidelines.",
|
||||
legalAgentReview: { ragStatus: "Green", feedback: "Disclaimers present and correct.", issues: [] },
|
||||
brandAgentReview: { ragStatus: "Green", feedback: "On brand colors used.", issues: [] },
|
||||
toneAgentReview: { ragStatus: "Green", feedback: "Professional tone.", issues: [] },
|
||||
channelAgentReview: { ragStatus: "Green", feedback: "Correct specs for FB.", issues: [] }
|
||||
channelBestPracticesAgentReview: { ragStatus: "Green", feedback: "Content strategy is effective.", issues: [] },
|
||||
channelTechSpecsAgentReview: { ragStatus: "Green", feedback: "Correct specs for FB.", issues: [] }
|
||||
},
|
||||
overallStatus: 'Passed',
|
||||
}
|
||||
|
|
@ -184,8 +184,8 @@ export const initialCampaignProofs: { [key: string]: any[] } = {
|
|||
leadAgentSummary: "Approved for IG Stories.",
|
||||
legalAgentReview: { ragStatus: "Green", feedback: "Compliant.", issues: [] },
|
||||
brandAgentReview: { ragStatus: "Green", feedback: "Brand aligned.", issues: [] },
|
||||
toneAgentReview: { ragStatus: "Green", feedback: "Engaging copy.", issues: [] },
|
||||
channelAgentReview: { ragStatus: "Green", feedback: "Optimized for mobile.", issues: [] }
|
||||
channelBestPracticesAgentReview: { ragStatus: "Green", feedback: "Engaging content strategy.", issues: [] },
|
||||
channelTechSpecsAgentReview: { ragStatus: "Green", feedback: "Optimized for mobile.", issues: [] }
|
||||
},
|
||||
overallStatus: 'Passed',
|
||||
}
|
||||
|
|
@ -211,8 +211,8 @@ export const initialCampaignProofs: { [key: string]: any[] } = {
|
|||
leadAgentSummary: "The proof has Passed review with no issues found across all categories. It is well-designed, compliant, and ready for deployment.",
|
||||
legalAgentReview: { ragStatus: "Green", feedback: "All claims are substantiated and disclaimers are correctly placed.", issues: [] },
|
||||
brandAgentReview: { ragStatus: "Green", feedback: "The proof adheres perfectly to all brand guidelines.", issues: [] },
|
||||
toneAgentReview: { ragStatus: "Green", feedback: "The copy is clear, accurate, and professional.", issues: [] },
|
||||
channelAgentReview: { ragStatus: "Green", feedback: "The infographic format is highly suitable for the selected channel.", issues: [] },
|
||||
channelBestPracticesAgentReview: { ragStatus: "Green", feedback: "The content strategy is effective and well-optimized for engagement.", issues: [] },
|
||||
channelTechSpecsAgentReview: { ragStatus: "Green", feedback: "The infographic format is highly suitable for the selected channel.", issues: [] },
|
||||
},
|
||||
overallStatus: 'Passed',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
import React from 'react';
|
||||
import { LegalIcon } from './icons/LegalIcon';
|
||||
import { BrandIcon } from './icons/BrandIcon';
|
||||
import { CopyIcon } from './icons/CopyIcon';
|
||||
import { ChannelIcon } from './icons/ChannelIcon';
|
||||
import { LeadAgentIcon } from './icons/LeadAgentIcon';
|
||||
|
||||
|
|
@ -27,15 +26,15 @@ const specialistAgents: CheckDetail[] = [
|
|||
description: 'Verifies logo usage, color palette, and visual identity.'
|
||||
},
|
||||
{
|
||||
name: 'Tone Agent',
|
||||
icon: <CopyIcon />,
|
||||
role: 'Voice & Clarity',
|
||||
description: 'Analyzes copy for clarity, brand voice, and tone consistency.'
|
||||
name: 'Channel Best Practices Agent',
|
||||
icon: <ChannelIcon />,
|
||||
role: 'Creative Strategy',
|
||||
description: 'Analyzes content strategy, engagement, and platform optimization.'
|
||||
},
|
||||
{
|
||||
name: 'Channel Agent',
|
||||
name: 'Channel Tech Specs Agent',
|
||||
icon: <ChannelIcon />,
|
||||
role: 'Platform Specs',
|
||||
role: 'Technical Specs',
|
||||
description: 'Checks assets against platform-specific technical specifications.'
|
||||
}
|
||||
];
|
||||
|
|
|
|||
|
|
@ -492,8 +492,8 @@ export const FeedbackReport: React.FC<{
|
|||
const agentReviews = [
|
||||
{ title: 'Legal Agent', review: feedback.legalAgentReview },
|
||||
{ title: 'Brand Agent', review: feedback.brandAgentReview },
|
||||
{ title: 'Tone Agent', review: feedback.toneAgentReview },
|
||||
{ title: 'Channel Agent', review: feedback.channelAgentReview },
|
||||
{ title: 'Channel Best Practices Agent', review: feedback.channelBestPracticesAgentReview },
|
||||
{ title: 'Channel Tech Specs Agent', review: feedback.channelTechSpecsAgentReview },
|
||||
];
|
||||
|
||||
const isFinancialPromotion = feedback.overallStatus === 'Requires Manual Legal Review';
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { BarclaysLogo } from './icons/BarclaysLogo';
|
|||
import { OliverLogo } from './icons/OliverLogo';
|
||||
import { LegalIcon } from './icons/LegalIcon';
|
||||
import { BrandIcon } from './icons/BrandIcon';
|
||||
import { CopyIcon } from './icons/CopyIcon';
|
||||
import { ChannelIcon } from './icons/ChannelIcon';
|
||||
|
||||
interface PDFReportProps {
|
||||
|
|
@ -87,8 +86,8 @@ export const PDFReport: React.FC<PDFReportProps> = ({ campaignName, proofs }) =>
|
|||
const agentReviews = [
|
||||
{ title: 'Legal Agent', review: feedback.legalAgentReview, icon: <LegalIcon style={{height: '24px', width: '24px'}} /> },
|
||||
{ title: 'Brand Agent', review: feedback.brandAgentReview, icon: <BrandIcon style={{height: '24px', width: '24px'}} /> },
|
||||
{ title: 'Tone Agent', review: feedback.toneAgentReview, icon: <CopyIcon style={{height: '24px', width: '24px'}} /> },
|
||||
{ title: 'Channel Agent', review: feedback.channelAgentReview, icon: <ChannelIcon style={{height: '24px', width: '24px'}} /> },
|
||||
{ title: 'Channel Best Practices Agent', review: feedback.channelBestPracticesAgentReview, icon: <ChannelIcon style={{height: '24px', width: '24px'}} /> },
|
||||
{ title: 'Channel Tech Specs Agent', review: feedback.channelTechSpecsAgentReview, icon: <ChannelIcon style={{height: '24px', width: '24px'}} /> },
|
||||
];
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -60,12 +60,12 @@ const IG_HERO_POST_1_FEEDBACK_V1: AgentReview = {
|
|||
feedback: "The agent could not analyze this asset with high confidence. This may be because the content is irrelevant, nonsensical, or too far outside of expected marketing materials.",
|
||||
issues: []
|
||||
},
|
||||
toneAgentReview: {
|
||||
channelBestPracticesAgentReview: {
|
||||
ragStatus: "Green",
|
||||
feedback: "The copy is clear, concise, and professional. The tone aligns well with the brand's voice and effectively communicates the new partnership.",
|
||||
feedback: "The content strategy is clear and effectively communicates the partnership message. The call-to-action is prominent.",
|
||||
issues: []
|
||||
},
|
||||
channelAgentReview: {
|
||||
channelTechSpecsAgentReview: {
|
||||
ragStatus: "Amber",
|
||||
feedback: "While the image quality is high, the composition is not optimized for vertical formats like Instagram Stories. The high ratio of text in the image could also potentially reduce advertising reach on some platforms.",
|
||||
issues: ["Image composition is not mobile-first or suitable for vertical formats.", "High ratio of text in the image may negatively impact ad performance."]
|
||||
|
|
@ -85,12 +85,12 @@ const IG_HERO_POST_1_FEEDBACK_V2: AgentReview = {
|
|||
feedback: "The asset now fully aligns with brand guidelines. The 'Principal partner' lockup uses the correct brand font, and the non-standard blue border has been removed, resulting in a cleaner, on-brand look.",
|
||||
issues: []
|
||||
},
|
||||
toneAgentReview: {
|
||||
channelBestPracticesAgentReview: {
|
||||
ragStatus: "Green",
|
||||
feedback: "The copy remains clear, professional, and well-aligned with the brand's tone of voice. No issues found.",
|
||||
feedback: "The content strategy is effective with clear messaging and well-optimized visual hierarchy. No issues found.",
|
||||
issues: []
|
||||
},
|
||||
channelAgentReview: {
|
||||
channelTechSpecsAgentReview: {
|
||||
ragStatus: "Amber",
|
||||
feedback: "The image composition has been improved and is suitable for standard feeds. However, for optimal performance on Instagram, creating a separate vertical version for Story placements is recommended.",
|
||||
issues: ["Consider creating a separate vertical version for Story placements."]
|
||||
|
|
@ -143,8 +143,8 @@ export const initialProjectAssets: { [key: string]: any[] } = {
|
|||
leadAgentSummary: "The asset has Passed review with no issues found across all categories. It is well-designed, compliant, and ready for deployment.",
|
||||
legalAgentReview: { ragStatus: "Green", feedback: "All claims are substantiated and disclaimers are correctly placed.", issues: [] },
|
||||
brandAgentReview: { ragStatus: "Green", feedback: "The asset adheres perfectly to all brand guidelines.", issues: [] },
|
||||
toneAgentReview: { ragStatus: "Green", feedback: "The copy is clear, accurate, and professional.", issues: [] },
|
||||
channelAgentReview: { ragStatus: "Green", feedback: "The infographic format is highly suitable for the selected channel.", issues: [] },
|
||||
channelBestPracticesAgentReview: { ragStatus: "Green", feedback: "The content strategy is effective and well-optimized for engagement.", issues: [] },
|
||||
channelTechSpecsAgentReview: { ragStatus: "Green", feedback: "The infographic format is highly suitable for the selected channel.", issues: [] },
|
||||
},
|
||||
overallStatus: 'Passed',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@ import type { ReviewStatus, AgentName, AgentStatus } from '../types';
|
|||
import { AGENT_NAMES } from '../constants';
|
||||
import { LegalIcon } from './icons/LegalIcon';
|
||||
import { BrandIcon } from './icons/BrandIcon';
|
||||
import { CopyIcon } from './icons/CopyIcon';
|
||||
import { CheckCircleIcon, ExclamationTriangleIcon, InformationCircleIcon } from './icons/StatusIcons';
|
||||
import { ChannelIcon } from './icons/ChannelIcon';
|
||||
import { BestPracticeIcon } from './icons/BestPracticeIcon';
|
||||
import { SpinnerIcon } from './icons/SpinnerIcon';
|
||||
|
||||
interface StatusDashboardProps {
|
||||
|
|
@ -20,12 +18,11 @@ interface StatusInfoProps {
|
|||
}
|
||||
|
||||
// FIX: Storing components instead of instantiated elements to avoid React.cloneElement type issues.
|
||||
// Fix: Removed 'Best Practice' as it does not exist on AgentName type.
|
||||
const agentIcons: Record<AgentName, React.FC<React.SVGProps<SVGSVGElement>>> = {
|
||||
'Legal Agent': LegalIcon,
|
||||
'Brand Agent': BrandIcon,
|
||||
'Tone Agent': CopyIcon,
|
||||
'Channel Agent': ChannelIcon,
|
||||
'Channel Best Practices Agent': ChannelIcon,
|
||||
'Channel Tech Specs Agent': ChannelIcon,
|
||||
};
|
||||
|
||||
const StatusInfo: React.FC<StatusInfoProps> = ({ status, isHeroVariant = false }) => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
import type { AgentName } from './types';
|
||||
|
||||
export const AGENT_NAMES: AgentName[] = ['Legal Agent', 'Brand Agent', 'Tone Agent', 'Channel Agent'];
|
||||
export const AGENT_NAMES: AgentName[] = ['Legal Agent', 'Brand Agent', 'Channel Best Practices Agent', 'Channel Tech Specs Agent'];
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
// Fix: Broke a circular dependency by defining the AgentName type directly in this file instead of importing it.
|
||||
export type AgentName = 'Legal Agent' | 'Brand Agent' | 'Tone Agent' | 'Channel Agent';
|
||||
export type AgentName = 'Legal Agent' | 'Brand Agent' | 'Channel Best Practices Agent' | 'Channel Tech Specs Agent';
|
||||
|
||||
export type AgentStatus = 'pending' | 'in-progress' | 'complete' | 'issues-found' | 'error';
|
||||
|
||||
|
|
@ -20,8 +20,8 @@ export type OverallStatus = 'Passed' | 'Failed' | 'Analysis Error' | 'Requires M
|
|||
export interface AgentReview {
|
||||
legalAgentReview: SubReview;
|
||||
brandAgentReview: SubReview;
|
||||
toneAgentReview: SubReview;
|
||||
channelAgentReview: SubReview;
|
||||
channelBestPracticesAgentReview: SubReview;
|
||||
channelTechSpecsAgentReview: SubReview;
|
||||
leadAgentSummary: string;
|
||||
overallStatus: OverallStatus;
|
||||
financialPromotionReason?: string;
|
||||
|
|
|
|||
59
prompts/channel_best_practices.md
Normal file
59
prompts/channel_best_practices.md
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
# Channel Best Practices Specification
|
||||
|
||||
This document contains channel best practices guidelines for analyzing marketing proofs.
|
||||
|
||||
## Content Strategy Guidelines
|
||||
|
||||
### Messaging Best Practices
|
||||
- Clear and concise messaging appropriate for the target platform
|
||||
- Strong value proposition visible within first 3 seconds
|
||||
- Call-to-action should be prominent and actionable
|
||||
|
||||
### Visual Hierarchy
|
||||
- Key message should be the focal point
|
||||
- Supporting elements should guide the eye naturally
|
||||
- White space used effectively for emphasis
|
||||
|
||||
### Platform Optimization
|
||||
- Content optimized for platform-specific engagement patterns
|
||||
- Safe zones respected for interactive elements
|
||||
- Text-to-image ratios appropriate for platform algorithms
|
||||
|
||||
## Engagement Best Practices
|
||||
|
||||
### Social Media
|
||||
- Hashtag usage follows platform best practices
|
||||
- Mentions and tags used appropriately
|
||||
- Content encourages interaction and sharing
|
||||
|
||||
### Mobile-First Design
|
||||
- All content legible on mobile devices
|
||||
- Touch targets appropriately sized (minimum 44x44 pixels)
|
||||
- Thumb-zone navigation considered for interactive elements
|
||||
|
||||
### Accessibility
|
||||
- Color contrast meets WCAG AA standards
|
||||
- Alt text and descriptions available where needed
|
||||
- Content understandable without audio (for video)
|
||||
|
||||
## Platform-Specific Guidelines
|
||||
|
||||
### Instagram
|
||||
- Feed posts: Strong opening visual, clear branding
|
||||
- Stories: Vertical format optimized, CTA visible
|
||||
- Reels: First frame engaging, sound-optional viewing
|
||||
|
||||
### Facebook
|
||||
- Feed: Scroll-stopping visuals, concise copy
|
||||
- Stories: Full-screen vertical format utilized
|
||||
- Video: Captions for silent viewing
|
||||
|
||||
### LinkedIn
|
||||
- Professional tone appropriate for B2B context
|
||||
- Value-driven content for business audience
|
||||
- Long-form content where appropriate
|
||||
|
||||
### Twitter/X
|
||||
- Concise messaging within character limits
|
||||
- Strong visual to stand out in feed
|
||||
- Hashtags used strategically (1-2 max)
|
||||
97
prompts/channel_tech_specs.md
Normal file
97
prompts/channel_tech_specs.md
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
# Channel Technical Specifications
|
||||
|
||||
This document contains technical specifications for digital marketing assets.
|
||||
|
||||
## Image Specifications
|
||||
|
||||
### Social Media Dimensions
|
||||
- Instagram Feed: 1080x1080 (1:1), 1080x1350 (4:5), 1080x566 (1.91:1)
|
||||
- Instagram Stories: 1080x1920 (9:16)
|
||||
- Facebook Feed: 1200x630 (1.91:1), 1080x1080 (1:1)
|
||||
- Facebook Stories: 1080x1920 (9:16)
|
||||
- LinkedIn Feed: 1200x627 (1.91:1), 1080x1080 (1:1)
|
||||
- Twitter/X: 1200x675 (16:9), 1200x1200 (1:1)
|
||||
|
||||
### File Formats
|
||||
- Static Images: JPG, PNG
|
||||
- Animated: GIF (max 15 seconds for most platforms)
|
||||
- Maximum file size: Varies by platform (typically 4-8MB for images)
|
||||
|
||||
### Resolution Requirements
|
||||
- Minimum 72 DPI for web
|
||||
- Minimum 150 DPI for print
|
||||
- Retina displays: 2x resolution recommended
|
||||
|
||||
## Typography Specifications
|
||||
|
||||
### Minimum Font Sizes
|
||||
- Body text: 12px minimum for legibility
|
||||
- Headlines: Scale appropriately based on format
|
||||
- Mobile: Consider 14px minimum for body text
|
||||
|
||||
### Character Limits
|
||||
- Headlines: 65 characters maximum
|
||||
- Body copy: 300 characters maximum
|
||||
- Social post copy: Platform-specific limits
|
||||
|
||||
### Font Stack
|
||||
- Primary: Barclays Effra
|
||||
- Fallback: Arial, sans-serif
|
||||
- Font weights: Regular, Medium, Bold
|
||||
|
||||
## Digital Grid System
|
||||
|
||||
### Desktop (1440px+)
|
||||
- 12-column grid
|
||||
- Column width: Flexible
|
||||
- Gutter: 24px
|
||||
- Margin: 80px
|
||||
|
||||
### Tablet (768px - 1439px)
|
||||
- 12-column grid
|
||||
- Column width: Flexible
|
||||
- Gutter: 24px
|
||||
- Margin: 40px
|
||||
|
||||
### Mobile (< 768px)
|
||||
- 6-column grid
|
||||
- Column width: Flexible
|
||||
- Gutter: 16px
|
||||
- Margin: 16px
|
||||
|
||||
### Baseline Grid
|
||||
- 8px baseline grid for consistent spacing
|
||||
- All spacing should be multiples of 8px
|
||||
|
||||
## Video Specifications
|
||||
|
||||
### Format Requirements
|
||||
- Format: MP4 (H.264 codec)
|
||||
- Aspect ratios: 16:9, 1:1, 4:5, 9:16
|
||||
- Frame rate: 24-30fps
|
||||
- Maximum duration: Platform-specific
|
||||
|
||||
### Audio
|
||||
- Sample rate: 48kHz
|
||||
- Bit rate: 128kbps minimum for stereo
|
||||
|
||||
### Captions/Subtitles
|
||||
- Required for accessibility
|
||||
- Clear, legible font
|
||||
- Adequate contrast with background
|
||||
|
||||
## Accessibility Requirements
|
||||
|
||||
### Color Contrast
|
||||
- WCAG AA: 4.5:1 for normal text
|
||||
- WCAG AA: 3:1 for large text (18px+ or 14px+ bold)
|
||||
- WCAG AAA: 7:1 for enhanced contrast
|
||||
|
||||
### Touch Targets
|
||||
- Minimum size: 44x44 pixels
|
||||
- Adequate spacing between interactive elements
|
||||
|
||||
### Safe Zones
|
||||
- Account for platform UI overlays
|
||||
- Keep critical content within safe areas
|
||||
- Allow for various device notches and bezels
|
||||
99
prompts/legal.md
Normal file
99
prompts/legal.md
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
# Legal Compliance Specification
|
||||
|
||||
This document contains legal compliance guidelines for marketing proof analysis.
|
||||
|
||||
## Financial Promotion Detection
|
||||
|
||||
### Definition
|
||||
A financial promotion is any communication that:
|
||||
- Invites or induces a person to engage in investment activity
|
||||
- Relates to controlled investments or controlled activities
|
||||
- Promotes financial products or services
|
||||
|
||||
### Indicators of Financial Promotion
|
||||
- Interest rates or APR mentioned
|
||||
- Loan terms or credit offers
|
||||
- Investment products or returns
|
||||
- Savings rates or account terms
|
||||
- Credit card promotional rates
|
||||
- Mortgage rates or terms
|
||||
- Insurance product details
|
||||
- Pension or retirement products
|
||||
|
||||
### Required Actions
|
||||
If financial promotion is detected:
|
||||
- Flag for separate manual legal review
|
||||
- Set isFinancialPromotion to true
|
||||
- Provide clear reason for classification
|
||||
|
||||
## Advertising Standards
|
||||
|
||||
### CAP Code Compliance
|
||||
- All claims must be substantiated
|
||||
- Comparative advertising must be fair and verifiable
|
||||
- No misleading pricing or availability claims
|
||||
- Clear identification of marketing communications
|
||||
|
||||
### ASA Requirements
|
||||
- Truthful and accurate claims
|
||||
- No hidden or unclear terms
|
||||
- Appropriate disclaimers where required
|
||||
- No exploitation of vulnerable groups
|
||||
|
||||
## Required Disclaimers
|
||||
|
||||
### Financial Products
|
||||
- Representative APR for credit products
|
||||
- Risk warnings for investments
|
||||
- Terms and conditions reference
|
||||
- Regulatory information (FCA authorization)
|
||||
|
||||
### Disclaimer Placement
|
||||
- Clear and prominent positioning
|
||||
- Legible font size (minimum 8pt for print)
|
||||
- Adequate contrast with background
|
||||
- Not obscured by other elements
|
||||
|
||||
### Disclaimer Content
|
||||
- Complete and accurate information
|
||||
- Plain language where possible
|
||||
- All material limitations disclosed
|
||||
|
||||
## FCA Regulatory Compliance
|
||||
|
||||
### Authorization Statements
|
||||
- Correct FCA registration details
|
||||
- Proper regulatory body references
|
||||
- Accurate firm status descriptions
|
||||
|
||||
### Risk Warnings
|
||||
- Capital at risk statements
|
||||
- Past performance disclaimers
|
||||
- Investment risk warnings
|
||||
- Credit risk warnings
|
||||
|
||||
### Fair, Clear and Not Misleading
|
||||
- Information must be fair
|
||||
- Communication must be clear
|
||||
- Content must not be misleading
|
||||
- All material information included
|
||||
|
||||
## Third-Party Content
|
||||
|
||||
### Permissions
|
||||
- Proper licensing for images/content
|
||||
- Model releases where applicable
|
||||
- Music/audio rights clearance
|
||||
- Brand partnership agreements
|
||||
|
||||
### Testimonials
|
||||
- Must be genuine and verifiable
|
||||
- Material connections disclosed
|
||||
- Representative of typical experience
|
||||
- Not cherry-picked unfairly
|
||||
|
||||
### Influencer/Celebrity Content
|
||||
- Partnership clearly disclosed
|
||||
- #ad or equivalent labeling
|
||||
- ASA influencer guidelines followed
|
||||
- Material connection stated
|
||||
Loading…
Add table
Reference in a new issue