siluzan-tso-cli 1.1.49-beta.2 → 1.1.49-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.js +40 -20
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/analytics/account-analytics.md +2 -2
- package/dist/skill/references/report-templates/bing-period-report.md +9 -9
- package/dist/skill/report-templates/bing-period-report.html +10 -2
- package/dist/skill/report-templates/bing-period-report.md +9 -9
- package/dist/skill/scripts/install.ps1 +1 -1
- package/dist/skill/scripts/install.sh +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
|
|
|
51
51
|
siluzan-tso init --force # 强制覆盖已存在文件
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
> **注意**:当前为测试版(1.1.49-beta.
|
|
54
|
+
> **注意**:当前为测试版(1.1.49-beta.3),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
55
55
|
|
|
56
56
|
| 助手 | 建议 `--ai` |
|
|
57
57
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -136024,6 +136024,7 @@ var BING_SECTIONS = [
|
|
|
136024
136024
|
}
|
|
136025
136025
|
];
|
|
136026
136026
|
var BING_SECTION_NAMES = BING_SECTIONS.map((s) => s.name);
|
|
136027
|
+
var BING_DEFAULT_SECTION_NAMES = BING_SECTION_NAMES.filter((name2) => name2 !== "audience-merged");
|
|
136027
136028
|
var BING_SECTION_ALIASES = {
|
|
136028
136029
|
devices: "device",
|
|
136029
136030
|
geo: "geographic",
|
|
@@ -136031,6 +136032,19 @@ var BING_SECTION_ALIASES = {
|
|
|
136031
136032
|
};
|
|
136032
136033
|
|
|
136033
136034
|
// src/commands/bing-analysis/resolve-sections.ts
|
|
136035
|
+
var AUDIENCE_SPLIT_NAMES = [
|
|
136036
|
+
"age-audience",
|
|
136037
|
+
"gender-audience"
|
|
136038
|
+
];
|
|
136039
|
+
function dropMergedWhenSplitPresent(defs) {
|
|
136040
|
+
const names = new Set(defs.map((d) => d.name));
|
|
136041
|
+
const hasSplit = AUDIENCE_SPLIT_NAMES.some((n) => names.has(n));
|
|
136042
|
+
if (!hasSplit || !names.has("audience-merged")) return defs;
|
|
136043
|
+
console.error(
|
|
136044
|
+
"\u5DF2\u8DF3\u8FC7 audience-merged\uFF08\u4E0E age-audience/gender-audience \u5E76\u884C\u4F1A\u89E6\u53D1 Bing SDK \u53D7\u4F17 csv \u6587\u4EF6\u9501\uFF09\u3002"
|
|
136045
|
+
);
|
|
136046
|
+
return defs.filter((d) => d.name !== "audience-merged");
|
|
136047
|
+
}
|
|
136034
136048
|
function normalizeSectionToken2(raw) {
|
|
136035
136049
|
const t = raw.trim();
|
|
136036
136050
|
if (!t) return null;
|
|
@@ -136056,8 +136070,9 @@ function resolveSectionList3(sections, exclude) {
|
|
|
136056
136070
|
}
|
|
136057
136071
|
const includeCanonical = new Set(include.map((n) => normalizeSectionToken2(n)).filter(Boolean));
|
|
136058
136072
|
const dropCanonical = new Set(dropRaw.map((n) => normalizeSectionToken2(n)).filter(Boolean));
|
|
136059
|
-
const
|
|
136060
|
-
|
|
136073
|
+
const defaultSet = new Set(BING_DEFAULT_SECTION_NAMES);
|
|
136074
|
+
const base = include.length > 0 ? BING_SECTIONS.filter((s) => includeCanonical.has(s.name)) : BING_SECTIONS.filter((s) => defaultSet.has(s.name));
|
|
136075
|
+
return dropMergedWhenSplitPresent(base.filter((s) => !dropCanonical.has(s.name)));
|
|
136061
136076
|
}
|
|
136062
136077
|
|
|
136063
136078
|
// src/commands/bing-analysis/fetch.ts
|
|
@@ -136333,10 +136348,8 @@ async function fetchBingAudienceMergedPayload(config, id, startDate, endDate, ve
|
|
|
136333
136348
|
const params = new URLSearchParams({ startDate, endDate });
|
|
136334
136349
|
const ageUrl = reportingUrl(config, id, "AgeAudienceData", params.toString());
|
|
136335
136350
|
const genderUrl = reportingUrl(config, id, "GenderAudienceData", params.toString());
|
|
136336
|
-
const
|
|
136337
|
-
|
|
136338
|
-
fetchBingJson(config, genderUrl, verbose)
|
|
136339
|
-
]);
|
|
136351
|
+
const ageData = await fetchBingJson(config, ageUrl, verbose);
|
|
136352
|
+
const genderData = await fetchBingJson(config, genderUrl, verbose);
|
|
136340
136353
|
return normalizeBingSectionPayload(
|
|
136341
136354
|
{
|
|
136342
136355
|
mergedParts: ["AgeAudienceData", "GenderAudienceData"],
|
|
@@ -136916,22 +136929,29 @@ function mapGeographicRows(payload) {
|
|
|
136916
136929
|
(r) => pickMetrics(r, ["countryOrRegion", "countryCriteriaId", "regionName", "cityName"])
|
|
136917
136930
|
);
|
|
136918
136931
|
}
|
|
136919
|
-
function
|
|
136932
|
+
function mapAudienceLabelRows(payload, labelKey) {
|
|
136920
136933
|
const obj = asRecord23(payload);
|
|
136921
|
-
|
|
136922
|
-
const ageAudience = asRecord23(data?.ageAudience);
|
|
136923
|
-
const genderAudience = asRecord23(data?.genderAudience);
|
|
136924
|
-
const audienceAge = asRows2(ageAudience?.audience).map((r) => {
|
|
136925
|
-
const m = pickMetrics(r, ["audience", "bidModifier"]);
|
|
136926
|
-
m.ageRange = r.audience;
|
|
136927
|
-
return m;
|
|
136928
|
-
});
|
|
136929
|
-
const audienceGender = asRows2(genderAudience?.audience).map((r) => {
|
|
136934
|
+
return asRows2(obj?.audience).map((r) => {
|
|
136930
136935
|
const m = pickMetrics(r, ["audience", "bidModifier"]);
|
|
136931
|
-
m
|
|
136936
|
+
m[labelKey] = r.audience;
|
|
136932
136937
|
return m;
|
|
136933
136938
|
});
|
|
136934
|
-
|
|
136939
|
+
}
|
|
136940
|
+
function mapAudienceFromMerged(payload) {
|
|
136941
|
+
const data = asRecord23(asRecord23(payload)?.data);
|
|
136942
|
+
return {
|
|
136943
|
+
audienceAge: mapAudienceLabelRows(data?.ageAudience, "ageRange"),
|
|
136944
|
+
audienceGender: mapAudienceLabelRows(data?.genderAudience, "gender")
|
|
136945
|
+
};
|
|
136946
|
+
}
|
|
136947
|
+
function resolveAudienceTables(sectionMap) {
|
|
136948
|
+
const fromMerged = mapAudienceFromMerged(sectionMap.get("audience-merged"));
|
|
136949
|
+
const fromAge = mapAudienceLabelRows(sectionMap.get("age-audience"), "ageRange");
|
|
136950
|
+
const fromGender = mapAudienceLabelRows(sectionMap.get("gender-audience"), "gender");
|
|
136951
|
+
return {
|
|
136952
|
+
audienceAge: fromMerged.audienceAge.length > 0 ? fromMerged.audienceAge : fromAge,
|
|
136953
|
+
audienceGender: fromMerged.audienceGender.length > 0 ? fromMerged.audienceGender : fromGender
|
|
136954
|
+
};
|
|
136935
136955
|
}
|
|
136936
136956
|
function mapCampaignRows2(payload) {
|
|
136937
136957
|
return asRows2(payload).map((r) => ({
|
|
@@ -137082,7 +137102,7 @@ async function mergeBingAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
137082
137102
|
const rows = mapGeographicRows(sectionMap.get("geographic"));
|
|
137083
137103
|
if (rows.length > 0) tables.geographic = rows;
|
|
137084
137104
|
}
|
|
137085
|
-
const audienceMapped =
|
|
137105
|
+
const audienceMapped = resolveAudienceTables(sectionMap);
|
|
137086
137106
|
if (audienceMapped.audienceAge.length > 0) tables.audienceAge = audienceMapped.audienceAge;
|
|
137087
137107
|
if (audienceMapped.audienceGender.length > 0) {
|
|
137088
137108
|
tables.audienceGender = audienceMapped.audienceGender;
|
|
@@ -137340,7 +137360,7 @@ function registerBatchCommand2(sectionHelp, aliasHelp) {
|
|
|
137340
137360
|
"\u5F00\u59CB\u65E5\u671F YYYY-MM-DD\uFF08\u4E0E --end \u540C\u4F20\u6216\u540C\u7701\u7565\uFF1B\u53EF\u542B\u6628\u5929/\u4ECA\u5929\uFF0C\u6570\u636E\u53EF\u80FD\u4E0D\u5B8C\u6574\uFF1B\u7701\u7565=\u622A\u81F3\u6628\u5929\u8FD1 7 \u5929\uFF09"
|
|
137341
137361
|
).option("--end <date>", "\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option(
|
|
137342
137362
|
"--sections <list>",
|
|
137343
|
-
`\u4EC5\u6267\u884C\u6307\u5B9A\u7EF4\u5EA6\uFF08\u9017\u53F7\u5206\u9694\uFF09\uFF0C\u5982 overview,campaigns,keywords\uFF1B\u7701\u7565=\
|
|
137363
|
+
`\u4EC5\u6267\u884C\u6307\u5B9A\u7EF4\u5EA6\uFF08\u9017\u53F7\u5206\u9694\uFF09\uFF0C\u5982 overview,campaigns,keywords\uFF1B\u7701\u7565=\u9ED8\u8BA4 10 \u4E2A\uFF08\u4E0D\u542B audience-merged\uFF0C\u907F\u514D\u4E0E\u5E74\u9F84/\u6027\u522B\u7EF4\u62A2 Bing SDK \u53D7\u4F17 csv\uFF09\u3002\u53EF\u9009\uFF1A${sectionHelp}\uFF1B\u522B\u540D\uFF1A${aliasHelp}`
|
|
137344
137364
|
).option("--exclude <list>", "\u6392\u9664\u6307\u5B9A\u7EF4\u5EA6\uFF08\u9017\u53F7\u5206\u9694\uFF09\uFF0C\u4E0E --sections \u53EF\u53E0\u52A0").option(
|
|
137345
137365
|
"--limit <n>",
|
|
137346
137366
|
"\u4EC5 keywords / search-terms\uFF1A\u6761\u6570\u4E0A\u9650\uFF08\u9ED8\u8BA4 100\uFF0C\u4E0E\u524D\u7AEF KeywordReport/SearchQueryReport \u4E00\u81F4\uFF09",
|
package/dist/skill/_meta.json
CHANGED
|
@@ -368,7 +368,7 @@ siluzan-tso tiktok-analysis official-report -a <mediaCustomerId> --json-out ./sn
|
|
|
368
368
|
|
|
369
369
|
| 选项 | 说明 |
|
|
370
370
|
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
371
|
-
| `--sections` / `--exclude` |
|
|
371
|
+
| `--sections` / `--exclude` | 可选 11 个:`overview` `device` `geographic` `age-audience` `gender-audience` `audience-merged` `campaigns` `ad-groups` `ads` `keywords` `search-terms`;**默认 10 个**(不含 `audience-merged`,勿与年龄/性别维同时拉);**别名**:`devices`→`device`,`geo`→`geographic`,`search-queries`→`search-terms` |
|
|
372
372
|
| `--limit` | 仅 `keywords` / `search-terms`:条数上限,默认 100 |
|
|
373
373
|
| `--start` / `--end` | 同传或同省略;可含昨天/今天(可能不完整);省略=截至昨天的近 7 天 |
|
|
374
374
|
| `--concurrency` | 默认 5,上限 16 |
|
|
@@ -376,7 +376,7 @@ siluzan-tso tiktok-analysis official-report -a <mediaCustomerId> --json-out ./sn
|
|
|
376
376
|
```bash
|
|
377
377
|
mkdir -p ./snap-bing
|
|
378
378
|
|
|
379
|
-
#
|
|
379
|
+
# 默认 10 维(含年龄/性别受众,不含 audience-merged)
|
|
380
380
|
siluzan-tso bing-analysis -a <mediaCustomerId> --json-out ./snap-bing
|
|
381
381
|
|
|
382
382
|
# 仅拉总览 + 关键词(limit 50)
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
| `overview` | 对象:`currentPeriod` / `previousPeriod` / `balance` / `averageDailyCost` … | → `meta` + `kpis`(环比、余额、日均) |
|
|
14
14
|
| `device` | `{ devices: Row[] }` | → `tables.devices[]` |
|
|
15
15
|
| `geographic` | `{ countries: Row[] }` | → `tables.geographic[]` |
|
|
16
|
-
| `audience
|
|
16
|
+
| `age-audience` / `gender-audience`(默认)或 `audience-merged` | 拆分维 `{ audience: [] }`;merged `{ data: { ageAudience, genderAudience } }` | → `tables.audienceAge[]` / `audienceGender[]`(merged 空则回退拆分维) |
|
|
17
17
|
| `campaigns` | **根节点数组** | → `tables.campaigns[]`;**本期 KPI 优先由此累加** |
|
|
18
18
|
| `ad-groups` | **根节点数组** | → `tables.adGroups[]`(含 `qualityScore`) |
|
|
19
19
|
| `ads` | **根节点数组** | → `tables.ads[]` |
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
|
|
29
29
|
| 步骤 | 执行者 | 动作 |
|
|
30
30
|
| ---------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
31
|
-
| **1. 拉数** | Agent 调 CLI | `bing-analysis -a <id> --start <s> --end <e> --json-out ./snap-bing
|
|
31
|
+
| **1. 拉数** | Agent 调 CLI | `bing-analysis -a <id> --start <s> --end <e> --json-out ./snap-bing`(见下方「日期规则」,默认 10 维含年龄/性别、不含 `audience-merged`) |
|
|
32
32
|
| **2. 分析** | Agent | 用 **node/python 脚本**读落盘 JSON(勿用 Read 打开业务 `*.json`),把网关原始字段映射为下方 `tables.*` 契约,完成聚合与洞察 |
|
|
33
33
|
| **3. 写 JSON** | Agent | 撰写 `bing-period-report.json`:仅 `meta.accountId` + `narrative`(9 个分析小节)为必填;`kpis`/`tables` 可省略由 `--snapshot-dir` 自动合并 |
|
|
34
34
|
| **4. 渲染 HTML** | CLI | `bing-analysis render` — **校验 narrative 9 个分析小节必含字段**,缺项报错不生成 HTML;**禁止** Agent 手写/拼接 HTML |
|
|
@@ -55,7 +55,7 @@ siluzan-tso bing-analysis render \
|
|
|
55
55
|
- `audienceGender[]`:`{gender, spend, impressions, clicks, ctr, averageCpc, conversions}`
|
|
56
56
|
- `campaigns[]`:`{campaignName, campaignStatus, campaignStatusDisplay, spend, impressions, clicks, ctr, conversions, costPerConversion}`
|
|
57
57
|
- `adGroups[]`:`{adGroupName, campaignName, qualityScore, spend, clicks, ctr, conversions, costPerConversion}`
|
|
58
|
-
- `ads[]`:`{adTitle, adGroupName, adType, spend, clicks, ctr, conversions}`
|
|
58
|
+
- `ads[]`:`{adTitle, adGroupName, adType, spend, clicks, ctr, conversions}`(RSA 常 `adTitle=""`,HTML 整列为空则不渲染该列并在表上方提醒)
|
|
59
59
|
- `keywords[]`:`{keyword, matchType, qualityScore, spend, ctr, averageCpc, conversions, costPerConversion}`
|
|
60
60
|
- `searchTerms[]`:`{searchQuery, keyword, deliveredMatchType, spend, ctr, conversions, costPerConversion}`
|
|
61
61
|
- `narrative`(**Agent 必填,唯一由 Agent 撰写的叙事内容**):
|
|
@@ -107,13 +107,13 @@ mkdir -p ./snap-bing
|
|
|
107
107
|
|
|
108
108
|
siluzan-tso list-accounts -m BingV2 -k <mediaCustomerId> --json-out ./snap-bing
|
|
109
109
|
|
|
110
|
-
#
|
|
110
|
+
# 一次批跑默认 10 维(含 age-audience / gender-audience,不含 audience-merged)
|
|
111
111
|
siluzan-tso bing-analysis -a <mediaCustomerId> --start <S> --end <E> --json-out ./snap-bing
|
|
112
112
|
siluzan-tso balance -m BingV2 --accounts <mediaCustomerId> --json-out ./snap-bing
|
|
113
113
|
|
|
114
|
-
# 或仅拉本次报告所需维度(--sections
|
|
114
|
+
# 或仅拉本次报告所需维度(--sections 逗号分隔;不要同时写拆分维和 audience-merged)
|
|
115
115
|
siluzan-tso bing-analysis -a <mediaCustomerId> --start <S> --end <E> \
|
|
116
|
-
--sections overview,campaigns,device,geographic,audience-
|
|
116
|
+
--sections overview,campaigns,device,geographic,age-audience,gender-audience,ad-groups,ads,keywords,search-terms \
|
|
117
117
|
--limit 100 --json-out ./snap-bing
|
|
118
118
|
```
|
|
119
119
|
|
|
@@ -206,9 +206,9 @@ Bing 网关常不返回 `averageDailyCost`、`activeDays`(或为 0)。CLI
|
|
|
206
206
|
|
|
207
207
|
## 4. 受众
|
|
208
208
|
|
|
209
|
-
- **CLI
|
|
209
|
+
- **CLI**:默认已含 `--sections age-audience,gender-audience`。不要与 `audience-merged` 同时拉(Bing SDK 会抢同一份受众 csv,merged 常 400)。`render --snapshot-dir` 优先 merged,空则回退拆分维。
|
|
210
210
|
|
|
211
|
-
**数据呈现**:年龄段、性别的展示、点击、消耗、CTR、CPC
|
|
211
|
+
**数据呈现**:年龄段、性别的展示、点击、消耗、CTR、CPC。拆分维读 `age-audience-*.json` / `gender-audience-*.json` 的 `audience[]`(标签字段 `audience`)。写入 JSON `tables.audienceAge[]`(`ageRange`)/ `tables.audienceGender[]`(`gender`)。
|
|
212
212
|
|
|
213
213
|
**分析(必写)** → 写入 `narrative.sections.audience.{analysis,suggestions}`:
|
|
214
214
|
|
|
@@ -225,7 +225,7 @@ Bing 网关常不返回 `averageDailyCost`、`activeDays`(或为 0)。CLI
|
|
|
225
225
|
| 广告组 | `bing-analysis --sections ad-groups` | `ad-groups-*.json` |
|
|
226
226
|
| 广告 | `bing-analysis --sections ads` | `ads-*.json` |
|
|
227
227
|
|
|
228
|
-
**数据呈现**:各表按消耗降序;系列含 `campaignStatus`;广告组可含质量分相关字段(以 outline 为准)。写入 JSON `tables.campaigns[]` / `tables.adGroups[]` / `tables.ads[]`。
|
|
228
|
+
**数据呈现**:各表按消耗降序;系列含 `campaignStatus`;广告组可含质量分相关字段(以 outline 为准)。写入 JSON `tables.campaigns[]` / `tables.adGroups[]` / `tables.ads[]`。RSA 的 `adTitle` 常为空串,HTML 不展示空标题列。
|
|
229
229
|
|
|
230
230
|
**分析(必写,三个子块各写一段,不可合并为一句带过)**:
|
|
231
231
|
|
|
@@ -472,6 +472,9 @@
|
|
|
472
472
|
color: var(--muted);
|
|
473
473
|
flex: none;
|
|
474
474
|
}
|
|
475
|
+
.empty-note + .table-wrap {
|
|
476
|
+
margin-top: 10px;
|
|
477
|
+
}
|
|
475
478
|
|
|
476
479
|
@keyframes fadeInUp {
|
|
477
480
|
from {
|
|
@@ -1022,10 +1025,14 @@
|
|
|
1022
1025
|
const currency = currencyOf(data);
|
|
1023
1026
|
const section = data.narrative?.sections?.ads;
|
|
1024
1027
|
const sorted = topBySpend(rows, 10);
|
|
1028
|
+
const showTitle = sorted.some((r) => String(r.adTitle || "").trim() !== "");
|
|
1029
|
+
const titleNotice = !showTitle && sorted.length > 0
|
|
1030
|
+
? `<div class="empty-note">Bing 响应式搜索广告的报表不返回单条标题,本表不展示「广告标题」列。</div>`
|
|
1031
|
+
: "";
|
|
1025
1032
|
const body = sorted
|
|
1026
1033
|
.map(
|
|
1027
1034
|
(r) => `<tr>
|
|
1028
|
-
|
|
1035
|
+
${showTitle ? `<td>${escapeHtml(r.adTitle || "—")}</td>` : ""}
|
|
1029
1036
|
<td>${escapeHtml(r.adGroupName || "—")}</td>
|
|
1030
1037
|
<td>${escapeHtml(r.adType || "—")}</td>
|
|
1031
1038
|
<td class="num">${money(r.spend, currency)}</td>
|
|
@@ -1038,8 +1045,9 @@
|
|
|
1038
1045
|
const table =
|
|
1039
1046
|
sorted.length > 0
|
|
1040
1047
|
? `<div class="card-title-row"><h3>广告 Top 10</h3><span class="hint">共 ${rows.length} 条广告,按消耗排序</span></div>
|
|
1048
|
+
${titleNotice}
|
|
1041
1049
|
<div class="table-wrap"><table>
|
|
1042
|
-
<thead><tr
|
|
1050
|
+
<thead><tr>${showTitle ? "<th>广告标题</th>" : ""}<th>广告组</th><th>广告类型</th><th class="num">消耗</th><th class="num">点击</th><th class="num">CTR</th><th class="num">转化</th></tr></thead>
|
|
1043
1051
|
<tbody>${body}</tbody>
|
|
1044
1052
|
</table></div>`
|
|
1045
1053
|
: emptyNoteHtml();
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
| `overview` | 对象:`currentPeriod` / `previousPeriod` / `balance` / `averageDailyCost` … | → `meta` + `kpis`(环比、余额、日均) |
|
|
14
14
|
| `device` | `{ devices: Row[] }` | → `tables.devices[]` |
|
|
15
15
|
| `geographic` | `{ countries: Row[] }` | → `tables.geographic[]` |
|
|
16
|
-
| `audience
|
|
16
|
+
| `age-audience` / `gender-audience`(默认)或 `audience-merged` | 拆分维 `{ audience: [] }`;merged `{ data: { ageAudience, genderAudience } }` | → `tables.audienceAge[]` / `audienceGender[]`(merged 空则回退拆分维) |
|
|
17
17
|
| `campaigns` | **根节点数组** | → `tables.campaigns[]`;**本期 KPI 优先由此累加** |
|
|
18
18
|
| `ad-groups` | **根节点数组** | → `tables.adGroups[]`(含 `qualityScore`) |
|
|
19
19
|
| `ads` | **根节点数组** | → `tables.ads[]` |
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
|
|
29
29
|
| 步骤 | 执行者 | 动作 |
|
|
30
30
|
| ---------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
31
|
-
| **1. 拉数** | Agent 调 CLI | `bing-analysis -a <id> --start <s> --end <e> --json-out ./snap-bing
|
|
31
|
+
| **1. 拉数** | Agent 调 CLI | `bing-analysis -a <id> --start <s> --end <e> --json-out ./snap-bing`(见下方「日期规则」,默认 10 维含年龄/性别、不含 `audience-merged`) |
|
|
32
32
|
| **2. 分析** | Agent | 用 **node/python 脚本**读落盘 JSON(勿用 Read 打开业务 `*.json`),把网关原始字段映射为下方 `tables.*` 契约,完成聚合与洞察 |
|
|
33
33
|
| **3. 写 JSON** | Agent | 撰写 `bing-period-report.json`:仅 `meta.accountId` + `narrative`(9 个分析小节)为必填;`kpis`/`tables` 可省略由 `--snapshot-dir` 自动合并 |
|
|
34
34
|
| **4. 渲染 HTML** | CLI | `bing-analysis render` — **校验 narrative 9 个分析小节必含字段**,缺项报错不生成 HTML;**禁止** Agent 手写/拼接 HTML |
|
|
@@ -55,7 +55,7 @@ siluzan-tso bing-analysis render \
|
|
|
55
55
|
- `audienceGender[]`:`{gender, spend, impressions, clicks, ctr, averageCpc, conversions}`
|
|
56
56
|
- `campaigns[]`:`{campaignName, campaignStatus, campaignStatusDisplay, spend, impressions, clicks, ctr, conversions, costPerConversion}`
|
|
57
57
|
- `adGroups[]`:`{adGroupName, campaignName, qualityScore, spend, clicks, ctr, conversions, costPerConversion}`
|
|
58
|
-
- `ads[]`:`{adTitle, adGroupName, adType, spend, clicks, ctr, conversions}`
|
|
58
|
+
- `ads[]`:`{adTitle, adGroupName, adType, spend, clicks, ctr, conversions}`(RSA 常 `adTitle=""`,HTML 整列为空则不渲染该列并在表上方提醒)
|
|
59
59
|
- `keywords[]`:`{keyword, matchType, qualityScore, spend, ctr, averageCpc, conversions, costPerConversion}`
|
|
60
60
|
- `searchTerms[]`:`{searchQuery, keyword, deliveredMatchType, spend, ctr, conversions, costPerConversion}`
|
|
61
61
|
- `narrative`(**Agent 必填,唯一由 Agent 撰写的叙事内容**):
|
|
@@ -107,13 +107,13 @@ mkdir -p ./snap-bing
|
|
|
107
107
|
|
|
108
108
|
siluzan-tso list-accounts -m BingV2 -k <mediaCustomerId> --json-out ./snap-bing
|
|
109
109
|
|
|
110
|
-
#
|
|
110
|
+
# 一次批跑默认 10 维(含 age-audience / gender-audience,不含 audience-merged)
|
|
111
111
|
siluzan-tso bing-analysis -a <mediaCustomerId> --start <S> --end <E> --json-out ./snap-bing
|
|
112
112
|
siluzan-tso balance -m BingV2 --accounts <mediaCustomerId> --json-out ./snap-bing
|
|
113
113
|
|
|
114
|
-
# 或仅拉本次报告所需维度(--sections
|
|
114
|
+
# 或仅拉本次报告所需维度(--sections 逗号分隔;不要同时写拆分维和 audience-merged)
|
|
115
115
|
siluzan-tso bing-analysis -a <mediaCustomerId> --start <S> --end <E> \
|
|
116
|
-
--sections overview,campaigns,device,geographic,audience-
|
|
116
|
+
--sections overview,campaigns,device,geographic,age-audience,gender-audience,ad-groups,ads,keywords,search-terms \
|
|
117
117
|
--limit 100 --json-out ./snap-bing
|
|
118
118
|
```
|
|
119
119
|
|
|
@@ -206,9 +206,9 @@ Bing 网关常不返回 `averageDailyCost`、`activeDays`(或为 0)。CLI
|
|
|
206
206
|
|
|
207
207
|
## 4. 受众
|
|
208
208
|
|
|
209
|
-
- **CLI
|
|
209
|
+
- **CLI**:默认已含 `--sections age-audience,gender-audience`。不要与 `audience-merged` 同时拉(Bing SDK 会抢同一份受众 csv,merged 常 400)。`render --snapshot-dir` 优先 merged,空则回退拆分维。
|
|
210
210
|
|
|
211
|
-
**数据呈现**:年龄段、性别的展示、点击、消耗、CTR、CPC
|
|
211
|
+
**数据呈现**:年龄段、性别的展示、点击、消耗、CTR、CPC。拆分维读 `age-audience-*.json` / `gender-audience-*.json` 的 `audience[]`(标签字段 `audience`)。写入 JSON `tables.audienceAge[]`(`ageRange`)/ `tables.audienceGender[]`(`gender`)。
|
|
212
212
|
|
|
213
213
|
**分析(必写)** → 写入 `narrative.sections.audience.{analysis,suggestions}`:
|
|
214
214
|
|
|
@@ -225,7 +225,7 @@ Bing 网关常不返回 `averageDailyCost`、`activeDays`(或为 0)。CLI
|
|
|
225
225
|
| 广告组 | `bing-analysis --sections ad-groups` | `ad-groups-*.json` |
|
|
226
226
|
| 广告 | `bing-analysis --sections ads` | `ads-*.json` |
|
|
227
227
|
|
|
228
|
-
**数据呈现**:各表按消耗降序;系列含 `campaignStatus`;广告组可含质量分相关字段(以 outline 为准)。写入 JSON `tables.campaigns[]` / `tables.adGroups[]` / `tables.ads[]`。
|
|
228
|
+
**数据呈现**:各表按消耗降序;系列含 `campaignStatus`;广告组可含质量分相关字段(以 outline 为准)。写入 JSON `tables.campaigns[]` / `tables.adGroups[]` / `tables.ads[]`。RSA 的 `adTitle` 常为空串,HTML 不展示空标题列。
|
|
229
229
|
|
|
230
230
|
**分析(必写,三个子块各写一段,不可合并为一句带过)**:
|
|
231
231
|
|
|
@@ -9,7 +9,7 @@ $ErrorActionPreference = 'Stop'
|
|
|
9
9
|
# -- Package info (injected at build time) ------------------------------------
|
|
10
10
|
$PKG_NAME = 'siluzan-tso-cli'
|
|
11
11
|
# PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
|
|
12
|
-
$PKG_VERSION = '1.1.49-beta.
|
|
12
|
+
$PKG_VERSION = '1.1.49-beta.3'
|
|
13
13
|
$CLI_BIN = 'siluzan-tso'
|
|
14
14
|
$SKILL_LABEL = 'Siluzan TSO'
|
|
15
15
|
$INSTALL_CMD = 'npm install -g siluzan-tso-cli@beta'
|
|
@@ -9,7 +9,7 @@ set -euo pipefail
|
|
|
9
9
|
# -- Package info (injected at build time) ------------------------------------
|
|
10
10
|
readonly PKG_NAME="siluzan-tso-cli"
|
|
11
11
|
# PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
|
|
12
|
-
readonly PKG_VERSION="1.1.49-beta.
|
|
12
|
+
readonly PKG_VERSION="1.1.49-beta.3"
|
|
13
13
|
readonly CLI_BIN="siluzan-tso"
|
|
14
14
|
readonly SKILL_LABEL="Siluzan TSO"
|
|
15
15
|
readonly INSTALL_CMD="npm install -g siluzan-tso-cli@beta"
|