Pass proof metadata (channel, sub-channel, proof type) to AI agents during analysis
Previously, proof metadata collected during upload was only used for database persistence. Now it flows through the entire analysis pipeline so agents can tailor their feedback to the specific channel and format being reviewed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
adc7a2cc71
commit
a957cf0276
7 changed files with 93 additions and 3 deletions
|
|
@ -71,6 +71,9 @@ Your response MUST include:
|
|||
images: List[Tuple[bytes, str]],
|
||||
previous_review: Optional[PreviousReviewContext] = None,
|
||||
brand: str = "Barclaycard",
|
||||
channel: Optional[str] = None,
|
||||
sub_channel: Optional[str] = None,
|
||||
proof_type: Optional[str] = None,
|
||||
) -> SubReview:
|
||||
"""
|
||||
Analyze the proof for brand guideline adherence.
|
||||
|
|
@ -79,6 +82,9 @@ Your response MUST include:
|
|||
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')
|
||||
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 brand compliance assessment
|
||||
|
|
@ -99,6 +105,14 @@ Here is the {brand} brand specification to use for your analysis:
|
|||
{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 brand requirements for this channel and format.
|
||||
---
|
||||
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ Your response MUST include:
|
|||
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,
|
||||
) -> SubReview:
|
||||
"""
|
||||
Analyze the proof for channel best practices and content strategy.
|
||||
|
|
@ -61,6 +64,9 @@ Your response MUST include:
|
|||
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 channel best practices assessment
|
||||
|
|
@ -81,6 +87,14 @@ Here are the channel best practices guidelines to use for your analysis:
|
|||
{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 best practices for this channel and format.
|
||||
---
|
||||
|
||||
Analyze the uploaded proof for adherence to channel best practices, checking:
|
||||
|
||||
1. **Content Strategy**:
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ Your response MUST include:
|
|||
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,
|
||||
) -> SubReview:
|
||||
"""
|
||||
Analyze the proof for technical specifications compliance.
|
||||
|
|
@ -61,6 +64,9 @@ Your response MUST include:
|
|||
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
|
||||
|
|
@ -81,6 +87,14 @@ Here are the channel technical specifications to use for your analysis:
|
|||
{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**:
|
||||
|
|
|
|||
|
|
@ -76,6 +76,9 @@ In your summary:
|
|||
self,
|
||||
reviews: dict[str, SubReview],
|
||||
previous_analysis: Optional[dict] = None,
|
||||
channel: Optional[str] = None,
|
||||
sub_channel: Optional[str] = None,
|
||||
proof_type: Optional[str] = None,
|
||||
) -> tuple[OverallStatus, str, str | None]:
|
||||
"""
|
||||
Synthesize specialist reviews into final verdict and summary.
|
||||
|
|
@ -84,6 +87,9 @@ In your summary:
|
|||
reviews: Dictionary mapping agent names to their SubReview results
|
||||
previous_analysis: Optional dict containing the previous version's analysis
|
||||
results. When provided, enables revision-aware summary.
|
||||
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:
|
||||
Tuple of (overall_status, summary, financial_promotion_reason)
|
||||
|
|
@ -106,11 +112,21 @@ In your summary:
|
|||
if previous_analysis and previous_analysis.get("version"):
|
||||
revision_context = self._build_revision_context(previous_analysis, reviews)
|
||||
|
||||
# Build proof metadata context
|
||||
metadata_context = f"""
|
||||
**PROOF METADATA**
|
||||
- Channel: {channel or "Not specified"}
|
||||
- Sub-Channel: {sub_channel or "Not specified"}
|
||||
- Proof Type: {proof_type or "Not specified"}
|
||||
"""
|
||||
|
||||
# Build the prompt for Gemini to generate summary
|
||||
prompt = f"""
|
||||
You are a Lead Agent responsible for auditing a marketing proof. You have received feedback from specialist AI agents.
|
||||
Your task is to provide a final verdict and write a concise, professional summary to the user.
|
||||
|
||||
{metadata_context}
|
||||
|
||||
Here is the logic you must follow:
|
||||
1. The Legal Agent has determined if this is a financial promotion: {is_financial_promotion}.
|
||||
2. If it IS a financial promotion, the final verdict MUST be 'Requires Manual Legal Review'. Your summary should state this clearly, explain that a separate manual legal review is required, and then summarize any other issues found by the other agents.
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ Your response MUST include:
|
|||
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,
|
||||
) -> SubReview:
|
||||
"""
|
||||
Analyze the proof for legal compliance.
|
||||
|
|
@ -61,6 +64,9 @@ Your response MUST include:
|
|||
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 legal compliance assessment
|
||||
|
|
@ -81,6 +87,14 @@ Here are the legal guidelines to use for your analysis:
|
|||
{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 legal requirements for this channel and format.
|
||||
---
|
||||
|
||||
Analyze the uploaded proof for legal compliance, checking:
|
||||
|
||||
1. **Financial Promotion Detection**:
|
||||
|
|
|
|||
|
|
@ -105,6 +105,9 @@ class AnalysisService:
|
|||
brand: str,
|
||||
on_agent_update: AgentCallback | None,
|
||||
previous_review: Optional[PreviousReviewContext] = None,
|
||||
channel: Optional[str] = None,
|
||||
sub_channel: Optional[str] = None,
|
||||
proof_type: Optional[str] = None,
|
||||
) -> Tuple[str, SubReview]:
|
||||
"""Run a single agent with callback notifications."""
|
||||
agent = self.agents[agent_name]
|
||||
|
|
@ -114,9 +117,9 @@ class AnalysisService:
|
|||
await on_agent_update(agent_name, None)
|
||||
|
||||
if agent_name == "Brand Agent":
|
||||
review = await agent.analyze(images, previous_review=previous_review, brand=brand)
|
||||
review = await agent.analyze(images, previous_review=previous_review, brand=brand, channel=channel, sub_channel=sub_channel, proof_type=proof_type)
|
||||
else:
|
||||
review = await agent.analyze(images, previous_review=previous_review)
|
||||
review = await agent.analyze(images, previous_review=previous_review, channel=channel, sub_channel=sub_channel, proof_type=proof_type)
|
||||
|
||||
logger.info(f"[ANALYSIS] Agent completed: {agent_name} - ragStatus: {review.ragStatus}")
|
||||
if on_agent_update:
|
||||
|
|
@ -132,6 +135,9 @@ class AnalysisService:
|
|||
is_wip: bool = False,
|
||||
brand: str = "Barclaycard",
|
||||
previous_analysis: Optional[dict] = None,
|
||||
channel: Optional[str] = None,
|
||||
sub_channel: Optional[str] = None,
|
||||
proof_type: Optional[str] = None,
|
||||
) -> Tuple[AgentReview, Optional[List[Tuple[bytes, int, int]]]]:
|
||||
"""
|
||||
Analyze a proof using all agents in parallel.
|
||||
|
|
@ -198,6 +204,9 @@ class AnalysisService:
|
|||
brand,
|
||||
on_agent_update,
|
||||
previous_review=self._extract_previous_review_context(agent_name, previous_analysis),
|
||||
channel=channel,
|
||||
sub_channel=sub_channel,
|
||||
proof_type=proof_type,
|
||||
)
|
||||
for agent_name in self.AGENT_ORDER
|
||||
]
|
||||
|
|
@ -210,7 +219,8 @@ class AnalysisService:
|
|||
await on_agent_update("Summary", None)
|
||||
|
||||
overall_status, summary, financial_promotion_reason = await self.lead_agent.synthesize(
|
||||
reviews, previous_analysis=previous_analysis
|
||||
reviews, previous_analysis=previous_analysis,
|
||||
channel=channel, sub_channel=sub_channel, proof_type=proof_type,
|
||||
)
|
||||
logger.info(f"[ANALYSIS] Analysis complete - overallStatus: {overall_status}")
|
||||
|
||||
|
|
|
|||
|
|
@ -127,6 +127,11 @@ async def handle_analyze_message(
|
|||
logger.warning(f"[WEBSOCKET] Failed to fetch previous analysis: {str(e)}")
|
||||
# Continue without previous analysis - still run the current analysis
|
||||
|
||||
# Extract proof metadata for agent context
|
||||
channel = data.get("channel")
|
||||
sub_channel = data.get("sub_channel")
|
||||
proof_type = data.get("proof_type")
|
||||
|
||||
# Run the analysis
|
||||
logger.info("[WEBSOCKET] Starting analysis...")
|
||||
result, pdf_pages = await analysis_service.analyze_proof(
|
||||
|
|
@ -136,6 +141,9 @@ async def handle_analyze_message(
|
|||
is_wip=is_wip,
|
||||
brand=brand,
|
||||
previous_analysis=previous_analysis,
|
||||
channel=channel,
|
||||
sub_channel=sub_channel,
|
||||
proof_type=proof_type,
|
||||
)
|
||||
|
||||
# Build the result dict
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue