siluzan-tso-cli 1.1.56-beta.2 → 1.1.56-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 +481 -219
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/report-templates/google-ads-diagnosis.md +22 -18
- package/dist/skill/report-templates/GoogleAdsDiagnosisReport.html +1 -15
- package/dist/skill/report-templates/google-ads-diagnosis.md +22 -18
- package/dist/skill/scripts/install.ps1 +1 -1
- package/dist/skill/scripts/install.sh +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -103126,7 +103126,7 @@ function narrativeClaimsMobileSpendLeads(text2) {
|
|
|
103126
103126
|
if (!t.includes("\u79FB\u52A8")) return false;
|
|
103127
103127
|
return /移动(?:端|设备)?(?:为|是)主要消耗/.test(t) || /移动(?:端|设备)?为主要(?:消耗)?设备/.test(t) || /移动(?:端|设备)?(?:消耗|花费|费用|流量)?占比高/.test(t);
|
|
103128
103128
|
}
|
|
103129
|
-
function
|
|
103129
|
+
function asRecord19(value) {
|
|
103130
103130
|
if (value && typeof value === "object" && !Array.isArray(value)) return value;
|
|
103131
103131
|
return null;
|
|
103132
103132
|
}
|
|
@@ -103134,16 +103134,16 @@ function stringList(value) {
|
|
|
103134
103134
|
return (Array.isArray(value) ? value : []).map((item) => typeof item === "string" ? item.trim() : "").filter(Boolean);
|
|
103135
103135
|
}
|
|
103136
103136
|
function collectOkkiNarrativeText(data) {
|
|
103137
|
-
const narrative =
|
|
103137
|
+
const narrative = asRecord19(data.narrative) ?? {};
|
|
103138
103138
|
const parts = [];
|
|
103139
|
-
const sheetAnalysis =
|
|
103139
|
+
const sheetAnalysis = asRecord19(narrative.sheetAnalysis) ?? {};
|
|
103140
103140
|
for (const block of Object.values(sheetAnalysis)) {
|
|
103141
|
-
const rec =
|
|
103141
|
+
const rec = asRecord19(block);
|
|
103142
103142
|
parts.push(...stringList(rec?.summary), ...stringList(rec?.suggestions));
|
|
103143
103143
|
}
|
|
103144
|
-
const review =
|
|
103144
|
+
const review = asRecord19(narrative.review) ?? {};
|
|
103145
103145
|
for (const block of Object.values(review)) {
|
|
103146
|
-
const rec =
|
|
103146
|
+
const rec = asRecord19(block);
|
|
103147
103147
|
for (const key of ["overview", "summary", "suggestion"]) {
|
|
103148
103148
|
const value = rec?.[key];
|
|
103149
103149
|
if (typeof value === "string" && value.trim()) parts.push(value.trim());
|
|
@@ -103160,7 +103160,7 @@ var init_okki_display = __esm({
|
|
|
103160
103160
|
// src/commands/google-analysis/merge-snapshot.ts
|
|
103161
103161
|
import * as fs27 from "fs/promises";
|
|
103162
103162
|
import * as path32 from "path";
|
|
103163
|
-
function
|
|
103163
|
+
function asRecord20(value) {
|
|
103164
103164
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
103165
103165
|
return value;
|
|
103166
103166
|
}
|
|
@@ -103256,7 +103256,7 @@ function periodMetricsFromRow(row) {
|
|
|
103256
103256
|
}
|
|
103257
103257
|
function items(envelope) {
|
|
103258
103258
|
if (!envelope || !Array.isArray(envelope.items)) return [];
|
|
103259
|
-
return envelope.items.filter((row) =>
|
|
103259
|
+
return envelope.items.filter((row) => asRecord20(row) !== null);
|
|
103260
103260
|
}
|
|
103261
103261
|
function record(envelope) {
|
|
103262
103262
|
return envelope?.record ?? null;
|
|
@@ -103303,14 +103303,14 @@ function sumCampaignRowsToPeriodKpis(rows) {
|
|
|
103303
103303
|
}
|
|
103304
103304
|
async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
103305
103305
|
const absDir = path32.resolve(snapshotDir);
|
|
103306
|
-
const metaAccountId = typeof
|
|
103306
|
+
const metaAccountId = typeof asRecord20(payload.meta)?.accountId === "string" ? asRecord20(payload.meta)?.accountId : void 0;
|
|
103307
103307
|
const manifest = await readManifest(snapshotDir, metaAccountId);
|
|
103308
103308
|
if (!manifest) {
|
|
103309
103309
|
throw new Error(`\u672A\u5728 ${absDir} \u627E\u5230 manifest*.json\uFF0C\u8BF7\u5148\u6267\u884C google-analysis --json-out`);
|
|
103310
103310
|
}
|
|
103311
103311
|
const accountId = manifest.googleAnalysis?.accountId ?? metaAccountId;
|
|
103312
103312
|
const dateRange = manifest.googleAnalysis?.dateRange;
|
|
103313
|
-
const preferredDateTag = dateTagFromRange(dateRange) ?? dateTagFromMeta(
|
|
103313
|
+
const preferredDateTag = dateTagFromRange(dateRange) ?? dateTagFromMeta(asRecord20(payload.meta) ?? void 0);
|
|
103314
103314
|
const sectionMap = /* @__PURE__ */ new Map();
|
|
103315
103315
|
for (const art of manifest.artifacts ?? []) {
|
|
103316
103316
|
const data = await loadSectionFile(absDir, art.file);
|
|
@@ -103318,8 +103318,8 @@ async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
103318
103318
|
}
|
|
103319
103319
|
await recoverMissingReportSections(sectionMap, absDir, accountId, preferredDateTag);
|
|
103320
103320
|
const overviewRecord = record(sectionMap.get("overview"));
|
|
103321
|
-
const currentPeriod =
|
|
103322
|
-
const previousPeriod =
|
|
103321
|
+
const currentPeriod = asRecord20(overviewRecord?.currentPeriod);
|
|
103322
|
+
const previousPeriod = asRecord20(overviewRecord?.previousPeriod);
|
|
103323
103323
|
const meta = { ...payload.meta ?? {} };
|
|
103324
103324
|
if (!meta.accountId && accountId) meta.accountId = accountId;
|
|
103325
103325
|
if (!meta.currency) {
|
|
@@ -103465,7 +103465,7 @@ function textLen(value) {
|
|
|
103465
103465
|
function asArray(value) {
|
|
103466
103466
|
return Array.isArray(value) ? value : [];
|
|
103467
103467
|
}
|
|
103468
|
-
function
|
|
103468
|
+
function asRecord21(value) {
|
|
103469
103469
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
103470
103470
|
return value;
|
|
103471
103471
|
}
|
|
@@ -103479,7 +103479,7 @@ function pushMissing(missing, id, chapter, dimension, hint) {
|
|
|
103479
103479
|
}
|
|
103480
103480
|
function validateOkkiWeeklyReportContent(data) {
|
|
103481
103481
|
const missing = [];
|
|
103482
|
-
const meta =
|
|
103482
|
+
const meta = asRecord21(data.meta) ?? {};
|
|
103483
103483
|
if (!textLen(meta.accountId)) {
|
|
103484
103484
|
pushMissing(
|
|
103485
103485
|
missing,
|
|
@@ -103489,7 +103489,7 @@ function validateOkkiWeeklyReportContent(data) {
|
|
|
103489
103489
|
"meta.accountId \u5FC5\u586B\uFF1B\u53EF\u7531 --snapshot-dir \u5408\u5E76 overview/manifest"
|
|
103490
103490
|
);
|
|
103491
103491
|
}
|
|
103492
|
-
const snapshotSections =
|
|
103492
|
+
const snapshotSections = asRecord21(data.snapshot?.sections) ?? {};
|
|
103493
103493
|
const snapshotPresent = {};
|
|
103494
103494
|
for (const section of OKKI_SNAPSHOT_SECTIONS) {
|
|
103495
103495
|
const present = snapshotSections[section] === true;
|
|
@@ -103504,12 +103504,12 @@ function validateOkkiWeeklyReportContent(data) {
|
|
|
103504
103504
|
);
|
|
103505
103505
|
}
|
|
103506
103506
|
}
|
|
103507
|
-
const narrative =
|
|
103508
|
-
const sheetAnalysis =
|
|
103509
|
-
const review =
|
|
103507
|
+
const narrative = asRecord21(data.narrative) ?? {};
|
|
103508
|
+
const sheetAnalysis = asRecord21(narrative.sheetAnalysis) ?? {};
|
|
103509
|
+
const review = asRecord21(narrative.review) ?? {};
|
|
103510
103510
|
const sheetAnalysisCounts = {};
|
|
103511
103511
|
for (const key of OKKI_SHEET_KEYS) {
|
|
103512
|
-
const block =
|
|
103512
|
+
const block = asRecord21(sheetAnalysis[key]);
|
|
103513
103513
|
const summary = stringList2(block?.summary);
|
|
103514
103514
|
const suggestions = stringList2(block?.suggestions);
|
|
103515
103515
|
sheetAnalysisCounts[key] = { summary: summary.length, suggestions: suggestions.length };
|
|
@@ -103535,7 +103535,7 @@ function validateOkkiWeeklyReportContent(data) {
|
|
|
103535
103535
|
}
|
|
103536
103536
|
const reviewFilled = {};
|
|
103537
103537
|
for (const key of OKKI_REVIEW_KEYS) {
|
|
103538
|
-
const block =
|
|
103538
|
+
const block = asRecord21(review[key]);
|
|
103539
103539
|
const overview = textLen(block?.overview);
|
|
103540
103540
|
const summary = textLen(block?.summary);
|
|
103541
103541
|
const suggestion = textLen(block?.suggestion);
|
|
@@ -103570,7 +103570,7 @@ function validateOkkiWeeklyReportContent(data) {
|
|
|
103570
103570
|
}
|
|
103571
103571
|
}
|
|
103572
103572
|
const deviceRows2 = Array.isArray(data.tables?.devices) ? data.tables.devices : [];
|
|
103573
|
-
const deviceSpend = summarizeOkkiDeviceSpend(deviceRows2.filter((row) =>
|
|
103573
|
+
const deviceSpend = summarizeOkkiDeviceSpend(deviceRows2.filter((row) => asRecord21(row) !== null));
|
|
103574
103574
|
if (deviceSpend.total > 0 && deviceSpend.desktop >= deviceSpend.mobile && narrativeClaimsMobileSpendLeads(collectOkkiNarrativeText(data))) {
|
|
103575
103575
|
pushMissing(
|
|
103576
103576
|
missing,
|
|
@@ -103659,7 +103659,7 @@ function round25(value) {
|
|
|
103659
103659
|
}
|
|
103660
103660
|
function items2(envelope) {
|
|
103661
103661
|
if (!envelope || !Array.isArray(envelope.items)) return [];
|
|
103662
|
-
return envelope.items.filter((row) =>
|
|
103662
|
+
return envelope.items.filter((row) => asRecord21(row) !== null);
|
|
103663
103663
|
}
|
|
103664
103664
|
function dateTagFromRange2(dateRange) {
|
|
103665
103665
|
if (!dateRange || dateRange.mode !== "range") return void 0;
|
|
@@ -103703,14 +103703,14 @@ async function loadSectionFile2(snapshotDir, file) {
|
|
|
103703
103703
|
}
|
|
103704
103704
|
async function mergeOkkiSnapshotIntoReport(payload, snapshotDir) {
|
|
103705
103705
|
const absDir = path33.resolve(snapshotDir);
|
|
103706
|
-
const metaAccountId = typeof
|
|
103706
|
+
const metaAccountId = typeof asRecord21(payload.meta)?.accountId === "string" ? asRecord21(payload.meta)?.accountId : void 0;
|
|
103707
103707
|
const manifest = await readManifest2(absDir, metaAccountId);
|
|
103708
103708
|
if (!manifest) {
|
|
103709
103709
|
throw new Error(`\u672A\u5728 ${absDir} \u627E\u5230 manifest*.json\uFF0C\u8BF7\u5148\u6267\u884C google-analysis --json-out`);
|
|
103710
103710
|
}
|
|
103711
103711
|
const accountId = manifest.googleAnalysis?.accountId ?? metaAccountId;
|
|
103712
103712
|
const dateRange = manifest.googleAnalysis?.dateRange;
|
|
103713
|
-
const preferredDateTag = dateTagFromRange2(dateRange) ?? dateTagFromMeta2(
|
|
103713
|
+
const preferredDateTag = dateTagFromRange2(dateRange) ?? dateTagFromMeta2(asRecord21(payload.meta) ?? void 0);
|
|
103714
103714
|
const sectionMap = /* @__PURE__ */ new Map();
|
|
103715
103715
|
for (const art of manifest.artifacts ?? []) {
|
|
103716
103716
|
const data = await loadSectionFile2(absDir, art.file);
|
|
@@ -103736,7 +103736,7 @@ async function mergeOkkiSnapshotIntoReport(payload, snapshotDir) {
|
|
|
103736
103736
|
snapshotPresent[section] = sectionMap.has(section);
|
|
103737
103737
|
}
|
|
103738
103738
|
const overviewRecord = sectionMap.get("overview")?.record ?? null;
|
|
103739
|
-
const currentPeriod =
|
|
103739
|
+
const currentPeriod = asRecord21(overviewRecord?.currentPeriod);
|
|
103740
103740
|
const meta = { ...payload.meta ?? {} };
|
|
103741
103741
|
if (!meta.accountId && accountId) meta.accountId = accountId;
|
|
103742
103742
|
if (!meta.currency) {
|
|
@@ -103879,18 +103879,18 @@ function prefixLines(items3, firstPrefix) {
|
|
|
103879
103879
|
});
|
|
103880
103880
|
}
|
|
103881
103881
|
function analysisLines(data, key) {
|
|
103882
|
-
const block =
|
|
103883
|
-
const rec =
|
|
103882
|
+
const block = asRecord21(asRecord21(data.narrative)?.sheetAnalysis)?.[key];
|
|
103883
|
+
const rec = asRecord21(block);
|
|
103884
103884
|
return [
|
|
103885
103885
|
...prefixLines(stringList2(rec?.summary), "\u603B\u7ED3\uFF1A"),
|
|
103886
103886
|
...prefixLines(stringList2(rec?.suggestions), "\u5EFA\u8BAE\uFF1A")
|
|
103887
103887
|
];
|
|
103888
103888
|
}
|
|
103889
103889
|
function reviewLines(data) {
|
|
103890
|
-
const review =
|
|
103890
|
+
const review = asRecord21(asRecord21(data.narrative)?.review) ?? {};
|
|
103891
103891
|
const lines = [];
|
|
103892
103892
|
OKKI_REVIEW_KEYS.forEach((key, idx) => {
|
|
103893
|
-
const block =
|
|
103893
|
+
const block = asRecord21(review[key]) ?? {};
|
|
103894
103894
|
lines.push(`${idx + 1}\u3001${REVIEW_LABELS2[key]}\uFF1A${str(block.overview, "")}`);
|
|
103895
103895
|
lines.push(` \u603B\u7ED3\uFF1A${str(block.summary, "")}`);
|
|
103896
103896
|
lines.push(` \u5EFA\u8BAE\uFF1A${str(block.suggestion, "")}`);
|
|
@@ -104022,7 +104022,7 @@ function geoRows(data) {
|
|
|
104022
104022
|
});
|
|
104023
104023
|
}
|
|
104024
104024
|
function buildOkkiWeeklySheetDrafts(data) {
|
|
104025
|
-
const meta =
|
|
104025
|
+
const meta = asRecord21(data.meta) ?? {};
|
|
104026
104026
|
const period = formatOkkiZhDateRange(str(meta.startDate, ""), str(meta.endDate, ""));
|
|
104027
104027
|
const campaigns = campaignRows(data);
|
|
104028
104028
|
const drafts = {
|
|
@@ -104283,7 +104283,7 @@ function textLen2(value) {
|
|
|
104283
104283
|
function asArray2(value) {
|
|
104284
104284
|
return Array.isArray(value) ? value : [];
|
|
104285
104285
|
}
|
|
104286
|
-
function
|
|
104286
|
+
function asRecord22(value) {
|
|
104287
104287
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
104288
104288
|
return value;
|
|
104289
104289
|
}
|
|
@@ -104294,9 +104294,9 @@ function pushMissing2(missing, id, chapter, dimension, hint) {
|
|
|
104294
104294
|
}
|
|
104295
104295
|
function validateGooglePeriodReportContent(data) {
|
|
104296
104296
|
const missing = [];
|
|
104297
|
-
const meta =
|
|
104298
|
-
const narrative =
|
|
104299
|
-
const sections =
|
|
104297
|
+
const meta = asRecord22(data.meta) ?? {};
|
|
104298
|
+
const narrative = asRecord22(data.narrative) ?? {};
|
|
104299
|
+
const sections = asRecord22(narrative.sections) ?? {};
|
|
104300
104300
|
if (!textLen2(meta.accountId)) {
|
|
104301
104301
|
pushMissing2(
|
|
104302
104302
|
missing,
|
|
@@ -104316,7 +104316,7 @@ function validateGooglePeriodReportContent(data) {
|
|
|
104316
104316
|
"\u22651 \u6BB5\u6267\u884C\u6458\u8981\uFF0C\u6982\u8FF0\u672C\u671F\u6D88\u8017/\u8F6C\u5316/CTR/CPA \u8D70\u52BF"
|
|
104317
104317
|
);
|
|
104318
104318
|
}
|
|
104319
|
-
const kpis =
|
|
104319
|
+
const kpis = asRecord22(data.kpis);
|
|
104320
104320
|
const hasCoreKpi = ["cost", "impressions", "clicks"].some(
|
|
104321
104321
|
(key) => Number.isFinite(Number(kpis?.[key]))
|
|
104322
104322
|
);
|
|
@@ -104332,7 +104332,7 @@ function validateGooglePeriodReportContent(data) {
|
|
|
104332
104332
|
const sectionAnalysisCounts = {};
|
|
104333
104333
|
const sectionSuggestionCounts = {};
|
|
104334
104334
|
for (const key of SECTION_KEYS) {
|
|
104335
|
-
const section =
|
|
104335
|
+
const section = asRecord22(sections[key]);
|
|
104336
104336
|
const analysis = asArray2(section?.analysis).filter((s) => textLen2(s) > 0);
|
|
104337
104337
|
const suggestions = asArray2(section?.suggestions).filter((s) => textLen2(s) > 0);
|
|
104338
104338
|
sectionAnalysisCounts[key] = analysis.length;
|
|
@@ -104358,7 +104358,7 @@ function validateGooglePeriodReportContent(data) {
|
|
|
104358
104358
|
}
|
|
104359
104359
|
const recommendations = asArray2(narrative.recommendations).filter((r) => {
|
|
104360
104360
|
if (typeof r === "string") return textLen2(r) > 0;
|
|
104361
|
-
const rec =
|
|
104361
|
+
const rec = asRecord22(r);
|
|
104362
104362
|
return textLen2(rec?.content) > 0;
|
|
104363
104363
|
});
|
|
104364
104364
|
if (recommendations.length < 3) {
|
|
@@ -104447,7 +104447,7 @@ async function readJsonFile3(filePath) {
|
|
|
104447
104447
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
104448
104448
|
}
|
|
104449
104449
|
}
|
|
104450
|
-
function
|
|
104450
|
+
function asRecord23(value) {
|
|
104451
104451
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
104452
104452
|
return value;
|
|
104453
104453
|
}
|
|
@@ -104462,7 +104462,7 @@ function injectReportData2(html, payload) {
|
|
|
104462
104462
|
}
|
|
104463
104463
|
async function runGoogleAnalysisRender(opts) {
|
|
104464
104464
|
const dataPath = path35.resolve(opts.dataFile);
|
|
104465
|
-
let data =
|
|
104465
|
+
let data = asRecord23(await readJsonFile3(dataPath));
|
|
104466
104466
|
if (opts.snapshotDir?.trim()) {
|
|
104467
104467
|
data = await mergeGoogleAnalysisSnapshotIntoReport(data, path35.resolve(opts.snapshotDir));
|
|
104468
104468
|
}
|
|
@@ -133428,11 +133428,12 @@ function buildGoogleAdsDiagnosisCollectAgentHint(snapDir) {
|
|
|
133428
133428
|
"Google Ads \u8BCA\u65AD collect \u5DF2\u5B8C\u6210\uFF08\u4EC5\u4E8B\u5B9E\u6570\u636E\uFF0C\u4E0D\u542B\u5EFA\u8BAE\u6027\u6587\u6848\uFF09\u3002",
|
|
133429
133429
|
`1) Read ${dir}/${GOOGLE_ADS_DIAGNOSIS_DIGEST_BASENAME}\uFF1A\u5404 section \u7ED3\u6784\u3001\u884C\u6570\u3001\u5F85\u586B\u5B57\u6BB5\u6E05\u5355\u90FD\u5728\u91CC\u9762\uFF1B`,
|
|
133430
133430
|
`2) ${dir}/${GOOGLE_ADS_DIAGNOSIS_REPORT_BASENAME} \u5DF2\u662F\u7EC8\u7A3F\u9AA8\u67B6\uFF08items \u4E8B\u5B9E\u884C\u5DF2\u586B\u597D\u3001\u53D9\u4E8B\u5B57\u6BB5\u7559\u7A7A\uFF09\uFF0C\u76F4\u63A5\u5728\u5B83\u4E0A\u9762\u586B\u7A7A\uFF1B`,
|
|
133431
|
-
"3) Read references/report-templates/google-ads-diagnosis.md\
|
|
133431
|
+
"3) Read references/report-templates/google-ads-diagnosis.md\u3002\u53EA\u5199\u4E3B\u89C2\u5206\u6790\uFF1AdiagnosisOverview.advantages/disadvantages\uFF08\u6BCF\u6761 {title, description}\uFF09\u3001\u5404\u6A21\u5757 analysis/suggestions\u3001summary\u3001accountInfo.businessModel/industry\u3002",
|
|
133432
133432
|
`4) siluzan-tso google-ads-diagnosis render --data ${dir}/${GOOGLE_ADS_DIAGNOSIS_REPORT_BASENAME} --out ${dir}/google-ads-diagnosis-report.html\uFF08\u9ED8\u8BA4\u540C\u76EE\u5F55 collect \u81EA\u52A8\u6062\u590D\u88AB\u6539\u574F\u7684 items\uFF09\u3002`,
|
|
133433
133433
|
`\u7981\u6B62\u7528 node -e \u9010\u6BB5 dump ${GOOGLE_ADS_DIAGNOSIS_COLLECT_BASENAME} \u6765\u6478\u7ED3\u6784\u2014\u2014\u7ED3\u6784\u770B digest\u3001\u6570\u5B57\u770B\u9AA8\u67B6\u6587\u4EF6\u5373\u53EF\u3002`,
|
|
133434
133434
|
"\u7981\u6B62\u5199\u5165/\u8986\u76D6 campaigns/geographic/keywords \u7684 items \u884C\uFF0C\u53EA\u586B analysis/suggestions\u3002",
|
|
133435
|
-
"\u7981\u6B62\u5728\u672A\u7ECF\u8FC7 Agent \u64B0\u5199\u7684\u60C5\u51B5\u4E0B\u76F4\u63A5 render\uFF1B\u7F3A\u4EFB\u4E00\u5EFA\u8BAE\u5B57\u6BB5 render \u4F1A\u5931\u8D25\u3002"
|
|
133435
|
+
"\u7981\u6B62\u5728\u672A\u7ECF\u8FC7 Agent \u64B0\u5199\u7684\u60C5\u51B5\u4E0B\u76F4\u63A5 render\uFF1B\u7F3A\u4EFB\u4E00\u5EFA\u8BAE\u5B57\u6BB5 render \u4F1A\u5931\u8D25\u3002",
|
|
133436
|
+
"\u9EC4\u91D1\u8D26\u6237\u8868\u3001\u9884\u7B97\u7ADE\u4E89\u529B\u3001\u51FA\u4EF7\u539F\u56E0\u3001\u65B0\u4EA7\u54C1\u72B6\u6001\u3001\u521B\u610F\u884C\u5EFA\u8BAE\u7531 render \u6309\u6570\u636E\u5199\u5165\u3002Agent \u4E0D\u8981\u586B\u8FD9\u4E9B\u5B57\u6BB5\uFF0C\u4E5F\u4E0D\u8981\u628A\u672A\u8FBE\u6807\u5199\u6210\u300C\u8BF7\u521B\u5EFA/\u6CA1\u6709\u300D\u3002"
|
|
133436
133437
|
].join("\n");
|
|
133437
133438
|
}
|
|
133438
133439
|
|
|
@@ -133485,17 +133486,21 @@ function buildGoogleAdsDiagnosisAgentBrief(input) {
|
|
|
133485
133486
|
},
|
|
133486
133487
|
comparisonTableItemCounts: input.comparisonTableItemCounts,
|
|
133487
133488
|
agentRules: {
|
|
133488
|
-
doNotModifyItemRows: [
|
|
133489
|
-
|
|
133490
|
-
|
|
133489
|
+
doNotModifyItemRows: [
|
|
133490
|
+
"campaigns.items",
|
|
133491
|
+
"geographic.items",
|
|
133492
|
+
"keywords.items",
|
|
133493
|
+
"budgetCompetitiveness[].strategy",
|
|
133491
133494
|
"biddingStrategy.items[].recommendationReason",
|
|
133492
133495
|
"newFeatures.items[].optimizerRecommendation",
|
|
133493
133496
|
"adCreativeOptimization.items[].suggestion"
|
|
133494
|
-
]
|
|
133497
|
+
],
|
|
133498
|
+
renderRestoresComparisonItemsFromCollect: "render \u9ED8\u8BA4\u540C\u76EE\u5F55 google-ads-diagnosis-collect.json \u4F1A\u4EE5 collect \u8986\u76D6\u4E0A\u8FF0 items\u3002\u9EC4\u91D1\u8D26\u6237\u8868\u3001\u9884\u7B97\u7ADE\u4E89\u529B strategy\u3001\u51FA\u4EF7 recommendationReason\u3001\u65B0\u4EA7\u54C1 optimizerRecommendation\u3001\u521B\u610F\u884C suggestion \u4E5F\u7531 render \u6309\u884C\u6570\u636E\u91CD\u5199\u3002Agent \u53EA\u586B\u4E3B\u89C2\u5206\u6790\u3002",
|
|
133499
|
+
mayEditItemFields: []
|
|
133495
133500
|
},
|
|
133496
133501
|
agentDeliverable: {
|
|
133497
133502
|
outputFile: "google-ads-diagnosis.json",
|
|
133498
|
-
structure: "\u4E0E reportData \u540C\u7ED3\u6784\u7684 sectionData\
|
|
133503
|
+
structure: "\u4E0E reportData \u540C\u7ED3\u6784\u7684 sectionData\u3002\u53EA\u586B\u4E3B\u89C2\u5206\u6790\uFF1AdiagnosisOverview.advantages/disadvantages\uFF08\u6BCF\u6761 {title, description}\uFF09\u3001\u5404\u6A21\u5757 analysis/suggestions\u3001summary.keyIssues\u3001summary.optimizationRoadmap[]\uFF08priority/focusArea/actionItems/expectedOutcome\uFF09\u3001accountInfo.businessModel/industry\u3002\u4E0D\u8981\u586B\u9EC4\u91D1\u8D26\u6237\u8868\u3001budgetCompetitiveness[].strategy\u3001biddingStrategy[].recommendationReason\u3001newFeatures[].optimizerRecommendation\u3001adCreativeOptimization.items[].suggestion",
|
|
133499
133504
|
thenRun: "siluzan-tso google-ads-diagnosis render --data ./<snap>/google-ads-diagnosis.json --out ./<snap>/google-ads-diagnosis-report.html"
|
|
133500
133505
|
}
|
|
133501
133506
|
};
|
|
@@ -133549,14 +133554,7 @@ function asRecord7(value) {
|
|
|
133549
133554
|
}
|
|
133550
133555
|
return null;
|
|
133551
133556
|
}
|
|
133552
|
-
|
|
133553
|
-
return gold.expandedTextAdQualified === true || gold.textAdQualified === true || gold.responsiveSearchAdQualified === true;
|
|
133554
|
-
}
|
|
133555
|
-
function applyTextAdQualification(gold) {
|
|
133556
|
-
if (!hasSearchTextAds(gold) || gold.expandedTextAdQualified === true) return gold;
|
|
133557
|
-
return { ...gold, expandedTextAdQualified: true };
|
|
133558
|
-
}
|
|
133559
|
-
var DISPLAY_PAUSED_SUGGESTION = "\u5DF2\u6709\u81EA\u9002\u5E94\u5C55\u793A\u5E7F\u544A\uFF0C\u6240\u5728\u5C55\u793A\u7CFB\u5217\u5DF2\u6682\u505C\uFF0C\u672C\u671F\u65E0\u6D88\u8017";
|
|
133557
|
+
var NOT_QUALIFIED = "\u672A\u8FBE\u5230\u8BE5\u9879\u9EC4\u91D1\u8D26\u6237\u6807\u51C6";
|
|
133560
133558
|
function statusOf(row) {
|
|
133561
133559
|
return String(row.statusV2 ?? row.status ?? "").toUpperCase();
|
|
133562
133560
|
}
|
|
@@ -133566,7 +133564,7 @@ function isEnabled(row) {
|
|
|
133566
133564
|
function hasEnabledExtension(rows, type) {
|
|
133567
133565
|
return rows.some((row) => String(row.typeV2 ?? "") === type && isEnabled(row));
|
|
133568
133566
|
}
|
|
133569
|
-
function
|
|
133567
|
+
function hasGa4Conversion(rows) {
|
|
133570
133568
|
return rows.some((row) => {
|
|
133571
133569
|
if (!isEnabled(row)) return false;
|
|
133572
133570
|
const type = String(row.type ?? "");
|
|
@@ -133574,12 +133572,25 @@ function hasGa4Link(rows) {
|
|
|
133574
133572
|
return type.startsWith("GoogleAnalytics") || /GA4/i.test(name2);
|
|
133575
133573
|
});
|
|
133576
133574
|
}
|
|
133577
|
-
function
|
|
133575
|
+
function hasAudienceRows(rows) {
|
|
133578
133576
|
return rows.some((row) => {
|
|
133579
133577
|
const type = String(row.criterionType ?? "");
|
|
133580
133578
|
return type === "UserList" || type === "CustomAudience" || type === "UserInterest" || type === "CustomIntent" || type === "CombinedAudience" || type === "CustomAffinity" || Number(row.impressions) > 0;
|
|
133581
133579
|
});
|
|
133582
133580
|
}
|
|
133581
|
+
function hasSearchTextAdRows(rows) {
|
|
133582
|
+
return rows.some((row) => {
|
|
133583
|
+
const type = String(row.typeV2 ?? "");
|
|
133584
|
+
return type === "RESPONSIVE_SEARCH_AD" || type === "EXPANDED_TEXT_AD";
|
|
133585
|
+
});
|
|
133586
|
+
}
|
|
133587
|
+
function campaignsUseBidding(rows) {
|
|
133588
|
+
return rows.some(
|
|
133589
|
+
(row) => /MAXIMIZE_|TARGET_|MANUAL_CPC|ENHANCED_CPC|COMMISSION/i.test(
|
|
133590
|
+
String(row.biddingStrategyTypeV2 ?? row.biddingStrategyType ?? "")
|
|
133591
|
+
)
|
|
133592
|
+
);
|
|
133593
|
+
}
|
|
133583
133594
|
function displayAds(rows) {
|
|
133584
133595
|
return rows.filter((row) => String(row.typeV2 ?? "") === "RESPONSIVE_DISPLAY_AD");
|
|
133585
133596
|
}
|
|
@@ -133588,28 +133599,109 @@ function displayIsServing(rows) {
|
|
|
133588
133599
|
(row) => isEnabled(row) && statusOf({ statusV2: row.parentCampaignStatusV2 }) === "ENABLED"
|
|
133589
133600
|
);
|
|
133590
133601
|
}
|
|
133602
|
+
function noteUnqualified(gold, suggestions, flag, itemName, present, sentence) {
|
|
133603
|
+
if (!present || gold[flag] !== false) return;
|
|
133604
|
+
suggestions[itemName] = sentence;
|
|
133605
|
+
}
|
|
133591
133606
|
function reconcileGoldAccount(gold, evidence = {}) {
|
|
133592
|
-
const next = { ...
|
|
133607
|
+
const next = { ...gold };
|
|
133608
|
+
const suggestions = { ...asRecord7(gold.goldItemSuggestions) ?? {} };
|
|
133609
|
+
const notes = {};
|
|
133593
133610
|
const conversions = evidence.conversionActions ?? [];
|
|
133594
133611
|
const extensions = evidence.extensions ?? [];
|
|
133595
133612
|
const audiences = evidence.audiences ?? [];
|
|
133596
133613
|
const ads = evidence.ads ?? [];
|
|
133597
|
-
|
|
133598
|
-
|
|
133599
|
-
if (
|
|
133600
|
-
|
|
133601
|
-
|
|
133602
|
-
|
|
133614
|
+
const presentBecause = (sentence) => `${NOT_QUALIFIED}\u3002${sentence}\u662F\u5426\u8FBE\u6807\u4E0D\u7531\u8BE5\u5BF9\u8C61\u662F\u5426\u5B58\u5728\u51B3\u5B9A\u3002`;
|
|
133615
|
+
const textAdsPresent = hasSearchTextAdRows(ads) || gold.responsiveSearchAdQualified === true || gold.textAdQualified === true || gold.expandedTextAdQualified === true;
|
|
133616
|
+
if (textAdsPresent) notes.textAds = true;
|
|
133617
|
+
noteUnqualified(
|
|
133618
|
+
gold,
|
|
133619
|
+
suggestions,
|
|
133620
|
+
"expandedTextAdQualified",
|
|
133621
|
+
"\u6587\u5B57\u5E7F\u544A",
|
|
133622
|
+
textAdsPresent,
|
|
133623
|
+
presentBecause("\u8D26\u6237\u91CC\u5DF2\u6709\u641C\u7D22\u6587\u5B57\u5E7F\u544A\uFF0C")
|
|
133624
|
+
);
|
|
133625
|
+
noteUnqualified(
|
|
133626
|
+
gold,
|
|
133627
|
+
suggestions,
|
|
133628
|
+
"responsiveSearchAdQualified",
|
|
133629
|
+
"\u81EA\u9002\u5E94\u641C\u7D22\u5E7F\u544A",
|
|
133630
|
+
hasSearchTextAdRows(ads),
|
|
133631
|
+
presentBecause("\u8D26\u6237\u91CC\u5DF2\u6709\u81EA\u9002\u5E94\u641C\u7D22\u5E7F\u544A\uFF0C")
|
|
133632
|
+
);
|
|
133603
133633
|
const responsiveDisplay = displayAds(ads);
|
|
133604
|
-
if (
|
|
133605
|
-
|
|
133606
|
-
|
|
133607
|
-
|
|
133608
|
-
|
|
133609
|
-
|
|
133610
|
-
|
|
133611
|
-
|
|
133612
|
-
|
|
133634
|
+
if (responsiveDisplay.length > 0) {
|
|
133635
|
+
notes.displayAds = true;
|
|
133636
|
+
if (gold.multiAssetResponsiveDisplayAdQualified === false) {
|
|
133637
|
+
suggestions["\u81EA\u9002\u5E94\u5C55\u793A\u5E7F\u544A"] = displayIsServing(responsiveDisplay) ? presentBecause("\u8D26\u6237\u91CC\u5DF2\u6709\u81EA\u9002\u5E94\u5C55\u793A\u5E7F\u544A\uFF0C") : `${NOT_QUALIFIED}\u3002\u8D26\u6237\u91CC\u5DF2\u6709\u81EA\u9002\u5E94\u5C55\u793A\u5E7F\u544A\uFF0C\u6240\u5728\u5C55\u793A\u7CFB\u5217\u5DF2\u6682\u505C\uFF0C\u672C\u671F\u65E0\u6D88\u8017\u3002`;
|
|
133638
|
+
}
|
|
133639
|
+
}
|
|
133640
|
+
if (hasGa4Conversion(conversions)) notes.ga4 = true;
|
|
133641
|
+
noteUnqualified(
|
|
133642
|
+
gold,
|
|
133643
|
+
suggestions,
|
|
133644
|
+
"gaConfigured",
|
|
133645
|
+
"G A\u4E0E\u5E7F\u544A\u8D26\u6237\u8054\u7ED3",
|
|
133646
|
+
hasGa4Conversion(conversions),
|
|
133647
|
+
presentBecause("\u8D26\u6237\u91CC\u5DF2\u6709\u542F\u7528\u7684 Google Analytics \u8F6C\u5316\uFF0C")
|
|
133648
|
+
);
|
|
133649
|
+
if (conversions.some((row) => isEnabled(row))) notes.conversion = true;
|
|
133650
|
+
noteUnqualified(
|
|
133651
|
+
gold,
|
|
133652
|
+
suggestions,
|
|
133653
|
+
"conversionTrackingQualified",
|
|
133654
|
+
"\u8F6C\u5316\u8FFD\u8E2A\u8BBE\u7F6E",
|
|
133655
|
+
conversions.some((row) => isEnabled(row)),
|
|
133656
|
+
presentBecause("\u8D26\u6237\u91CC\u5DF2\u6709\u542F\u7528\u7684\u8F6C\u5316\u52A8\u4F5C\uFF0C")
|
|
133657
|
+
);
|
|
133658
|
+
const extensionNote = (type, flag, itemName, noteKey, found) => {
|
|
133659
|
+
if (!hasEnabledExtension(extensions, type)) return;
|
|
133660
|
+
notes[noteKey] = true;
|
|
133661
|
+
noteUnqualified(gold, suggestions, flag, itemName, true, presentBecause(found));
|
|
133662
|
+
};
|
|
133663
|
+
extensionNote(
|
|
133664
|
+
"CALLOUT",
|
|
133665
|
+
"adsCalloutExtensionQualified",
|
|
133666
|
+
"\u9644\u52A0\u5BA3\u4F20\u4FE1\u606F",
|
|
133667
|
+
"callout",
|
|
133668
|
+
"\u8D26\u6237\u91CC\u5DF2\u6709\u542F\u7528\u7684\u5BA3\u4F20\u4FE1\u606F\uFF0C"
|
|
133669
|
+
);
|
|
133670
|
+
extensionNote(
|
|
133671
|
+
"STRUCTURED_SNIPPET",
|
|
133672
|
+
"adsStructuredSnippetExtensionQualified",
|
|
133673
|
+
"\u9644\u52A0\u7ED3\u6784\u5316\u4FE1\u606F\u6458\u8981",
|
|
133674
|
+
"snippet",
|
|
133675
|
+
"\u8D26\u6237\u91CC\u5DF2\u6709\u542F\u7528\u7684\u7ED3\u6784\u5316\u4FE1\u606F\u6458\u8981\uFF0C"
|
|
133676
|
+
);
|
|
133677
|
+
extensionNote(
|
|
133678
|
+
"SITELINK",
|
|
133679
|
+
"adsSitelinkExtensionQualified",
|
|
133680
|
+
"\u9644\u52A0\u94FE\u63A5",
|
|
133681
|
+
"sitelink",
|
|
133682
|
+
"\u8D26\u6237\u91CC\u5DF2\u6709\u542F\u7528\u7684\u9644\u52A0\u94FE\u63A5\uFF0C"
|
|
133683
|
+
);
|
|
133684
|
+
extensionNote("CALL", "adsCallExtensionQualified", "\u9644\u52A0\u7535\u8BDD\u4FE1\u606F", "call", "\u8D26\u6237\u91CC\u5DF2\u6709\u542F\u7528\u7684\u7535\u8BDD\u4FE1\u606F\uFF0C");
|
|
133685
|
+
if (hasAudienceRows(audiences)) notes.audience = true;
|
|
133686
|
+
noteUnqualified(
|
|
133687
|
+
gold,
|
|
133688
|
+
suggestions,
|
|
133689
|
+
"audienceQualified",
|
|
133690
|
+
"\u53D7\u4F17\u7FA4\u4F53\u8BBE\u7F6E",
|
|
133691
|
+
hasAudienceRows(audiences),
|
|
133692
|
+
presentBecause("\u8D26\u6237\u91CC\u5DF2\u6709\u53D7\u4F17\uFF0C")
|
|
133693
|
+
);
|
|
133694
|
+
if (campaignsUseBidding(evidence.campaigns ?? [])) notes.bidding = true;
|
|
133695
|
+
noteUnqualified(
|
|
133696
|
+
gold,
|
|
133697
|
+
suggestions,
|
|
133698
|
+
"biddingPolicyQualified",
|
|
133699
|
+
"\u51FA\u4EF7\u7B56\u7565",
|
|
133700
|
+
campaignsUseBidding(evidence.campaigns ?? []),
|
|
133701
|
+
presentBecause("\u7CFB\u5217\u5DF2\u8BBE\u7F6E\u51FA\u4EF7\u7B56\u7565\uFF0C")
|
|
133702
|
+
);
|
|
133703
|
+
if (Object.keys(suggestions).length > 0) next.goldItemSuggestions = suggestions;
|
|
133704
|
+
if (Object.keys(notes).length > 0) next.goldAssetNotes = notes;
|
|
133613
133705
|
return next;
|
|
133614
133706
|
}
|
|
133615
133707
|
function parsePeriod(period) {
|
|
@@ -133617,24 +133709,23 @@ function parsePeriod(period) {
|
|
|
133617
133709
|
if (!matched) return {};
|
|
133618
133710
|
return { start: matched[1], end: matched[2] };
|
|
133619
133711
|
}
|
|
133712
|
+
function loadEvidence(snapDir, accountId, start, end) {
|
|
133713
|
+
const items3 = (section) => sectionItems(loadSectionSnapshot(snapDir, section, accountId, start, end));
|
|
133714
|
+
return {
|
|
133715
|
+
ads: items3("ads"),
|
|
133716
|
+
extensions: items3("extensions"),
|
|
133717
|
+
conversionActions: items3("conversion-actions"),
|
|
133718
|
+
audiences: items3("audience"),
|
|
133719
|
+
campaigns: items3("campaigns")
|
|
133720
|
+
};
|
|
133721
|
+
}
|
|
133620
133722
|
function reconcileGoldAccountInReport(data, snapDir) {
|
|
133621
133723
|
const gold = asRecord7(data.goldAccount) ?? {};
|
|
133622
133724
|
const account = asRecord7(data.accountInfo);
|
|
133623
133725
|
const accountId = String(account?.companyId ?? "").replace(/\D/g, "");
|
|
133624
133726
|
const { start, end } = parsePeriod(String(account?.period ?? ""));
|
|
133625
|
-
const evidence = {};
|
|
133626
|
-
|
|
133627
|
-
evidence.conversionActions = sectionItems(
|
|
133628
|
-
loadSectionSnapshot(snapDir, "conversion-actions", accountId, start, end)
|
|
133629
|
-
);
|
|
133630
|
-
evidence.extensions = sectionItems(
|
|
133631
|
-
loadSectionSnapshot(snapDir, "extensions", accountId, start, end)
|
|
133632
|
-
);
|
|
133633
|
-
evidence.audiences = sectionItems(loadSectionSnapshot(snapDir, "audience", accountId, start, end));
|
|
133634
|
-
evidence.ads = sectionItems(loadSectionSnapshot(snapDir, "ads", accountId, start, end));
|
|
133635
|
-
}
|
|
133636
|
-
const next = reconcileGoldAccount(gold, evidence);
|
|
133637
|
-
return { ...data, goldAccount: next };
|
|
133727
|
+
const evidence = snapDir && accountId ? loadEvidence(snapDir, accountId, start, end) : {};
|
|
133728
|
+
return { ...data, goldAccount: reconcileGoldAccount(gold, evidence) };
|
|
133638
133729
|
}
|
|
133639
133730
|
|
|
133640
133731
|
// src/commands/google-ads-diagnosis/default-section-data.ts
|
|
@@ -134281,7 +134372,8 @@ function buildGoogleAdsDiagnosisCollectPayload(opts) {
|
|
|
134281
134372
|
conversionActions: conversionRows,
|
|
134282
134373
|
extensions: extensionRows,
|
|
134283
134374
|
audiences: audienceRows,
|
|
134284
|
-
ads: adRows
|
|
134375
|
+
ads: adRows,
|
|
134376
|
+
campaigns: campaignCurrent
|
|
134285
134377
|
});
|
|
134286
134378
|
data.goldAccount = goldRecord;
|
|
134287
134379
|
data.fullAudience = {
|
|
@@ -134426,6 +134518,7 @@ function narrativeChecklist(shapes) {
|
|
|
134426
134518
|
const lines = [
|
|
134427
134519
|
"- `accountInfo.businessModel`\u3001`accountInfo.industry`",
|
|
134428
134520
|
'- `diagnosisOverview.advantages`\u3001`diagnosisOverview.disadvantages`\uFF1A\u6BCF\u6761 `{"title":"\u77ED\u6807\u9898","description":"\u4F9D\u636E"}`\u3002\u7EAF\u5B57\u7B26\u4E32\u4F1A\u5728 render \u65F6\u6309\u7B2C\u4E00\u4E2A\u300C\uFF1A\u300D\u62C6\u5F00\uFF1B\u7F3A title \u6216 description \u5219\u62D2\u7EDD\u51FA HTML\uFF08\u5426\u5219\u9875\u9762\u663E\u793A\u300C\u672A\u586B\u5199\u300D\uFF09',
|
|
134521
|
+
"- \u9EC4\u91D1\u8D26\u6237\u8868\u3001\u9884\u7B97\u7ADE\u4E89\u529B strategy\u3001\u51FA\u4EF7 recommendationReason\u3001\u65B0\u4EA7\u54C1 optimizerRecommendation\u3001\u521B\u610F\u884C suggestion \u7531 render \u6309\u6570\u636E\u5199\u5165\uFF0CAgent \u4E0D\u8981\u586B",
|
|
134429
134522
|
"- `summary.keyIssues`\u3001`summary.optimizationRoadmap`"
|
|
134430
134523
|
];
|
|
134431
134524
|
for (const shape of shapes) {
|
|
@@ -134433,10 +134526,6 @@ function narrativeChecklist(shapes) {
|
|
|
134433
134526
|
lines.push(`- \`${shape.section}.analysis\`\u3001\`${shape.section}.suggestions\``);
|
|
134434
134527
|
}
|
|
134435
134528
|
}
|
|
134436
|
-
lines.push("- `budgetCompetitiveness.items[].strategy`");
|
|
134437
|
-
lines.push("- `biddingStrategy.items[].recommendationReason`");
|
|
134438
|
-
lines.push("- `newFeatures.items[].optimizerRecommendation`");
|
|
134439
|
-
lines.push("- `adCreativeOptimization.items[].suggestion`\uFF08\u6BCF\u884C\u72EC\u7ACB\uFF0C\u7981\u6B62\u590D\u5236\u540C\u4E00\u53E5\uFF09");
|
|
134440
134529
|
return lines;
|
|
134441
134530
|
}
|
|
134442
134531
|
function buildCollectDigest(reportData, meta) {
|
|
@@ -134806,7 +134895,7 @@ function validateBudgetCompetitivenessStrategies(data) {
|
|
|
134806
134895
|
const row = asRecord11(items3[i]);
|
|
134807
134896
|
const name2 = String(row?.name ?? row?.metric ?? i);
|
|
134808
134897
|
if (!hasNarrativeContent(row?.strategy)) {
|
|
134809
|
-
warnings.push(`budgetCompetitiveness[${name2}].strategy \u4E3A\u7A7A\
|
|
134898
|
+
warnings.push(`budgetCompetitiveness[${name2}].strategy \u4E3A\u7A7A\uFF08render \u4F1A\u6309\u672C\u671F\u6570\u503C\u4E0E\u6807\u51C6\u751F\u6210\uFF0C\u4E0D\u5E94\u7531 Agent \u586B\u5199\uFF09`);
|
|
134810
134899
|
}
|
|
134811
134900
|
}
|
|
134812
134901
|
return warnings;
|
|
@@ -134821,7 +134910,7 @@ function validateNewFeatureRecommendations(data) {
|
|
|
134821
134910
|
const row = asRecord11(items3[i]);
|
|
134822
134911
|
const name2 = String(row?.strategyName ?? row?.feature ?? row?.strategy ?? i);
|
|
134823
134912
|
if (!hasNarrativeContent(row?.optimizerRecommendation)) {
|
|
134824
|
-
warnings.push(`newFeatures.items[${name2}].optimizerRecommendation \u4E3A\u7A7A\
|
|
134913
|
+
warnings.push(`newFeatures.items[${name2}].optimizerRecommendation \u4E3A\u7A7A\uFF08render \u4F1A\u6309\u542F\u7528\u72B6\u6001\u751F\u6210\uFF0C\u4E0D\u5E94\u7531 Agent \u586B\u5199\uFF09`);
|
|
134825
134914
|
}
|
|
134826
134915
|
}
|
|
134827
134916
|
return warnings;
|
|
@@ -134856,7 +134945,7 @@ function validateAdCreativeItemSuggestions(data) {
|
|
|
134856
134945
|
const row = asRecord11(items3[i]);
|
|
134857
134946
|
const title = String(row?.adTitle ?? i);
|
|
134858
134947
|
if (!hasNarrativeContent(row?.suggestion ?? row?.suggestions)) {
|
|
134859
|
-
warnings.push(`adCreativeOptimization.items[${title}].suggestion \u4E3A\u7A7A\
|
|
134948
|
+
warnings.push(`adCreativeOptimization.items[${title}].suggestion \u4E3A\u7A7A\uFF08render \u4F1A\u6309\u6807\u9898/\u63CF\u8FF0\u6761\u6570\u751F\u6210\uFF0C\u4E0D\u5E94\u7531 Agent \u586B\u5199\uFF09`);
|
|
134860
134949
|
}
|
|
134861
134950
|
}
|
|
134862
134951
|
return warnings;
|
|
@@ -134960,7 +135049,7 @@ var MODULE_ITEM_ERROR_HINT = {
|
|
|
134960
135049
|
geographic: "\u7F3A\u5C11 title/currentCost/currentClicks \u6216\u73AF\u6BD4\u5B57\u6BB5\u88AB\u5199\u6210\u5B57\u7B26\u4E32\uFF08\u987B\u4FDD\u7559 collect \u4E8B\u5B9E\u884C\uFF0C\u4EC5\u7531 Agent \u586B\u5199 analysis/suggestions\uFF09",
|
|
134961
135050
|
keywords: "\u7F3A\u5C11 title/currentCost/currentClicks \u6216\u73AF\u6BD4\u5B57\u6BB5\u88AB\u5199\u6210\u5B57\u7B26\u4E32\uFF08\u987B\u4FDD\u7559 collect \u4E8B\u5B9E\u884C\uFF0C\u4EC5\u7531 Agent \u586B\u5199 analysis/suggestions\uFF09",
|
|
134962
135051
|
biddingStrategy: "\u7F3A\u5C11 campaignName/duration(\u5929\u6570)/biddingStrategyType\uFF08Agent \u52FF\u628A duration \u5199\u6210\u6587\u6848\u5B57\u7B26\u4E32\uFF0C\u52FF\u7528 currentStrategy \u66FF\u4EE3 biddingStrategyType\uFF09",
|
|
134963
|
-
newFeatures: "\u7F3A\u5C11 strategyName/strategy\uFF08collect \u4E8B\u5B9E\u884C\
|
|
135052
|
+
newFeatures: "\u7F3A\u5C11 strategyName/strategy\uFF08collect \u4E8B\u5B9E\u884C\uFF1BoptimizerRecommendation \u7531 render \u6309 accountStatus \u751F\u6210\uFF0C\u52FF\u6539\u7528 feature \u5B57\u6BB5\u66FF\u4EE3 strategyName\uFF09"
|
|
134964
135053
|
};
|
|
134965
135054
|
function moduleItemsNeedRestore(items3, validator) {
|
|
134966
135055
|
if (!Array.isArray(items3) || items3.length === 0) return false;
|
|
@@ -135124,6 +135213,61 @@ var NARRATIVE_CONSISTENCY_RULES = [
|
|
|
135124
135213
|
hint: "\u7740\u9646\u9875\u6D4B\u901F\u672A\u83B7\u53D6\u662F Lighthouse API \u5931\u8D25\uFF0C\u4E0D\u662F\u8D26\u6237\u6295\u653E\u6838\u5FC3\u95EE\u9898\u3002\u7981\u6B62\u5199\u5165 keyIssues/disadvantages\uFF1B\u4EC5\u5728 \xA707 landingPageAnalysis.analysis \u8BF4\u660E source=none\u3002"
|
|
135125
135214
|
}
|
|
135126
135215
|
];
|
|
135216
|
+
function goldAssetNoted(data, key) {
|
|
135217
|
+
const notes = asRecord13(asRecord13(data.goldAccount)?.goldAssetNotes);
|
|
135218
|
+
return notes?.[key] === true;
|
|
135219
|
+
}
|
|
135220
|
+
var GOLD_CLAIM_RULES = [
|
|
135221
|
+
{
|
|
135222
|
+
id: "ga-already-linked",
|
|
135223
|
+
textPattern: /(请将|请把|未将).{0,40}(Google Analytics|GA4|GA).{0,24}关联|(Google Analytics|GA4|GA).{0,12}未关联|未关联.{0,12}(Google Analytics|GA4|GA)/,
|
|
135224
|
+
isContradicted: (data) => goldAccountFlag(data, "gaConfigured") === true || goldAssetNoted(data, "ga4"),
|
|
135225
|
+
hint: "GA \u8054\u7ED3\u5DF2\u8FBE\u6807\uFF0C\u6216\u8F6C\u5316\u52A8\u4F5C\u91CC\u5DF2\u6709\u542F\u7528\u7684 Google Analytics \u8F6C\u5316\u3002\u7981\u6B62\u5199\u6210\u300C\u8BF7\u5173\u8054 / \u672A\u5173\u8054\u300D\u3002\u672A\u8FBE\u6807\u4E0D\u7B49\u4E8E\u8D26\u6237\u91CC\u6CA1\u6709\u8FD9\u4E9B\u8F6C\u5316\u3002"
|
|
135226
|
+
},
|
|
135227
|
+
{
|
|
135228
|
+
id: "text-ads-already-exist",
|
|
135229
|
+
textPattern: /请创建文字广告|没有文字广告|缺少文字广告|未创建文字广告/,
|
|
135230
|
+
isContradicted: (data) => goldAssetNoted(data, "textAds") || goldAccountFlag(data, "expandedTextAdQualified") === true || goldAccountFlag(data, "responsiveSearchAdQualified") === true,
|
|
135231
|
+
hint: "\u8D26\u6237\u5DF2\u6709\u641C\u7D22\u6587\u5B57\u5E7F\u544A\u3002\u6587\u5B57\u5E7F\u544A\u9879\u672A\u8FBE\u6807\u4E0D\u7B49\u4E8E\u6CA1\u6709\u5E7F\u544A\uFF0C\u7981\u6B62\u5199\u300C\u8BF7\u521B\u5EFA\u6587\u5B57\u5E7F\u544A\u300D\u3002"
|
|
135232
|
+
},
|
|
135233
|
+
{
|
|
135234
|
+
id: "callout-already-exists",
|
|
135235
|
+
textPattern: /请添加宣传信息|缺少宣传信息|没有宣传信息|未添加宣传信息/,
|
|
135236
|
+
isContradicted: (data) => goldAssetNoted(data, "callout") || goldAccountFlag(data, "adsCalloutExtensionQualified") === true,
|
|
135237
|
+
hint: "\u5DF2\u6709\u542F\u7528\u7684\u5BA3\u4F20\u4FE1\u606F\uFF0C\u6216\u8BE5\u9879\u5DF2\u8FBE\u6807\u3002\u7981\u6B62\u5199\u300C\u8BF7\u6DFB\u52A0\u5BA3\u4F20\u4FE1\u606F\u300D\u3002\u672A\u8FBE\u6807\u4E0D\u8868\u793A\u8D26\u6237\u91CC\u6CA1\u6709\u3002"
|
|
135238
|
+
},
|
|
135239
|
+
{
|
|
135240
|
+
id: "snippet-already-exists",
|
|
135241
|
+
textPattern: /请添加结构化信息摘要|缺少结构化信息摘要|没有结构化摘要|未添加结构化/,
|
|
135242
|
+
isContradicted: (data) => goldAssetNoted(data, "snippet") || goldAccountFlag(data, "adsStructuredSnippetExtensionQualified") === true,
|
|
135243
|
+
hint: "\u5DF2\u6709\u542F\u7528\u7684\u7ED3\u6784\u5316\u4FE1\u606F\u6458\u8981\uFF0C\u6216\u8BE5\u9879\u5DF2\u8FBE\u6807\u3002\u7981\u6B62\u5199\u300C\u8BF7\u6DFB\u52A0\u7ED3\u6784\u5316\u4FE1\u606F\u6458\u8981\u300D\u3002"
|
|
135244
|
+
},
|
|
135245
|
+
{
|
|
135246
|
+
id: "audience-already-exists",
|
|
135247
|
+
textPattern: /请设置受众|未设置受众|没有受众群体|缺少受众群体/,
|
|
135248
|
+
isContradicted: (data) => goldAssetNoted(data, "audience") || goldAccountFlag(data, "audienceQualified") === true,
|
|
135249
|
+
hint: "\u53D7\u4F17\u62A5\u8868\u91CC\u5DF2\u6709\u53D7\u4F17\uFF0C\u6216\u8BE5\u9879\u5DF2\u8FBE\u6807\u3002\u7981\u6B62\u5199\u300C\u8BF7\u8BBE\u7F6E\u53D7\u4F17\u7FA4\u4F53\u300D\u3002"
|
|
135250
|
+
},
|
|
135251
|
+
{
|
|
135252
|
+
id: "display-ads-already-exist",
|
|
135253
|
+
textPattern: /请使用自适应展示广告|没有自适应展示广告|未创建展示广告/,
|
|
135254
|
+
isContradicted: (data) => goldAssetNoted(data, "displayAds") || goldAccountFlag(data, "multiAssetResponsiveDisplayAdQualified") === true,
|
|
135255
|
+
hint: "\u5DF2\u6709\u81EA\u9002\u5E94\u5C55\u793A\u5E7F\u544A\u3002\u672A\u8FBE\u6807\u4E0D\u7B49\u4E8E\u6CA1\u6709\u5E7F\u544A\uFF1B\u7CFB\u5217\u6682\u505C\u65F6\u5199\u300C\u5C55\u793A\u7CFB\u5217\u5DF2\u6682\u505C\uFF0C\u672C\u671F\u65E0\u6D88\u8017\u300D\uFF0C\u7981\u6B62\u5199\u300C\u8BF7\u4F7F\u7528\u300D\u3002"
|
|
135256
|
+
}
|
|
135257
|
+
];
|
|
135258
|
+
function collectGoldClaimTexts(data) {
|
|
135259
|
+
const texts = collectNarrativeTexts(data);
|
|
135260
|
+
const overview = asRecord13(data.diagnosisOverview);
|
|
135261
|
+
for (const key of ["advantages", "disadvantages"]) {
|
|
135262
|
+
const items3 = overview?.[key];
|
|
135263
|
+
if (!Array.isArray(items3)) continue;
|
|
135264
|
+
for (const item of items3) {
|
|
135265
|
+
const rec = asRecord13(item);
|
|
135266
|
+
if (rec) texts.push(String(rec.title ?? ""), String(rec.description ?? ""));
|
|
135267
|
+
}
|
|
135268
|
+
}
|
|
135269
|
+
return texts.filter((text2) => text2.trim().length > 0);
|
|
135270
|
+
}
|
|
135127
135271
|
function findIdenticalTexts(texts, minCount) {
|
|
135128
135272
|
const counts = /* @__PURE__ */ new Map();
|
|
135129
135273
|
for (const t of texts) {
|
|
@@ -135185,6 +135329,13 @@ function getNarrativeConsistencyErrors(data) {
|
|
|
135185
135329
|
errors.push(`\u53D9\u4E8B\u77DB\u76FE\uFF08${rule.id}\uFF09\uFF1A\u300C${hitText}\u300D\u2014\u2014 ${rule.hint}`);
|
|
135186
135330
|
}
|
|
135187
135331
|
}
|
|
135332
|
+
const goldClaimTexts = collectGoldClaimTexts(data);
|
|
135333
|
+
for (const rule of GOLD_CLAIM_RULES) {
|
|
135334
|
+
const hitText = goldClaimTexts.find((t) => rule.textPattern.test(t));
|
|
135335
|
+
if (hitText && rule.isContradicted(data)) {
|
|
135336
|
+
errors.push(`\u53D9\u4E8B\u77DB\u76FE\uFF08${rule.id}\uFF09\uFF1A\u300C${hitText}\u300D\u2014\u2014 ${rule.hint}`);
|
|
135337
|
+
}
|
|
135338
|
+
}
|
|
135188
135339
|
errors.push(...getRepetitiveNarrativeErrors(data));
|
|
135189
135340
|
errors.push(...getLandingPageTopicErrors(data));
|
|
135190
135341
|
return errors;
|
|
@@ -135257,8 +135408,118 @@ function normalizeDiagnosisOverview(data) {
|
|
|
135257
135408
|
};
|
|
135258
135409
|
}
|
|
135259
135410
|
|
|
135260
|
-
// src/commands/google-ads-diagnosis/
|
|
135411
|
+
// src/commands/google-ads-diagnosis/data-rendered-copy.ts
|
|
135261
135412
|
function asRecord15(value) {
|
|
135413
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
135414
|
+
return value;
|
|
135415
|
+
}
|
|
135416
|
+
return null;
|
|
135417
|
+
}
|
|
135418
|
+
function compareToBenchmark(reportValue, benchmark) {
|
|
135419
|
+
const value = Number(reportValue.replace(/[^\d.]/g, ""));
|
|
135420
|
+
const matched = benchmark.match(/(≥|>=|≤|<=|>|<)\s*([\d.]+)/);
|
|
135421
|
+
if (!Number.isFinite(value) || !matched) return "\u5BF9\u7167\u6807\u51C6\u89C1\u672C\u884C";
|
|
135422
|
+
const bar = Number(matched[2]);
|
|
135423
|
+
const op = matched[1];
|
|
135424
|
+
const reached = op === "\u2265" || op === ">=" ? value >= bar : op === ">" ? value > bar : op === "\u2264" || op === "<=" ? value <= bar : value < bar;
|
|
135425
|
+
return reached ? "\u8FBE\u5230\u672C\u884C\u6807\u51C6" : "\u672A\u8FBE\u5230\u672C\u884C\u6807\u51C6";
|
|
135426
|
+
}
|
|
135427
|
+
function budgetStrategyFromRow(row) {
|
|
135428
|
+
const name2 = String(row.name ?? row.metric ?? "\u8BE5\u9879");
|
|
135429
|
+
const reportValue = String(row.reportValue ?? "\u2014");
|
|
135430
|
+
const benchmark = String(row.benchmark ?? "\u2014");
|
|
135431
|
+
return `${name2}\u672C\u671F\u4E3A ${reportValue}\uFF0C\u6807\u51C6 ${benchmark}\uFF0C${compareToBenchmark(reportValue, benchmark)}\u3002`;
|
|
135432
|
+
}
|
|
135433
|
+
function biddingReasonFromRow(row) {
|
|
135434
|
+
const name2 = String(row.campaignName ?? "\u8BE5\u7CFB\u5217");
|
|
135435
|
+
const current = String(row.biddingStrategyType ?? row.currentStrategy ?? "\u672A\u77E5");
|
|
135436
|
+
const recommended = String(row.recommendedStrategy ?? "\u2014");
|
|
135437
|
+
if (row.isCorrect === true) {
|
|
135438
|
+
return `${name2}\u5F53\u524D\u51FA\u4EF7\u7B56\u7565\u4E3A ${current}\uFF0C\u4E0E\u672C\u671F\u5EFA\u8BAE ${recommended} \u4E00\u81F4\u3002`;
|
|
135439
|
+
}
|
|
135440
|
+
return `${name2}\u5F53\u524D\u51FA\u4EF7\u7B56\u7565\u4E3A ${current}\uFF0C\u672C\u671F\u5BF9\u7167\u5EFA\u8BAE\u4E3A ${recommended}\u3002`;
|
|
135441
|
+
}
|
|
135442
|
+
function featureRecommendationFromRow(row) {
|
|
135443
|
+
const name2 = String(row.strategyName ?? row.strategy ?? "\u8BE5\u80FD\u529B");
|
|
135444
|
+
if (row.accountStatus === true) return `${name2}\uFF1A\u8D26\u6237\u5DF2\u542F\u7528\u3002`;
|
|
135445
|
+
return `${name2}\uFF1A\u672C\u671F\u672A\u68C0\u6D4B\u5230\u5BF9\u5E94\u7CFB\u5217\u3002`;
|
|
135446
|
+
}
|
|
135447
|
+
function creativeSuggestionFromRow(row) {
|
|
135448
|
+
const title = String(row.adTitle ?? "\u8BE5\u5E7F\u544A");
|
|
135449
|
+
const headlines = row.headlinesCount ?? "\u2014";
|
|
135450
|
+
const descriptions = row.descriptionsCount ?? "\u2014";
|
|
135451
|
+
const headlinesStatus = String(row.headlinesStatus ?? "\u2014");
|
|
135452
|
+
const descriptionsStatus = String(row.descriptionsStatus ?? "\u2014");
|
|
135453
|
+
return `${title}\uFF1A\u6807\u9898 ${headlines} \u6761\uFF08${headlinesStatus}\uFF09\uFF0C\u63CF\u8FF0 ${descriptions} \u6761\uFF08${descriptionsStatus}\uFF09\u3002`;
|
|
135454
|
+
}
|
|
135455
|
+
function distinctCopies(rows, key) {
|
|
135456
|
+
const counts = /* @__PURE__ */ new Map();
|
|
135457
|
+
for (const row of rows) {
|
|
135458
|
+
const text2 = String(row[key] ?? "");
|
|
135459
|
+
counts.set(text2, (counts.get(text2) ?? 0) + 1);
|
|
135460
|
+
}
|
|
135461
|
+
const seen = /* @__PURE__ */ new Map();
|
|
135462
|
+
return rows.map((row) => {
|
|
135463
|
+
const text2 = String(row[key] ?? "");
|
|
135464
|
+
if ((counts.get(text2) ?? 0) < 3) return row;
|
|
135465
|
+
const n = (seen.get(text2) ?? 0) + 1;
|
|
135466
|
+
seen.set(text2, n);
|
|
135467
|
+
return { ...row, [key]: `${text2}\uFF08\u540C\u7ED3\u6784\u7B2C ${n} \u6761\uFF09` };
|
|
135468
|
+
});
|
|
135469
|
+
}
|
|
135470
|
+
function mapRows(rows, write) {
|
|
135471
|
+
if (!Array.isArray(rows)) return rows;
|
|
135472
|
+
const written = rows.map((item) => {
|
|
135473
|
+
const row = asRecord15(item);
|
|
135474
|
+
return row ? write(row) : item;
|
|
135475
|
+
});
|
|
135476
|
+
return written;
|
|
135477
|
+
}
|
|
135478
|
+
function applyDataRenderedCopy(data) {
|
|
135479
|
+
const next = { ...data };
|
|
135480
|
+
const budgetRows = mapRows(data.budgetCompetitiveness, (row) => ({
|
|
135481
|
+
...row,
|
|
135482
|
+
strategy: budgetStrategyFromRow(row)
|
|
135483
|
+
}));
|
|
135484
|
+
if (Array.isArray(budgetRows)) {
|
|
135485
|
+
next.budgetCompetitiveness = distinctCopies(budgetRows, "strategy");
|
|
135486
|
+
}
|
|
135487
|
+
const bidding = asRecord15(data.biddingStrategy);
|
|
135488
|
+
if (bidding) {
|
|
135489
|
+
next.biddingStrategy = {
|
|
135490
|
+
...bidding,
|
|
135491
|
+
items: mapRows(bidding.items, (row) => ({
|
|
135492
|
+
...row,
|
|
135493
|
+
recommendationReason: biddingReasonFromRow(row)
|
|
135494
|
+
}))
|
|
135495
|
+
};
|
|
135496
|
+
}
|
|
135497
|
+
const features = asRecord15(data.newFeatures);
|
|
135498
|
+
if (features) {
|
|
135499
|
+
next.newFeatures = {
|
|
135500
|
+
...features,
|
|
135501
|
+
items: mapRows(features.items, (row) => ({
|
|
135502
|
+
...row,
|
|
135503
|
+
optimizerRecommendation: featureRecommendationFromRow(row)
|
|
135504
|
+
}))
|
|
135505
|
+
};
|
|
135506
|
+
}
|
|
135507
|
+
const creative = asRecord15(data.adCreativeOptimization);
|
|
135508
|
+
if (creative) {
|
|
135509
|
+
const creativeRows = mapRows(creative.items, (row) => ({
|
|
135510
|
+
...row,
|
|
135511
|
+
suggestion: creativeSuggestionFromRow(row)
|
|
135512
|
+
}));
|
|
135513
|
+
next.adCreativeOptimization = {
|
|
135514
|
+
...creative,
|
|
135515
|
+
items: Array.isArray(creativeRows) ? distinctCopies(creativeRows, "suggestion") : creativeRows
|
|
135516
|
+
};
|
|
135517
|
+
}
|
|
135518
|
+
return next;
|
|
135519
|
+
}
|
|
135520
|
+
|
|
135521
|
+
// src/commands/google-ads-diagnosis/render-report.ts
|
|
135522
|
+
function asRecord16(value) {
|
|
135262
135523
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
135263
135524
|
return value;
|
|
135264
135525
|
}
|
|
@@ -135267,8 +135528,8 @@ function asRecord15(value) {
|
|
|
135267
135528
|
async function tryLoadCollectReportData(collectPath) {
|
|
135268
135529
|
try {
|
|
135269
135530
|
const raw = JSON.parse(await fs22.readFile(collectPath, "utf8"));
|
|
135270
|
-
const root =
|
|
135271
|
-
const reportData =
|
|
135531
|
+
const root = asRecord16(raw);
|
|
135532
|
+
const reportData = asRecord16(root?.reportData);
|
|
135272
135533
|
return reportData ?? root;
|
|
135273
135534
|
} catch {
|
|
135274
135535
|
return null;
|
|
@@ -135285,7 +135546,7 @@ async function runGoogleAdsDiagnosisRender(opts) {
|
|
|
135285
135546
|
`);
|
|
135286
135547
|
process.exit(1);
|
|
135287
135548
|
}
|
|
135288
|
-
let data =
|
|
135549
|
+
let data = asRecord16(dataRaw);
|
|
135289
135550
|
if (!opts.noMergeCollect) {
|
|
135290
135551
|
const collectPath = path26.resolve(
|
|
135291
135552
|
opts.collectFile ?? path26.join(path26.dirname(dataPath), GOOGLE_ADS_DIAGNOSIS_COLLECT_BASENAME)
|
|
@@ -135318,6 +135579,7 @@ async function runGoogleAdsDiagnosisRender(opts) {
|
|
|
135318
135579
|
}
|
|
135319
135580
|
}
|
|
135320
135581
|
data = reconcileGoldAccountInReport(data, path26.dirname(dataPath));
|
|
135582
|
+
data = applyDataRenderedCopy(data);
|
|
135321
135583
|
const overview = normalizeDiagnosisOverview(data);
|
|
135322
135584
|
data = overview.data;
|
|
135323
135585
|
if (overview.coerced.length > 0) {
|
|
@@ -135365,7 +135627,7 @@ async function runGoogleAdsDiagnosisRender(opts) {
|
|
|
135365
135627
|
\u274C ${formatGoogleAdsDiagnosisContentErrors(contentCheck)}
|
|
135366
135628
|
`);
|
|
135367
135629
|
console.error(
|
|
135368
|
-
" \u987B\u5148\u7531 Agent \u8865\u5168\
|
|
135630
|
+
" \u987B\u5148\u7531 Agent \u8865\u5168\u4E3B\u89C2\u5206\u6790\uFF08\u5404\u6A21\u5757 analysis/suggestions\u3001\u8BCA\u65AD\u6982\u89C8\u3001\u603B\u7ED3\u3001\u4E1A\u52A1\u6A21\u5F0F\u4E0E\u884C\u4E1A\uFF09\u540E\u518D render\uFF1B\u8C03\u8BD5\u53EF\u52A0 --lenient\u3002\n"
|
|
135369
135631
|
);
|
|
135370
135632
|
process.exit(1);
|
|
135371
135633
|
}
|
|
@@ -136626,26 +136888,26 @@ import fs26 from "fs/promises";
|
|
|
136626
136888
|
import path31 from "path";
|
|
136627
136889
|
|
|
136628
136890
|
// src/commands/google-quarterly/report-content.ts
|
|
136629
|
-
function
|
|
136891
|
+
function asRecord17(value) {
|
|
136630
136892
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
136631
136893
|
}
|
|
136632
136894
|
function asStringArray(value) {
|
|
136633
136895
|
return Array.isArray(value) ? value.map((x) => String(x).trim()).filter(Boolean) : [];
|
|
136634
136896
|
}
|
|
136635
136897
|
function validateQuarterlyNarrative(data) {
|
|
136636
|
-
const root =
|
|
136637
|
-
const narrative =
|
|
136898
|
+
const root = asRecord17(data);
|
|
136899
|
+
const narrative = asRecord17(root?.narrative);
|
|
136638
136900
|
const missing = [];
|
|
136639
136901
|
if (!narrative) {
|
|
136640
136902
|
return { ok: false, missing: ["narrative"] };
|
|
136641
136903
|
}
|
|
136642
136904
|
if (asStringArray(narrative.executiveSummary).length < 1) missing.push("narrative.executiveSummary");
|
|
136643
|
-
const sections =
|
|
136905
|
+
const sections = asRecord17(narrative.sections);
|
|
136644
136906
|
for (const key of ["efficiency", "adType", "region", "summary"]) {
|
|
136645
|
-
const block =
|
|
136907
|
+
const block = asRecord17(sections?.[key]);
|
|
136646
136908
|
if (asStringArray(block?.analysis).length < 1) missing.push(`narrative.sections.${key}.analysis`);
|
|
136647
136909
|
}
|
|
136648
|
-
const plan =
|
|
136910
|
+
const plan = asRecord17(narrative.plan);
|
|
136649
136911
|
if (asStringArray(plan?.analysis ?? plan?.goals).length < 1 && !String(plan?.text ?? "").trim()) {
|
|
136650
136912
|
missing.push("narrative.plan");
|
|
136651
136913
|
}
|
|
@@ -136658,8 +136920,8 @@ function mergeCollectFacts(agentData, collect) {
|
|
|
136658
136920
|
...facts,
|
|
136659
136921
|
narrative: agentData.narrative ?? collect.narrative,
|
|
136660
136922
|
meta: {
|
|
136661
|
-
...
|
|
136662
|
-
...
|
|
136923
|
+
...asRecord17(collect.meta) ?? {},
|
|
136924
|
+
...asRecord17(agentData.meta) ?? {}
|
|
136663
136925
|
}
|
|
136664
136926
|
};
|
|
136665
136927
|
}
|
|
@@ -136671,7 +136933,7 @@ import { fileURLToPath as fileURLToPath8 } from "url";
|
|
|
136671
136933
|
var TSO_CLI_ROOT = path30.join(path30.dirname(fileURLToPath8(import.meta.url)), "../..");
|
|
136672
136934
|
|
|
136673
136935
|
// src/commands/google-quarterly/render-report.ts
|
|
136674
|
-
function
|
|
136936
|
+
function asRecord18(value) {
|
|
136675
136937
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
136676
136938
|
return value;
|
|
136677
136939
|
}
|
|
@@ -136700,7 +136962,7 @@ async function runGoogleQuarterlyRender(opts) {
|
|
|
136700
136962
|
`);
|
|
136701
136963
|
process.exit(1);
|
|
136702
136964
|
}
|
|
136703
|
-
const merged = mergeCollectFacts(
|
|
136965
|
+
const merged = mergeCollectFacts(asRecord18(agentRaw), asRecord18(collectRaw));
|
|
136704
136966
|
const check = validateQuarterlyNarrative(merged);
|
|
136705
136967
|
if (!check.ok && !opts.lenient) {
|
|
136706
136968
|
console.error("\n\u274C narrative \u4E0D\u5B8C\u6574\uFF0C\u62D2\u7EDD\u51FA HTML\uFF1A\n");
|
|
@@ -136864,7 +137126,7 @@ import * as fs33 from "fs/promises";
|
|
|
136864
137126
|
import * as path40 from "path";
|
|
136865
137127
|
|
|
136866
137128
|
// src/commands/facebook-analysis/report-metrics.ts
|
|
136867
|
-
function
|
|
137129
|
+
function asRecord24(value) {
|
|
136868
137130
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
136869
137131
|
return value;
|
|
136870
137132
|
}
|
|
@@ -137001,7 +137263,7 @@ function localizeFacebookReportLabels(payload) {
|
|
|
137001
137263
|
for (const rows of Object.values(tables)) {
|
|
137002
137264
|
if (!Array.isArray(rows)) continue;
|
|
137003
137265
|
for (const row of rows) {
|
|
137004
|
-
localizeMetricLabels(
|
|
137266
|
+
localizeMetricLabels(asRecord24(row));
|
|
137005
137267
|
}
|
|
137006
137268
|
}
|
|
137007
137269
|
return payload;
|
|
@@ -137034,7 +137296,7 @@ async function readManifest3(snapshotDir) {
|
|
|
137034
137296
|
async function loadSectionFile3(snapshotDir, file) {
|
|
137035
137297
|
try {
|
|
137036
137298
|
const raw = await fs33.readFile(path40.join(snapshotDir, file), "utf8");
|
|
137037
|
-
return
|
|
137299
|
+
return asRecord24(JSON.parse(raw));
|
|
137038
137300
|
} catch {
|
|
137039
137301
|
return null;
|
|
137040
137302
|
}
|
|
@@ -137090,7 +137352,7 @@ async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
|
|
|
137090
137352
|
if (data) sectionMap.set(art.section, data);
|
|
137091
137353
|
}
|
|
137092
137354
|
const overview = sectionMap.get("overview");
|
|
137093
|
-
const current =
|
|
137355
|
+
const current = asRecord24(overview?.currentPeriod);
|
|
137094
137356
|
const accountName = typeof overview?.accountName === "string" ? overview.accountName : void 0;
|
|
137095
137357
|
const accountId = manifest.accountId ?? (typeof overview?.accountId === "string" ? overview.accountId : void 0);
|
|
137096
137358
|
const kpis = { ...payload.kpis ?? {} };
|
|
@@ -137227,7 +137489,7 @@ function writeSimpleXlsx(filePath, sheets, opts = {}) {
|
|
|
137227
137489
|
}
|
|
137228
137490
|
|
|
137229
137491
|
// src/commands/facebook-analysis/render-excel.ts
|
|
137230
|
-
function
|
|
137492
|
+
function asRecord25(value) {
|
|
137231
137493
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
137232
137494
|
return value;
|
|
137233
137495
|
}
|
|
@@ -137275,8 +137537,8 @@ function bullets(value) {
|
|
|
137275
137537
|
return asArray3(value).map((item) => typeof item === "string" ? item.trim() : "").filter(Boolean);
|
|
137276
137538
|
}
|
|
137277
137539
|
function insightLines(section) {
|
|
137278
|
-
const rec =
|
|
137279
|
-
const insight =
|
|
137540
|
+
const rec = asRecord25(section);
|
|
137541
|
+
const insight = asRecord25(rec?.insight) ?? rec;
|
|
137280
137542
|
return [...bullets(insight?.analysis), ...bullets(insight?.advice)];
|
|
137281
137543
|
}
|
|
137282
137544
|
function numberedSection(index, title, lines) {
|
|
@@ -137285,15 +137547,15 @@ function numberedSection(index, title, lines) {
|
|
|
137285
137547
|
${body}`;
|
|
137286
137548
|
}
|
|
137287
137549
|
function buildSummaryNarrative(data) {
|
|
137288
|
-
const kpis =
|
|
137289
|
-
const meta =
|
|
137290
|
-
const sections =
|
|
137550
|
+
const kpis = asRecord25(data.kpis) ?? {};
|
|
137551
|
+
const meta = asRecord25(data.meta) ?? {};
|
|
137552
|
+
const sections = asRecord25(data.sections) ?? {};
|
|
137291
137553
|
const period = str2(meta.periodLabel) || `${str2(meta.startDate)} ~ ${str2(meta.endDate)}`.trim();
|
|
137292
137554
|
const account = str2(meta.accountName) || "Facebook \u5E7F\u544A\u8D26\u6237";
|
|
137293
137555
|
const campaign = str2(meta.campaignName);
|
|
137294
137556
|
const resultLabel = displayResultType(kpis.resultType ?? meta.resultType) || "\u6210\u6548";
|
|
137295
137557
|
const resultNoun = /潜在客户|lead/i.test(resultLabel) ? "\u4E2A\u6F5C\u5728\u5BA2\u6237\u8868\u5355" : `\u4E2A${resultLabel}`;
|
|
137296
|
-
const firstQuestion =
|
|
137558
|
+
const firstQuestion = asRecord25(asArray3(data.fourQuestions)[0]);
|
|
137297
137559
|
const extra = str2(firstQuestion?.verdict);
|
|
137298
137560
|
const spendLine = [
|
|
137299
137561
|
campaign ? `\uFF08\u5E7F\u544A\u7CFB\u5217\uFF1A${campaign}\uFF09` : "",
|
|
@@ -137313,7 +137575,7 @@ function buildSummaryNarrative(data) {
|
|
|
137313
137575
|
numberedSection(3, "\u5E7F\u544A\u9891\u6B21\u4E0E\u65E5\u8D8B\u52BF", insightLines(sections.daily))
|
|
137314
137576
|
].join("\n");
|
|
137315
137577
|
const recBlocks = asArray3(data.recommendations).map((raw, i) => {
|
|
137316
|
-
const rec =
|
|
137578
|
+
const rec = asRecord25(raw);
|
|
137317
137579
|
if (!rec) return "";
|
|
137318
137580
|
const title = [str2(rec.title), str2(rec.tag)].filter(Boolean).join(" \xB7 ");
|
|
137319
137581
|
return numberedSection(i + 1, title || "\u4F18\u5316\u5EFA\u8BAE", bullets(rec.items));
|
|
@@ -137324,9 +137586,9 @@ function buildSummaryNarrative(data) {
|
|
|
137324
137586
|
return [partOne, partTwo, partThree];
|
|
137325
137587
|
}
|
|
137326
137588
|
function buildMetaPeriodExcelSheets(data) {
|
|
137327
|
-
const meta =
|
|
137328
|
-
const kpis =
|
|
137329
|
-
const tables =
|
|
137589
|
+
const meta = asRecord25(data.meta) ?? {};
|
|
137590
|
+
const kpis = asRecord25(data.kpis) ?? {};
|
|
137591
|
+
const tables = asRecord25(data.tables) ?? {};
|
|
137330
137592
|
const currency = str2(meta.currency) || "USD";
|
|
137331
137593
|
const resultType = displayResultType(kpis.resultType ?? meta.resultType);
|
|
137332
137594
|
const attribution = displayAttribution(kpis.attributionSetting ?? meta.attributionSetting);
|
|
@@ -137345,19 +137607,19 @@ function buildMetaPeriodExcelSheets(data) {
|
|
|
137345
137607
|
];
|
|
137346
137608
|
const dailyRows = [metricHeaders(currency, "\u5355\u65E5")];
|
|
137347
137609
|
for (const raw of asArray3(tables.daily)) {
|
|
137348
|
-
const row =
|
|
137610
|
+
const row = asRecord25(raw);
|
|
137349
137611
|
if (!row) continue;
|
|
137350
137612
|
dailyRows.push([normalizeInsightDate(row.date), ...metricCells(row)]);
|
|
137351
137613
|
}
|
|
137352
137614
|
const countryRows = [metricHeaders(currency, "\u56FD\u5BB6/\u5730\u533A")];
|
|
137353
137615
|
for (const raw of asArray3(tables.countries)) {
|
|
137354
|
-
const row =
|
|
137616
|
+
const row = asRecord25(raw);
|
|
137355
137617
|
if (!row) continue;
|
|
137356
137618
|
countryRows.push([str2(row.countryOrRegion), ...metricCells(row)]);
|
|
137357
137619
|
}
|
|
137358
137620
|
const campaignRows3 = [metricHeaders(currency, "\u5E7F\u544A\u7CFB\u5217\u540D\u79F0")];
|
|
137359
137621
|
for (const raw of asArray3(tables.campaigns)) {
|
|
137360
|
-
const row =
|
|
137622
|
+
const row = asRecord25(raw);
|
|
137361
137623
|
if (!row) continue;
|
|
137362
137624
|
campaignRows3.push([str2(row.campaignName), ...metricCells(row)]);
|
|
137363
137625
|
}
|
|
@@ -137376,7 +137638,7 @@ function buildMetaPeriodExcelSheets(data) {
|
|
|
137376
137638
|
]
|
|
137377
137639
|
];
|
|
137378
137640
|
for (const raw of asArray3(tables.audiences)) {
|
|
137379
|
-
const row =
|
|
137641
|
+
const row = asRecord25(raw);
|
|
137380
137642
|
if (!row) continue;
|
|
137381
137643
|
audienceRows.push([str2(row.age), str2(row.gender), ...metricCells(row)]);
|
|
137382
137644
|
}
|
|
@@ -137408,7 +137670,7 @@ function isFiniteNumber(value) {
|
|
|
137408
137670
|
function asArray4(value) {
|
|
137409
137671
|
return Array.isArray(value) ? value : [];
|
|
137410
137672
|
}
|
|
137411
|
-
function
|
|
137673
|
+
function asRecord26(value) {
|
|
137412
137674
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
137413
137675
|
return value;
|
|
137414
137676
|
}
|
|
@@ -137421,8 +137683,8 @@ function stringList3(value) {
|
|
|
137421
137683
|
return asArray4(value).map((item) => typeof item === "string" ? item.trim() : "").filter(Boolean);
|
|
137422
137684
|
}
|
|
137423
137685
|
function insightLists(section) {
|
|
137424
|
-
const rec =
|
|
137425
|
-
const insight =
|
|
137686
|
+
const rec = asRecord26(section);
|
|
137687
|
+
const insight = asRecord26(rec?.insight) ?? rec;
|
|
137426
137688
|
return {
|
|
137427
137689
|
analysis: stringList3(insight?.analysis),
|
|
137428
137690
|
advice: stringList3(insight?.advice)
|
|
@@ -137452,11 +137714,11 @@ function requireInsight(missing, key, chapter, section, required) {
|
|
|
137452
137714
|
}
|
|
137453
137715
|
function validateMetaPeriodReportContent(data) {
|
|
137454
137716
|
const missing = [];
|
|
137455
|
-
const meta =
|
|
137456
|
-
const kpis =
|
|
137457
|
-
const tables =
|
|
137458
|
-
const charts =
|
|
137459
|
-
const sections =
|
|
137717
|
+
const meta = asRecord26(data.meta) ?? {};
|
|
137718
|
+
const kpis = asRecord26(data.kpis) ?? {};
|
|
137719
|
+
const tables = asRecord26(data.tables) ?? {};
|
|
137720
|
+
const charts = asRecord26(data.charts) ?? {};
|
|
137721
|
+
const sections = asRecord26(data.sections) ?? {};
|
|
137460
137722
|
const fourQuestions = asArray4(data.fourQuestions);
|
|
137461
137723
|
const recommendations = asArray4(data.recommendations);
|
|
137462
137724
|
if (!textLen3(meta.accountName) && !textLen3(meta.accountId)) {
|
|
@@ -137535,7 +137797,7 @@ function validateMetaPeriodReportContent(data) {
|
|
|
137535
137797
|
"\u987B\u6709 tables.audiences \u6570\u7EC4\uFF1B\u62C9\u6570\u52A0 --sections audience\uFF0Crender \u65F6\u4F20 --snapshot-dir\u3002\u672C\u671F\u65E0\u6D88\u8017\u53EF\u4E3A []"
|
|
137536
137798
|
);
|
|
137537
137799
|
}
|
|
137538
|
-
const dailyChart =
|
|
137800
|
+
const dailyChart = asRecord26(charts.daily);
|
|
137539
137801
|
if (!Array.isArray(dailyChart?.labels)) {
|
|
137540
137802
|
pushMissing3(
|
|
137541
137803
|
missing,
|
|
@@ -137545,7 +137807,7 @@ function validateMetaPeriodReportContent(data) {
|
|
|
137545
137807
|
"\u987B\u6709 charts.daily.labels \u6570\u7EC4\uFF1B\u53EF\u7531 --snapshot-dir \u5408\u5E76 daily\u3002\u672C\u671F\u65E0\u6D88\u8017\u53EF\u4E3A []"
|
|
137546
137808
|
);
|
|
137547
137809
|
}
|
|
137548
|
-
const countryChart =
|
|
137810
|
+
const countryChart = asRecord26(charts.country);
|
|
137549
137811
|
if (!Array.isArray(countryChart?.labels)) {
|
|
137550
137812
|
pushMissing3(
|
|
137551
137813
|
missing,
|
|
@@ -137555,7 +137817,7 @@ function validateMetaPeriodReportContent(data) {
|
|
|
137555
137817
|
"\u987B\u6709 charts.country.labels \u6570\u7EC4\uFF1B\u53EF\u7531 --snapshot-dir \u5408\u5E76 country\u3002\u672C\u671F\u65E0\u6D88\u8017\u53EF\u4E3A []"
|
|
137556
137818
|
);
|
|
137557
137819
|
}
|
|
137558
|
-
const audienceChart =
|
|
137820
|
+
const audienceChart = asRecord26(charts.audience);
|
|
137559
137821
|
if (!Array.isArray(audienceChart?.labels)) {
|
|
137560
137822
|
pushMissing3(
|
|
137561
137823
|
missing,
|
|
@@ -137574,7 +137836,7 @@ function validateMetaPeriodReportContent(data) {
|
|
|
137574
137836
|
"\u5FC5\u987B\u6070\u597D 4 \u95EE\uFF1A\u94B1\u82B1\u5F97\u503C\u4E0D\u503C / \u8C01\u771F\u7684\u60F3\u4E70 / \u5E7F\u544A\u8FD8\u65B0\u9C9C\u5417 / \u7528\u6237\u4E3A\u4EC0\u4E48\u4E0D\u7559\u8D44"
|
|
137575
137837
|
);
|
|
137576
137838
|
} else {
|
|
137577
|
-
const titles = fourQuestions.map((q) =>
|
|
137839
|
+
const titles = fourQuestions.map((q) => asRecord26(q)?.title);
|
|
137578
137840
|
for (const title of FOUR_QUESTION_TITLES) {
|
|
137579
137841
|
if (!titles.includes(title)) {
|
|
137580
137842
|
pushMissing3(
|
|
@@ -137587,7 +137849,7 @@ function validateMetaPeriodReportContent(data) {
|
|
|
137587
137849
|
}
|
|
137588
137850
|
}
|
|
137589
137851
|
for (let i = 0; i < fourQuestions.length; i++) {
|
|
137590
|
-
const q =
|
|
137852
|
+
const q = asRecord26(fourQuestions[i]);
|
|
137591
137853
|
if (textLen3(q?.verdict) < 8) {
|
|
137592
137854
|
pushMissing3(
|
|
137593
137855
|
missing,
|
|
@@ -137627,7 +137889,7 @@ function validateMetaPeriodReportContent(data) {
|
|
|
137627
137889
|
);
|
|
137628
137890
|
} else {
|
|
137629
137891
|
for (let i = 0; i < recommendations.length; i++) {
|
|
137630
|
-
const rec =
|
|
137892
|
+
const rec = asRecord26(recommendations[i]);
|
|
137631
137893
|
if (textLen3(rec?.title) < 2) {
|
|
137632
137894
|
pushMissing3(
|
|
137633
137895
|
missing,
|
|
@@ -137720,7 +137982,7 @@ async function readJsonFile4(filePath) {
|
|
|
137720
137982
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
137721
137983
|
}
|
|
137722
137984
|
}
|
|
137723
|
-
function
|
|
137985
|
+
function asRecord27(value) {
|
|
137724
137986
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
137725
137987
|
return value;
|
|
137726
137988
|
}
|
|
@@ -137749,7 +138011,7 @@ function defaultOutPath(dataPath, format, out) {
|
|
|
137749
138011
|
}
|
|
137750
138012
|
async function runFacebookAnalysisRender(opts) {
|
|
137751
138013
|
const dataPath = path41.resolve(opts.dataFile);
|
|
137752
|
-
let data =
|
|
138014
|
+
let data = asRecord27(await readJsonFile4(dataPath));
|
|
137753
138015
|
if (opts.snapshotDir?.trim()) {
|
|
137754
138016
|
data = await mergeFacebookSnapshotIntoReport(data, path41.resolve(opts.snapshotDir));
|
|
137755
138017
|
}
|
|
@@ -137813,7 +138075,7 @@ import { fileURLToPath as fileURLToPath11 } from "url";
|
|
|
137813
138075
|
// src/commands/facebook-analysis/diagnosis-merge-snapshot.ts
|
|
137814
138076
|
import * as fs35 from "fs/promises";
|
|
137815
138077
|
import * as path42 from "path";
|
|
137816
|
-
function
|
|
138078
|
+
function asRecord28(value) {
|
|
137817
138079
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
137818
138080
|
return value;
|
|
137819
138081
|
}
|
|
@@ -137824,7 +138086,7 @@ function num8(value) {
|
|
|
137824
138086
|
return Number.isFinite(n) ? n : void 0;
|
|
137825
138087
|
}
|
|
137826
138088
|
function asRows(value) {
|
|
137827
|
-
return Array.isArray(value) ? value.filter((r) =>
|
|
138089
|
+
return Array.isArray(value) ? value.filter((r) => asRecord28(r) !== null) : [];
|
|
137828
138090
|
}
|
|
137829
138091
|
function pickMetricExtras(row, extras) {
|
|
137830
138092
|
const out = {
|
|
@@ -137873,14 +138135,14 @@ async function readManifest4(snapshotDir, accountId) {
|
|
|
137873
138135
|
async function loadSectionFile4(snapshotDir, file) {
|
|
137874
138136
|
try {
|
|
137875
138137
|
const raw = await fs35.readFile(path42.join(snapshotDir, file), "utf8");
|
|
137876
|
-
return
|
|
138138
|
+
return asRecord28(JSON.parse(raw));
|
|
137877
138139
|
} catch {
|
|
137878
138140
|
return null;
|
|
137879
138141
|
}
|
|
137880
138142
|
}
|
|
137881
138143
|
async function mergeMetaDiagnosisSnapshotIntoReport(payload, snapshotDir) {
|
|
137882
138144
|
const absDir = path42.resolve(snapshotDir);
|
|
137883
|
-
const metaAccountId = typeof
|
|
138145
|
+
const metaAccountId = typeof asRecord28(payload.meta)?.accountId === "string" ? asRecord28(payload.meta)?.accountId : void 0;
|
|
137884
138146
|
const manifest = await readManifest4(snapshotDir, metaAccountId);
|
|
137885
138147
|
if (!manifest) {
|
|
137886
138148
|
throw new Error(
|
|
@@ -137893,8 +138155,8 @@ async function mergeMetaDiagnosisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
137893
138155
|
if (data) sectionMap.set(art.section, data);
|
|
137894
138156
|
}
|
|
137895
138157
|
const overview = sectionMap.get("overview");
|
|
137896
|
-
const currentPeriod =
|
|
137897
|
-
const previousPeriod =
|
|
138158
|
+
const currentPeriod = asRecord28(overview?.currentPeriod);
|
|
138159
|
+
const previousPeriod = asRecord28(overview?.previousPeriod);
|
|
137898
138160
|
const accountId = manifest.accountId ?? metaAccountId;
|
|
137899
138161
|
const meta = { ...payload.meta ?? {} };
|
|
137900
138162
|
if (!meta.accountId && accountId) meta.accountId = accountId;
|
|
@@ -138028,7 +138290,7 @@ function textLen4(value) {
|
|
|
138028
138290
|
function asArray5(value) {
|
|
138029
138291
|
return Array.isArray(value) ? value : [];
|
|
138030
138292
|
}
|
|
138031
|
-
function
|
|
138293
|
+
function asRecord29(value) {
|
|
138032
138294
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
138033
138295
|
return value;
|
|
138034
138296
|
}
|
|
@@ -138039,9 +138301,9 @@ function pushMissing4(missing, id, chapter, dimension, hint) {
|
|
|
138039
138301
|
}
|
|
138040
138302
|
function validateMetaDiagnosisReportContent(data) {
|
|
138041
138303
|
const missing = [];
|
|
138042
|
-
const meta =
|
|
138043
|
-
const narrative =
|
|
138044
|
-
const sections =
|
|
138304
|
+
const meta = asRecord29(data.meta) ?? {};
|
|
138305
|
+
const narrative = asRecord29(data.narrative) ?? {};
|
|
138306
|
+
const sections = asRecord29(narrative.sections) ?? {};
|
|
138045
138307
|
if (!textLen4(meta.accountId)) {
|
|
138046
138308
|
pushMissing4(missing, "meta-account", "\u5143\u4FE1\u606F", "\u8D26\u6237 ID", "meta.accountId \u5FC5\u586B");
|
|
138047
138309
|
}
|
|
@@ -138059,7 +138321,7 @@ function validateMetaDiagnosisReportContent(data) {
|
|
|
138059
138321
|
const sectionSuggestionCounts = {};
|
|
138060
138322
|
const sectionNotAvailable = {};
|
|
138061
138323
|
for (const key of NORMAL_SECTION_KEYS) {
|
|
138062
|
-
const section =
|
|
138324
|
+
const section = asRecord29(sections[key]);
|
|
138063
138325
|
const analysis = asArray5(section?.analysis).filter((s) => textLen4(s) > 0);
|
|
138064
138326
|
const suggestions = asArray5(section?.suggestions).filter((s) => textLen4(s) > 0);
|
|
138065
138327
|
sectionAnalysisCounts[key] = analysis.length;
|
|
@@ -138085,7 +138347,7 @@ function validateMetaDiagnosisReportContent(data) {
|
|
|
138085
138347
|
}
|
|
138086
138348
|
}
|
|
138087
138349
|
for (const key of NA_SECTION_KEYS) {
|
|
138088
|
-
const section =
|
|
138350
|
+
const section = asRecord29(sections[key]);
|
|
138089
138351
|
const analysis = asArray5(section?.analysis).filter((s) => textLen4(s) > 0);
|
|
138090
138352
|
const suggestions = asArray5(section?.suggestions).filter((s) => textLen4(s) > 0);
|
|
138091
138353
|
const notAvailable = section?.notAvailable === true;
|
|
@@ -138107,7 +138369,7 @@ function validateMetaDiagnosisReportContent(data) {
|
|
|
138107
138369
|
}
|
|
138108
138370
|
const recommendations = asArray5(narrative.recommendations).filter((r) => {
|
|
138109
138371
|
if (typeof r === "string") return textLen4(r) > 0;
|
|
138110
|
-
const rec =
|
|
138372
|
+
const rec = asRecord29(r);
|
|
138111
138373
|
return textLen4(rec?.content) > 0;
|
|
138112
138374
|
});
|
|
138113
138375
|
if (recommendations.length < 3) {
|
|
@@ -138180,7 +138442,7 @@ async function readJsonFile5(filePath) {
|
|
|
138180
138442
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
138181
138443
|
}
|
|
138182
138444
|
}
|
|
138183
|
-
function
|
|
138445
|
+
function asRecord30(value) {
|
|
138184
138446
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
138185
138447
|
return value;
|
|
138186
138448
|
}
|
|
@@ -138195,7 +138457,7 @@ function injectReportData4(html, payload) {
|
|
|
138195
138457
|
}
|
|
138196
138458
|
async function runFacebookAnalysisDiagnosisRender(opts) {
|
|
138197
138459
|
const dataPath = path43.resolve(opts.dataFile);
|
|
138198
|
-
let data =
|
|
138460
|
+
let data = asRecord30(await readJsonFile5(dataPath));
|
|
138199
138461
|
if (opts.snapshotDir?.trim()) {
|
|
138200
138462
|
data = await mergeMetaDiagnosisSnapshotIntoReport(data, path43.resolve(opts.snapshotDir));
|
|
138201
138463
|
}
|
|
@@ -138394,7 +138656,7 @@ function resolveFacebookPageSize(raw, fallback = FB_ENTITY_PAGE_SIZE_DEFAULT) {
|
|
|
138394
138656
|
if (!Number.isFinite(n) || n <= 0) return fallback;
|
|
138395
138657
|
return Math.min(Math.max(Math.floor(n), 1), FB_ENTITY_PAGE_SIZE_MAX);
|
|
138396
138658
|
}
|
|
138397
|
-
function
|
|
138659
|
+
function asRecord31(value) {
|
|
138398
138660
|
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
138399
138661
|
}
|
|
138400
138662
|
function pickProp(obj, ...keys) {
|
|
@@ -138404,12 +138666,12 @@ function pickProp(obj, ...keys) {
|
|
|
138404
138666
|
return void 0;
|
|
138405
138667
|
}
|
|
138406
138668
|
function unwrapFacebookPaged(raw) {
|
|
138407
|
-
const rec =
|
|
138669
|
+
const rec = asRecord31(raw);
|
|
138408
138670
|
if (!rec) return { items: [] };
|
|
138409
138671
|
const data = pickProp(rec, "data", "Data");
|
|
138410
138672
|
const items3 = Array.isArray(data) ? data : [];
|
|
138411
|
-
const paging =
|
|
138412
|
-
const cursors = paging ?
|
|
138673
|
+
const paging = asRecord31(pickProp(rec, "paging", "Paging"));
|
|
138674
|
+
const cursors = paging ? asRecord31(pickProp(paging, "cursors", "Cursors")) : void 0;
|
|
138413
138675
|
const afterRaw = cursors ? pickProp(cursors, "after", "After") : void 0;
|
|
138414
138676
|
const after = typeof afterRaw === "string" && afterRaw.trim() ? afterRaw.trim() : void 0;
|
|
138415
138677
|
return { items: items3, after };
|
|
@@ -138557,7 +138819,7 @@ async function fetchFacebookInsights(config, digits, level, opts) {
|
|
|
138557
138819
|
opts.verbose
|
|
138558
138820
|
);
|
|
138559
138821
|
if (Array.isArray(raw)) return raw;
|
|
138560
|
-
const rec =
|
|
138822
|
+
const rec = asRecord31(raw);
|
|
138561
138823
|
const data = rec ? pickProp(rec, "data", "Data") : void 0;
|
|
138562
138824
|
return Array.isArray(data) ? data : [];
|
|
138563
138825
|
}
|
|
@@ -138566,7 +138828,7 @@ function sumActionArray(raw) {
|
|
|
138566
138828
|
let sum = 0;
|
|
138567
138829
|
let hit = false;
|
|
138568
138830
|
for (const item of raw) {
|
|
138569
|
-
const rec =
|
|
138831
|
+
const rec = asRecord31(item);
|
|
138570
138832
|
if (!rec) continue;
|
|
138571
138833
|
const n = Number(rec.value);
|
|
138572
138834
|
if (!Number.isFinite(n)) continue;
|
|
@@ -139845,7 +140107,7 @@ import { fileURLToPath as fileURLToPath12 } from "url";
|
|
|
139845
140107
|
// src/commands/bing-analysis/merge-snapshot.ts
|
|
139846
140108
|
import * as fs37 from "fs/promises";
|
|
139847
140109
|
import * as path46 from "path";
|
|
139848
|
-
function
|
|
140110
|
+
function asRecord32(value) {
|
|
139849
140111
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
139850
140112
|
return value;
|
|
139851
140113
|
}
|
|
@@ -139860,7 +140122,7 @@ function round27(value) {
|
|
|
139860
140122
|
}
|
|
139861
140123
|
function asRows2(value) {
|
|
139862
140124
|
if (Array.isArray(value)) {
|
|
139863
|
-
return value.filter((r) =>
|
|
140125
|
+
return value.filter((r) => asRecord32(r) !== null);
|
|
139864
140126
|
}
|
|
139865
140127
|
return [];
|
|
139866
140128
|
}
|
|
@@ -139942,17 +140204,17 @@ function campaignStatusDisplay(status) {
|
|
|
139942
140204
|
return status == null || status === "" ? "\u2014" : String(status);
|
|
139943
140205
|
}
|
|
139944
140206
|
function mapDeviceRows(payload) {
|
|
139945
|
-
const obj =
|
|
140207
|
+
const obj = asRecord32(payload);
|
|
139946
140208
|
return asRows2(obj?.devices).map((r) => pickMetrics(r, ["deviceType"]));
|
|
139947
140209
|
}
|
|
139948
140210
|
function mapGeographicRows(payload) {
|
|
139949
|
-
const obj =
|
|
140211
|
+
const obj = asRecord32(payload);
|
|
139950
140212
|
return asRows2(obj?.countries).map(
|
|
139951
140213
|
(r) => pickMetrics(r, ["countryOrRegion", "countryCriteriaId", "regionName", "cityName"])
|
|
139952
140214
|
);
|
|
139953
140215
|
}
|
|
139954
140216
|
function mapAudienceLabelRows(payload, labelKey) {
|
|
139955
|
-
const obj =
|
|
140217
|
+
const obj = asRecord32(payload);
|
|
139956
140218
|
return asRows2(obj?.audience).map((r) => {
|
|
139957
140219
|
const m = pickMetrics(r, ["audience", "bidModifier"]);
|
|
139958
140220
|
m[labelKey] = r.audience;
|
|
@@ -139960,7 +140222,7 @@ function mapAudienceLabelRows(payload, labelKey) {
|
|
|
139960
140222
|
});
|
|
139961
140223
|
}
|
|
139962
140224
|
function mapAudienceFromMerged(payload) {
|
|
139963
|
-
const data =
|
|
140225
|
+
const data = asRecord32(asRecord32(payload)?.data);
|
|
139964
140226
|
return {
|
|
139965
140227
|
audienceAge: mapAudienceLabelRows(data?.ageAudience, "ageRange"),
|
|
139966
140228
|
audienceGender: mapAudienceLabelRows(data?.genderAudience, "gender")
|
|
@@ -140055,7 +140317,7 @@ function mapSearchTermRows(payload) {
|
|
|
140055
140317
|
}
|
|
140056
140318
|
async function mergeBingAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
140057
140319
|
const absDir = path46.resolve(snapshotDir);
|
|
140058
|
-
const metaAccountId = typeof
|
|
140320
|
+
const metaAccountId = typeof asRecord32(payload.meta)?.accountId === "string" ? asRecord32(payload.meta)?.accountId : void 0;
|
|
140059
140321
|
const manifest = await readManifest5(snapshotDir, metaAccountId);
|
|
140060
140322
|
if (!manifest) {
|
|
140061
140323
|
throw new Error(`\u672A\u5728 ${absDir} \u627E\u5230 report-manifest*.json\uFF0C\u8BF7\u5148\u6267\u884C bing-analysis --json-out`);
|
|
@@ -140065,9 +140327,9 @@ async function mergeBingAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
140065
140327
|
const data = await loadSectionPayload(absDir, art.file);
|
|
140066
140328
|
if (data != null) sectionMap.set(art.section, data);
|
|
140067
140329
|
}
|
|
140068
|
-
const overview =
|
|
140069
|
-
const currentPeriod =
|
|
140070
|
-
const previousPeriod =
|
|
140330
|
+
const overview = asRecord32(sectionMap.get("overview"));
|
|
140331
|
+
const currentPeriod = asRecord32(overview?.currentPeriod);
|
|
140332
|
+
const previousPeriod = asRecord32(overview?.previousPeriod);
|
|
140071
140333
|
const accountId = manifest.accountId ?? metaAccountId;
|
|
140072
140334
|
const campaignRows3 = mapCampaignRows2(sectionMap.get("campaigns"));
|
|
140073
140335
|
const campaignKpis = sumBingCampaignRowsToPeriodKpis(campaignRows3);
|
|
@@ -140194,7 +140456,7 @@ function textLen5(value) {
|
|
|
140194
140456
|
function asArray6(value) {
|
|
140195
140457
|
return Array.isArray(value) ? value : [];
|
|
140196
140458
|
}
|
|
140197
|
-
function
|
|
140459
|
+
function asRecord33(value) {
|
|
140198
140460
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
140199
140461
|
return value;
|
|
140200
140462
|
}
|
|
@@ -140205,9 +140467,9 @@ function pushMissing5(missing, id, chapter, dimension, hint) {
|
|
|
140205
140467
|
}
|
|
140206
140468
|
function validateBingPeriodReportContent(data) {
|
|
140207
140469
|
const missing = [];
|
|
140208
|
-
const meta =
|
|
140209
|
-
const narrative =
|
|
140210
|
-
const sections =
|
|
140470
|
+
const meta = asRecord33(data.meta) ?? {};
|
|
140471
|
+
const narrative = asRecord33(data.narrative) ?? {};
|
|
140472
|
+
const sections = asRecord33(narrative.sections) ?? {};
|
|
140211
140473
|
if (!textLen5(meta.accountId)) {
|
|
140212
140474
|
pushMissing5(missing, "meta-account", "\u5143\u4FE1\u606F", "\u8D26\u6237 ID", "meta.accountId \u5FC5\u586B");
|
|
140213
140475
|
}
|
|
@@ -140224,7 +140486,7 @@ function validateBingPeriodReportContent(data) {
|
|
|
140224
140486
|
const sectionAnalysisCounts = {};
|
|
140225
140487
|
const sectionSuggestionCounts = {};
|
|
140226
140488
|
for (const key of SECTION_KEYS2) {
|
|
140227
|
-
const section =
|
|
140489
|
+
const section = asRecord33(sections[key]);
|
|
140228
140490
|
const analysis = asArray6(section?.analysis).filter((s) => textLen5(s) > 0);
|
|
140229
140491
|
const suggestions = asArray6(section?.suggestions).filter((s) => textLen5(s) > 0);
|
|
140230
140492
|
sectionAnalysisCounts[key] = analysis.length;
|
|
@@ -140250,7 +140512,7 @@ function validateBingPeriodReportContent(data) {
|
|
|
140250
140512
|
}
|
|
140251
140513
|
const recommendations = asArray6(narrative.recommendations).filter((r) => {
|
|
140252
140514
|
if (typeof r === "string") return textLen5(r) > 0;
|
|
140253
|
-
const rec =
|
|
140515
|
+
const rec = asRecord33(r);
|
|
140254
140516
|
return textLen5(rec?.content) > 0;
|
|
140255
140517
|
});
|
|
140256
140518
|
if (recommendations.length < 3) {
|
|
@@ -140311,7 +140573,7 @@ async function readJsonFile6(filePath) {
|
|
|
140311
140573
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
140312
140574
|
}
|
|
140313
140575
|
}
|
|
140314
|
-
function
|
|
140576
|
+
function asRecord34(value) {
|
|
140315
140577
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
140316
140578
|
return value;
|
|
140317
140579
|
}
|
|
@@ -140326,7 +140588,7 @@ function injectReportData5(html, payload) {
|
|
|
140326
140588
|
}
|
|
140327
140589
|
async function runBingAnalysisRender(opts) {
|
|
140328
140590
|
const dataPath = path47.resolve(opts.dataFile);
|
|
140329
|
-
let data =
|
|
140591
|
+
let data = asRecord34(await readJsonFile6(dataPath));
|
|
140330
140592
|
if (opts.snapshotDir?.trim()) {
|
|
140331
140593
|
data = await mergeBingAnalysisSnapshotIntoReport(data, path47.resolve(opts.snapshotDir));
|
|
140332
140594
|
}
|
|
@@ -140799,7 +141061,7 @@ import { fileURLToPath as fileURLToPath13 } from "url";
|
|
|
140799
141061
|
// src/commands/tiktok-analysis/merge-snapshot.ts
|
|
140800
141062
|
import * as fs39 from "fs/promises";
|
|
140801
141063
|
import * as path49 from "path";
|
|
140802
|
-
function
|
|
141064
|
+
function asRecord35(value) {
|
|
140803
141065
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
140804
141066
|
return value;
|
|
140805
141067
|
}
|
|
@@ -140977,7 +141239,7 @@ function mapAudienceMerged(payload) {
|
|
|
140977
141239
|
}
|
|
140978
141240
|
async function mergeTikTokAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
140979
141241
|
const absDir = path49.resolve(snapshotDir);
|
|
140980
|
-
const metaAccountId = typeof
|
|
141242
|
+
const metaAccountId = typeof asRecord35(payload.meta)?.accountId === "string" ? asRecord35(payload.meta)?.accountId : void 0;
|
|
140981
141243
|
const manifest = await readManifest6(snapshotDir, metaAccountId);
|
|
140982
141244
|
if (!manifest) {
|
|
140983
141245
|
throw new Error(
|
|
@@ -141091,7 +141353,7 @@ function textLen6(value) {
|
|
|
141091
141353
|
function asArray7(value) {
|
|
141092
141354
|
return Array.isArray(value) ? value : [];
|
|
141093
141355
|
}
|
|
141094
|
-
function
|
|
141356
|
+
function asRecord36(value) {
|
|
141095
141357
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
141096
141358
|
return value;
|
|
141097
141359
|
}
|
|
@@ -141102,9 +141364,9 @@ function pushMissing6(missing, id, chapter, dimension, hint) {
|
|
|
141102
141364
|
}
|
|
141103
141365
|
function validateTikTokPeriodReportContent(data) {
|
|
141104
141366
|
const missing = [];
|
|
141105
|
-
const meta =
|
|
141106
|
-
const narrative =
|
|
141107
|
-
const sections =
|
|
141367
|
+
const meta = asRecord36(data.meta) ?? {};
|
|
141368
|
+
const narrative = asRecord36(data.narrative) ?? {};
|
|
141369
|
+
const sections = asRecord36(narrative.sections) ?? {};
|
|
141108
141370
|
if (!textLen6(meta.accountId)) {
|
|
141109
141371
|
pushMissing6(missing, "meta-account", "\u5143\u4FE1\u606F", "\u8D26\u6237 ID", "meta.accountId \u5FC5\u586B");
|
|
141110
141372
|
}
|
|
@@ -141121,7 +141383,7 @@ function validateTikTokPeriodReportContent(data) {
|
|
|
141121
141383
|
const sectionAnalysisCounts = {};
|
|
141122
141384
|
const sectionSuggestionCounts = {};
|
|
141123
141385
|
for (const key of SECTION_KEYS3) {
|
|
141124
|
-
const section =
|
|
141386
|
+
const section = asRecord36(sections[key]);
|
|
141125
141387
|
const analysis = asArray7(section?.analysis).filter((s) => textLen6(s) > 0);
|
|
141126
141388
|
const suggestions = asArray7(section?.suggestions).filter((s) => textLen6(s) > 0);
|
|
141127
141389
|
sectionAnalysisCounts[key] = analysis.length;
|
|
@@ -141147,7 +141409,7 @@ function validateTikTokPeriodReportContent(data) {
|
|
|
141147
141409
|
}
|
|
141148
141410
|
const recommendations = asArray7(narrative.recommendations).filter((r) => {
|
|
141149
141411
|
if (typeof r === "string") return textLen6(r) > 0;
|
|
141150
|
-
const rec =
|
|
141412
|
+
const rec = asRecord36(r);
|
|
141151
141413
|
return textLen6(rec?.content) > 0;
|
|
141152
141414
|
});
|
|
141153
141415
|
if (recommendations.length < 3) {
|
|
@@ -141208,7 +141470,7 @@ async function readJsonFile7(filePath) {
|
|
|
141208
141470
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
141209
141471
|
}
|
|
141210
141472
|
}
|
|
141211
|
-
function
|
|
141473
|
+
function asRecord37(value) {
|
|
141212
141474
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
141213
141475
|
return value;
|
|
141214
141476
|
}
|
|
@@ -141223,7 +141485,7 @@ function injectReportData6(html, payload) {
|
|
|
141223
141485
|
}
|
|
141224
141486
|
async function runTikTokAnalysisRender(opts) {
|
|
141225
141487
|
const dataPath = path50.resolve(opts.dataFile);
|
|
141226
|
-
let data =
|
|
141488
|
+
let data = asRecord37(await readJsonFile7(dataPath));
|
|
141227
141489
|
if (opts.snapshotDir?.trim()) {
|
|
141228
141490
|
data = await mergeTikTokAnalysisSnapshotIntoReport(data, path50.resolve(opts.snapshotDir));
|
|
141229
141491
|
}
|
|
@@ -142322,7 +142584,7 @@ function endpointHintForYandexSection(def) {
|
|
|
142322
142584
|
// src/commands/yandex-analysis/merge-snapshot.ts
|
|
142323
142585
|
import * as fs41 from "fs/promises";
|
|
142324
142586
|
import * as path51 from "path";
|
|
142325
|
-
function
|
|
142587
|
+
function asRecord38(value) {
|
|
142326
142588
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
142327
142589
|
return value;
|
|
142328
142590
|
}
|
|
@@ -142342,11 +142604,11 @@ function normalizeYandexRoi(value) {
|
|
|
142342
142604
|
return r === -1 ? void 0 : r;
|
|
142343
142605
|
}
|
|
142344
142606
|
function asItems(payload) {
|
|
142345
|
-
const obj =
|
|
142607
|
+
const obj = asRecord38(payload);
|
|
142346
142608
|
if (!obj) return [];
|
|
142347
142609
|
const items3 = obj.items;
|
|
142348
142610
|
if (!Array.isArray(items3)) return [];
|
|
142349
|
-
return items3.filter((r) =>
|
|
142611
|
+
return items3.filter((r) => asRecord38(r) !== null);
|
|
142350
142612
|
}
|
|
142351
142613
|
function pickMetrics2(row, extras = []) {
|
|
142352
142614
|
const spend = num12(row.spend) ?? 0;
|
|
@@ -142482,7 +142744,7 @@ function aggregateDailyToWeekly(dailyRows) {
|
|
|
142482
142744
|
});
|
|
142483
142745
|
}
|
|
142484
142746
|
function prepareYandexDailyPayload(payload) {
|
|
142485
|
-
const obj =
|
|
142747
|
+
const obj = asRecord38(payload) ?? {};
|
|
142486
142748
|
const items3 = asItems(obj).map((r) => {
|
|
142487
142749
|
const date = normalizeYandexDailyDate(r.date);
|
|
142488
142750
|
return date ? { ...r, date } : r;
|
|
@@ -142551,7 +142813,7 @@ function mapDeviceRows2(payload) {
|
|
|
142551
142813
|
}
|
|
142552
142814
|
async function mergeYandexAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
142553
142815
|
const absDir = path51.resolve(snapshotDir);
|
|
142554
|
-
const metaAccountId = typeof
|
|
142816
|
+
const metaAccountId = typeof asRecord38(payload.meta)?.accountId === "string" ? asRecord38(payload.meta)?.accountId : void 0;
|
|
142555
142817
|
const manifest = await readManifest7(snapshotDir, metaAccountId);
|
|
142556
142818
|
if (!manifest) {
|
|
142557
142819
|
throw new Error(
|
|
@@ -142563,8 +142825,8 @@ async function mergeYandexAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
142563
142825
|
const data = await loadSectionPayload3(absDir, art.file);
|
|
142564
142826
|
if (data != null) sectionMap.set(art.section, data);
|
|
142565
142827
|
}
|
|
142566
|
-
const overview =
|
|
142567
|
-
const totals =
|
|
142828
|
+
const overview = asRecord38(sectionMap.get("overview"));
|
|
142829
|
+
const totals = asRecord38(overview?.totals);
|
|
142568
142830
|
const accountId = manifest.accountId ?? metaAccountId;
|
|
142569
142831
|
const meta = { ...payload.meta ?? {} };
|
|
142570
142832
|
if (!meta.accountId && accountId) meta.accountId = accountId;
|
|
@@ -142786,7 +143048,7 @@ function textLen7(value) {
|
|
|
142786
143048
|
function asArray8(value) {
|
|
142787
143049
|
return Array.isArray(value) ? value : [];
|
|
142788
143050
|
}
|
|
142789
|
-
function
|
|
143051
|
+
function asRecord39(value) {
|
|
142790
143052
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
142791
143053
|
return value;
|
|
142792
143054
|
}
|
|
@@ -142799,23 +143061,23 @@ function normKey(value) {
|
|
|
142799
143061
|
return String(value ?? "").trim().toLowerCase();
|
|
142800
143062
|
}
|
|
142801
143063
|
function insightMatchRecord(item) {
|
|
142802
|
-
const rec =
|
|
143064
|
+
const rec = asRecord39(item);
|
|
142803
143065
|
if (!rec) return {};
|
|
142804
|
-
return
|
|
143066
|
+
return asRecord39(rec.match) ?? rec;
|
|
142805
143067
|
}
|
|
142806
143068
|
function findRowInsight(list, primaryField, primaryValue, row) {
|
|
142807
143069
|
const target = normKey(primaryValue);
|
|
142808
143070
|
if (!target) return null;
|
|
142809
143071
|
const candidates = list.filter((it) => normKey(insightMatchRecord(it)[primaryField]) === target);
|
|
142810
|
-
if (candidates.length <= 1) return
|
|
143072
|
+
if (candidates.length <= 1) return asRecord39(candidates[0]);
|
|
142811
143073
|
const campaign = normKey(row.campaignName);
|
|
142812
143074
|
const narrowed = candidates.find(
|
|
142813
143075
|
(it) => normKey(insightMatchRecord(it).campaignName) === campaign
|
|
142814
143076
|
);
|
|
142815
|
-
return
|
|
143077
|
+
return asRecord39(narrowed ?? candidates[0]);
|
|
142816
143078
|
}
|
|
142817
143079
|
function topRowsBySpend(rows, limit) {
|
|
142818
|
-
return rows.map((r) =>
|
|
143080
|
+
return rows.map((r) => asRecord39(r)).filter((r) => r != null).sort((a, b) => (Number(b.spend) || 0) - (Number(a.spend) || 0)).slice(0, limit);
|
|
142819
143081
|
}
|
|
142820
143082
|
var ROW_INSIGHT_SPECS = [
|
|
142821
143083
|
{
|
|
@@ -142830,17 +143092,17 @@ var ROW_INSIGHT_SPECS = [
|
|
|
142830
143092
|
];
|
|
142831
143093
|
function validateYandexPeriodReportContent(data) {
|
|
142832
143094
|
const missing = [];
|
|
142833
|
-
const meta =
|
|
142834
|
-
const narrative =
|
|
142835
|
-
const sections =
|
|
142836
|
-
const kpis =
|
|
143095
|
+
const meta = asRecord39(data.meta) ?? {};
|
|
143096
|
+
const narrative = asRecord39(data.narrative) ?? {};
|
|
143097
|
+
const sections = asRecord39(narrative.sections) ?? {};
|
|
143098
|
+
const kpis = asRecord39(data.kpis) ?? {};
|
|
142837
143099
|
if (!textLen7(meta.accountId)) {
|
|
142838
143100
|
pushMissing7(missing, "meta-account", "\u5143\u4FE1\u606F", "\u8D26\u6237 ID", "meta.accountId \u5FC5\u586B");
|
|
142839
143101
|
}
|
|
142840
143102
|
const sectionAnalysisCounts = {};
|
|
142841
143103
|
const sectionSuggestionCounts = {};
|
|
142842
143104
|
for (const key of SECTION_KEYS4) {
|
|
142843
|
-
const section =
|
|
143105
|
+
const section = asRecord39(sections[key]);
|
|
142844
143106
|
const analysis = asArray8(section?.analysis).filter((s) => textLen7(s) > 0);
|
|
142845
143107
|
const suggestions = asArray8(section?.suggestions).filter((s) => textLen7(s) > 0);
|
|
142846
143108
|
sectionAnalysisCounts[key] = analysis.length;
|
|
@@ -142866,7 +143128,7 @@ function validateYandexPeriodReportContent(data) {
|
|
|
142866
143128
|
}
|
|
142867
143129
|
const recommendations = asArray8(narrative.recommendations).filter((r) => {
|
|
142868
143130
|
if (typeof r === "string") return textLen7(r) > 0;
|
|
142869
|
-
const rec =
|
|
143131
|
+
const rec = asRecord39(r);
|
|
142870
143132
|
return textLen7(rec?.content) > 0 || textLen7(rec?.text) > 0;
|
|
142871
143133
|
});
|
|
142872
143134
|
if (recommendations.length < 3) {
|
|
@@ -142888,8 +143150,8 @@ function validateYandexPeriodReportContent(data) {
|
|
|
142888
143150
|
"\u81F3\u5C11\u4E00\u9879\u6709\u6548\u6570\u5B57\uFF08\u8BF7\u4F20 --snapshot-dir \u7531 CLI \u4ECE overview \u5408\u5E76\uFF09"
|
|
142889
143151
|
);
|
|
142890
143152
|
}
|
|
142891
|
-
const tables =
|
|
142892
|
-
const weeklyRows = asArray8(tables.weekly).map((r) =>
|
|
143153
|
+
const tables = asRecord39(data.tables) ?? {};
|
|
143154
|
+
const weeklyRows = asArray8(tables.weekly).map((r) => asRecord39(r)).filter((r) => r != null);
|
|
142893
143155
|
for (const [i, row] of weeklyRows.entries()) {
|
|
142894
143156
|
const label2 = `${row.weekLabel ?? ""} ${row.startDate ?? ""} ${row.endDate ?? ""}`;
|
|
142895
143157
|
if (/nan/i.test(label2) || !normalizeYandexDailyDate(row.startDate) || !normalizeYandexDailyDate(row.endDate)) {
|
|
@@ -142902,7 +143164,7 @@ function validateYandexPeriodReportContent(data) {
|
|
|
142902
143164
|
);
|
|
142903
143165
|
}
|
|
142904
143166
|
}
|
|
142905
|
-
const rowInsights =
|
|
143167
|
+
const rowInsights = asRecord39(narrative.rowInsights) ?? {};
|
|
142906
143168
|
const rowInsightCoverage = {};
|
|
142907
143169
|
for (const spec of ROW_INSIGHT_SPECS) {
|
|
142908
143170
|
const shown = topRowsBySpend(asArray8(tables[spec.tableKey]), spec.limit).filter(
|
|
@@ -142982,7 +143244,7 @@ async function readJsonFile8(filePath) {
|
|
|
142982
143244
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
142983
143245
|
}
|
|
142984
143246
|
}
|
|
142985
|
-
function
|
|
143247
|
+
function asRecord40(value) {
|
|
142986
143248
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
142987
143249
|
return value;
|
|
142988
143250
|
}
|
|
@@ -143010,7 +143272,7 @@ function injectReportData7(html, payload) {
|
|
|
143010
143272
|
}
|
|
143011
143273
|
async function runYandexAnalysisRender(opts) {
|
|
143012
143274
|
const dataPath = path53.resolve(opts.dataFile);
|
|
143013
|
-
let data =
|
|
143275
|
+
let data = asRecord40(await readJsonFile8(dataPath));
|
|
143014
143276
|
if (opts.snapshotDir?.trim()) {
|
|
143015
143277
|
data = await mergeYandexAnalysisSnapshotIntoReport(data, path53.resolve(opts.snapshotDir));
|
|
143016
143278
|
}
|
|
@@ -143206,7 +143468,7 @@ function unwrapYandexItems(raw) {
|
|
|
143206
143468
|
}
|
|
143207
143469
|
return [];
|
|
143208
143470
|
}
|
|
143209
|
-
function
|
|
143471
|
+
function asRecord41(raw) {
|
|
143210
143472
|
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
143211
143473
|
}
|
|
143212
143474
|
|
|
@@ -143285,7 +143547,7 @@ async function runYandexAccountStatus(opts) {
|
|
|
143285
143547
|
} catch (err) {
|
|
143286
143548
|
fail3("\u67E5\u8BE2 Yandex \u8D26\u6237\u603B\u89C8\u5931\u8D25", err);
|
|
143287
143549
|
}
|
|
143288
|
-
const row =
|
|
143550
|
+
const row = asRecord41(result.raw);
|
|
143289
143551
|
await emitOrTable(opts, {
|
|
143290
143552
|
section: "yandex-account-status",
|
|
143291
143553
|
commandLabel: "yandex-analysis account-status",
|