tt-help-cli-ycl 1.4.2 → 1.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tt-help-cli-ycl",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "description": "TikTok user & video data scraper - extract ttSeller, verified, locationCreated from HTML source",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli/tag.js CHANGED
@@ -580,6 +580,7 @@ export async function handleScoreAll(parsed) {
580
580
  countries,
581
581
  serverUrl,
582
582
  autoDiscover,
583
+ discoverCount = 10,
583
584
  port,
584
585
  proxy: cliProxy,
585
586
  } = tagScoreAll || {};
@@ -731,15 +732,21 @@ export async function handleScoreAll(parsed) {
731
732
  totalScored > 0 &&
732
733
  totalScored % periodicRecycleEvery === 0
733
734
  ) {
734
- await recycleCdpSession(`periodic every ${totalScored} tasks`, { switchPort: false });
735
+ await recycleCdpSession(`periodic every ${totalScored} tasks`, {
736
+ switchPort: false,
737
+ });
735
738
  }
736
739
  }
737
740
 
738
741
  let totalScored = 0;
739
742
  let emptyRounds = 0; // 连续无任务的轮数
740
743
  let consecutive403 = 0; // 连续 HTTP 403 次数,达 3 次认为被封
741
- const DISCOVER_AFTER_EMPTY = 3; // 连续 3 轮无任务时触发 discover
744
+ const DISCOVER_AFTER_EMPTY = 3; // 连续 3 轮无任务时触发 discover(兜底)
742
745
  const CONSECUTIVE_403_BLOCKED = 3; // 连续 3 次 403 认为账号被封
746
+ const DISCOVER_LOW_THRESHOLD = 5; // 剩余 new 标签 < 5 时提前触发发现
747
+ const DISCOVER_COOLDOWN_MS = 5 * 60 * 1000; // 发现冷却时间 5 分钟,防止频繁调用 LLM
748
+ let discoverPromise = null; // 正在后台执行的发现 Promise
749
+ let lastDiscoverTime = 0; // 上次发现完成的时间戳
743
750
 
744
751
  // 生成客户端 ID,用于服务端追踪
745
752
  const clientId = randomUUID();
@@ -764,38 +771,82 @@ export async function handleScoreAll(parsed) {
764
771
  };
765
772
  process.on("SIGINT", cleanup);
766
773
 
774
+ // 异步发现函数:后台为所有目标国家生成标签,不阻塞打分循环
775
+ async function runDiscoverInBackground() {
776
+ if (discoverPromise) return; // 已在执行中,不重复触发
777
+ const elapsed = Date.now() - lastDiscoverTime;
778
+ if (elapsed < DISCOVER_COOLDOWN_MS) {
779
+ const remainMin = Math.ceil((DISCOVER_COOLDOWN_MS - elapsed) / 60000);
780
+ log(`🔍 发现冷却中,还需 ${remainMin} 分钟后才能再次触发`);
781
+ return;
782
+ }
783
+ log(`🔍 剩余标签不足,后台为 ${targetCountries.length} 个国家生成标签...`);
784
+ discoverPromise = (async () => {
785
+ let totalInserted = 0;
786
+ for (const country of targetCountries) {
787
+ try {
788
+ const discRes = await fetch(
789
+ `${baseUrl}/api/tags/discover?country=${country}&count=${discoverCount}`,
790
+ { headers: buildClientHeaders(clientId, clientMeta) },
791
+ );
792
+ const discData = await discRes.json();
793
+ if (discData.added) {
794
+ totalInserted += discData.added;
795
+ log(` ${country}: 新增 ${discData.added} 个`);
796
+ }
797
+ } catch (e) {
798
+ log(` ${country}: 请求失败 (${e.message})`);
799
+ }
800
+ }
801
+ log(` ✅ 发现完成,共入库 ${totalInserted} 个新标签`);
802
+ lastDiscoverTime = Date.now(); // 记录完成时间,开始冷却
803
+ discoverPromise = null;
804
+ })();
805
+ }
806
+
767
807
  try {
768
808
  while (true) {
769
809
  try {
770
- // 从服务端取下一个 new 标签
810
+ // 从服务端取下一个 new 标签(同时查剩余数量)
771
811
  const tagsRes = await fetch(`${baseUrl}/api/tags?status=new&limit=1`, {
772
812
  headers: buildClientHeaders(clientId, clientMeta),
773
813
  });
774
814
  const tagsData = await tagsRes.json();
815
+
816
+ // 提前触发发现:剩余 new 标签低于阈值且不在冷却期时后台生成
817
+ if (
818
+ autoDiscover &&
819
+ !discoverPromise &&
820
+ Date.now() - lastDiscoverTime >= DISCOVER_COOLDOWN_MS &&
821
+ (tagsData.total || 0) < DISCOVER_LOW_THRESHOLD
822
+ ) {
823
+ runDiscoverInBackground();
824
+ }
825
+
775
826
  if (!tagsData.tags || tagsData.tags.length === 0) {
776
827
  emptyRounds++;
777
828
 
778
- // 自动发现:连续 N 轮无任务时自动生成标签
829
+ // 兜底发现:连续 N 轮无任务(提前发现可能没生效)
779
830
  if (autoDiscover && emptyRounds >= DISCOVER_AFTER_EMPTY) {
780
- log(
781
- `🔍 连续 ${emptyRounds} 轮无待打分标签,自动为 ${targetCountries.length} 个国家生成标签...`,
782
- );
783
- for (const country of targetCountries) {
784
- try {
785
- const discRes = await fetch(
786
- `${baseUrl}/api/tags/discover?country=${country}&count=5`,
787
- { headers: buildClientHeaders(clientId, clientMeta) },
788
- );
789
- const discData = await discRes.json();
790
- if (discData.inserted) {
791
- log(` ${country}: 新增 ${discData.inserted} 个`);
792
- }
793
- } catch (e) {
794
- log(` ${country}: 请求失败 (${e.message})`);
795
- }
831
+ // 等后台发现完成(如果正在跑)
832
+ if (discoverPromise) {
833
+ log(` ⏳ 等待后台发现完成...`);
834
+ await discoverPromise;
835
+ } else if (Date.now() - lastDiscoverTime >= DISCOVER_COOLDOWN_MS) {
836
+ // 冷却期已过,触发一次同步发现
837
+ log(`🔍 连续 ${emptyRounds} 轮无待打分标签,同步生成标签...`);
838
+ await runDiscoverInBackground();
839
+ await discoverPromise;
840
+ } else {
841
+ const remainMin = Math.ceil(
842
+ (DISCOVER_COOLDOWN_MS - (Date.now() - lastDiscoverTime)) /
843
+ 60000,
844
+ );
845
+ log(
846
+ `🔍 连续 ${emptyRounds} 轮空,但发现冷却中(还需 ${remainMin} 分钟),继续等待...`,
847
+ );
796
848
  }
797
- emptyRounds = 0; // 重置计数器
798
- // 等 3 秒让服务端处理完
849
+ emptyRounds = 0;
799
850
  await new Promise((r) => setTimeout(r, 3000));
800
851
  continue;
801
852
  }
package/src/lib/args.js CHANGED
@@ -740,6 +740,7 @@ function parseTagArgs(args) {
740
740
  let isScore = false;
741
741
  let isScoreAll = false;
742
742
  let scoreAllPort = 7222;
743
+ let discoverCountScoreAll = 10;
743
744
  let scoreProxy = null;
744
745
  let scoreTag = null;
745
746
  let scoreCountries = null;
@@ -781,6 +782,8 @@ function parseTagArgs(args) {
781
782
  discoverCount = parseInt(args[++i]) || 4;
782
783
  } else if (arg === "--auto-discover") {
783
784
  autoDiscover = true;
785
+ } else if (arg === "--discover-count") {
786
+ discoverCountScoreAll = parseInt(args[++i]) || 10;
784
787
  } else if (arg === "--countries") {
785
788
  scoreCountries = args[++i]
786
789
  .split(",")
@@ -879,6 +882,7 @@ function parseTagArgs(args) {
879
882
  countries: scoreCountries,
880
883
  serverUrl,
881
884
  autoDiscover,
885
+ discoverCount: discoverCountScoreAll,
882
886
  port: scoreAllPort,
883
887
  proxy: scoreProxy,
884
888
  },
@@ -261,7 +261,8 @@ const HELP_TEXT = [
261
261
  " --countries <CSV> 目标国家,逗号分隔(默认 13 个欧洲国家)",
262
262
  " -s, --server <URL> 服务端地址(默认 http://127.0.0.1:3000)",
263
263
  " --port <N> 起始 CDP 端口,端口池默认为 N~N+9(默认 7222)",
264
- " --discover 开启自动发现:连续 3 轮无新标签时自动生成",
264
+ " --discover 开启自动发现:剩余 new 标签 < 5 时后台异步生成,连续 3 轮空兜底",
265
+ " --discover-count <N> 每次发现每个国家生成标签数(默认 10,上限 20)",
265
266
  " 行为:",
266
267
  " 连续 3 次 HTTP 403 → 判断账号被封 → 等 2 分钟后自动切换到池中另一端口",
267
268
  " 环境变量:",
@@ -1169,9 +1169,18 @@ export function startWatchServer(
1169
1169
  tags = store.getAllTags(limit, offset, upperCountry);
1170
1170
  }
1171
1171
 
1172
- // 获取总数(带国家过滤)
1172
+ // 获取总数(带国家过滤,按 status 返回对应计数)
1173
1173
  const stats = store.getTagStats(upperCountry);
1174
- const total = stats ? stats.total : tags.length;
1174
+ let total;
1175
+ if (stats) {
1176
+ if (status === "new") total = stats.new;
1177
+ else if (status === "productive") total = stats.productive;
1178
+ else if (status === "dead") total = stats.dead;
1179
+ else if (status === "scoring") total = stats.scoring;
1180
+ else total = stats.total;
1181
+ } else {
1182
+ total = tags.length;
1183
+ }
1175
1184
  sendJSON(res, 200, { tags, total, offset, limit });
1176
1185
  return;
1177
1186
  }