target fix
This commit is contained in:
@@ -85,9 +85,12 @@ public class AiTargetologistService {
|
|||||||
return """
|
return """
|
||||||
SYSTEM ROLE & ARCHITECTURE MANDATE
|
SYSTEM ROLE & ARCHITECTURE MANDATE
|
||||||
You are "Antigravity", an enterprise-grade AI Targeting Orchestrator and Media Buying Architect. Your sole function is to process sanitized marketing strategies and ready-made media assets, compiling them into a highly structured, production-ready payload for Ads Platform APIs (Meta Graph API, Google Ads API, TikTok Marketing API).
|
You are "Antigravity", an enterprise-grade AI Targeting Orchestrator and Media Buying Architect. Your sole function is to process sanitized marketing strategies and ready-made media assets, compiling them into a highly structured, production-ready payload for Ads Platform APIs (Meta Graph API, Google Ads API, TikTok Marketing API).
|
||||||
|
|
||||||
You DO NOT generate basic raw creatives from scratch if ready-made texts exist. You DO NOT alter the core strategy. You map inputs to rigid targeting parameters, establish A/B testing matrices, calculate budget pacing, and define algorithmic optimization rules.
|
You DO NOT generate basic raw creatives from scratch if ready-made texts exist. You DO NOT alter the core strategy. You map inputs to rigid targeting parameters, establish A/B testing matrices, calculate budget pacing, and define algorithmic optimization rules.
|
||||||
|
|
||||||
|
CRITICAL BUDGET RULE:
|
||||||
|
The input context contains "campaign_daily_budget_usd_approx" and "campaign_total_budget_usd_approx". You MUST use EXACTLY these values for all budget fields in the output JSON (daily_budget_usd, campaign_daily_budget_usd). Distribute total budget proportionally across adsets but NEVER exceed the total. Do NOT invent or inflate budget numbers.
|
||||||
|
|
||||||
OUTPUT CONTRACT:
|
OUTPUT CONTRACT:
|
||||||
Your output must be EXCLUSIVELY a valid JSON object. DO NOT wrap it in markdown block quotes. DO NOT include any natural language explanation, introductory text, or concluding remarks. Just raw valid JSON.
|
Your output must be EXCLUSIVELY a valid JSON object. DO NOT wrap it in markdown block quotes. DO NOT include any natural language explanation, introductory text, or concluding remarks. Just raw valid JSON.
|
||||||
The JSON keys must be strictly snake_case conforming to the supplied schema structure.
|
The JSON keys must be strictly snake_case conforming to the supplied schema structure.
|
||||||
@@ -101,10 +104,21 @@ public class AiTargetologistService {
|
|||||||
List<SocialMediaCredentials> credentials) throws JsonProcessingException {
|
List<SocialMediaCredentials> credentials) throws JsonProcessingException {
|
||||||
|
|
||||||
// 1. Business Metrics Context
|
// 1. Business Metrics Context
|
||||||
|
double totalKzt = campaign.getBudget() != null && campaign.getBudget().getTotalBudget() != null
|
||||||
|
? campaign.getBudget().getTotalBudget() : 0.0;
|
||||||
|
double dailyKzt = campaign.getBudget() != null && campaign.getBudget().getDailyBudget() != null
|
||||||
|
? campaign.getBudget().getDailyBudget() : (totalKzt / 30.0);
|
||||||
|
// KZT to USD approximate rate for AI context (1 USD ~ 470 KZT)
|
||||||
|
double totalUsd = Math.round(totalKzt / 470.0 * 100.0) / 100.0;
|
||||||
|
double dailyUsd = Math.round(dailyKzt / 470.0 * 100.0) / 100.0;
|
||||||
|
|
||||||
Map<String, Object> businessMetrics = new HashMap<>();
|
Map<String, Object> businessMetrics = new HashMap<>();
|
||||||
businessMetrics.put("target_objective", campaign.getObjective() != null ? campaign.getObjective().name() : "TRAFFIC");
|
businessMetrics.put("target_objective", campaign.getObjective() != null ? campaign.getObjective().name() : "TRAFFIC");
|
||||||
businessMetrics.put("campaign_daily_budget_kzt", campaign.getBudget() != null ? campaign.getBudget().getDailyBudget() : 0);
|
businessMetrics.put("campaign_daily_budget_kzt", dailyKzt);
|
||||||
businessMetrics.put("campaign_total_budget_kzt", campaign.getBudget() != null ? campaign.getBudget().getTotalBudget() : 0);
|
businessMetrics.put("campaign_total_budget_kzt", totalKzt);
|
||||||
|
businessMetrics.put("campaign_daily_budget_usd_approx", dailyUsd);
|
||||||
|
businessMetrics.put("campaign_total_budget_usd_approx", totalUsd);
|
||||||
|
businessMetrics.put("budget_currency_note", "IMPORTANT: All budget fields in output JSON (daily_budget_usd, campaign_daily_budget_usd) MUST use the USD amounts provided above. Do NOT invent new budget amounts.");
|
||||||
businessMetrics.put("target_platforms", campaign.getPlatforms());
|
businessMetrics.put("target_platforms", campaign.getPlatforms());
|
||||||
|
|
||||||
// 2. Extracted Media Assets (Texts with hashtags)
|
// 2. Extracted Media Assets (Texts with hashtags)
|
||||||
|
|||||||
@@ -66,6 +66,9 @@ public class TargetingCampaignService {
|
|||||||
if (req.getTotalBudgetKzt() == null || req.getTotalBudgetKzt() <= 0) {
|
if (req.getTotalBudgetKzt() == null || req.getTotalBudgetKzt() <= 0) {
|
||||||
throw new ValidationException("totalBudgetKzt", req.getTotalBudgetKzt(), "Бюджет должен быть больше 0");
|
throw new ValidationException("totalBudgetKzt", req.getTotalBudgetKzt(), "Бюджет должен быть больше 0");
|
||||||
}
|
}
|
||||||
|
if (req.getTotalBudgetKzt() > 500_000_000) {
|
||||||
|
throw new ValidationException("totalBudgetKzt", req.getTotalBudgetKzt(), "Бюджет не может превышать 500,000,000 KZT");
|
||||||
|
}
|
||||||
|
|
||||||
TargetingRecommendationDto recommendation =
|
TargetingRecommendationDto recommendation =
|
||||||
aiTargetingSystemService.generateLinkedRecommendation(strategy, analysis);
|
aiTargetingSystemService.generateLinkedRecommendation(strategy, analysis);
|
||||||
@@ -77,6 +80,11 @@ public class TargetingCampaignService {
|
|||||||
LocalDateTime startDate = req.getStartDate() != null ? req.getStartDate() : LocalDateTime.now();
|
LocalDateTime startDate = req.getStartDate() != null ? req.getStartDate() : LocalDateTime.now();
|
||||||
LocalDateTime endDate = req.getEndDate() != null ? req.getEndDate() : startDate.plusDays(durationDays);
|
LocalDateTime endDate = req.getEndDate() != null ? req.getEndDate() : startDate.plusDays(durationDays);
|
||||||
|
|
||||||
|
// Если дневной бюджет не передан — вычисляем автоматически
|
||||||
|
if (req.getDailyBudgetKzt() == null || req.getDailyBudgetKzt() <= 0) {
|
||||||
|
req.setDailyBudgetKzt(Math.round(req.getTotalBudgetKzt() / durationDays * 100.0) / 100.0);
|
||||||
|
}
|
||||||
|
|
||||||
TargetingAudienceProfile audienceProfile =
|
TargetingAudienceProfile audienceProfile =
|
||||||
buildAudienceProfile(recommendation, req.getAudienceOverride());
|
buildAudienceProfile(recommendation, req.getAudienceOverride());
|
||||||
|
|
||||||
@@ -87,6 +95,32 @@ public class TargetingCampaignService {
|
|||||||
audienceProfile.setEstimatedReachMax(RangeParser.extractMax(reach));
|
audienceProfile.setEstimatedReachMax(RangeParser.extractMax(reach));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Перезаписываем бюджетные поля AI-рекомендации реальными значениями пользователя,
|
||||||
|
// чтобы AI не показывал фантастические миллиарды
|
||||||
|
if (recommendation != null) {
|
||||||
|
kz.konturai.parser.dto.targeting.TargetingBudgetDto realBudget =
|
||||||
|
kz.konturai.parser.dto.targeting.TargetingBudgetDto.builder()
|
||||||
|
.dailyBudget(String.format("%.0f KZT", req.getDailyBudgetKzt()))
|
||||||
|
.monthlyBudget(String.format("%.0f KZT", req.getTotalBudgetKzt()))
|
||||||
|
.bidStrategy(recommendation.getBudgetRecommendation() != null
|
||||||
|
? recommendation.getBudgetRecommendation().getBidStrategy()
|
||||||
|
: "LOWEST_COST_WITHOUT_CAP")
|
||||||
|
.rationale(recommendation.getBudgetRecommendation() != null
|
||||||
|
? recommendation.getBudgetRecommendation().getRationale()
|
||||||
|
: null)
|
||||||
|
.estimatedCpc(recommendation.getBudgetRecommendation() != null
|
||||||
|
? recommendation.getBudgetRecommendation().getEstimatedCpc()
|
||||||
|
: null)
|
||||||
|
.estimatedCpl(recommendation.getBudgetRecommendation() != null
|
||||||
|
? recommendation.getBudgetRecommendation().getEstimatedCpl()
|
||||||
|
: null)
|
||||||
|
.estimatedDailyReach(recommendation.getBudgetRecommendation() != null
|
||||||
|
? recommendation.getBudgetRecommendation().getEstimatedDailyReach()
|
||||||
|
: null)
|
||||||
|
.build();
|
||||||
|
recommendation.setBudgetRecommendation(realBudget);
|
||||||
|
}
|
||||||
|
|
||||||
TargetingAIAnalysisResult aiAnalysisResult =
|
TargetingAIAnalysisResult aiAnalysisResult =
|
||||||
buildAiAnalysisResult(strategy, analysis, recommendation);
|
buildAiAnalysisResult(strategy, analysis, recommendation);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user