Initial Daily Campaign Agent release

This commit is contained in:
joliehill294-hue
2026-09-16 21:00:13 +08:00
commit 14fc94b3f0
86 changed files with 10766 additions and 0 deletions
@@ -0,0 +1,12 @@
日期,平台 Campaign Name,平台 Ad Group Name,平台 Ad Name,消耗,归因安装量,D1 留存人数
2026-08-19,Campaign Demo,Group One,Creative Alpha,30,10,1
2026-08-20,Campaign Demo,Group One,Creative Alpha,32,10,1
2026-08-21,Campaign Demo,Group One,Creative Alpha,34,10,2
2026-08-22,Campaign Demo,Group One,Creative Alpha,36,10,1
2026-08-23,Campaign Demo,Group One,Creative Alpha,38,10,1
2026-08-24,Campaign Demo,Group One,Creative Alpha,40,10,2
2026-08-25,Campaign Demo,Group One,Creative Alpha,42,10,0
2026-08-22,Campaign Demo,Group Two,Creative Beta,15,3,0
2026-08-23,Campaign Demo,Group Two,Creative Beta,20,4,0
2026-08-24,Campaign Demo,Group Two,Creative Beta,25,5,1
2026-08-25,Campaign Demo,Group Two,Creative Beta,30,6,0
1 日期 平台 Campaign Name 平台 Ad Group Name 平台 Ad Name 消耗 归因安装量 D1 留存人数
2 2026-08-19 Campaign Demo Group One Creative Alpha 30 10 1
3 2026-08-20 Campaign Demo Group One Creative Alpha 32 10 1
4 2026-08-21 Campaign Demo Group One Creative Alpha 34 10 2
5 2026-08-22 Campaign Demo Group One Creative Alpha 36 10 1
6 2026-08-23 Campaign Demo Group One Creative Alpha 38 10 1
7 2026-08-24 Campaign Demo Group One Creative Alpha 40 10 2
8 2026-08-25 Campaign Demo Group One Creative Alpha 42 10 0
9 2026-08-22 Campaign Demo Group Two Creative Beta 15 3 0
10 2026-08-23 Campaign Demo Group Two Creative Beta 20 4 0
11 2026-08-24 Campaign Demo Group Two Creative Beta 25 5 1
12 2026-08-25 Campaign Demo Group Two Creative Beta 30 6 0
@@ -0,0 +1,49 @@
import json
import subprocess
import sys
import tempfile
import unittest
import zipfile
from pathlib import Path
from xml.etree import ElementTree as ET
ROOT = Path(__file__).resolve().parents[1]
class ScriptTests(unittest.TestCase):
def test_csv_analysis_separates_maturity_dates(self):
with tempfile.TemporaryDirectory() as tmp:
output = Path(tmp) / "analysis.json"
subprocess.run([
sys.executable, str(ROOT / "scripts/analyze_report.py"),
str(ROOT / "tests/fixtures/sample-report.csv"),
"--analysis-date", "2026-08-25", "--retention-lag-days", "1",
"--output", str(output),
], check=True, capture_output=True, text=True)
data = json.loads(output.read_text(encoding="utf-8"))
self.assertEqual(data["dates"]["analysis_date"], "2026-08-25")
self.assertEqual(data["dates"]["retention_mature_date"], "2026-08-24")
self.assertEqual(len(data["ads"]), 2)
self.assertNotIn("tier", data["ads"][0])
self.assertAlmostEqual(data["portfolio"]["analysis_day"]["spend"], 72)
def test_docx_contract_and_forbidden_headings(self):
with tempfile.TemporaryDirectory() as tmp:
output = Path(tmp) / "brief.docx"
subprocess.run([
sys.executable, str(ROOT / "scripts/build_brief.py"),
str(ROOT / "examples/brief.example.json"), "--output", str(output),
], check=True, capture_output=True, text=True)
self.assertTrue(zipfile.is_zipfile(output))
with zipfile.ZipFile(output) as archive:
root = ET.fromstring(archive.read("word/document.xml"))
text = "".join(root.itertext())
for heading in ("1. 是否达标", "2. 问题分析", "3. 建议动作", "4. 近7天表现好的 Ads"):
self.assertIn(heading, text)
for forbidden in ("核心判断", "规则一", "规则二", "Campaign层级", "层级判断"):
self.assertNotIn(forbidden, text)
self.assertIn("决定", text)
if __name__ == "__main__":
unittest.main()