siluzan-tso-cli 1.0.0-beta.51 → 1.0.0-beta.53

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 CHANGED
@@ -20,7 +20,7 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
20
20
  siluzan-tso init --force # 强制覆盖已存在文件
21
21
  ```
22
22
 
23
- > **注意**:当前为测试版(1.0.0-beta.51),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
23
+ > **注意**:当前为测试版(1.0.0-beta.53),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
24
24
 
25
25
  | 助手 | 建议 `--ai` |
26
26
  |------|-------------|
package/dist/index.js CHANGED
@@ -4557,6 +4557,7 @@ async function runInvoiceInfoDelete(opts) {
4557
4557
 
4558
4558
  // src/commands/ad.ts
4559
4559
  import { randomUUID } from "crypto";
4560
+ import { readFileSync as readFileSync6 } from "fs";
4560
4561
  async function findItemInList(listUrl, config, id, verbose) {
4561
4562
  const res = await apiFetch2(listUrl, config, {}, verbose);
4562
4563
  const item = (res.data ?? []).find((x) => x["id"] === id);
@@ -5200,8 +5201,59 @@ function buildAdsForBatchJob(opts) {
5200
5201
  return [ad];
5201
5202
  }
5202
5203
  async function runAdCampaignCreate(opts) {
5203
- const config = loadConfig(opts.token);
5204
- console.log(opts);
5204
+ if (opts.configFile) {
5205
+ let fileConfig;
5206
+ try {
5207
+ fileConfig = JSON.parse(readFileSync6(opts.configFile, "utf8"));
5208
+ } catch (err) {
5209
+ console.error(`
5210
+ \u274C \u8BFB\u53D6\u914D\u7F6E\u6587\u4EF6\u5931\u8D25\uFF08${opts.configFile}\uFF09\uFF1A${err instanceof Error ? err.message : String(err)}
5211
+ `);
5212
+ process.exit(1);
5213
+ }
5214
+ const fromFile = {
5215
+ account: fileConfig.account,
5216
+ customerName: fileConfig.customerName,
5217
+ name: fileConfig.name,
5218
+ budget: fileConfig.budget,
5219
+ // CampaignCreateConfig.bidding → AdCampaignCreateOptions.biddingStrategy
5220
+ biddingStrategy: fileConfig.bidding,
5221
+ bidCeiling: fileConfig.bidCeiling,
5222
+ targetCpa: fileConfig.targetCpa,
5223
+ targetRoas: fileConfig.targetRoas,
5224
+ locationIds: fileConfig.locationIds,
5225
+ languageIds: fileConfig.languageIds,
5226
+ startDate: fileConfig.startDate,
5227
+ endDate: fileConfig.endDate,
5228
+ url: fileConfig.url,
5229
+ status: fileConfig.status,
5230
+ adgroupName: fileConfig.adgroupName,
5231
+ maxCpc: fileConfig.maxCpc,
5232
+ matchType: fileConfig.matchType,
5233
+ keywords: fileConfig.keywords,
5234
+ headlines: fileConfig.headlines,
5235
+ descriptions: fileConfig.descriptions,
5236
+ finalUrl: fileConfig.finalUrl,
5237
+ path1: fileConfig.path1,
5238
+ path2: fileConfig.path2,
5239
+ productWords: fileConfig.productWords,
5240
+ negativeKeywords: fileConfig.negativeKeywords,
5241
+ // CampaignCreateConfig.extensions/extraAdGroups → extensionsJson/extraAdGroupsJson
5242
+ extensionsJson: fileConfig.extensions,
5243
+ extraAdGroupsJson: fileConfig.extraAdGroups,
5244
+ draft: fileConfig.draft,
5245
+ targetSearchNetwork: fileConfig.targetSearchNetwork,
5246
+ targetContentNetwork: fileConfig.targetContentNetwork
5247
+ };
5248
+ opts = {
5249
+ ...fromFile,
5250
+ ...Object.fromEntries(
5251
+ Object.entries(opts).filter(([, v]) => v !== void 0 && v !== "" && !(Array.isArray(v) && v.length === 0))
5252
+ ),
5253
+ configFile: void 0
5254
+ };
5255
+ }
5256
+ const config = await ensureDataPermission(loadConfig(opts.token));
5205
5257
  if (!config.apiBaseUrl) {
5206
5258
  console.error("\n\u274C \u672A\u914D\u7F6E apiBaseUrl\uFF0C\u8BF7\u6267\u884C\uFF1Asiluzan-tso config set --api-base <URL>\n");
5207
5259
  process.exit(1);
@@ -5209,9 +5261,12 @@ async function runAdCampaignCreate(opts) {
5209
5261
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
5210
5262
  const defaultEnd = "2037-12-30";
5211
5263
  const budgetBatch = Math.round(opts.budget * 100);
5212
- const maxCpcBatch = String(Math.round(opts.maxCpc * 100));
5264
+ const maxCpcBatch = Math.round(opts.maxCpc * 100);
5213
5265
  const campaign = {
5266
+ // 预算共享(Web 默认 false = 独立预算)
5267
+ BudgetShared: false,
5214
5268
  Budget: budgetBatch,
5269
+ BudgetId: 0,
5215
5270
  Name: opts.name,
5216
5271
  StatusV2: opts.status ?? "Enabled",
5217
5272
  ChannelTypeV2: "SEARCH",
@@ -5222,22 +5277,51 @@ async function runAdCampaignCreate(opts) {
5222
5277
  ...opts.targetRoas ? { TargetRoas: opts.targetRoas } : {},
5223
5278
  TargetGoogleSearch: true,
5224
5279
  TargetSearchNetwork: opts.targetSearchNetwork ?? true,
5280
+ // 地理位置定向类型(0 = DONT_CARE,与 Web 一致)
5281
+ NegativeGeoTargetType: 0,
5282
+ PositiveGeoTargetType: 0,
5283
+ // DSA 动态搜索广告配置(搜索广告系列保持默认空值即可)
5284
+ DSADomainName: "",
5285
+ DSALanguageCode: "en",
5225
5286
  TargetContentNetwork: opts.targetContentNetwork ?? false,
5226
5287
  StartTime: opts.startDate ?? today,
5227
5288
  EndTime: opts.endDate ?? defaultEnd,
5228
- // 地理位置定向
5289
+ // 否定关键词(传入则写入第一条记录;不传则空数组,后续可用 ad negative-keyword-create 追加)
5290
+ NegativeKeywordsForBatchJob: opts.negativeKeywords && opts.negativeKeywords.length > 0 ? [{
5291
+ KeywordText: opts.negativeKeywords,
5292
+ MatchTypeV2: "BROAD",
5293
+ FinalURL: ""
5294
+ }] : [],
5295
+ // 广告附加功能(CALL / STRUCTURED_SNIPPET / SITELINK 等,不传则空数组)
5296
+ ExtensionsForBatchJob: opts.extensionsJson ?? [],
5297
+ // 第一个广告组(关键词与广告:不传则为空,后续用 ad keyword-create / ad ad-create 补充)
5298
+ AdGroupsForBatchJob: [
5299
+ {
5300
+ Name: opts.adgroupName,
5301
+ StatusV2: "Enabled",
5302
+ TypeV2: "SEARCH_STANDARD",
5303
+ RotationModeV2: "Unspecified",
5304
+ MaxCPCAmount: maxCpcBatch,
5305
+ AdsForBatchJob: buildAdsForBatchJob(opts),
5306
+ KeywordsForBatchJob: buildKeywordsForBatchJob(opts)
5307
+ },
5308
+ // 可通过 --extra-adgroups-json 追加更多广告组
5309
+ ...opts.extraAdGroupsJson ?? []
5310
+ ],
5311
+ // 地理位置定向(id 保持字符串类型,与 Web API 一致)
5229
5312
  targetedLocations: opts.locationIds.map((id) => ({
5313
+ id: String(id),
5230
5314
  bidModifier: 0,
5231
- bidModifierSpecified: false,
5232
- id: Number(id)
5315
+ bidModifierSpecified: false
5233
5316
  })),
5234
5317
  excludedLocations: [],
5235
5318
  // 语言(默认英语 1000)
5236
5319
  targetedLanguages: (opts.languageIds ?? ["1000"]).map((id) => ({ id: Number(id) })),
5237
- // 设备(默认 PC + 移动)
5320
+ // 设备:30000=全部,30001=移动,30002=平板(与 Web 默认三端投放一致)
5238
5321
  targetedPlatforms: [
5239
- { id: 3e4, bidModifier: 0 },
5240
- { id: 30001, bidModifier: 0 }
5322
+ { id: 30001, bidModifier: 0 },
5323
+ { id: 30002, bidModifier: 0 },
5324
+ { id: 3e4, bidModifier: 0 }
5241
5325
  ],
5242
5326
  // 全周全天投放
5243
5327
  adSchedules: [2, 3, 4, 5, 6, 7, 8].map((day) => ({
@@ -5246,19 +5330,7 @@ async function runAdCampaignCreate(opts) {
5246
5330
  StartMinuteV2: 2,
5247
5331
  endHour: 24,
5248
5332
  EndMinuteV2: 2
5249
- })),
5250
- NegativeKeywordsForBatchJob: [],
5251
- ExtensionsForBatchJob: [],
5252
- // 第一个广告组(关键词与广告:不传则为空,后续用 ad keyword-create / ad ad-create 补充)
5253
- AdGroupsForBatchJob: [{
5254
- Name: opts.adgroupName,
5255
- StatusV2: "Enabled",
5256
- TypeV2: "SEARCH_STANDARD",
5257
- RotationModeV2: "Unspecified",
5258
- MaxCPCAmount: maxCpcBatch,
5259
- AdsForBatchJob: buildAdsForBatchJob(opts),
5260
- KeywordsForBatchJob: buildKeywordsForBatchJob(opts)
5261
- }]
5333
+ }))
5262
5334
  };
5263
5335
  const adGroupsForBatchJob = campaign.AdGroupsForBatchJob;
5264
5336
  const keywordRecommendations = (adGroupsForBatchJob ?? []).filter((g) => typeof g.Name === "string" && g.Name.trim().length > 0).map((g) => ({
@@ -5270,9 +5342,10 @@ async function runAdCampaignCreate(opts) {
5270
5342
  customerName: opts.customerName,
5271
5343
  campaignName: opts.name,
5272
5344
  url: opts.url ?? "",
5273
- // 前端页面会传入覆盖范围与产品词,这里暂时缺少同等丰富的来源,先留空数组以通过后端字段校验
5345
+ // locations 为地理位置名称的展示字符串列表(前端只读,后端不做校验,可留空)
5274
5346
  locations: [],
5275
- productWords: [],
5347
+ // productWords 为产品核心词,用于 AI 生成关键词推荐,可通过 --product-words 传入
5348
+ productWords: opts.productWords ?? [],
5276
5349
  // Web 端异步创建在走「立即发布」时会使用非空的 GoogleDataRecordId(UUID)且 DraftStatus 为 Published;
5277
5350
  // 这里保持一致,使用随机 UUID 作为唯一标识。是否直接发布由 draft 开关控制:
5278
5351
  // - draft=true → DraftStatus = Draft(仅创建草稿,需后续 ad batch publish 发布)
@@ -9901,20 +9974,20 @@ adCmd.command("keyword-negative-delete").description("\u5220\u9664\u5426\u5B9A\u
9901
9974
  });
9902
9975
  adCmd.command("campaign-create").description(
9903
9976
  '\u65B0\u5EFA\u641C\u7D22\u5E7F\u544A\u7CFB\u5217\uFF08\u542B\u7B2C\u4E00\u4E2A\u5E7F\u544A\u7EC4\uFF0C\u5F02\u6B65\u63D0\u4EA4\uFF1B\u9ED8\u8BA4\u7ACB\u5373\u53D1\u5E03\uFF0C\u53EF\u52A0 --draft \u4EC5\u4FDD\u5B58\u4E3A\u8349\u7A3F\uFF09\n\n \u524D\u7F6E\u6B65\u9AA4\uFF1A\n 1. siluzan-tso ad geo search -a <accountId> -q "United States" # \u83B7\u53D6 locationId\n 2. \u586B\u5165 --location-ids\uFF0C\u521B\u5EFA\u5B8C\u6BD5\u540E\u7528 ad batch get --id <taskId> \u8DDF\u8FDB\u72B6\u6001'
9904
- ).requiredOption("-a, --account <id>", "Google \u8D26\u6237 mediaCustomerId").requiredOption("--customer-name <name>", "\u8D26\u6237\u540D\u79F0\uFF08\u6765\u81EA list-accounts --json \u7684 mediaAccountName \u5B57\u6BB5\uFF09").requiredOption("--name <name>", "\u5E7F\u544A\u7CFB\u5217\u540D\u79F0").requiredOption(
9977
+ ).option("-a, --account <id>", "Google \u8D26\u6237 mediaCustomerId\uFF08\u4F7F\u7528 --config-file \u65F6\u53EF\u7701\u7565\uFF0C\u4ECE\u6587\u4EF6\u8BFB\u53D6\uFF09").option("--customer-name <name>", "\u8D26\u6237\u540D\u79F0\uFF08\u6765\u81EA list-accounts --json \u7684 mediaAccountName \u5B57\u6BB5\uFF09").option("--name <name>", "\u5E7F\u544A\u7CFB\u5217\u540D\u79F0").option(
9905
9978
  "--budget <amount>",
9906
- "\u65E5\u9884\u7B97\uFF1A\u8D26\u6237\u4E3B\u5E01\u79CD\u91D1\u989D\uFF08\u5982 100 = \u6BCF\u5929 100 USD/CNY\uFF1B\u4E0E Web / ad smart create \u4E00\u81F4\uFF0C\u5185\u90E8 \xD7100 \u5199\u5165\u63A5\u53E3\uFF09",
9979
+ "\u65E5\u9884\u7B97\uFF1A\u8D26\u6237\u4E3B\u5E01\u79CD\u91D1\u989D\uFF08\u5982 100 = \u6BCF\u5929 100 USD/CNY\uFF1B\u5185\u90E8 \xD7100 \u5199\u5165\u63A5\u53E3\uFF09",
9907
9980
  parseFloat
9908
- ).requiredOption(
9981
+ ).option(
9909
9982
  "--bidding <strategy>",
9910
9983
  "\u51FA\u4EF7\u7B56\u7565\uFF1ATARGET_SPEND | MANUAL_CPC | TARGET_CPA | TARGET_ROAS"
9911
- ).requiredOption(
9984
+ ).option(
9912
9985
  "--location-ids <ids>",
9913
9986
  "\u6295\u653E\u5730\u7406\u4F4D\u7F6E ID\uFF0C\u9017\u53F7\u5206\u9694\uFF08\u7528 ad geo search \u83B7\u53D6\uFF0C\u5982 2840=\u7F8E\u56FD\uFF09",
9914
9987
  (v) => v.split(",").map((s) => s.trim())
9915
- ).requiredOption("--adgroup-name <name>", "\u7B2C\u4E00\u4E2A\u5E7F\u544A\u7EC4\u540D\u79F0").requiredOption(
9988
+ ).option("--adgroup-name <name>", "\u7B2C\u4E00\u4E2A\u5E7F\u544A\u7EC4\u540D\u79F0").option(
9916
9989
  "--max-cpc <amount>",
9917
- "\u7B2C\u4E00\u4E2A\u5E7F\u544A\u7EC4\u6700\u9AD8 CPC\uFF1A\u4E3B\u5E01\u79CD\u91D1\u989D\uFF08\u5982 1.5 = \u6BCF\u6B21\u70B9\u51FB 1.50\uFF1B\u4E0E Web / ad smart create \u4E00\u81F4\uFF0C\u5185\u90E8 \xD7100 \u5199\u5165 MaxCPCAmount\uFF09",
9990
+ "\u7B2C\u4E00\u4E2A\u5E7F\u544A\u7EC4\u6700\u9AD8 CPC\uFF1A\u4E3B\u5E01\u79CD\u91D1\u989D\uFF08\u5982 1.5 = \u6BCF\u6B21\u70B9\u51FB 1.50\uFF1B\u5185\u90E8 \xD7100 \u5199\u5165 MaxCPCAmount\uFF09",
9918
9991
  parseFloat
9919
9992
  ).option(
9920
9993
  "--bid-ceiling <amount>",
@@ -9936,9 +10009,44 @@ adCmd.command("campaign-create").description(
9936
10009
  "--descriptions <descs>",
9937
10010
  "\u5E7F\u544A\u63CF\u8FF0\uFF0C\u9017\u53F7\u5206\u9694\uFF0C\u81F3\u5C11 2 \u6761\uFF0C\u6BCF\u6761 \u2264 90 \u5B57\u7B26",
9938
10011
  (v) => v.split(",").map((s) => s.trim())
9939
- ).option("--final-url <url>", "\u5E7F\u544A\u843D\u5730\u9875\uFF08\u5173\u952E\u8BCD\u548C\u5E7F\u544A\u5171\u7528\uFF1B\u4E0D\u4F20\u5219\u7EE7\u627F --url\uFF09").option("--path1 <path>", "\u5C55\u793A URL \u8DEF\u5F84 1\uFF08\u2264 15 \u5B57\u7B26\uFF0C\u53EF\u9009\uFF09").option("--path2 <path>", "\u5C55\u793A URL \u8DEF\u5F84 2\uFF08\u2264 15 \u5B57\u7B26\uFF0C\u53EF\u9009\uFF09").option("--draft", "\u4EC5\u4FDD\u5B58\u4E3A\u8349\u7A3F\uFF08DraftStatus=Draft\uFF0C\u9700\u8981\u540E\u7EED ad batch publish \u53D1\u5E03\uFF09", false).option("-t, --token <token>", "Auth Token").option("--json", "JSON \u683C\u5F0F\u8F93\u51FA\u539F\u59CB\u54CD\u5E94", false).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
10012
+ ).option("--final-url <url>", "\u5E7F\u544A\u843D\u5730\u9875\uFF08\u5173\u952E\u8BCD\u548C\u5E7F\u544A\u5171\u7528\uFF1B\u4E0D\u4F20\u5219\u7EE7\u627F --url\uFF09").option("--path1 <path>", "\u5C55\u793A URL \u8DEF\u5F84 1\uFF08\u2264 15 \u5B57\u7B26\uFF0C\u53EF\u9009\uFF09").option("--path2 <path>", "\u5C55\u793A URL \u8DEF\u5F84 2\uFF08\u2264 15 \u5B57\u7B26\uFF0C\u53EF\u9009\uFF09").option(
10013
+ "--product-words <words>",
10014
+ "\u63A8\u5E7F\u4EA7\u54C1\u8BCD\uFF0C\u9017\u53F7\u5206\u9694\uFF08\u5199\u5165\u5916\u5C42 productWords\uFF0C\u7528\u4E8E AI \u5173\u952E\u8BCD\u63A8\u8350\uFF09",
10015
+ (v) => v.split(",").map((s) => s.trim())
10016
+ ).option(
10017
+ "--negative-keywords <kws>",
10018
+ "\u5426\u5B9A\u5173\u952E\u8BCD\uFF0C\u9017\u53F7\u5206\u9694\uFF08\u751F\u6210 NegativeKeywordsForBatchJob\uFF0C\u9ED8\u8BA4 BROAD \u5339\u914D\uFF09",
10019
+ (v) => v.split(",").map((s) => s.trim())
10020
+ ).option(
10021
+ "--extensions-json <json>",
10022
+ "\u5E7F\u544A\u9644\u52A0\u529F\u80FD JSON \u6570\u7EC4\u5B57\u7B26\u4E32\uFF08ExtensionsForBatchJob\uFF1B\u5305\u542B CALL/SITELINK/STRUCTURED_SNIPPET \u7B49\uFF09"
10023
+ ).option(
10024
+ "--extra-adgroups-json <json>",
10025
+ "\u989D\u5916\u5E7F\u544A\u7EC4 JSON \u6570\u7EC4\u5B57\u7B26\u4E32\uFF08\u8FFD\u52A0\u5230 AdGroupsForBatchJob\uFF1B\u6BCF\u6761\u987B\u5305\u542B Name/MaxCPCAmount/AdsForBatchJob/KeywordsForBatchJob \u7B49\u5B57\u6BB5\uFF09"
10026
+ ).option(
10027
+ "--config-file <path>",
10028
+ "JSON \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF08\u63A8\u8350 AI \u4F7F\u7528\uFF09\uFF1A\u5C06\u6240\u6709\u53C2\u6570\u5199\u5165 JSON \u6587\u4EF6\u518D\u4F20\u6B64\u8DEF\u5F84\uFF0C\u652F\u6301 headlines \u6570\u7EC4\uFF08\u5141\u8BB8\u5143\u7D20\u5185\u542B\u9017\u53F7\uFF09\u3001extensions/extraAdGroups \u76F4\u63A5\u4F5C\u4E3A JSON \u6570\u7EC4\uFF0CCLI \u663E\u5F0F\u4F20\u5165\u7684\u53C2\u6570\u4F1A\u8986\u76D6\u6587\u4EF6\u4E2D\u7684\u540C\u540D\u5B57\u6BB5"
10029
+ ).option("--draft", "\u4EC5\u4FDD\u5B58\u4E3A\u8349\u7A3F\uFF08DraftStatus=Draft\uFF0C\u9700\u8981\u540E\u7EED ad batch publish \u53D1\u5E03\uFF09", false).option("-t, --token <token>", "Auth Token").option("--json", "JSON \u683C\u5F0F\u8F93\u51FA\u539F\u59CB\u54CD\u5E94", false).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
10030
+ if (!opts.configFile) {
10031
+ const missing = [];
10032
+ if (!opts.account) missing.push("-a/--account");
10033
+ if (!opts.customerName) missing.push("--customer-name");
10034
+ if (!opts.name) missing.push("--name");
10035
+ if (opts.budget === void 0) missing.push("--budget");
10036
+ if (!opts.bidding) missing.push("--bidding");
10037
+ if (!opts.locationIds?.length) missing.push("--location-ids");
10038
+ if (!opts.adgroupName) missing.push("--adgroup-name");
10039
+ if (opts.maxCpc === void 0) missing.push("--max-cpc");
10040
+ if (missing.length > 0) {
10041
+ console.error(`
10042
+ \u274C \u7F3A\u5C11\u5FC5\u586B\u53C2\u6570\uFF1A${missing.join("\uFF0C")}
10043
+ \u63D0\u793A\uFF1A\u53EF\u4F7F\u7528 --config-file <path> \u4ECE JSON \u6587\u4EF6\u8BFB\u53D6\u6240\u6709\u53C2\u6570
10044
+ `);
10045
+ process.exit(1);
10046
+ }
10047
+ }
9940
10048
  const strategies = ["TARGET_SPEND", "MANUAL_CPC", "TARGET_CPA", "TARGET_ROAS"];
9941
- if (!strategies.includes(opts.bidding)) {
10049
+ if (opts.bidding && !strategies.includes(opts.bidding)) {
9942
10050
  console.error(`
9943
10051
  \u274C --bidding \u53EA\u63A5\u53D7 ${strategies.join(" | ")}
9944
10052
  `);
@@ -9955,26 +10063,46 @@ adCmd.command("campaign-create").description(
9955
10063
  `);
9956
10064
  process.exit(1);
9957
10065
  }
10066
+ let extensionsJson;
10067
+ if (opts.extensionsJson) {
10068
+ try {
10069
+ extensionsJson = JSON.parse(opts.extensionsJson);
10070
+ } catch {
10071
+ console.error("\n\u274C --extensions-json \u683C\u5F0F\u9519\u8BEF\uFF0C\u8BF7\u4F20\u5165\u5408\u6CD5\u7684 JSON \u6570\u7EC4\u5B57\u7B26\u4E32\n");
10072
+ process.exit(1);
10073
+ }
10074
+ }
10075
+ let extraAdGroupsJson;
10076
+ if (opts.extraAdgroupsJson) {
10077
+ try {
10078
+ extraAdGroupsJson = JSON.parse(opts.extraAdgroupsJson);
10079
+ } catch {
10080
+ console.error("\n\u274C --extra-adgroups-json \u683C\u5F0F\u9519\u8BEF\uFF0C\u8BF7\u4F20\u5165\u5408\u6CD5\u7684 JSON \u6570\u7EC4\u5B57\u7B26\u4E32\n");
10081
+ process.exit(1);
10082
+ }
10083
+ }
9958
10084
  await runAdCampaignCreate({
10085
+ configFile: opts.configFile,
9959
10086
  token: opts.token,
9960
- account: opts.account,
9961
- customerName: opts.customerName,
9962
- name: opts.name,
9963
- budget: opts.budget,
9964
- biddingStrategy: opts.bidding,
10087
+ // 未使用 config-file 时,这些字段已通过上方校验确保非空;config-file 场景下函数内部会从文件补全
10088
+ account: opts.account ?? "",
10089
+ customerName: opts.customerName ?? "",
10090
+ name: opts.name ?? "",
10091
+ budget: opts.budget ?? 0,
10092
+ biddingStrategy: opts.bidding ?? "",
9965
10093
  bidCeiling: opts.bidCeiling,
9966
10094
  targetCpa: opts.targetCpa,
9967
10095
  targetRoas: opts.targetRoas,
9968
10096
  targetSearchNetwork: opts.searchNetwork,
9969
10097
  targetContentNetwork: opts.contentNetwork,
9970
- locationIds: opts.locationIds,
10098
+ locationIds: opts.locationIds ?? [],
9971
10099
  languageIds: opts.langIds,
9972
10100
  startDate: opts.start,
9973
10101
  endDate: opts.end,
9974
10102
  url: opts.url,
9975
10103
  status: opts.status ?? "Enabled",
9976
- adgroupName: opts.adgroupName,
9977
- maxCpc: opts.maxCpc,
10104
+ adgroupName: opts.adgroupName ?? "",
10105
+ maxCpc: opts.maxCpc ?? 0,
9978
10106
  keywords: opts.keywords,
9979
10107
  matchType: opts.matchType,
9980
10108
  headlines: opts.headlines,
@@ -9982,6 +10110,10 @@ adCmd.command("campaign-create").description(
9982
10110
  finalUrl: opts.finalUrl,
9983
10111
  path1: opts.path1,
9984
10112
  path2: opts.path2,
10113
+ productWords: opts.productWords,
10114
+ negativeKeywords: opts.negativeKeywords,
10115
+ extensionsJson,
10116
+ extraAdGroupsJson,
9985
10117
  draft: opts.draft,
9986
10118
  json: opts.json,
9987
10119
  verbose: opts.verbose
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "slug": "siluzan-tso",
3
- "version": "1.0.0-beta.51",
4
- "publishedAt": 1775023908902
3
+ "version": "1.0.0-beta.53",
4
+ "publishedAt": 1775034415747
5
5
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  > 所属 skill:`siluzan-tso`。
4
4
  >
5
- > 用途:AI 根据用户需求生成投放计划 → 以本模板格式呈现给用户确认 → 用户确认后按计划执行 CLI 命令创建广告。
5
+ > 用途:AI 根据用户需求生成投放计划 → 以本模板格式呈现给用户确认 → 用户确认后由助手在后台完成账户内创建。**勿向用户展示命令行或 `siluzan-tso` 等工具细节**(具体命令见文末「助手执行计划」)。
6
6
  > 触发场景:用户要求「帮我投广告」「创建广告系列」「制定投放方案」等。
7
7
 
8
8
  ---
@@ -13,14 +13,34 @@
13
13
  1. 收集信息:向用户了解产品/服务、目标、预算、地域、网站等
14
14
  2. 生成计划:按下方模板格式输出完整方案
15
15
  3. 用户确认:用户逐项审阅,提出修改
16
- 4. 执行创建:确认后按「执行命令」章节的 CLI 命令依次执行
16
+ 4. 执行创建:用户确认后,助手在后台按计划完成创建;**不向用户复述或展示任何命令行**
17
17
  ```
18
18
 
19
19
  **关键原则**:
20
- - 计划中每个字段都必须能直接映射到 CLI 参数,不写无法执行的内容
21
- - 关键词和广告文案必须通过合规检查(参考 `google-ads-compliance.md` 第十一章)
20
+
21
+ - 用户可见正文只写业务字段(预算、地域、文案等),不出现命令行、可执行脚本或工具名称
22
+ - 助手侧须保证每个业务字段可落实为实际创建步骤(映射关系见文末「助手执行计划」);**搜索网络仅限 Google 搜索、关闭搜索合作伙伴与展示网络**为必选策略
23
+ - 关键词和广告文案必须通过合规检查(参考 `references/google-ads-rules/google-ads-compliance.md` 第十一章)
22
24
  - 敏感行业须额外标注合规要求(参考 `sensitive-industries.md`)
23
25
 
26
+ ### 各模块推荐数量一览
27
+
28
+ 以下与 `references/google-ads-rules/google-ads-compliance.md` 第七章、`references/google-ads-rules/google-ads-keyword-strategy.md`、`references/google-ads-rules/google-ads-creative-optimization.md` 第一章与第五章对齐;**正文结构以本节下「模板正文」中 Google Ads 搜索详细执行方案为准**。生成计划时按推荐条数填满表格,勿仅用少量示例占位。
29
+
30
+ | 模块 | 最少 | 推荐 | 上限 / 说明 |
31
+ |------|------|------|----------------|
32
+ | 每广告组正向关键词 | 20 条 | **20–30 条** | >30 条宜拆广告组;**组内意图须高度一致**以利质量得分 |
33
+ | 账户级否定词包分类 | 3 类 | **5 类**(见模板「账户级否定关键词表」) | 每类下列多条广泛/词组否定词;列表须应用到**所有**系列 |
34
+ | 系列级补充否定词 | 3 条 | **5–10 条** | 系列专属;与账户列表互补 |
35
+ | RSA Headlines | 12 条 | **12–15 条** | 最多 15 条;**关键位置按模板用「固定📌」标注** |
36
+ | RSA Descriptions | 4 条 | **4 条** | 最多 4 条 |
37
+ | Sitelink | 6 条 | **6–8 条** | 创意文档亦给出更高账户级上限,计划内以本表为准 |
38
+ | Callout | 6 条 | **6–8 条** | 每条宜 12–15 字符(效果参考创意文档) |
39
+ | Structured Snippet | 1 组 | **1–2 组** | 每组 **≥4 个值**(`values`) |
40
+ | 附加电话(CALL) | 0 | **有合规客服号则 1 条** | 无电话则可不填 |
41
+ | 潜在客户表单(Lead Form) | 0 | **线索类 B2B 可 1 套** | 在 Google Ads 后台配置;CLI 当前无对应命令时由助手说明后台步骤 |
42
+ | 合规提示下的限制条目(Tier 2/3) | — | **每条实质限制 2–4 条** | 过少易漏项,过多影响可读性 |
43
+
24
44
  ---
25
45
 
26
46
  ## 模板正文
@@ -41,6 +61,8 @@ AI 生成计划时,按以下格式输出。`{{占位符}}` 由 AI 根据用户
41
61
 
42
62
  ## 一、投放目标
43
63
 
64
+ **表项**:下表 **5 行**均需填写(产品、核心目标、KPI、受众、行业分级)。
65
+
44
66
  | 项目 | 内容 |
45
67
  |---|---|
46
68
  | 推广产品/服务 | {{产品或服务描述}} |
@@ -50,138 +72,204 @@ AI 生成计划时,按以下格式输出。`{{占位符}}` 由 AI 根据用户
50
72
  | 行业分类 | {{行业}} — {{Tier 1 标准 / Tier 2 受限 / Tier 3 高度管制}} |
51
73
 
52
74
  {{如为 Tier 2/3,在此插入合规提示:}}
53
- > ⚠️ **合规提示**:{{行业}}属于{{Tier等级}}行业,须遵守以下限制:
75
+ > ⚠️ **合规提示**(推荐列出 **2–4 条**核心限制):{{行业}}属于{{Tier等级}}行业,须遵守以下限制:
54
76
  > - {{限制条目 1}}
55
77
  > - {{限制条目 2}}
78
+ > - {{限制条目 3(可选)}}
56
79
  > - 详见 `sensitive-industries.md` 第{{X}}节
57
80
 
58
81
  ---
59
82
 
60
83
  ## 二、预算与排期
61
84
 
85
+ **表项**:下表 **4 行**(月预算、日预算、启动日、周期)。多系列时,各系列单日预算可写在第三章表格的「单日预算」列(区间或定额均可)。
86
+
62
87
  | 项目 | 内容 |
63
88
  |---|---|
64
89
  | 月度总预算 | {{金额}} {{币种}} |
65
- | 日预算 | {{金额}} {{币种}}(= 月预算 ÷ 30.4 |
90
+ | 日预算(账户/合计) | {{金额}} {{币种}}(= 月预算 ÷ 30.4,或与各系列日预算之和一致) |
66
91
  | 启动日期 | {{YYYY-MM-DD}} |
67
92
  | 计划周期 | {{如:持续投放 / 3个月试投 / 活动期间 MM-DD ~ MM-DD}} |
68
93
 
69
94
  ---
70
95
 
71
- ## 三、广告系列架构
96
+ ## 三、Google Ads 搜索广告详细执行方案
72
97
 
73
- ### 系列总览
98
+ ### 3.1 网络与流量质量(必选)
74
99
 
75
- | # | 系列名称 | 类型 | 日预算 | 出价策略 | 地域 |
76
- |---|---|---|---|---|---|
77
- | 1 | {{系列名}} | Search | {{金额}} | {{策略}} | {{地域}} |
78
- | 2 | {{系列名}} | Search | {{金额}} | {{策略}} | {{地域}} |
100
+ **注意**:**绝不要**勾选「包括 Google 搜索网络合作伙伴」和「包括 Google 展示广告网络」,否则会引入大量低质流量。
79
101
 
80
- ### 系列 1:{{系列名称}}
102
+ | 要求 | 说明 |
103
+ |---|---|
104
+ | 投放网络 | **仅限 Google 搜索网络(Google Search Network only)** |
105
+ | 禁止项 | 不启用搜索合作伙伴;不启用展示广告网络 |
81
106
 
82
- **基本设置**
107
+ ---
83
108
 
84
- | 参数 | 值 | CLI 映射 |
85
- |---|---|---|
86
- | 系列名称 | {{名称}} | `--name` |
87
- | 日预算 | {{金额}} {{币种}} | `--budget` |
88
- | 出价策略 | {{TARGET_SPEND / MANUAL_CPC / TARGET_CPA / TARGET_ROAS}} | `--bidding` |
89
- | 出价上限/目标 | {{如有:CPC上限/tCPA/tROAS值}} | `--bid-ceiling` / `--target-cpa` / `--target-roas` |
90
- | 投放地域 | {{地域名称}}(ID: {{geo_id}}) | `--location-ids` |
91
- | 投放语言 | {{语言}}(ID: {{lang_id}}) | `--lang-ids` |
92
- | 落地页 | {{URL}} | `--url` |
93
- | 初始状态 | {{Enabled / Paused}} | `--status` |
109
+ ### 3.2 广告系列(Campaign)基础设置
94
110
 
95
- #### 广告组 1-1:{{广告组名称}}
111
+ **表项**:按系列列展开(常见 **2–3 个搜索系列**;多于 3 个时继续增列并写清预算占比)。**广告轮换**统一建议:**优先展示效果最佳的广告(Optimize)**。
96
112
 
97
- **关键词**
113
+ | 设置项 | {{系列 1 名称}} | {{系列 2 名称}} | {{系列 3(可选)}} |
114
+ |---|---|---|---|
115
+ | 单日预算 | {{如:$100 – $150}} | {{如:$50 – $100}} | {{…}} |
116
+ | 投放网络 | 仅限 Google 搜索网络 | 同左 | 同左 |
117
+ | 地理位置 | {{如:美国、加拿大、英国;预算紧则先美国}} | {{…}} | {{…}} |
118
+ | 语言 | {{如:English}} | {{…}} | {{…}} |
119
+ | 出价策略(首月) | {{如:每次点击费用人工出价 Manual CPC;关闭「智能点击付费 (eCPC)」,以便卡死出价上限、摸清底价}} | {{如:尽可能争取更多点击次数 Maximize Clicks,并设最高 CPC 限制(如 $3.50),用于爆款/测流}} | {{…}} |
120
+ | 出价策略(次月) | {{如:近 30 天满 30 个目标转化后,切换为目标每次转化费用 tCPA = $X}} | {{同逻辑或单独写 tCPA}} | {{…}} |
121
+ | 广告轮换 | 优先展示效果最佳的广告 | 同左 | 同左 |
98
122
 
99
- | 关键词 | 匹配类型 | 格式 |
100
- |---|---|---|
101
- | {{keyword 1}} | 完全匹配 | `[keyword 1]` |
102
- | {{keyword 2}} | 词组匹配 | `"keyword 2"` |
103
- | {{keyword 3}} | 广泛匹配 | `keyword 3` |
104
- | ... | ... | ... |
123
+ > **落地页**:各系列默认 URL 在下方广告组/创意节中按组填写;若全账户统一落地页,可在本表下增加一行「默认落地页 | {{URL}}」。
124
+
125
+ ---
105
126
 
106
- **否定关键词**(系列级)
127
+ ### 3.3 广告组(Ad Group)与关键词矩阵
128
+
129
+ **原则**:每一个广告组内的关键词**意图必须高度一致**,广告文案与落地页与意图对齐,**质量得分(Quality Score)**才容易拉高。匹配符号:`[完全]`、`"词组"`、广泛无括号。
130
+
131
+ #### 系列 1:{{系列名称}}
132
+
133
+ | 广告组名称 | 核心关键词(带匹配符号) | 对应搜索意图 | 建议基准出价 (CPC) |
134
+ |---|---|---|---|
135
+ | {{AG 1 名称}} | {{`"词1"` / `[词2]` / 广泛词 …,补足 10–20 条时在组下列全表}} | {{意图一句话}} | {{币种区间或定额}} |
136
+ | {{AG 2 名称}} | {{…}} | {{…}} | {{…}} |
137
+
138
+ (每个广告组下可再拆「关键词」子表:| 关键词 | 匹配类型 | 格式 |,列满推荐条数,勿停留在 3 条示例。)
139
+
140
+ #### 系列 2:{{系列名称}}
141
+
142
+ | 广告组名称 | 核心关键词(带匹配符号) | 对应搜索意图 | 建议基准出价 (CPC) |
143
+ |---|---|---|---|
144
+ | {{AG 1 名称}} | {{…}} | {{…}} | {{…}} |
145
+ | {{AG 2 名称}} | {{…}} | {{…}} | {{…}} |
146
+
147
+ (系列较多时继续复制本小节。)
148
+
149
+ **系列级补充否定关键词**(除账户级列表外;**推荐 5–10 条**,**最少 3 条**)
107
150
 
108
151
  | 否定词 | 匹配类型 | 原因 |
109
152
  |---|---|---|
110
153
  | {{negative 1}} | 完全匹配 | {{原因}} |
111
154
  | {{negative 2}} | 词组匹配 | {{原因}} |
155
+ | … | … | … |
156
+
157
+ ---
158
+
159
+ ### 3.4 账户级否定关键词表
160
+
161
+ **操作位置**:Google Ads **工具与设置 → 否定关键词列表(Negative keyword lists)** 中建立,并**应用到所有广告系列**。
162
+
163
+ | 否定词包分类 | 具体否定词(填入后台;默认建议**广泛匹配** unless 另有说明) |
164
+ |---|---|
165
+ | 平台 / 零售商 | {{如:amazon, ebay, aliexpress, walmart, home depot, lowes, target, best buy, sears}} |
166
+ | C 端意图词 | {{如:repair, fix, DIY, near me, local, store, tutorial, video, manual, guide, how to, broken, replacing}} |
167
+ | 微量采购词 | {{如:single, 1 pc, one piece, individual, personal}} |
168
+ | 低质流量词 | {{如:free, cheap, used, second hand, discount, craigslist, forum, reddit}} |
169
+ | 服务类词汇 | {{如:service, technician, mechanic, company near me, repairman}} |
170
+ | {{自定义分类}} | {{按需增列:品牌误触、招聘、学术等}} |
171
+
172
+ > **搜索词报告**:上线后每日查看实际触发词;发现 C 端/教程类长句可**复制为完全匹配否定**加入列表或系列级否定(例如将整句 `[how to replace my whirlpool dryer belt]` 否定)。
173
+
174
+ ---
175
+
176
+ ### 3.5 响应式搜索广告(RSA)
112
177
 
113
- **广告创意(RSA)**
178
+ **优化师操作指令**:以下资产全部填入后台,由系统组合展示。**带【固定📌】的**,须在 Google Ads 编辑器中对应该 **Headline / Description 位置** 使用**图钉**锁定(位置 1、2… 与后台一致)。
114
179
 
115
- Headlines({{N}} 条):
180
+ **每个广告组配置 1 个 RSA** 即可(若策略需 A/B 再增列)。
116
181
 
117
- | # | 标题 | 主题类别 | 字符数 |
182
+ #### 广告组:{{AG 名称}}(所属系列:{{系列名}})
183
+
184
+ | 资产类型 | 广告文案 | 字符数 | 后台设置指令 |
118
185
  |---|---|---|---|
119
- | H1 | {{标题文本}} | 关键词相关 | {{N}} |
120
- | H2 | {{标题文本}} | 价值主张 | {{N}} |
121
- | H3 | {{标题文本}} | CTA | {{N}} |
122
- | H4 | {{标题文本}} | 社会证明 | {{N}} |
123
- | H5 | {{标题文本}} | 品牌 | {{N}} |
124
- | ... | ... | ... | ... |
186
+ | Headline 1 | {{文案}} | {{N}} | 【固定📌在位置 1】{{说明,如:保证第一眼看到核心定位}} |
187
+ | Headline 2 | {{文案}} | {{N}} | 【固定📌在位置 2】{{说明,如:拦截非目标客群}} |
188
+ | Headline 3 | {{文案}} | {{N}} | 自由轮换 |
189
+ | Headline 4 | {{文案}} | {{N}} | 自由轮换 |
190
+ | | | | |
191
+ | Headline 15(上限) | {{文案}} | {{N}} | 自由轮换 |
125
192
 
126
- Descriptions{{N}} 条):
193
+ Headlines **推荐 12–15 条**;主题分配仍参考 `references/google-ads-rules/google-ads-creative-optimization.md` 1.2 六类主题法。)
127
194
 
128
- | # | 描述 | 字符数 |
129
- |---|---|---|
130
- | D1 | {{描述文本}} | {{N}} |
131
- | D2 | {{描述文本}} | {{N}} |
195
+ | 资产类型 | 广告文案 | 字符数 | 后台设置指令 |
196
+ |---|---|---|---|
197
+ | Description 1 | {{文案}} | {{N}} | 【固定📌在位置 1】{{说明}} |
198
+ | Description 2 | {{文案}} | {{N}} | 自由轮换 |
199
+ | Description 3 | {{文案}} | {{N}} | 自由轮换 |
200
+ | Description 4 | {{文案}} | {{N}} | 自由轮换 |
201
+
202
+ Display URL:`{{domain}}/{{path1}}/{{path2}}`(Path1/Path2 各 ≤ 15 字符)
132
203
 
133
- Display URL:`{{domain}}/{{path1}}/{{path2}}`
204
+ **广告组默认最高 CPC**:{{金额}} {{币种}}(与 3.3 矩阵一致)
134
205
 
135
- **广告组 CPC**:{{金额}} {{币种}} → `--max-cpc`
206
+ (多广告组时重复「广告组:{{AG}}」小节。)
136
207
 
137
208
  ---
138
209
 
139
- {{如有多个系列,重复「系列 N」章节}}
210
+ ### 3.6 广告附加信息(Assets / Extensions)
140
211
 
212
+ **数量**:Sitelink **推荐 6–8**;Callout **推荐 6–8**;Structured Snippet **至少 1 组,推荐 1–2 组**,每组 **≥4 值**;**CALL** 有合规号码则 **1 条**;**Lead Form** 按业务 **0–1 套**。
213
+
214
+ **联系方式**:电话走 **CALL**;**无独立「邮箱」附加信息类型**,邮箱用 **Sitelink** 指向 `mailto:` 或联系页(勿写入 RSA 正文,见 `references/google-ads-rules/google-ads-compliance.md`)。
215
+
216
+ #### 附加链接(Sitelinks)
217
+
218
+ | # | 建议文案 | 落地页 URL / 说明 |
219
+ |---|---|---|
220
+ | 1 | {{如:OEM & ODM Service}} | {{独立页或首页锚点}} |
221
+ | 2 | {{如:Factory Tour / 验厂}} | {{URL}} |
222
+ | 3 | {{如:Request Bulk Quote}} | {{URL}} |
223
+ | 4 | {{如:Download Catalog}} | {{URL}} |
224
+ | 5 | {{邮件咨询 / 联系我们(若需邮箱)}} | {{mailto: 或联系表单页}} |
225
+ | … | (补足 **6–8** 条) | … |
226
+
227
+ #### 附加宣传信息(Callouts)
228
+
229
+ | Callout 文本 |
230
+ |---|
231
+ | {{如:No Middleman Markups}} |
232
+ | {{如:ISO 9001 Certified}} |
233
+ | … |
141
234
  ---
142
235
 
143
- ## 四、附加信息
236
+ ### 3.7 优化师日常操作 S.O.P(执行规范)
144
237
 
145
- | 类型 | 内容 | 链接/值 |
238
+ | 频次 | 必做事项 |
239
+ |---|---|
240
+ | **每日(建议前 14 天)** | 查**搜索词报告**:发现 C 端/教程/无关意图,**立即**将具体词或整句以合适匹配类型加入**账户否定列表**或系列否定;这是控制流量质量的关键 |
241
+ | **每周** | **砍烂词**:某关键词花费 > {{如:$15}} 且无有效转化(或无线索/WhatsApp 等约定动作),**暂停**;**调出价**:有效 B2B/目标动作词可提价 **10%–15%**,争取**绝对页首展示份额** |
242
+ | **每月** | 核对 CRM/销售数据,算真实 ROI;对「垃圾线索」来源词**降价或暂停**;评估是否满足切换 **tCPA / 智能出价** 的数据门槛 |
243
+
244
+ **阶段总览**(与 `references/google-ads-rules/google-ads-campaign-optimization.md` 可对照,不替代上表日常动作):
245
+
246
+ | 阶段 | 时间 | 重点任务 |
146
247
  |---|---|---|
147
- | Sitelink | {{文本}} | {{URL}} |
148
- | Sitelink | {{文本}} | {{URL}} |
149
- | Sitelink | {{文本}} | {{URL}} |
150
- | Sitelink | {{文本}} | {{URL}} |
151
- | Callout | {{文本}} | — |
152
- | Callout | {{文本}} | — |
153
- | Callout | {{文本}} | — |
154
- | Callout | {{文本}} | — |
155
- | Structured Snippet | {{Header}}: {{值1, 值2, 值3, 值4}} | — |
156
- | Call(如适用) | {{电话号码}} | 国家码: {{+XX}} |
248
+ | 学习期 | 1–2 周 | 少大改结构;盯审核、展示量、CTR |
249
+ | 数据积累 | 2–4 周 | 搜索词报告驱动否定词;替换低效词 |
250
+ | 策略校准 | 4–8 周 | 满足条件后智能出价;刷新创意 |
251
+ | 持续优化 | 8 周+ | 地域/设备;扩系列与关键词 |
157
252
 
158
253
  ---
159
254
 
160
- ## 五、转化追踪建议
255
+ ## 四、转化追踪建议
256
+
257
+ **条目**:本表固定 **4 项**(主转化、EC、离线导入、归因),每项一行写清建议,勿留空壳占位。
161
258
 
162
259
  | 项目 | 建议 |
163
260
  |---|---|
164
- | 主转化动作 | {{如:表单提交 / 购买 / 60秒+通话}} |
261
+ | 主转化动作 | {{如:表单提交 / Lead Form 提交 / 购买 / 60秒+通话}} |
165
262
  | Enhanced Conversions | {{建议启用 Web 版 / Leads 版}} |
166
263
  | 离线转化导入 | {{是否需要,频率建议}} |
167
264
  | 归因模型 | {{DDA(推荐)/ Last-click}} |
168
265
 
169
- > 转化追踪需在 Google Ads 后台或 GTM 中配置,CLI 暂不支持直接设置。
266
+ > 转化追踪在 Google Ads **GTM** 中配置;本计划为策略说明,具体安装与调试在后台完成。
170
267
 
171
268
  ---
172
269
 
173
- ## 六、启动后优化节奏
174
-
175
- | 阶段 | 时间 | 重点任务 |
176
- |---|---|---|
177
- | 学习期 | 第 1-2 周 | 不做大调整;监控审核状态、展示量、基础 CTR |
178
- | 数据积累 | 第 2-4 周 | 分析搜索词报告,添加否定词;替换低效关键词 |
179
- | 策略校准 | 第 4-8 周 | 根据 CPA 数据切换至 Smart Bidding;优化广告文案 |
180
- | 持续优化 | 第 8 周+ | 地域/设备出价调整;扩展新系列/关键词;创意刷新 |
181
-
182
- ---
270
+ ## 五、合规检查清单
183
271
 
184
- ## 七、合规检查清单
272
+ **条数**:以下 **8 条**逐项勾选(与 `references/google-ads-rules/google-ads-compliance.md` 第十一章呼应,不增删序号以免漏检)。
185
273
 
186
274
  - [ ] 所有 headline ≤ 30 字符(CJK 按 2 字符/字计算)
187
275
  - [ ] 所有 description ≤ 90 字符
@@ -194,15 +282,32 @@ Display URL:`{{domain}}/{{path1}}/{{path2}}`
194
282
 
195
283
  ---
196
284
 
197
- ## 八、执行命令预览
285
+ ## 六、落地与执行说明
286
+
287
+ 确认本计划后,助手将按上述结构在您的广告账户中完成系列、广告组、关键词、创意与附加信息的创建与配置(**不含搜索合作伙伴与展示网络**),并在过程中同步进度与结果。若部分能力(如 **RSA 图钉位置**、**账户级否定词列表批量应用**、**Lead Form**)需仅在 Google Ads 界面完成,助手将明确说明由您在后台确认的操作步骤。
288
+
289
+ ---
290
+
291
+ **请确认以上方案,或告知需要调整的部分。确认后我将开始为您落地投放结构。**
292
+ ````
293
+
294
+ ---
295
+
296
+ ## 助手执行计划(内部,勿向用户展示或复述)
297
+
298
+ 用户确认方案后,助手在后台按下列顺序执行(参数须与计划正文中的业务字段一致)。**不要**把本节内容粘贴给用户或逐条朗读命令。
299
+
300
+ **与产品方案对齐的硬规则**:
198
301
 
199
- 确认后将依次执行以下命令:
302
+ - 创建/编辑系列时:**仅 Google 搜索网络**;**勿启用**搜索合作伙伴与展示网络(若 API/后台选项由平台暴露,须显式关闭)。
303
+ - **账户级否定关键词列表**:若当前 CLI/API 仅支持系列级否定,则对每个系列执行否定词创建,或与用户说明需在后台一次性绑定列表;**计划正文仍以「账户列表 + 全系列应用」为准**。
304
+ - **RSA 图钉(Headline/Description 固定位置)**、**Lead Form 附加信息**:若 CLI 无字段,在 Google Ads 界面按计划补全(不向用户展示命令)。
200
305
 
201
306
  ```bash
202
307
  # 1. 查询地域 ID(如尚未确认)
203
308
  siluzan-tso ad geo search -a {{CID}} -q "{{地域名}}"
204
309
 
205
- # 2. 创建系列 1(一体化模式)
310
+ # 2. 创建系列 1(一体化模式;网络选项须与计划 3.1 一致)
206
311
  siluzan-tso ad campaign-create \
207
312
  -a {{CID}} \
208
313
  --customer-name "{{账户名}}" \
@@ -247,14 +352,16 @@ siluzan-tso ad ad-create \
247
352
  --descriptions "{{descriptions}}" \
248
353
  --path1 "{{path1}}" --path2 "{{path2}}"
249
354
 
250
- # 7. 添加否定关键词(系列级)
355
+ # 7. 添加否定关键词(系列级;账户级列表若后台统一管理,此处可逐系列同步同一批词)
251
356
  siluzan-tso ad keyword-negative-create \
252
357
  -a {{CID}} \
253
358
  --campaign-id <系列ID> \
254
359
  --keyword "{{否定词}}" \
255
360
  --match-type {{EXACT/PHRASE}}
256
361
 
257
- # 8. 部署附加信息
362
+ # 8. 部署附加信息(Lead Form 无 CLI 时跳过,改后台)
363
+ siluzan-tso ad extension call -a {{CID}} --country-code "{{+XX}}" --phone "{{本地号码}}"
364
+ # (无客服电话则跳过 call;邮箱用 sitelink:mailto: 或联系页 URL,勿写入 RSA)
258
365
  siluzan-tso ad extension sitelink -a {{CID}} --text "{{文本}}" --url "{{URL}}"
259
366
  siluzan-tso ad extension callout -a {{CID}} --text "{{文本}}"
260
367
  siluzan-tso ad extension snippet -a {{CID}} --header "{{Header}}" --values "{{值列表}}"
@@ -265,11 +372,6 @@ siluzan-tso ad geo add -a {{CID}} --campaign-id <ID> --location-id <排除地域
265
372
 
266
373
  ---
267
374
 
268
- **请确认以上方案,或告知需要调整的部分。确认后我将立即开始创建。**
269
- ````
270
-
271
- ---
272
-
273
375
  ## AI 填充指引
274
376
 
275
377
  生成计划时遵循以下规则:
@@ -280,29 +382,32 @@ siluzan-tso ad geo add -a {{CID}} --campaign-id <ID> --location-id <排除地域
280
382
 
281
383
  | 必须 | 信息 | 用途 |
282
384
  |---|---|---|
283
- | ✅ | 账户 ID(`-a`) | 所有命令的前提 |
385
+ | ✅ | 广告账户 ID | 关联投放账户(执行时由助手使用,勿向用户解释命令行) |
284
386
  | ✅ | 推广的产品/服务 | 决定关键词和文案方向 |
285
387
  | ✅ | 目标(线索/销售/曝光) | 决定系列类型和出价策略 |
286
- | ✅ | 月度预算 | 计算日预算、系列数量 |
287
- | ✅ | 投放地域 | `--location-ids` |
288
- | ✅ | 落地页 URL | `--url` / `--final-url` |
289
- | 建议 | 目标 CPA / ROAS | 出价策略参数 |
290
- | 建议 | 竞品/行业背景 | 关键词策略 |
388
+ | ✅ | 月度预算 | 计算日预算、系列数量与 3.2 表各列预算 |
389
+ | ✅ | 投放地域 | 地域定向与地域 ID |
390
+ | ✅ | 落地页 URL | 落地页与最终到达网址 |
391
+ | 建议 | 客服电话、邮箱或联系页 URL | **CALL** 与「邮件/联系」**Sitelink** |
392
+ | 建议 | 目标 CPA、首月最高 CPC、转化门槛 | **Manual CPC / Max Clicks / tCPA** 切换条件(见下表) |
393
+ | 建议 | 竞品/行业背景 | 关键词矩阵与否定词包 |
291
394
  | 建议 | 已有投放数据 | 优化起点 |
292
395
 
293
396
  ### 字段填充规则
294
397
 
295
398
  | 字段 | 规则 |
296
399
  |---|---|
297
- | 系列命名 | 遵循 `[类型]_[目标]_[定向]_[地域]_[匹配]` 规范(参考 `google-ads-campaign-optimization.md` 2.1 节) |
298
- | 出价策略 | 新系列默认 `TARGET_SPEND`;有历史数据且月转化 30+ 可用 `TARGET_CPA`/`TARGET_ROAS`(参考 3.1 节) |
299
- | 关键词 | STAG/SIAG 分组;核心高意图词用 `[完全]`,拓展词用 `"词组"` 或广泛(参考 `google-ads-keyword-strategy.md` 第二、三章) |
300
- | Headlines | 按六类主题法生成,目标 8-15 条;每条 30 字符(参考 `google-ads-creative-optimization.md` 1.2 节) |
301
- | Descriptions | 2-4 条,各自独立可用;至少 1 条含 CTA,1 条含关键词;每条 90 字符 |
302
- | 否定关键词 | 至少列出明显的品牌保护词和无关意图词 |
303
- | 附加信息 | Sitelink 4 + Callout 4 条 + Snippet ≥ 1 组 |
304
- | 地域 | 先用 `ad geo search` 确认 ID;多数业务建议 Presence only 模式 |
305
- | 日预算 | 2-3× 目标 CPA(参考 `google-ads-campaign-optimization.md` 7.1 节) |
400
+ | 投放网络 | **仅限 Google 搜索**;正文与助手侧均**禁止**默认开启搜索合作伙伴与展示网络 |
401
+ | 系列命名 | 遵循 `[类型]_[目标]_[定向]_[地域]_[匹配]` 规范(参考 `google-ads-campaign-optimization.md` 2.1 节);可与业务名并用(如「B2B 源头寻源」) |
402
+ | 出价策略(首月) | **产品默认**:核心系列用 **Manual CPC**,且**关闭 eCPC**,写明建议 CPC 上限区间;测流/爆款系列可用 **Maximize Clicks + 最高 CPC**;与 `TARGET_SPEND` 等等价映射以实际 CLI/API 可选值为准时在助手侧转换,**用户可见正文始终用 Google Ads 界面用语** |
403
+ | 出价策略(次月) | **产品默认**:近 **30 天满 30 个**约定转化(如表单)后切换 **tCPA**;无足够数据则延续人工或 Max Clicks 并写明条件 |
404
+ | 关键词(每广告组) | **组内意图高度一致**;**最少 5、推荐 10–20**;`[完全]` / `"词组"` / 广泛分层(`google-ads-keyword-strategy.md`) |
405
+ | 否定词 | **账户级 5 类词包**填满模板表;系列级补充 5–10 条;上线后搜索词**每日**迭代 |
406
+ | RSA | **12–15** 标题、**4** 描述;**至少 H1、H2 D1** 在表中标注【固定📌】及目标位置与理由;字符合规见第十一章 |
407
+ | 附加信息 | Sitelink **6–8**(可含 OEM/验厂/报价/目录/联系);Callout **6–8**;Snippet **≥1 组、每组 ≥4 值**;**Lead Form** 线索业务建议填标题与必填字段 |
408
+ | 投放设备 | **默认全设备**;仅在用户明确要求时写侧策略,并与 `google-ads-campaign-optimization.md` 第五章一致 |
409
+ | 地域 | 助手侧先确认 Google 地域 ID(见「助手执行计划」第 1 步);多数业务建议 Presence only 模式 |
410
+ | 日预算 | ≥ 2–3× 目标 CPA(参考 `google-ads-campaign-optimization.md` 7.1 节);与 3.2 表区间一致 |
306
411
 
307
412
  ### 合规检查
308
413
 
@@ -312,14 +417,14 @@ siluzan-tso ad geo add -a {{CID}} --campaign-id <ID> --location-id <排除地域
312
417
 
313
418
  - 品牌词始终独立一个系列(Exact Match + 低 CPA)
314
419
  - 竞品词独立系列(Manual CPC 或 Max Clicks + CPC 上限)
315
- - 非品牌高意图词和中意图词可按意图层分系列
316
- - 每个系列的预算分配写在「系列总览」表中
317
- - 预算分配参考:品牌 10-15% / 高意图非品牌 50-60% / 中意图拓展 20-30% / 竞品 5-10%
420
+ - 非品牌高意图与中意图可按意图分系列(与 3.3 矩阵一致)
421
+ - 每个系列的预算分配写在 **3.2** 表的「单日预算」列
422
+ - 预算分配参考:品牌 1015% / 高意图非品牌 5060% / 中意图拓展 2030% / 竞品 510%
318
423
 
319
424
  ### 输出格式要求
320
425
 
321
426
  - 直接输出 Markdown 文本,不需要代码围栏包裹
322
427
  - 所有金额标注币种
323
428
  - 字符数必须实际计算并填入(CJK 字符按 2 计)
324
- - 执行命令区域的参数必须与计划表格中的值完全一致
325
- - 如系列较多(>3),可将命令预览精简为仅展示第一个系列的完整命令 + 其余系列的差异说明
429
+ - **用户可见正文中不得出现**:`siluzan-tso`、shell/bash 代码块、命令行参数(如 `--budget`)、或任何可复制的终端命令;执行细节仅保留在助手侧,对照「助手执行计划」与计划表格保持一致即可
430
+ - 如系列较多(>3),助手侧可分系列执行;用户可见方案写全业务表格即可
@@ -9,7 +9,7 @@
9
9
 
10
10
  ### 第一步:规则文档阅读(不得跳过)
11
11
 
12
- 操作开始前,**AI 必须先阅读完下面所有相关文档**,并在心智模型中内化规则后,才能进入任何「方案规划 / 广告创建 / 调整」步骤,严禁只读 `google-ads-launch-plan-template.md` 就直接出方案。
12
+ 操作开始前,**AI 必须先阅读完下面所有文档**,并在心智模型中内化规则后,才能进入任何「方案规划 / 广告创建 / 调整」步骤,严禁只读 `google-ads-launch-plan-template.md` 就直接出方案。
13
13
 
14
14
  | 文档地址 | 文档内容 |
15
15
  |----------|-----------|
@@ -591,7 +591,7 @@ siluzan-tso keyword -k "running shoes" --json
591
591
 
592
592
  ## ad campaign-create — 广告系列新增
593
593
 
594
- 新建搜索广告系列(异步批量任务)。支持两种模式:
594
+ 新建搜索广告系列(异步批量任务)。支持两种创建模式:
595
595
 
596
596
  - **一体化模式**(推荐):传入 `--keywords`、`--headlines`、`--descriptions`,一条命令完成系列 + 组 + 关键词 + 广告创意,与网页 AI 创建向导行为等价。
597
597
  - **骨架模式**:仅创建系列和空广告组,后续用 `ad keyword-create`、`ad ad-create` 补充内容。
@@ -603,41 +603,202 @@ siluzan-tso keyword -k "running shoes" --json
603
603
  > 广告组、关键词、广告创意的直接创建走另一套 Google 网关 API,均有对应的 `adgroup-create`、`keyword-create`、`ad-create` 等命令。
604
604
  > 任务异步处理,任务 ID 可通过 `ad batch get --id <id>` 跟进进度。
605
605
 
606
- ### 选项
606
+ ---
607
+
608
+ ### 🤖 AI 推荐用法:--config-file(JSON 配置文件)
609
+
610
+ **当参数复杂(多广告组、含附加功能、标题中有逗号)时,AI 应优先使用此方式**:将所有参数写入一个 JSON 文件,再用 `--config-file` 传入路径。
611
+
612
+ **优势:**
613
+ - `headlines` 是真正的字符串数组,元素内**允许含逗号**(如 `"Global Reach, Local Impact"`)
614
+ - `extensions` / `extraAdGroups` 直接写 JSON,不需要序列化为字符串
615
+ - 参数复杂时无 shell 转义问题,AI 一次生成即可成功
616
+
617
+ **AI 执行步骤:**
618
+ 1. 用 Write 工具将配置写入 JSON 文件(如 `/tmp/campaign.json`)
619
+ 2. 执行 `siluzan-tso ad campaign-create --config-file /tmp/campaign.json`
620
+ 3. 用返回的任务 ID 查询进度
621
+
622
+ **JSON 配置文件完整 Schema:**
623
+
624
+ ```json
625
+ {
626
+ "account": "6326027735",
627
+ "customerName": "账户显示名称(来自 list-accounts --json 的 mediaAccountName)",
628
+ "name": "搜索-品牌词-2026",
629
+ "budget": 100,
630
+ "bidding": "TARGET_SPEND",
631
+ "bidCeiling": 1.5,
632
+ "locationIds": ["2840", "2826", "2036"],
633
+ "languageIds": ["1000", "1017"],
634
+ "startDate": "2026-04-01",
635
+ "endDate": "2027-04-01",
636
+ "url": "https://www.example.com",
637
+ "status": "Enabled",
638
+ "adgroupName": "核心词_品牌词",
639
+ "maxCpc": 1.5,
640
+ "matchType": "BROAD",
641
+ "keywords": [
642
+ "brand keyword 1",
643
+ "brand keyword 2",
644
+ "brand keyword 3"
645
+ ],
646
+ "headlines": [
647
+ "Brand Name: Quality Products",
648
+ "Trusted For Over 20 Years",
649
+ "Global Reach, Local Impact",
650
+ "Contact Us Today",
651
+ "Request A Free Quote Now"
652
+ ],
653
+ "descriptions": [
654
+ "Top-quality products with certified standards. Contact us today!",
655
+ "Trusted by global partners. Request a free quote now!"
656
+ ],
657
+ "finalUrl": "https://www.example.com/products",
658
+ "path1": "products",
659
+ "path2": "2026",
660
+ "productWords": ["brand", "product"],
661
+ "negativeKeywords": [
662
+ "free", "cheap", "wikipedia", "pdf", "ebay", "amazon"
663
+ ],
664
+ "extensions": [
665
+ {
666
+ "level": "Campaign",
667
+ "typeV2": "CALL",
668
+ "AssetFieldType": "CALL",
669
+ "Properties": { "ContryCode": "CN", "PhoneNumber": "+86 400-XXX-XXXX" }
670
+ },
671
+ {
672
+ "level": "Campaign",
673
+ "typeV2": "SITELINK",
674
+ "AssetFieldType": "SITELINK",
675
+ "properties": {
676
+ "DestinationUrl": "https://www.example.com/about",
677
+ "Text": "About Us",
678
+ "Line2": "Learn about our story",
679
+ "Line3": "Explore our mission"
680
+ }
681
+ },
682
+ {
683
+ "level": "Campaign",
684
+ "typeV2": "STRUCTURED_SNIPPET",
685
+ "AssetFieldType": "STRUCTURED_SNIPPET",
686
+ "StructuredSnippetHeaderValue": {
687
+ "key": "Services",
688
+ "value": ["Quality Certified", "Global Shipping", "24/7 Support"]
689
+ }
690
+ }
691
+ ],
692
+ "extraAdGroups": [
693
+ {
694
+ "MaxCPCAmount": 150,
695
+ "Name": "通用词_行业词",
696
+ "StatusV2": "Enabled",
697
+ "TypeV2": "SEARCH_STANDARD",
698
+ "RotationModeV2": "Unspecified",
699
+ "KeywordsForBatchJob": [
700
+ {
701
+ "KeywordText": ["industry keyword 1", "industry keyword 2"],
702
+ "MatchTypeV2": "BROAD",
703
+ "Finalurl": "https://www.example.com"
704
+ }
705
+ ],
706
+ "AdsForBatchJob": [
707
+ {
708
+ "AdTitle": null,
709
+ "DestinationUrl": "https://www.example.com",
710
+ "Finalurl": "https://www.example.com",
711
+ "Path1": "", "Path2": "",
712
+ "TypeV2": "RESPONSIVE_SEARCH_AD",
713
+ "headlinePart1": "Industry Leading Products",
714
+ "headlinePart2": "Certified Quality Standards",
715
+ "headlinePart3": "Get A Free Quote Today",
716
+ "AddtionalHeadlines": [
717
+ "Trusted By Global Partners",
718
+ "20+ Years Of Experience",
719
+ "Contact Us Now"
720
+ ],
721
+ "adDescription": "Top-quality industry products with global shipping. Contact us today!",
722
+ "adDescription2": "Certified standards and reliable delivery. Request a quote now!"
723
+ }
724
+ ]
725
+ }
726
+ ],
727
+ "draft": false
728
+ }
729
+ ```
730
+
731
+ **字段说明:**
732
+
733
+ | 字段 | 必填 | 类型 | 说明 |
734
+ |------|------|------|------|
735
+ | `account` | ✅ | string | Google 账户 mediaCustomerId |
736
+ | `customerName` | ✅ | string | 账户名称(`list-accounts --json` 的 `mediaAccountName`) |
737
+ | `name` | ✅ | string | 广告系列名称 |
738
+ | `budget` | ✅ | number | 日预算,**主币种展示金额**(100 = 每天 100 USD/CNY,内部 ×100) |
739
+ | `bidding` | ✅ | string | 出价策略:`TARGET_SPEND` \| `MANUAL_CPC` \| `TARGET_CPA` \| `TARGET_ROAS` |
740
+ | `locationIds` | ✅ | string[] | 地理位置 ID 数组(`ad geo search` 获取) |
741
+ | `adgroupName` | ✅ | string | 第一个广告组名称 |
742
+ | `maxCpc` | ✅ | number | 第一个广告组最高 CPC,主币种展示金额(1.5 = 1.50 USD,内部 ×100) |
743
+ | `bidCeiling` | — | number | TARGET_SPEND 出价上限(主币种,内部 ×100) |
744
+ | `targetCpa` | — | number | TARGET_CPA 目标 CPA(主币种,内部 ×100) |
745
+ | `targetRoas` | — | number | TARGET_ROAS 目标 ROAS(如 2.5) |
746
+ | `languageIds` | — | string[] | 语言 ID 数组(默认 `["1000"]` = 英语,中文 = `"1017"`) |
747
+ | `startDate` / `endDate` | — | string | 日期 YYYY-MM-DD(默认:今天 / 2037-12-30) |
748
+ | `url` | — | string | 落地页 URL |
749
+ | `status` | — | string | `Enabled` \| `Paused`(默认 Enabled) |
750
+ | `matchType` | — | string | 默认匹配类型:`BROAD` \| `PHRASE` \| `EXACT` |
751
+ | `keywords` | — | string[] | 第一个广告组关键词 |
752
+ | `headlines` | — | string[] | 标题数组,至少 3 条,推荐 15 条,每条 ≤ 30 字符,**元素内允许含逗号** |
753
+ | `descriptions` | — | string[] | 描述数组,至少 2 条,推荐 4 条,每条 ≤ 90 字符 |
754
+ | `finalUrl` | — | string | 广告落地页 |
755
+ | `path1` / `path2` | — | string | 展示 URL 路径(各 ≤ 15 字符) |
756
+ | `productWords` | — | string[] | 推广产品词(用于 AI 关键词推荐) |
757
+ | `negativeKeywords` | — | string[] | 否定关键词数组(默认 BROAD 匹配) |
758
+ | `extensions` | — | array | 广告附加功能(CALL / SITELINK / STRUCTURED_SNIPPET),见 Schema |
759
+ | `extraAdGroups` | — | array | 额外广告组,追加到 AdGroupsForBatchJob,见 Schema |
760
+ | `draft` | — | boolean | `true` = 仅保存草稿(需后续 `ad batch publish` 发布) |
761
+
762
+ ---
763
+
764
+ ### 命令行直接传参(简单场景适用)
765
+
766
+ 所有参数也可以直接通过 CLI 选项传入(复杂场景推荐用 `--config-file`):
607
767
 
608
768
  | 选项 | 必填 | 说明 |
609
769
  |------|------|------|
610
- | `-a, --account <id>` | | Google 账户 mediaCustomerId |
611
- | `--customer-name <name>` | | 账户名称(来自 `list-accounts --json` 的 `mediaAccountName`) |
612
- | `--name <name>` | | 广告系列名称 |
613
- | `--budget <amount>` | | 日预算:**账户主币种展示金额**(如 `100` = 每天 100 USD/CNY;与 Web、`ad smart create` 一致,内部 `×100` 写入 `Budget`,**非** Google micros) |
614
- | `--bidding <strategy>` | | 出价策略:`TARGET_SPEND` \| `MANUAL_CPC` \| `TARGET_CPA` \| `TARGET_ROAS` |
615
- | `--location-ids <ids>` | | 地理位置 ID,逗号分隔(用 `ad geo search` 获取,2840=美国) |
616
- | `--adgroup-name <name>` | | 第一个广告组名称 |
617
- | `--max-cpc <amount>` | | 第一个广告组最高 CPC:**主币种展示金额**(如 `1.5` = 每次点击 1.50;内部 `×100` 写入批量体 `MaxCPCAmount` 字符串) |
618
- | `--keywords <kws>` | — | 关键词,逗号分隔;格式:词→BROAD,`*词*`→PHRASE,`[词]`→EXACT |
619
- | `--match-type <type>` | — | 无格式前缀关键词的默认匹配类型(默认 BROAD) |
620
- | `--headlines <titles>` | — | 广告标题,逗号分隔,至少 3 条 推荐15条,每条 ≤ 30 字符 |
621
- | `--descriptions <descs>` | — | 广告描述,逗号分隔,至少 2 条 推荐4条,每条 ≤ 90 字符 |
622
- | `--final-url <url>` | — | 广告落地页(关键词 / 广告共用;不传则继承 `--url`) |
623
- | `--path1 / --path2` | — | 展示 URL 路径(各 ≤ 15 字符) |
624
- | `--url <url>` | — | 推广落地页(附在外层 body) |
625
- | `--lang-ids <ids>` | — | 投放语言 ID,逗号分隔(默认 1000=英语;中文=1017) |
626
- | `--bid-ceiling <amount>` | — | TARGET_SPEND 出价上限:主币种金额(内部 `×100`;0=不限) |
627
- | `--target-cpa <amount>` | — | TARGET_CPA 目标 CPA:主币种金额(内部 `×100`) |
628
- | `--target-roas <n>` | — | TARGET_ROAS 目标 ROAS(如 2.5;最大 1000) |
629
- | `--start / --end` | — | 广告系列开始/结束日期(默认:今天 / 2037-12-30) |
630
- | `--status` | — | 初始状态:`Enabled` \| `Paused`(默认 Enabled) |
631
- | `--draft` | — | 仅保存为草稿(`DraftStatus=Draft`,需后续 `ad batch publish` 发布) |
632
-
633
- **典型用法**
770
+ | `-a, --account <id>` | ✅* | Google 账户 mediaCustomerId(*使用 `--config-file` 时可从文件读取) |
771
+ | `--customer-name <name>` | ✅* | 账户名称 |
772
+ | `--name <name>` | ✅* | 广告系列名称 |
773
+ | `--budget <amount>` | ✅* | 日预算(主币种展示金额) |
774
+ | `--bidding <strategy>` | ✅* | 出价策略 |
775
+ | `--location-ids <ids>` | ✅* | 地理位置 ID,逗号分隔 |
776
+ | `--adgroup-name <name>` | ✅* | 第一个广告组名称 |
777
+ | `--max-cpc <amount>` | ✅* | 最高 CPC(主币种展示金额) |
778
+ | `--keywords <kws>` | — | 关键词,逗号分隔 |
779
+ | `--headlines <titles>` | — | 广告标题,逗号分隔(⚠️ 标题内不能含逗号,含逗号请用 `--config-file`) |
780
+ | `--descriptions <descs>` | — | 广告描述,逗号分隔 |
781
+ | `--product-words <words>` | — | 产品词,逗号分隔 |
782
+ | `--negative-keywords <kws>` | — | 否定关键词,逗号分隔 |
783
+ | `--extensions-json <json>` | — | 附加功能 JSON 数组字符串 |
784
+ | `--extra-adgroups-json <json>` | — | 额外广告组 JSON 数组字符串 |
785
+ | `--lang-ids <ids>` | — | 语言 ID,逗号分隔(默认 1000=英语) |
786
+ | `--bid-ceiling / --target-cpa / --target-roas` | — | 出价相关参数 |
787
+ | `--start / --end` | — | 日期 YYYY-MM-DD |
788
+ | `--url / --final-url` | — | 落地页 |
789
+ | `--path1 / --path2` | — | 展示路径 |
790
+ | `--status` | — | Enabled \| Paused |
791
+ | `--draft` | — | 仅保存草稿 |
792
+ | `--config-file <path>` | — | JSON 配置文件路径(AI 推荐) |
793
+
794
+ **典型用法(简单场景):**
634
795
 
635
796
  ```bash
636
797
  # 前置:搜索投放地区 ID
637
798
  siluzan-tso ad geo search -a 6326027735 -q "United States"
638
799
  # 取出 id 字段,如 2840
639
800
 
640
- # 一体化创建(系列 + 关键词 + 广告创意,推荐)
801
+ # 一体化创建(CLI 直接传参,适合参数较少的场景)
641
802
  siluzan-tso ad campaign-create \
642
803
  -a 6326027735 \
643
804
  --customer-name "测试账户" \
@@ -648,17 +809,28 @@ siluzan-tso ad campaign-create \
648
809
  --adgroup-name "核心词_跑步鞋" \
649
810
  --max-cpc 5 \
650
811
  --url "https://www.brand-a.com/running-shoes" \
651
- --keywords "running shoes,sport shoes,[trail running]" \
652
- --headlines "专业跑步鞋,轻量透气设计,品牌直销价" \
653
- --descriptions "全球百万跑者信赖,专业助力每一步。,免费配送,30天无理由退换。" \
812
+ --keywords "running shoes,sport shoes,trail running" \
813
+ --headlines "Brand Running Shoes,Lightweight Design,Direct Factory Price" \
814
+ --descriptions "Trusted by millions worldwide.,Free shipping and 30-day returns." \
654
815
  --final-url "https://www.brand-a.com/running-shoes" \
655
- --path1 "跑步鞋" \
656
- --path2 "特惠"
816
+ --path1 "running" \
817
+ --path2 "shoes"
657
818
 
658
- # 第四步:用返回的任务 ID 查看创建进度
819
+ # 查看创建进度
659
820
  siluzan-tso ad batch get --id <taskId>
660
821
  ```
661
822
 
823
+ **典型用法(AI 推荐,config-file 方式):**
824
+
825
+ ```bash
826
+ # 1. AI 先写好 JSON 配置文件(使用 Write 工具)
827
+ # 2. 执行创建
828
+ siluzan-tso ad campaign-create --config-file /tmp/campaign-config.json
829
+
830
+ # 3. 查看进度
831
+ siluzan-tso ad batch get --id <返回的taskId>
832
+ ```
833
+
662
834
  ---
663
835
 
664
836
  ## ad campaign-edit — 广告系列编辑
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "siluzan-tso-cli",
3
- "version": "1.0.0-beta.51",
3
+ "version": "1.0.0-beta.53",
4
4
  "description": "Siluzan 广告账户管理 CLI — 查询账户、余额、消耗数据,管理绑定关系与充值。",
5
5
  "type": "module",
6
6
  "bin": {