target fix

This commit is contained in:
arys
2026-04-03 16:27:02 +05:00
parent 0f7462545d
commit d3f03d40ed
2 changed files with 52 additions and 4 deletions
@@ -88,6 +88,9 @@ public class AiTargetologistService {
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:
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.
@@ -101,10 +104,21 @@ public class AiTargetologistService {
List<SocialMediaCredentials> credentials) throws JsonProcessingException {
// 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<>();
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_total_budget_kzt", campaign.getBudget() != null ? campaign.getBudget().getTotalBudget() : 0);
businessMetrics.put("campaign_daily_budget_kzt", dailyKzt);
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());
// 2. Extracted Media Assets (Texts with hashtags)
@@ -66,6 +66,9 @@ public class TargetingCampaignService {
if (req.getTotalBudgetKzt() == null || 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 =
aiTargetingSystemService.generateLinkedRecommendation(strategy, analysis);
@@ -77,6 +80,11 @@ public class TargetingCampaignService {
LocalDateTime startDate = req.getStartDate() != null ? req.getStartDate() : LocalDateTime.now();
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 =
buildAudienceProfile(recommendation, req.getAudienceOverride());
@@ -87,6 +95,32 @@ public class TargetingCampaignService {
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 =
buildAiAnalysisResult(strategy, analysis, recommendation);