@kaikybrofc/omnizap-system 2.2.9 → 2.3.0
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 +20 -18
- package/app/config/adminIdentity.js +1 -3
- package/app/connection/socketController.js +10 -20
- package/app/controllers/messageController.js +7 -28
- package/app/modules/aiModule/catCommand.js +29 -192
- package/app/modules/broadcastModule/noticeCommand.js +28 -97
- package/app/modules/gameModule/diceCommand.js +6 -32
- package/app/modules/playModule/playCommand.js +57 -258
- package/app/modules/quoteModule/quoteCommand.js +2 -4
- package/app/modules/rpgPokemonModule/rpgPokemonRepository.js +1 -13
- package/app/modules/statsModule/noMessageCommand.js +16 -84
- package/app/modules/statsModule/rankingCommand.js +5 -25
- package/app/modules/statsModule/rankingCommon.js +1 -9
- package/app/modules/stickerModule/convertToWebp.js +4 -27
- package/app/modules/stickerModule/stickerCommand.js +13 -24
- package/app/modules/stickerModule/stickerTextCommand.js +13 -25
- package/app/modules/stickerPackModule/autoPackCollectorService.js +16 -7
- package/app/modules/stickerPackModule/domainEventOutboxRepository.js +20 -36
- package/app/modules/stickerPackModule/domainEvents.js +2 -11
- package/app/modules/stickerPackModule/semanticReclassificationEngine.js +13 -50
- package/app/modules/stickerPackModule/semanticReclassificationEngine.test.js +2 -15
- package/app/modules/stickerPackModule/semanticThemeClusterService.js +14 -41
- package/app/modules/stickerPackModule/stickerAssetClassificationRepository.js +25 -95
- package/app/modules/stickerPackModule/stickerAssetRepository.js +12 -31
- package/app/modules/stickerPackModule/stickerAssetReprocessQueueRepository.js +13 -18
- package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +284 -709
- package/app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js +27 -106
- package/app/modules/stickerPackModule/stickerClassificationService.js +46 -77
- package/app/modules/stickerPackModule/stickerDedicatedTaskWorkerRuntime.js +13 -53
- package/app/modules/stickerPackModule/stickerDomainEventBus.js +10 -16
- package/app/modules/stickerPackModule/stickerDomainEventConsumerRuntime.js +13 -34
- package/app/modules/stickerPackModule/stickerMarketplaceDriftService.js +1 -4
- package/app/modules/stickerPackModule/stickerObjectStorageService.js +26 -26
- package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +32 -187
- package/app/modules/stickerPackModule/stickerPackInteractionEventRepository.js +6 -15
- package/app/modules/stickerPackModule/stickerPackItemRepository.js +6 -32
- package/app/modules/stickerPackModule/stickerPackMarketplaceService.js +12 -36
- package/app/modules/stickerPackModule/stickerPackMessageService.js +12 -40
- package/app/modules/stickerPackModule/stickerPackRepository.js +23 -66
- package/app/modules/stickerPackModule/stickerPackScoreSnapshotRepository.js +9 -21
- package/app/modules/stickerPackModule/stickerPackScoreSnapshotRuntime.js +10 -40
- package/app/modules/stickerPackModule/stickerPackService.js +50 -115
- package/app/modules/stickerPackModule/stickerPackServiceRuntime.js +2 -21
- package/app/modules/stickerPackModule/stickerPackUtils.js +13 -3
- package/app/modules/stickerPackModule/stickerStorageService.js +16 -65
- package/app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js +4 -22
- package/app/modules/stickerPackModule/stickerWorkerTaskQueueRepository.js +14 -29
- package/app/modules/systemMetricsModule/pingCommand.js +9 -39
- package/app/modules/tiktokModule/tiktokCommand.js +17 -109
- package/app/modules/userModule/userCommand.js +2 -88
- package/app/observability/metrics.js +5 -16
- package/app/services/captchaService.js +1 -6
- package/app/services/dbWriteQueue.js +3 -18
- package/app/services/featureFlagService.js +2 -8
- package/app/services/newsBroadcastService.js +0 -1
- package/app/services/queueUtils.js +2 -4
- package/app/services/whatsappLoginLinkService.js +7 -9
- package/app/store/premiumUserStore.js +1 -2
- package/app/utils/antiLink/antiLinkModule.js +3 -233
- package/app/utils/logger/loggerModule.js +9 -34
- package/app/utils/systemMetrics/systemMetricsModule.js +1 -4
- package/database/init.js +1 -8
- package/docker-compose.yml +27 -27
- package/docs/seo/omnizap-seo-playbook-br-2026-02-28.md +220 -0
- package/docs/seo/satellite-page-template.md +91 -0
- package/docs/seo/satellite-pages-phase1.json +349 -0
- package/eslint.config.js +2 -15
- package/index.js +8 -36
- package/ml/clip_classifier/README.md +4 -6
- package/observability/alert-rules.yml +12 -12
- package/observability/grafana/provisioning/dashboards/dashboards.yml +1 -1
- package/package.json +8 -3
- package/public/api-docs/index.html +224 -141
- package/public/bot-whatsapp-para-grupo/index.html +306 -0
- package/public/bot-whatsapp-sem-programar/index.html +306 -0
- package/public/comandos/index.html +428 -0
- package/public/como-automatizar-avisos-no-whatsapp/index.html +306 -0
- package/public/como-criar-comandos-whatsapp/index.html +306 -0
- package/public/como-evitar-spam-no-whatsapp/index.html +306 -0
- package/public/como-moderar-grupo-whatsapp/index.html +306 -0
- package/public/como-organizar-comunidade-whatsapp/index.html +306 -0
- package/public/css/github-project-panel.css +20 -15
- package/public/css/stickers-admin.css +55 -39
- package/public/css/styles.css +37 -29
- package/public/index.html +1060 -1417
- package/public/js/apps/apiDocsApp.js +36 -153
- package/public/js/apps/createPackApp.js +69 -332
- package/public/js/apps/homeApp.js +201 -434
- package/public/js/apps/loginApp.js +3 -12
- package/public/js/apps/stickersAdminApp.js +190 -181
- package/public/js/apps/stickersApp.js +507 -1366
- package/public/js/catalog.js +11 -74
- package/public/js/github-panel/components/ErrorState.js +1 -8
- package/public/js/github-panel/components/GithubProjectPanel.js +2 -9
- package/public/js/github-panel/components/SkeletonPanel.js +1 -11
- package/public/js/github-panel/components/StatCard.js +1 -7
- package/public/js/github-panel/vendor/react.js +1 -9
- package/public/js/runtime/react-runtime.js +1 -9
- package/public/licenca/index.html +104 -86
- package/public/login/index.html +315 -321
- package/public/melhor-bot-whatsapp-para-grupos/index.html +306 -0
- package/public/sitemap.xml +45 -0
- package/public/stickers/admin/index.html +14 -19
- package/public/stickers/create/index.html +39 -43
- package/public/stickers/index.html +97 -41
- package/public/termos-de-uso/index.html +142 -115
- package/public/user/index.html +347 -346
- package/scripts/cache-bust.mjs +5 -24
- package/scripts/generate-seo-satellite-pages.mjs +431 -0
- package/scripts/run-prettier-all.mjs +25 -0
- package/scripts/sticker-catalog-loadtest.mjs +13 -11
- package/scripts/sticker-worker-task.mjs +1 -4
- package/scripts/sync-readme-snapshot.mjs +3 -2
- package/server/controllers/stickerCatalogController.js +407 -704
- package/server/http/httpServer.js +2 -10
- package/server/routes/stickerCatalog/catalogHandlers/catalogAdminHttp.js +1 -8
- package/server/routes/stickerCatalog/catalogHandlers/catalogAuthHttp.js +1 -9
- package/server/routes/stickerCatalog/catalogHandlers/catalogPublicHttp.js +10 -11
- package/server/routes/stickerCatalog/catalogHandlers/catalogUploadHttp.js +1 -10
- package/server/routes/stickerCatalog/catalogRouter.js +11 -13
- package/kaikybrofc-omnizap-system-2.2.9.tgz +0 -0
|
@@ -3,30 +3,11 @@ import { getActiveSocket } from '../../services/socketState.js';
|
|
|
3
3
|
import { normalizeJid, resolveBotJid } from '../../config/baileysConfig.js';
|
|
4
4
|
import { recordStickerAutoPackCycle } from '../../observability/metrics.js';
|
|
5
5
|
import stickerPackService from './stickerPackServiceRuntime.js';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from './
|
|
10
|
-
import {
|
|
11
|
-
listClipImageEmbeddingsByImageHashes,
|
|
12
|
-
listStickerClassificationsByAssetIds,
|
|
13
|
-
} from './stickerAssetClassificationRepository.js';
|
|
14
|
-
import {
|
|
15
|
-
decorateStickerClassification,
|
|
16
|
-
submitStickerClassificationFeedback,
|
|
17
|
-
} from './stickerClassificationService.js';
|
|
18
|
-
import {
|
|
19
|
-
findStickerPackById,
|
|
20
|
-
listStickerAutoPacksForCuration,
|
|
21
|
-
listStickerPacksByOwner,
|
|
22
|
-
softDeleteStickerPack,
|
|
23
|
-
updateStickerPackFields,
|
|
24
|
-
} from './stickerPackRepository.js';
|
|
25
|
-
import {
|
|
26
|
-
listStickerPackItems,
|
|
27
|
-
listStickerPackItemsByPackIds,
|
|
28
|
-
removeStickerPackItemsByPackId,
|
|
29
|
-
} from './stickerPackItemRepository.js';
|
|
6
|
+
import { countClassifiedStickerAssetsWithoutPack, listClassifiedStickerAssetsForCuration } from './stickerAssetRepository.js';
|
|
7
|
+
import { listClipImageEmbeddingsByImageHashes, listStickerClassificationsByAssetIds } from './stickerAssetClassificationRepository.js';
|
|
8
|
+
import { decorateStickerClassification, submitStickerClassificationFeedback } from './stickerClassificationService.js';
|
|
9
|
+
import { findStickerPackById, listStickerAutoPacksForCuration, listStickerPacksByOwner, softDeleteStickerPack, updateStickerPackFields } from './stickerPackRepository.js';
|
|
10
|
+
import { listStickerPackItems, listStickerPackItemsByPackIds, removeStickerPackItemsByPackId } from './stickerPackItemRepository.js';
|
|
30
11
|
import { listStickerPackEngagementByPackIds } from './stickerPackEngagementRepository.js';
|
|
31
12
|
|
|
32
13
|
const parseEnvBool = (value, fallback) => {
|
|
@@ -58,16 +39,10 @@ const INTERVAL_MIN_MS_RAW = Number(process.env.STICKER_AUTO_PACK_BY_TAGS_INTERVA
|
|
|
58
39
|
const INTERVAL_MAX_MS_RAW = Number(process.env.STICKER_AUTO_PACK_BY_TAGS_INTERVAL_MAX_MS);
|
|
59
40
|
const DEFAULT_INTERVAL_MIN_MS = 5 * 60_000;
|
|
60
41
|
const DEFAULT_INTERVAL_MAX_MS = 10 * 60_000;
|
|
61
|
-
const INTERVAL_MIN_MS = Number.isFinite(INTERVAL_MIN_MS_RAW)
|
|
62
|
-
|
|
63
|
-
: DEFAULT_INTERVAL_MIN_MS;
|
|
64
|
-
const INTERVAL_MAX_MS_FROM_ENV = Number.isFinite(INTERVAL_MAX_MS_RAW)
|
|
65
|
-
? Math.max(60_000, Math.min(3_600_000, INTERVAL_MAX_MS_RAW))
|
|
66
|
-
: DEFAULT_INTERVAL_MAX_MS;
|
|
42
|
+
const INTERVAL_MIN_MS = Number.isFinite(INTERVAL_MIN_MS_RAW) ? Math.max(60_000, Math.min(3_600_000, INTERVAL_MIN_MS_RAW)) : DEFAULT_INTERVAL_MIN_MS;
|
|
43
|
+
const INTERVAL_MAX_MS_FROM_ENV = Number.isFinite(INTERVAL_MAX_MS_RAW) ? Math.max(60_000, Math.min(3_600_000, INTERVAL_MAX_MS_RAW)) : DEFAULT_INTERVAL_MAX_MS;
|
|
67
44
|
const INTERVAL_MAX_MS = Math.max(INTERVAL_MIN_MS, INTERVAL_MAX_MS_FROM_ENV);
|
|
68
|
-
const LEGACY_FIXED_INTERVAL_MS = Number.isFinite(LEGACY_INTERVAL_MS) && LEGACY_INTERVAL_MS > 0
|
|
69
|
-
? Math.max(60_000, Math.min(3_600_000, LEGACY_INTERVAL_MS))
|
|
70
|
-
: null;
|
|
45
|
+
const LEGACY_FIXED_INTERVAL_MS = Number.isFinite(LEGACY_INTERVAL_MS) && LEGACY_INTERVAL_MS > 0 ? Math.max(60_000, Math.min(3_600_000, LEGACY_INTERVAL_MS)) : null;
|
|
71
46
|
const EFFECTIVE_INTERVAL_MIN_MS = LEGACY_FIXED_INTERVAL_MS || INTERVAL_MIN_MS;
|
|
72
47
|
const EFFECTIVE_INTERVAL_MAX_MS = LEGACY_FIXED_INTERVAL_MS || INTERVAL_MAX_MS;
|
|
73
48
|
const TARGET_PACK_SIZE = Math.max(5, Math.min(30, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_TARGET_SIZE) || 30));
|
|
@@ -76,307 +51,119 @@ const MAX_TAG_GROUPS = Math.max(0, Math.min(500, Number(process.env.STICKER_AUTO
|
|
|
76
51
|
const ENABLE_SEMANTIC_CLUSTERING = parseEnvBool(process.env.ENABLE_SEMANTIC_CLUSTERING, false);
|
|
77
52
|
const MAX_SCAN_ASSETS = Math.max(0, Math.min(250_000, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MAX_SCAN_ASSETS) || 0));
|
|
78
53
|
const MAX_ADDITIONS_PER_CYCLE = Math.max(10, Math.min(2000, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MAX_ADDITIONS_PER_CYCLE) || 300));
|
|
79
|
-
const AUTO_PACK_VISIBILITY =
|
|
54
|
+
const AUTO_PACK_VISIBILITY =
|
|
55
|
+
String(process.env.STICKER_AUTO_PACK_BY_TAGS_VISIBILITY || 'public')
|
|
56
|
+
.trim()
|
|
57
|
+
.toLowerCase() || 'public';
|
|
80
58
|
const AUTO_PUBLISHER = String(process.env.STICKER_AUTO_PACK_BY_TAGS_PUBLISHER || 'OmniZap Auto').trim() || 'OmniZap Auto';
|
|
81
59
|
const TOP_TAGS_PER_ASSET = Math.max(1, Math.min(5, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_TOP_TAGS_PER_ASSET) || 3));
|
|
82
60
|
const SCAN_PASSES = Math.max(1, Math.min(9, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_SCAN_PASSES) || 3));
|
|
83
|
-
const SCAN_PASS_JITTER_PERCENT = Math.max(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
);
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
? Math.max(0, Math.min(1, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MIN_ASSET_ACCEPTANCE_RATE)))
|
|
92
|
-
: 0.5;
|
|
93
|
-
const MIN_THEME_DOMINANCE_RATIO = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MIN_THEME_DOMINANCE_RATIO))
|
|
94
|
-
? Math.max(0, Math.min(1, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MIN_THEME_DOMINANCE_RATIO)))
|
|
95
|
-
: 0.55;
|
|
96
|
-
const SCORE_STDDEV_PENALTY = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_SCORE_STDDEV_PENALTY))
|
|
97
|
-
? Math.max(0, Math.min(1.2, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_SCORE_STDDEV_PENALTY)))
|
|
98
|
-
: 0.18;
|
|
99
|
-
const NSFW_THRESHOLD = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_NSFW_THRESHOLD))
|
|
100
|
-
? Number(process.env.STICKER_AUTO_PACK_BY_TAGS_NSFW_THRESHOLD)
|
|
101
|
-
: 0.7;
|
|
102
|
-
const NSFW_SUGGESTIVE_THRESHOLD = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_NSFW_SUGGESTIVE_THRESHOLD))
|
|
103
|
-
? Number(process.env.STICKER_AUTO_PACK_BY_TAGS_NSFW_SUGGESTIVE_THRESHOLD)
|
|
104
|
-
: 0.4;
|
|
105
|
-
const NSFW_EXPLICIT_THRESHOLD = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_NSFW_EXPLICIT_THRESHOLD))
|
|
106
|
-
? Number(process.env.STICKER_AUTO_PACK_BY_TAGS_NSFW_EXPLICIT_THRESHOLD)
|
|
107
|
-
: 0.78;
|
|
61
|
+
const SCAN_PASS_JITTER_PERCENT = Math.max(0, Math.min(35, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_SCAN_PASS_JITTER_PERCENT) || 15));
|
|
62
|
+
const STABILITY_Z_SCORE = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_STABILITY_Z_SCORE)) ? Math.max(0, Math.min(3.5, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_STABILITY_Z_SCORE))) : 1.282;
|
|
63
|
+
const MIN_ASSET_ACCEPTANCE_RATE = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MIN_ASSET_ACCEPTANCE_RATE)) ? Math.max(0, Math.min(1, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MIN_ASSET_ACCEPTANCE_RATE))) : 0.5;
|
|
64
|
+
const MIN_THEME_DOMINANCE_RATIO = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MIN_THEME_DOMINANCE_RATIO)) ? Math.max(0, Math.min(1, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MIN_THEME_DOMINANCE_RATIO))) : 0.55;
|
|
65
|
+
const SCORE_STDDEV_PENALTY = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_SCORE_STDDEV_PENALTY)) ? Math.max(0, Math.min(1.2, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_SCORE_STDDEV_PENALTY))) : 0.18;
|
|
66
|
+
const NSFW_THRESHOLD = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_NSFW_THRESHOLD)) ? Number(process.env.STICKER_AUTO_PACK_BY_TAGS_NSFW_THRESHOLD) : 0.7;
|
|
67
|
+
const NSFW_SUGGESTIVE_THRESHOLD = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_NSFW_SUGGESTIVE_THRESHOLD)) ? Number(process.env.STICKER_AUTO_PACK_BY_TAGS_NSFW_SUGGESTIVE_THRESHOLD) : 0.4;
|
|
68
|
+
const NSFW_EXPLICIT_THRESHOLD = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_NSFW_EXPLICIT_THRESHOLD)) ? Number(process.env.STICKER_AUTO_PACK_BY_TAGS_NSFW_EXPLICIT_THRESHOLD) : 0.78;
|
|
108
69
|
const MIN_ASSET_EDGE = Math.max(32, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MIN_ASSET_EDGE) || 192);
|
|
109
70
|
const MIN_ASSET_AREA = Math.max(32 * 32, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MIN_ASSET_AREA) || 192 * 192);
|
|
110
71
|
const MIN_ASSET_BYTES = Math.max(512, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MIN_ASSET_BYTES) || 6 * 1024);
|
|
111
|
-
const MAX_BLURRY_SCORE = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MAX_BLURRY_SCORE))
|
|
112
|
-
|
|
113
|
-
: 0.82;
|
|
114
|
-
const MAX_LOW_QUALITY_SCORE = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MAX_LOW_QUALITY_SCORE))
|
|
115
|
-
? Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MAX_LOW_QUALITY_SCORE)
|
|
116
|
-
: 0.82;
|
|
72
|
+
const MAX_BLURRY_SCORE = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MAX_BLURRY_SCORE)) ? Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MAX_BLURRY_SCORE) : 0.82;
|
|
73
|
+
const MAX_LOW_QUALITY_SCORE = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MAX_LOW_QUALITY_SCORE)) ? Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MAX_LOW_QUALITY_SCORE) : 0.82;
|
|
117
74
|
const REBUILD_ENABLED = parseEnvBool(process.env.STICKER_AUTO_PACK_BY_TAGS_REBUILD_ENABLED, true);
|
|
118
|
-
const INCLUDE_PACKED_WHEN_REBUILD_DISABLED = parseEnvBool(
|
|
119
|
-
process.env.STICKER_AUTO_PACK_BY_TAGS_INCLUDE_PACKED_WHEN_REBUILD_DISABLED,
|
|
120
|
-
false,
|
|
121
|
-
);
|
|
75
|
+
const INCLUDE_PACKED_WHEN_REBUILD_DISABLED = parseEnvBool(process.env.STICKER_AUTO_PACK_BY_TAGS_INCLUDE_PACKED_WHEN_REBUILD_DISABLED, false);
|
|
122
76
|
const MAX_REMOVALS_PER_CYCLE = Math.max(0, Math.min(500, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MAX_REMOVALS_PER_CYCLE) || 120));
|
|
123
|
-
const DEDUPE_SIMILARITY_THRESHOLD = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_DEDUPE_SIMILARITY_THRESHOLD))
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
: 0.76;
|
|
141
|
-
const ENTROPY_WEIGHT = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ENTROPY_WEIGHT))
|
|
142
|
-
? Math.max(0, Math.min(1.5, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ENTROPY_WEIGHT)))
|
|
143
|
-
: 0.09;
|
|
144
|
-
const AMBIGUOUS_FLAG_PENALTY = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_AMBIGUOUS_FLAG_PENALTY))
|
|
145
|
-
? Math.max(0, Math.min(0.5, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_AMBIGUOUS_FLAG_PENALTY)))
|
|
146
|
-
: 0.06;
|
|
147
|
-
const ADAPTIVE_BONUS_WEIGHT = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ADAPTIVE_BONUS_WEIGHT))
|
|
148
|
-
? Math.max(0, Math.min(1.2, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ADAPTIVE_BONUS_WEIGHT)))
|
|
149
|
-
: 0.18;
|
|
150
|
-
const MARGIN_BONUS_WEIGHT = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MARGIN_BONUS_WEIGHT))
|
|
151
|
-
? Math.max(0, Math.min(1.2, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MARGIN_BONUS_WEIGHT)))
|
|
152
|
-
: 0.12;
|
|
153
|
-
const SIMILAR_IMAGES_PENALTY_WEIGHT = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_SIMILAR_IMAGES_PENALTY_WEIGHT))
|
|
154
|
-
? Math.max(0, Math.min(1.2, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_SIMILAR_IMAGES_PENALTY_WEIGHT)))
|
|
155
|
-
: 0.08;
|
|
156
|
-
const LLM_TRAIT_WEIGHT = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_LLM_TRAIT_WEIGHT))
|
|
157
|
-
? Math.max(0, Math.min(0.6, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_LLM_TRAIT_WEIGHT)))
|
|
158
|
-
: 0.1;
|
|
159
|
-
const ASSET_QUALITY_W1 = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ASSET_QUALITY_W1))
|
|
160
|
-
? Math.max(0, Math.min(2, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ASSET_QUALITY_W1)))
|
|
161
|
-
: 0.34;
|
|
162
|
-
const ASSET_QUALITY_W2 = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ASSET_QUALITY_W2))
|
|
163
|
-
? Math.max(0, Math.min(2, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ASSET_QUALITY_W2)))
|
|
164
|
-
: 0.24;
|
|
165
|
-
const ASSET_QUALITY_W3 = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ASSET_QUALITY_W3))
|
|
166
|
-
? Math.max(0, Math.min(2, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ASSET_QUALITY_W3)))
|
|
167
|
-
: 0.18;
|
|
168
|
-
const ASSET_QUALITY_W4 = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ASSET_QUALITY_W4))
|
|
169
|
-
? Math.max(0, Math.min(2, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ASSET_QUALITY_W4)))
|
|
170
|
-
: 0.24;
|
|
171
|
-
const AFFINITY_WEIGHT_CAP = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_AFFINITY_CAP))
|
|
172
|
-
? Math.max(0, Math.min(1, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_AFFINITY_CAP)))
|
|
173
|
-
: 0.85;
|
|
77
|
+
const DEDUPE_SIMILARITY_THRESHOLD = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_DEDUPE_SIMILARITY_THRESHOLD)) ? Number(process.env.STICKER_AUTO_PACK_BY_TAGS_DEDUPE_SIMILARITY_THRESHOLD) : 0.985;
|
|
78
|
+
const COHESION_REBUILD_THRESHOLD = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_COHESION_REBUILD_THRESHOLD)) ? Number(process.env.STICKER_AUTO_PACK_BY_TAGS_COHESION_REBUILD_THRESHOLD) : 0.56;
|
|
79
|
+
const MOVE_OUT_THEME_SCORE_THRESHOLD = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MOVE_OUT_THRESHOLD)) ? Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MOVE_OUT_THRESHOLD) : 0.22;
|
|
80
|
+
const MOVE_IN_THEME_SCORE_THRESHOLD = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MOVE_IN_THRESHOLD)) ? Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MOVE_IN_THRESHOLD) : 0.12;
|
|
81
|
+
const ENTROPY_THRESHOLD = Number.isFinite(Number(process.env.ENTROPY_THRESHOLD)) ? Number(process.env.ENTROPY_THRESHOLD) : 2.5;
|
|
82
|
+
const ENTROPY_NORMALIZED_THRESHOLD = Number.isFinite(Number(process.env.ENTROPY_NORMALIZED_THRESHOLD)) ? Math.max(0, Math.min(1, Number(process.env.ENTROPY_NORMALIZED_THRESHOLD))) : 0.76;
|
|
83
|
+
const ENTROPY_WEIGHT = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ENTROPY_WEIGHT)) ? Math.max(0, Math.min(1.5, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ENTROPY_WEIGHT))) : 0.09;
|
|
84
|
+
const AMBIGUOUS_FLAG_PENALTY = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_AMBIGUOUS_FLAG_PENALTY)) ? Math.max(0, Math.min(0.5, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_AMBIGUOUS_FLAG_PENALTY))) : 0.06;
|
|
85
|
+
const ADAPTIVE_BONUS_WEIGHT = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ADAPTIVE_BONUS_WEIGHT)) ? Math.max(0, Math.min(1.2, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ADAPTIVE_BONUS_WEIGHT))) : 0.18;
|
|
86
|
+
const MARGIN_BONUS_WEIGHT = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MARGIN_BONUS_WEIGHT)) ? Math.max(0, Math.min(1.2, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MARGIN_BONUS_WEIGHT))) : 0.12;
|
|
87
|
+
const SIMILAR_IMAGES_PENALTY_WEIGHT = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_SIMILAR_IMAGES_PENALTY_WEIGHT)) ? Math.max(0, Math.min(1.2, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_SIMILAR_IMAGES_PENALTY_WEIGHT))) : 0.08;
|
|
88
|
+
const LLM_TRAIT_WEIGHT = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_LLM_TRAIT_WEIGHT)) ? Math.max(0, Math.min(0.6, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_LLM_TRAIT_WEIGHT))) : 0.1;
|
|
89
|
+
const ASSET_QUALITY_W1 = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ASSET_QUALITY_W1)) ? Math.max(0, Math.min(2, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ASSET_QUALITY_W1))) : 0.34;
|
|
90
|
+
const ASSET_QUALITY_W2 = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ASSET_QUALITY_W2)) ? Math.max(0, Math.min(2, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ASSET_QUALITY_W2))) : 0.24;
|
|
91
|
+
const ASSET_QUALITY_W3 = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ASSET_QUALITY_W3)) ? Math.max(0, Math.min(2, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ASSET_QUALITY_W3))) : 0.18;
|
|
92
|
+
const ASSET_QUALITY_W4 = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ASSET_QUALITY_W4)) ? Math.max(0, Math.min(2, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_ASSET_QUALITY_W4))) : 0.24;
|
|
93
|
+
const AFFINITY_WEIGHT_CAP = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_AFFINITY_CAP)) ? Math.max(0, Math.min(1, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_AFFINITY_CAP))) : 0.85;
|
|
174
94
|
const ENABLE_AFFINITY_LOG_SCALING = parseEnvBool(process.env.STICKER_AUTO_PACK_BY_TAGS_ENABLE_AFFINITY_LOG_SCALING, true);
|
|
175
|
-
const AFFINITY_LOG_SCALE = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_AFFINITY_LOG_SCALE))
|
|
176
|
-
|
|
177
|
-
: 4;
|
|
178
|
-
const REVIEW_SAMPLE_PERCENT = Math.max(
|
|
179
|
-
0,
|
|
180
|
-
Math.min(100, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_RECHECK_SAMPLE_PERCENT) || 5),
|
|
181
|
-
);
|
|
95
|
+
const AFFINITY_LOG_SCALE = Number.isFinite(Number(process.env.STICKER_AUTO_PACK_BY_TAGS_AFFINITY_LOG_SCALE)) ? Math.max(0.1, Math.min(20, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_AFFINITY_LOG_SCALE))) : 4;
|
|
96
|
+
const REVIEW_SAMPLE_PERCENT = Math.max(0, Math.min(100, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_RECHECK_SAMPLE_PERCENT) || 5));
|
|
182
97
|
const REVIEW_VERSION_TARGET = String(process.env.STICKER_AUTO_PACK_BY_TAGS_REVIEW_CLASSIFICATION_VERSION || '').trim();
|
|
183
|
-
const CURATION_OWNERS_POOL_RAW = String(
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
);
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
);
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
Math.min(TARGET_PACK_SIZE, Number(process.env.SEMANTIC_CLUSTER_MIN_SIZE_FOR_PACK) || HARD_MIN_GROUP_SIZE),
|
|
197
|
-
);
|
|
198
|
-
const EFFECTIVE_HARD_MIN_GROUP_SIZE = ENABLE_SEMANTIC_CLUSTERING
|
|
199
|
-
? Math.max(HARD_MIN_GROUP_SIZE, SEMANTIC_CLUSTER_MIN_SIZE_FOR_PACK)
|
|
200
|
-
: HARD_MIN_GROUP_SIZE;
|
|
201
|
-
const HARD_MIN_PACK_ITEMS = Math.max(
|
|
202
|
-
1,
|
|
203
|
-
Math.min(TARGET_PACK_SIZE, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_HARD_MIN_PACK_ITEMS) || 12),
|
|
204
|
-
);
|
|
205
|
-
const READY_PACK_MIN_ITEMS = Math.max(
|
|
206
|
-
HARD_MIN_PACK_ITEMS,
|
|
207
|
-
Math.min(TARGET_PACK_SIZE, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_READY_MIN_ITEMS) || 20),
|
|
208
|
-
);
|
|
209
|
-
const MAX_PACKS_PER_THEME = Math.max(
|
|
210
|
-
1,
|
|
211
|
-
Math.min(10, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MAX_PACKS_PER_THEME) || 1),
|
|
212
|
-
);
|
|
213
|
-
const GLOBAL_AUTO_PACK_LIMIT = Math.max(
|
|
214
|
-
10,
|
|
215
|
-
Math.min(10_000, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_GLOBAL_PACK_LIMIT) || 300),
|
|
216
|
-
);
|
|
217
|
-
const DYNAMIC_GROUP_LIMIT_BASE = Math.max(
|
|
218
|
-
3,
|
|
219
|
-
Math.min(500, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_DYNAMIC_GROUP_LIMIT_BASE) || 30),
|
|
220
|
-
);
|
|
221
|
-
const RETRO_CONSOLIDATION_ENABLED = parseEnvBool(
|
|
222
|
-
process.env.STICKER_AUTO_PACK_BY_TAGS_RETRO_CONSOLIDATION_ENABLED,
|
|
223
|
-
true,
|
|
224
|
-
);
|
|
225
|
-
const RETRO_CONSOLIDATION_THEME_LIMIT = Math.max(
|
|
226
|
-
1,
|
|
227
|
-
Math.min(2000, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_RETRO_CONSOLIDATION_THEME_LIMIT) || 1000),
|
|
228
|
-
);
|
|
229
|
-
const RETRO_CONSOLIDATION_MUTATION_LIMIT = Math.max(
|
|
230
|
-
10,
|
|
231
|
-
Math.min(10_000, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_RETRO_CONSOLIDATION_MUTATION_LIMIT) || 2000),
|
|
232
|
-
);
|
|
98
|
+
const CURATION_OWNERS_POOL_RAW = String(process.env.CURATION_OWNERS_POOL || process.env.STICKER_AUTO_PACK_CURATION_OWNERS_POOL || '').trim();
|
|
99
|
+
const MAX_PACKS_PER_OWNER = parseMaxPacksPerOwnerLimit(process.env.STICKER_AUTO_PACK_BY_TAGS_MAX_PACKS_PER_OWNER || process.env.STICKER_PACK_MAX_PACKS_PER_OWNER, 50);
|
|
100
|
+
const HARD_MIN_GROUP_SIZE = Math.max(3, Math.min(TARGET_PACK_SIZE, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_HARD_MIN_GROUP_SIZE) || 12));
|
|
101
|
+
const SEMANTIC_CLUSTER_MIN_SIZE_FOR_PACK = Math.max(HARD_MIN_GROUP_SIZE, Math.min(TARGET_PACK_SIZE, Number(process.env.SEMANTIC_CLUSTER_MIN_SIZE_FOR_PACK) || HARD_MIN_GROUP_SIZE));
|
|
102
|
+
const EFFECTIVE_HARD_MIN_GROUP_SIZE = ENABLE_SEMANTIC_CLUSTERING ? Math.max(HARD_MIN_GROUP_SIZE, SEMANTIC_CLUSTER_MIN_SIZE_FOR_PACK) : HARD_MIN_GROUP_SIZE;
|
|
103
|
+
const HARD_MIN_PACK_ITEMS = Math.max(1, Math.min(TARGET_PACK_SIZE, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_HARD_MIN_PACK_ITEMS) || 12));
|
|
104
|
+
const READY_PACK_MIN_ITEMS = Math.max(HARD_MIN_PACK_ITEMS, Math.min(TARGET_PACK_SIZE, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_READY_MIN_ITEMS) || 20));
|
|
105
|
+
const MAX_PACKS_PER_THEME = Math.max(1, Math.min(10, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_MAX_PACKS_PER_THEME) || 1));
|
|
106
|
+
const GLOBAL_AUTO_PACK_LIMIT = Math.max(10, Math.min(10_000, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_GLOBAL_PACK_LIMIT) || 300));
|
|
107
|
+
const DYNAMIC_GROUP_LIMIT_BASE = Math.max(3, Math.min(500, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_DYNAMIC_GROUP_LIMIT_BASE) || 30));
|
|
108
|
+
const RETRO_CONSOLIDATION_ENABLED = parseEnvBool(process.env.STICKER_AUTO_PACK_BY_TAGS_RETRO_CONSOLIDATION_ENABLED, true);
|
|
109
|
+
const RETRO_CONSOLIDATION_THEME_LIMIT = Math.max(1, Math.min(2000, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_RETRO_CONSOLIDATION_THEME_LIMIT) || 1000));
|
|
110
|
+
const RETRO_CONSOLIDATION_MUTATION_LIMIT = Math.max(10, Math.min(10_000, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_RETRO_CONSOLIDATION_MUTATION_LIMIT) || 2000));
|
|
233
111
|
const PRIORITIZE_COMPLETION = parseEnvBool(process.env.STICKER_AUTO_PACK_BY_TAGS_PRIORITIZE_COMPLETION, true);
|
|
234
112
|
const COMPLETION_TRANSFER_ENABLED = parseEnvBool(process.env.STICKER_AUTO_PACK_BY_TAGS_COMPLETION_TRANSFER_ENABLED, true);
|
|
235
|
-
const COMPLETION_TRANSFER_MIN_DONOR_ITEMS = Math.max(
|
|
236
|
-
1,
|
|
237
|
-
Math.min(
|
|
238
|
-
TARGET_PACK_SIZE - 1,
|
|
239
|
-
Number(process.env.STICKER_AUTO_PACK_BY_TAGS_COMPLETION_TRANSFER_MIN_DONOR_ITEMS)
|
|
240
|
-
|| Math.max(2, Math.min(TARGET_PACK_SIZE - 1, 8)),
|
|
241
|
-
),
|
|
242
|
-
);
|
|
113
|
+
const COMPLETION_TRANSFER_MIN_DONOR_ITEMS = Math.max(1, Math.min(TARGET_PACK_SIZE - 1, Number(process.env.STICKER_AUTO_PACK_BY_TAGS_COMPLETION_TRANSFER_MIN_DONOR_ITEMS) || Math.max(2, Math.min(TARGET_PACK_SIZE - 1, 8))));
|
|
243
114
|
const ENABLE_GLOBAL_OPTIMIZATION = parseEnvBool(process.env.ENABLE_GLOBAL_OPTIMIZATION, true);
|
|
244
115
|
const OPTIMIZATION_CYCLES = Math.max(1, Math.min(8, Number(process.env.OPTIMIZATION_CYCLES) || 3));
|
|
245
|
-
const OPTIMIZATION_EPSILON = Number.isFinite(Number(process.env.OPTIMIZATION_EPSILON))
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
const
|
|
249
|
-
1,
|
|
250
|
-
Math.min(5, Number(process.env.OPTIMIZATION_STABLE_CYCLES) || 2),
|
|
251
|
-
);
|
|
252
|
-
const TRANSFER_THRESHOLD = Number.isFinite(Number(process.env.TRANSFER_THRESHOLD))
|
|
253
|
-
? Math.max(-0.2, Math.min(1, Number(process.env.TRANSFER_THRESHOLD)))
|
|
254
|
-
: 0.02;
|
|
255
|
-
const MERGE_THRESHOLD = Number.isFinite(Number(process.env.MERGE_THRESHOLD))
|
|
256
|
-
? Math.max(0, Math.min(1, Number(process.env.MERGE_THRESHOLD)))
|
|
257
|
-
: 0.75;
|
|
116
|
+
const OPTIMIZATION_EPSILON = Number.isFinite(Number(process.env.OPTIMIZATION_EPSILON)) ? Math.max(0.000001, Math.min(0.5, Number(process.env.OPTIMIZATION_EPSILON))) : 0.001;
|
|
117
|
+
const OPTIMIZATION_STABLE_CYCLES = Math.max(1, Math.min(5, Number(process.env.OPTIMIZATION_STABLE_CYCLES) || 2));
|
|
118
|
+
const TRANSFER_THRESHOLD = Number.isFinite(Number(process.env.TRANSFER_THRESHOLD)) ? Math.max(-0.2, Math.min(1, Number(process.env.TRANSFER_THRESHOLD))) : 0.02;
|
|
119
|
+
const MERGE_THRESHOLD = Number.isFinite(Number(process.env.MERGE_THRESHOLD)) ? Math.max(0, Math.min(1, Number(process.env.MERGE_THRESHOLD))) : 0.75;
|
|
258
120
|
const MIN_PACK_SIZE = Math.max(1, Math.min(TARGET_PACK_SIZE, Number(process.env.MIN_PACK_SIZE) || 8));
|
|
259
|
-
const AUTO_ARCHIVE_BELOW_PERCENTILE = Number.isFinite(Number(process.env.AUTO_ARCHIVE_BELOW_PERCENTILE))
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
: 0.24;
|
|
283
|
-
const PACK_QUALITY_W3 = Number.isFinite(Number(process.env.PACK_QUALITY_W3))
|
|
284
|
-
? Math.max(0, Math.min(3, Number(process.env.PACK_QUALITY_W3)))
|
|
285
|
-
: 0.16;
|
|
286
|
-
const PACK_QUALITY_W4 = Number.isFinite(Number(process.env.PACK_QUALITY_W4))
|
|
287
|
-
? Math.max(0, Math.min(3, Number(process.env.PACK_QUALITY_W4)))
|
|
288
|
-
: 0.14;
|
|
289
|
-
const PACK_QUALITY_W5 = Number.isFinite(Number(process.env.PACK_QUALITY_W5))
|
|
290
|
-
? Math.max(0, Math.min(3, Number(process.env.PACK_QUALITY_W5)))
|
|
291
|
-
: 0.09;
|
|
292
|
-
const PACK_QUALITY_W6 = Number.isFinite(Number(process.env.PACK_QUALITY_W6))
|
|
293
|
-
? Math.max(0, Math.min(3, Number(process.env.PACK_QUALITY_W6)))
|
|
294
|
-
: 0.07;
|
|
295
|
-
const MIGRATION_CANDIDATE_LIMIT = Number.isFinite(Number(process.env.MIGRATION_CANDIDATE_LIMIT))
|
|
296
|
-
? Math.max(4, Math.min(64, Number(process.env.MIGRATION_CANDIDATE_LIMIT)))
|
|
297
|
-
: 16;
|
|
298
|
-
const TRANSFER_CANDIDATE_SIMILARITY_FLOOR = Number.isFinite(Number(process.env.TRANSFER_CANDIDATE_SIMILARITY_FLOOR))
|
|
299
|
-
? Math.max(0, Math.min(1, Number(process.env.TRANSFER_CANDIDATE_SIMILARITY_FLOOR)))
|
|
300
|
-
: 0.35;
|
|
301
|
-
const INTER_PACK_SIMILARITY_THRESHOLD = Number.isFinite(Number(process.env.INTER_PACK_SIMILARITY_THRESHOLD))
|
|
302
|
-
? Math.max(0, Math.min(1, Number(process.env.INTER_PACK_SIMILARITY_THRESHOLD)))
|
|
303
|
-
: 0.85;
|
|
304
|
-
const PACK_TIER_QUALITY_W1 = Number.isFinite(Number(process.env.PACK_TIER_QUALITY_W1))
|
|
305
|
-
? Math.max(0, Math.min(1, Number(process.env.PACK_TIER_QUALITY_W1)))
|
|
306
|
-
: 0.40;
|
|
307
|
-
const PACK_TIER_QUALITY_W2 = Number.isFinite(Number(process.env.PACK_TIER_QUALITY_W2))
|
|
308
|
-
? Math.max(0, Math.min(1, Number(process.env.PACK_TIER_QUALITY_W2)))
|
|
309
|
-
: 0.25;
|
|
310
|
-
const PACK_TIER_QUALITY_W3 = Number.isFinite(Number(process.env.PACK_TIER_QUALITY_W3))
|
|
311
|
-
? Math.max(0, Math.min(1, Number(process.env.PACK_TIER_QUALITY_W3)))
|
|
312
|
-
: 0.15;
|
|
313
|
-
const PACK_TIER_QUALITY_W4 = Number.isFinite(Number(process.env.PACK_TIER_QUALITY_W4))
|
|
314
|
-
? Math.max(0, Math.min(1, Number(process.env.PACK_TIER_QUALITY_W4)))
|
|
315
|
-
: 0.10;
|
|
316
|
-
const PACK_TIER_QUALITY_W5 = Number.isFinite(Number(process.env.PACK_TIER_QUALITY_W5))
|
|
317
|
-
? Math.max(0, Math.min(1, Number(process.env.PACK_TIER_QUALITY_W5)))
|
|
318
|
-
: 0.10;
|
|
319
|
-
const AUTO_PACK_PROFILE = String(process.env.AUTO_PACK_PROFILE || 'BALANCED').trim().toUpperCase();
|
|
121
|
+
const AUTO_ARCHIVE_BELOW_PERCENTILE = Number.isFinite(Number(process.env.AUTO_ARCHIVE_BELOW_PERCENTILE)) ? Math.max(0, Math.min(100, Number(process.env.AUTO_ARCHIVE_BELOW_PERCENTILE))) : 20;
|
|
122
|
+
const SYSTEM_REDUNDANCY_LAMBDA = Number.isFinite(Number(process.env.SYSTEM_REDUNDANCY_LAMBDA)) ? Math.max(0, Math.min(2, Number(process.env.SYSTEM_REDUNDANCY_LAMBDA))) : 0.2;
|
|
123
|
+
const MATRIX_ALPHA = Number.isFinite(Number(process.env.STICKER_MATRIX_ALPHA)) ? Math.max(0, Math.min(3, Number(process.env.STICKER_MATRIX_ALPHA))) : 0.38;
|
|
124
|
+
const MATRIX_BETA = Number.isFinite(Number(process.env.STICKER_MATRIX_BETA)) ? Math.max(0, Math.min(3, Number(process.env.STICKER_MATRIX_BETA))) : 0.27;
|
|
125
|
+
const MATRIX_GAMMA = Number.isFinite(Number(process.env.STICKER_MATRIX_GAMMA)) ? Math.max(0, Math.min(3, Number(process.env.STICKER_MATRIX_GAMMA))) : 0.23;
|
|
126
|
+
const MATRIX_DELTA = Number.isFinite(Number(process.env.STICKER_MATRIX_DELTA)) ? Math.max(0, Math.min(3, Number(process.env.STICKER_MATRIX_DELTA))) : 0.18;
|
|
127
|
+
const PACK_QUALITY_W1 = Number.isFinite(Number(process.env.PACK_QUALITY_W1)) ? Math.max(0, Math.min(3, Number(process.env.PACK_QUALITY_W1))) : 0.32;
|
|
128
|
+
const PACK_QUALITY_W2 = Number.isFinite(Number(process.env.PACK_QUALITY_W2)) ? Math.max(0, Math.min(3, Number(process.env.PACK_QUALITY_W2))) : 0.24;
|
|
129
|
+
const PACK_QUALITY_W3 = Number.isFinite(Number(process.env.PACK_QUALITY_W3)) ? Math.max(0, Math.min(3, Number(process.env.PACK_QUALITY_W3))) : 0.16;
|
|
130
|
+
const PACK_QUALITY_W4 = Number.isFinite(Number(process.env.PACK_QUALITY_W4)) ? Math.max(0, Math.min(3, Number(process.env.PACK_QUALITY_W4))) : 0.14;
|
|
131
|
+
const PACK_QUALITY_W5 = Number.isFinite(Number(process.env.PACK_QUALITY_W5)) ? Math.max(0, Math.min(3, Number(process.env.PACK_QUALITY_W5))) : 0.09;
|
|
132
|
+
const PACK_QUALITY_W6 = Number.isFinite(Number(process.env.PACK_QUALITY_W6)) ? Math.max(0, Math.min(3, Number(process.env.PACK_QUALITY_W6))) : 0.07;
|
|
133
|
+
const MIGRATION_CANDIDATE_LIMIT = Number.isFinite(Number(process.env.MIGRATION_CANDIDATE_LIMIT)) ? Math.max(4, Math.min(64, Number(process.env.MIGRATION_CANDIDATE_LIMIT))) : 16;
|
|
134
|
+
const TRANSFER_CANDIDATE_SIMILARITY_FLOOR = Number.isFinite(Number(process.env.TRANSFER_CANDIDATE_SIMILARITY_FLOOR)) ? Math.max(0, Math.min(1, Number(process.env.TRANSFER_CANDIDATE_SIMILARITY_FLOOR))) : 0.35;
|
|
135
|
+
const INTER_PACK_SIMILARITY_THRESHOLD = Number.isFinite(Number(process.env.INTER_PACK_SIMILARITY_THRESHOLD)) ? Math.max(0, Math.min(1, Number(process.env.INTER_PACK_SIMILARITY_THRESHOLD))) : 0.85;
|
|
136
|
+
const PACK_TIER_QUALITY_W1 = Number.isFinite(Number(process.env.PACK_TIER_QUALITY_W1)) ? Math.max(0, Math.min(1, Number(process.env.PACK_TIER_QUALITY_W1))) : 0.4;
|
|
137
|
+
const PACK_TIER_QUALITY_W2 = Number.isFinite(Number(process.env.PACK_TIER_QUALITY_W2)) ? Math.max(0, Math.min(1, Number(process.env.PACK_TIER_QUALITY_W2))) : 0.25;
|
|
138
|
+
const PACK_TIER_QUALITY_W3 = Number.isFinite(Number(process.env.PACK_TIER_QUALITY_W3)) ? Math.max(0, Math.min(1, Number(process.env.PACK_TIER_QUALITY_W3))) : 0.15;
|
|
139
|
+
const PACK_TIER_QUALITY_W4 = Number.isFinite(Number(process.env.PACK_TIER_QUALITY_W4)) ? Math.max(0, Math.min(1, Number(process.env.PACK_TIER_QUALITY_W4))) : 0.1;
|
|
140
|
+
const PACK_TIER_QUALITY_W5 = Number.isFinite(Number(process.env.PACK_TIER_QUALITY_W5)) ? Math.max(0, Math.min(1, Number(process.env.PACK_TIER_QUALITY_W5))) : 0.1;
|
|
141
|
+
const AUTO_PACK_PROFILE = String(process.env.AUTO_PACK_PROFILE || 'BALANCED')
|
|
142
|
+
.trim()
|
|
143
|
+
.toUpperCase();
|
|
320
144
|
const IS_AGGRESSIVE_PROFILE = AUTO_PACK_PROFILE === 'AGGRESSIVE';
|
|
321
|
-
const AGGRESSIVE_MIGRATION_THRESHOLD = Number.isFinite(Number(process.env.AGGRESSIVE_MIGRATION_THRESHOLD))
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
);
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
const GLOBAL_ENERGY_W4 = Number.isFinite(Number(process.env.GLOBAL_ENERGY_W4))
|
|
338
|
-
? Math.max(0, Math.min(2, Number(process.env.GLOBAL_ENERGY_W4)))
|
|
339
|
-
: 0.15;
|
|
340
|
-
const GLOBAL_ENERGY_W5 = Number.isFinite(Number(process.env.GLOBAL_ENERGY_W5))
|
|
341
|
-
? Math.max(0, Math.min(2, Number(process.env.GLOBAL_ENERGY_W5)))
|
|
342
|
-
: 0.10;
|
|
343
|
-
const PACK_TIER_GOLD_THRESHOLD = Number.isFinite(Number(process.env.PACK_TIER_GOLD_THRESHOLD))
|
|
344
|
-
? Math.max(0, Math.min(2, Number(process.env.PACK_TIER_GOLD_THRESHOLD)))
|
|
345
|
-
: 0.80;
|
|
346
|
-
const PACK_TIER_SILVER_THRESHOLD = Number.isFinite(Number(process.env.PACK_TIER_SILVER_THRESHOLD))
|
|
347
|
-
? Math.max(0, Math.min(PACK_TIER_GOLD_THRESHOLD, Number(process.env.PACK_TIER_SILVER_THRESHOLD)))
|
|
348
|
-
: 0.65;
|
|
349
|
-
const PACK_TIER_BRONZE_THRESHOLD = Number.isFinite(Number(process.env.PACK_TIER_BRONZE_THRESHOLD))
|
|
350
|
-
? Math.max(0, Math.min(PACK_TIER_SILVER_THRESHOLD, Number(process.env.PACK_TIER_BRONZE_THRESHOLD)))
|
|
351
|
-
: 0.50;
|
|
352
|
-
|
|
353
|
-
const EFFECTIVE_MIN_ASSET_ACCEPTANCE_RATE = IS_AGGRESSIVE_PROFILE
|
|
354
|
-
? Math.max(0.3, MIN_ASSET_ACCEPTANCE_RATE * 0.82)
|
|
355
|
-
: MIN_ASSET_ACCEPTANCE_RATE;
|
|
356
|
-
const EFFECTIVE_MIN_THEME_DOMINANCE_RATIO = IS_AGGRESSIVE_PROFILE
|
|
357
|
-
? Math.max(0.35, MIN_THEME_DOMINANCE_RATIO * 0.82)
|
|
358
|
-
: MIN_THEME_DOMINANCE_RATIO;
|
|
359
|
-
const EFFECTIVE_SCORE_STDDEV_PENALTY = IS_AGGRESSIVE_PROFILE
|
|
360
|
-
? Math.max(0.05, SCORE_STDDEV_PENALTY * 0.82)
|
|
361
|
-
: SCORE_STDDEV_PENALTY;
|
|
362
|
-
const EFFECTIVE_TRANSFER_THRESHOLD = IS_AGGRESSIVE_PROFILE
|
|
363
|
-
? Math.min(TRANSFER_THRESHOLD, AGGRESSIVE_MIGRATION_THRESHOLD)
|
|
364
|
-
: TRANSFER_THRESHOLD;
|
|
365
|
-
const EFFECTIVE_MERGE_THRESHOLD = IS_AGGRESSIVE_PROFILE
|
|
366
|
-
? Math.max(MERGE_THRESHOLD, 0.85)
|
|
367
|
-
: MERGE_THRESHOLD;
|
|
145
|
+
const AGGRESSIVE_MIGRATION_THRESHOLD = Number.isFinite(Number(process.env.AGGRESSIVE_MIGRATION_THRESHOLD)) ? Math.max(-0.1, Math.min(1, Number(process.env.AGGRESSIVE_MIGRATION_THRESHOLD))) : 0.01;
|
|
146
|
+
const ARCHIVE_LOW_SCORE_PACKS = parseEnvBool(process.env.ARCHIVE_LOW_SCORE_PACKS, IS_AGGRESSIVE_PROFILE);
|
|
147
|
+
const GLOBAL_ENERGY_W1 = Number.isFinite(Number(process.env.GLOBAL_ENERGY_W1)) ? Math.max(0, Math.min(2, Number(process.env.GLOBAL_ENERGY_W1))) : 0.4;
|
|
148
|
+
const GLOBAL_ENERGY_W2 = Number.isFinite(Number(process.env.GLOBAL_ENERGY_W2)) ? Math.max(0, Math.min(2, Number(process.env.GLOBAL_ENERGY_W2))) : 0.25;
|
|
149
|
+
const GLOBAL_ENERGY_W3 = Number.isFinite(Number(process.env.GLOBAL_ENERGY_W3)) ? Math.max(0, Math.min(2, Number(process.env.GLOBAL_ENERGY_W3))) : 0.1;
|
|
150
|
+
const GLOBAL_ENERGY_W4 = Number.isFinite(Number(process.env.GLOBAL_ENERGY_W4)) ? Math.max(0, Math.min(2, Number(process.env.GLOBAL_ENERGY_W4))) : 0.15;
|
|
151
|
+
const GLOBAL_ENERGY_W5 = Number.isFinite(Number(process.env.GLOBAL_ENERGY_W5)) ? Math.max(0, Math.min(2, Number(process.env.GLOBAL_ENERGY_W5))) : 0.1;
|
|
152
|
+
const PACK_TIER_GOLD_THRESHOLD = Number.isFinite(Number(process.env.PACK_TIER_GOLD_THRESHOLD)) ? Math.max(0, Math.min(2, Number(process.env.PACK_TIER_GOLD_THRESHOLD))) : 0.8;
|
|
153
|
+
const PACK_TIER_SILVER_THRESHOLD = Number.isFinite(Number(process.env.PACK_TIER_SILVER_THRESHOLD)) ? Math.max(0, Math.min(PACK_TIER_GOLD_THRESHOLD, Number(process.env.PACK_TIER_SILVER_THRESHOLD))) : 0.65;
|
|
154
|
+
const PACK_TIER_BRONZE_THRESHOLD = Number.isFinite(Number(process.env.PACK_TIER_BRONZE_THRESHOLD)) ? Math.max(0, Math.min(PACK_TIER_SILVER_THRESHOLD, Number(process.env.PACK_TIER_BRONZE_THRESHOLD))) : 0.5;
|
|
155
|
+
|
|
156
|
+
const EFFECTIVE_MIN_ASSET_ACCEPTANCE_RATE = IS_AGGRESSIVE_PROFILE ? Math.max(0.3, MIN_ASSET_ACCEPTANCE_RATE * 0.82) : MIN_ASSET_ACCEPTANCE_RATE;
|
|
157
|
+
const EFFECTIVE_MIN_THEME_DOMINANCE_RATIO = IS_AGGRESSIVE_PROFILE ? Math.max(0.35, MIN_THEME_DOMINANCE_RATIO * 0.82) : MIN_THEME_DOMINANCE_RATIO;
|
|
158
|
+
const EFFECTIVE_SCORE_STDDEV_PENALTY = IS_AGGRESSIVE_PROFILE ? Math.max(0.05, SCORE_STDDEV_PENALTY * 0.82) : SCORE_STDDEV_PENALTY;
|
|
159
|
+
const EFFECTIVE_TRANSFER_THRESHOLD = IS_AGGRESSIVE_PROFILE ? Math.min(TRANSFER_THRESHOLD, AGGRESSIVE_MIGRATION_THRESHOLD) : TRANSFER_THRESHOLD;
|
|
160
|
+
const EFFECTIVE_MERGE_THRESHOLD = IS_AGGRESSIVE_PROFILE ? Math.max(MERGE_THRESHOLD, 0.85) : MERGE_THRESHOLD;
|
|
368
161
|
const EFFECTIVE_INTER_PACK_SIMILARITY_THRESHOLD = Math.max(EFFECTIVE_MERGE_THRESHOLD, INTER_PACK_SIMILARITY_THRESHOLD);
|
|
369
|
-
const EFFECTIVE_AUTO_ARCHIVE_BELOW_PERCENTILE = ARCHIVE_LOW_SCORE_PACKS && IS_AGGRESSIVE_PROFILE
|
|
370
|
-
? Math.max(AUTO_ARCHIVE_BELOW_PERCENTILE, 35)
|
|
371
|
-
: AUTO_ARCHIVE_BELOW_PERCENTILE;
|
|
162
|
+
const EFFECTIVE_AUTO_ARCHIVE_BELOW_PERCENTILE = ARCHIVE_LOW_SCORE_PACKS && IS_AGGRESSIVE_PROFILE ? Math.max(AUTO_ARCHIVE_BELOW_PERCENTILE, 35) : AUTO_ARCHIVE_BELOW_PERCENTILE;
|
|
372
163
|
const EFFECTIVE_PRIORITIZE_COMPLETION = PRIORITIZE_COMPLETION || IS_AGGRESSIVE_PROFILE;
|
|
373
164
|
const EFFECTIVE_COMPLETION_TRANSFER_ENABLED = COMPLETION_TRANSFER_ENABLED || IS_AGGRESSIVE_PROFILE;
|
|
374
|
-
const EFFECTIVE_MIGRATION_CANDIDATE_LIMIT = IS_AGGRESSIVE_PROFILE
|
|
375
|
-
|
|
376
|
-
: MIGRATION_CANDIDATE_LIMIT;
|
|
377
|
-
const EFFECTIVE_TRANSFER_CANDIDATE_SIMILARITY_FLOOR = IS_AGGRESSIVE_PROFILE
|
|
378
|
-
? Math.max(0.15, TRANSFER_CANDIDATE_SIMILARITY_FLOOR * 0.72)
|
|
379
|
-
: TRANSFER_CANDIDATE_SIMILARITY_FLOOR;
|
|
165
|
+
const EFFECTIVE_MIGRATION_CANDIDATE_LIMIT = IS_AGGRESSIVE_PROFILE ? Math.max(MIGRATION_CANDIDATE_LIMIT, 24) : MIGRATION_CANDIDATE_LIMIT;
|
|
166
|
+
const EFFECTIVE_TRANSFER_CANDIDATE_SIMILARITY_FLOOR = IS_AGGRESSIVE_PROFILE ? Math.max(0.15, TRANSFER_CANDIDATE_SIMILARITY_FLOOR * 0.72) : TRANSFER_CANDIDATE_SIMILARITY_FLOOR;
|
|
380
167
|
|
|
381
168
|
const EXPLICIT_OWNER = String(process.env.STICKER_AUTO_PACK_OWNER_JID || process.env.USER_ADMIN || '').trim();
|
|
382
169
|
|
|
@@ -388,14 +175,7 @@ const LABEL_TO_TAG = {
|
|
|
388
175
|
cartoon: 'cartoon',
|
|
389
176
|
};
|
|
390
177
|
|
|
391
|
-
const TECHNICAL_TAGS = new Set([
|
|
392
|
-
'low-quality-compressed-image',
|
|
393
|
-
'blurry-image',
|
|
394
|
-
'text-only-image',
|
|
395
|
-
'sticker-style-image',
|
|
396
|
-
'whatsapp-sticker-style',
|
|
397
|
-
'telegram-sticker-style',
|
|
398
|
-
]);
|
|
178
|
+
const TECHNICAL_TAGS = new Set(['low-quality-compressed-image', 'blurry-image', 'text-only-image', 'sticker-style-image', 'whatsapp-sticker-style', 'telegram-sticker-style']);
|
|
399
179
|
|
|
400
180
|
const normalizeTag = (value) =>
|
|
401
181
|
String(value || '')
|
|
@@ -416,7 +196,9 @@ const toNumericClusterId = (value) => {
|
|
|
416
196
|
const isSemanticClusterSubthemeTag = (value) => /^cluster-\d+$/.test(normalizeTag(value));
|
|
417
197
|
|
|
418
198
|
const toTagFromLabel = (label) => {
|
|
419
|
-
const key = String(label || '')
|
|
199
|
+
const key = String(label || '')
|
|
200
|
+
.trim()
|
|
201
|
+
.toLowerCase();
|
|
420
202
|
return LABEL_TO_TAG[key] || normalizeTag(key);
|
|
421
203
|
};
|
|
422
204
|
|
|
@@ -476,7 +258,9 @@ const buildThemeKey = (theme, subtheme = '') => {
|
|
|
476
258
|
return normalizedSubtheme ? `${normalizedTheme}:${normalizedSubtheme}` : normalizedTheme;
|
|
477
259
|
};
|
|
478
260
|
const parseThemeKey = (raw) => {
|
|
479
|
-
const normalized = String(raw || '')
|
|
261
|
+
const normalized = String(raw || '')
|
|
262
|
+
.trim()
|
|
263
|
+
.toLowerCase();
|
|
480
264
|
if (!normalized) return { theme: '', subtheme: '' };
|
|
481
265
|
const [theme = '', subtheme = ''] = normalized.split(':', 2);
|
|
482
266
|
return {
|
|
@@ -497,10 +281,7 @@ const buildAutoPackName = (theme, subtheme, index) => {
|
|
|
497
281
|
return `${base} • Vol. ${index}`;
|
|
498
282
|
};
|
|
499
283
|
const buildAutoPackMarker = (themeKey) => `[auto-theme:${themeKey}]`;
|
|
500
|
-
const buildAutoPackDescription = ({ theme, subtheme, themeKey, groupScore }) =>
|
|
501
|
-
`${buildAutoPackMarker(themeKey)} Curadoria automática por tema. Tema: ${theme}${
|
|
502
|
-
subtheme ? ` / ${subtheme}` : ''
|
|
503
|
-
}. score=${Number(groupScore || 0).toFixed(4)}.`;
|
|
284
|
+
const buildAutoPackDescription = ({ theme, subtheme, themeKey, groupScore }) => `${buildAutoPackMarker(themeKey)} Curadoria automática por tema. Tema: ${theme}${subtheme ? ` / ${subtheme}` : ''}. score=${Number(groupScore || 0).toFixed(4)}.`;
|
|
504
285
|
|
|
505
286
|
const clampNumber = (value, min, max) => Math.max(min, Math.min(max, Number(value)));
|
|
506
287
|
|
|
@@ -556,10 +337,12 @@ const meanArray = (values) => {
|
|
|
556
337
|
const varianceArray = (values) => {
|
|
557
338
|
if (!Array.isArray(values) || values.length <= 1) return 0;
|
|
558
339
|
const mean = meanArray(values);
|
|
559
|
-
return
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
340
|
+
return (
|
|
341
|
+
values.reduce((sum, value) => {
|
|
342
|
+
const delta = Number(value || 0) - mean;
|
|
343
|
+
return sum + delta * delta;
|
|
344
|
+
}, 0) / values.length
|
|
345
|
+
);
|
|
563
346
|
};
|
|
564
347
|
|
|
565
348
|
const percentileValue = (values, percentile) => {
|
|
@@ -645,12 +428,7 @@ const dominantTagRatio = (stickerIds, classificationByAssetId) => {
|
|
|
645
428
|
return best / total;
|
|
646
429
|
};
|
|
647
430
|
|
|
648
|
-
const computeStickerPackMatrixScore = ({
|
|
649
|
-
stickerId,
|
|
650
|
-
packStickerIds,
|
|
651
|
-
classificationByAssetId,
|
|
652
|
-
centroidVector,
|
|
653
|
-
}) => {
|
|
431
|
+
const computeStickerPackMatrixScore = ({ stickerId, packStickerIds, classificationByAssetId, centroidVector }) => {
|
|
654
432
|
const classification = classificationByAssetId.get(stickerId);
|
|
655
433
|
if (!classification) return 0;
|
|
656
434
|
const stickerVector = buildStickerFeatureVector(classification);
|
|
@@ -669,11 +447,13 @@ const computeStickerPackMatrixScore = ({
|
|
|
669
447
|
|
|
670
448
|
const confidence = Number(classification.confidence || 0);
|
|
671
449
|
const themeStrength = Number(buildTopTags(classification)[0]?.score || 0);
|
|
672
|
-
const entropyStability =
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
450
|
+
const entropyStability =
|
|
451
|
+
1 -
|
|
452
|
+
normalizeEntropy({
|
|
453
|
+
entropy: classification.entropy,
|
|
454
|
+
entropyNormalized: classification.entropy_normalized,
|
|
455
|
+
topLabelCount: Array.isArray(classification.top_labels) ? classification.top_labels.length : 0,
|
|
456
|
+
});
|
|
677
457
|
const affinityWeight = normalizeAffinityWeight(classification.affinity_weight);
|
|
678
458
|
const impactOnGroupScore = confidence * 0.4 + themeStrength * 0.35 + entropyStability * 0.15 + affinityWeight * 0.1;
|
|
679
459
|
|
|
@@ -687,11 +467,7 @@ const computeStickerPackMatrixScore = ({
|
|
|
687
467
|
duplicationPenalty = dupHits / Math.max(1, others.length);
|
|
688
468
|
}
|
|
689
469
|
|
|
690
|
-
const matrixScore =
|
|
691
|
-
MATRIX_ALPHA * semanticSimilarity
|
|
692
|
-
+ MATRIX_BETA * cohesion
|
|
693
|
-
+ MATRIX_GAMMA * impactOnGroupScore
|
|
694
|
-
- MATRIX_DELTA * duplicationPenalty;
|
|
470
|
+
const matrixScore = MATRIX_ALPHA * semanticSimilarity + MATRIX_BETA * cohesion + MATRIX_GAMMA * impactOnGroupScore - MATRIX_DELTA * duplicationPenalty;
|
|
695
471
|
|
|
696
472
|
return clampNumber(matrixScore, 0, 1.6);
|
|
697
473
|
};
|
|
@@ -724,11 +500,7 @@ const buildNormalizedZScoreMap = (valueByKey = new Map()) => {
|
|
|
724
500
|
return normalized;
|
|
725
501
|
};
|
|
726
502
|
|
|
727
|
-
const computePackCohesionScore = (profile) => clampNumber(
|
|
728
|
-
Number(profile?.semanticCohesion || 0) * 0.7 + Number(profile?.topicDominance || 0) * 0.3,
|
|
729
|
-
0,
|
|
730
|
-
1,
|
|
731
|
-
);
|
|
503
|
+
const computePackCohesionScore = (profile) => clampNumber(Number(profile?.semanticCohesion || 0) * 0.7 + Number(profile?.topicDominance || 0) * 0.3, 0, 1);
|
|
732
504
|
|
|
733
505
|
const computePackObjectiveScore = ({ profile, engagementScore = 0 }) => {
|
|
734
506
|
const meanAssetQuality = clampNumber(Number(profile?.meanAssetQuality || 0), 0, 1);
|
|
@@ -736,14 +508,7 @@ const computePackObjectiveScore = ({ profile, engagementScore = 0 }) => {
|
|
|
736
508
|
const volumeScore = clampNumber(Number(profile?.volumeScore || 0), 0, 1);
|
|
737
509
|
const engagementComponent = clampNumber(Number(engagementScore || 0), 0, 1);
|
|
738
510
|
|
|
739
|
-
return clampNumber(
|
|
740
|
-
GLOBAL_ENERGY_W1 * meanAssetQuality
|
|
741
|
-
+ GLOBAL_ENERGY_W2 * cohesionScore
|
|
742
|
-
+ GLOBAL_ENERGY_W3 * volumeScore
|
|
743
|
-
+ GLOBAL_ENERGY_W4 * engagementComponent,
|
|
744
|
-
0,
|
|
745
|
-
2,
|
|
746
|
-
);
|
|
511
|
+
return clampNumber(GLOBAL_ENERGY_W1 * meanAssetQuality + GLOBAL_ENERGY_W2 * cohesionScore + GLOBAL_ENERGY_W3 * volumeScore + GLOBAL_ENERGY_W4 * engagementComponent, 0, 2);
|
|
747
512
|
};
|
|
748
513
|
|
|
749
514
|
const computePackOfficialQualityScore = ({ profile, engagementZscore = 0 }) => {
|
|
@@ -752,12 +517,7 @@ const computePackOfficialQualityScore = ({ profile, engagementZscore = 0 }) => {
|
|
|
752
517
|
const completionRatio = clampNumber(Number(profile?.volumeScore || 0), 0, 1);
|
|
753
518
|
const stabilityIndex = clampNumber(1 - Math.max(0, Number(profile?.internalVariance || 0)), 0, 1);
|
|
754
519
|
const engagementComponent = clampNumber(Number(engagementZscore || 0), 0, 1);
|
|
755
|
-
const raw =
|
|
756
|
-
PACK_TIER_QUALITY_W1 * meanAssetQuality
|
|
757
|
-
+ PACK_TIER_QUALITY_W2 * cohesionScore
|
|
758
|
-
+ PACK_TIER_QUALITY_W3 * engagementComponent
|
|
759
|
-
+ PACK_TIER_QUALITY_W4 * completionRatio
|
|
760
|
-
+ PACK_TIER_QUALITY_W5 * stabilityIndex;
|
|
520
|
+
const raw = PACK_TIER_QUALITY_W1 * meanAssetQuality + PACK_TIER_QUALITY_W2 * cohesionScore + PACK_TIER_QUALITY_W3 * engagementComponent + PACK_TIER_QUALITY_W4 * completionRatio + PACK_TIER_QUALITY_W5 * stabilityIndex;
|
|
761
521
|
return clampNumber(raw, 0, 1.2);
|
|
762
522
|
};
|
|
763
523
|
|
|
@@ -767,12 +527,10 @@ const buildPackPairKey = (leftPackId, rightPackId) => {
|
|
|
767
527
|
return left < right ? `${left}::${right}` : `${right}::${left}`;
|
|
768
528
|
};
|
|
769
529
|
|
|
770
|
-
const computePackSemanticSimilarity = (leftProfile, rightProfile) =>
|
|
771
|
-
clampNumber(cosineSimilarity(leftProfile?.centroidVector || {}, rightProfile?.centroidVector || {}), 0, 1);
|
|
530
|
+
const computePackSemanticSimilarity = (leftProfile, rightProfile) => clampNumber(cosineSimilarity(leftProfile?.centroidVector || {}, rightProfile?.centroidVector || {}), 0, 1);
|
|
772
531
|
|
|
773
532
|
const buildInterPackSimilarityMatrix = (profiles) => {
|
|
774
|
-
const profileList = Array.from(
|
|
775
|
-
.filter((profile) => Array.isArray(profile?.stickerIds) && profile.stickerIds.length > 0);
|
|
533
|
+
const profileList = Array.from(profiles instanceof Map ? profiles.values() : []).filter((profile) => Array.isArray(profile?.stickerIds) && profile.stickerIds.length > 0);
|
|
776
534
|
const matrix = new Map();
|
|
777
535
|
let sum = 0;
|
|
778
536
|
let count = 0;
|
|
@@ -812,12 +570,7 @@ const computeMeanNormalizedEntropy = (stickerIds, classificationByAssetId) => {
|
|
|
812
570
|
return count > 0 ? total / count : 0;
|
|
813
571
|
};
|
|
814
572
|
|
|
815
|
-
const computePackEnergyDelta = ({
|
|
816
|
-
baseEnergySnapshot,
|
|
817
|
-
profiles,
|
|
818
|
-
profileScores,
|
|
819
|
-
changes,
|
|
820
|
-
}) => {
|
|
573
|
+
const computePackEnergyDelta = ({ baseEnergySnapshot, profiles, profileScores, changes }) => {
|
|
821
574
|
const updates = changes instanceof Map ? changes : new Map();
|
|
822
575
|
if (!updates.size) {
|
|
823
576
|
return {
|
|
@@ -880,12 +633,7 @@ const computePackEnergyDelta = ({
|
|
|
880
633
|
};
|
|
881
634
|
};
|
|
882
635
|
|
|
883
|
-
const computePackProfile = ({
|
|
884
|
-
packId,
|
|
885
|
-
stickerIds,
|
|
886
|
-
themeKey,
|
|
887
|
-
classificationByAssetId,
|
|
888
|
-
}) => {
|
|
636
|
+
const computePackProfile = ({ packId, stickerIds, themeKey, classificationByAssetId }) => {
|
|
889
637
|
const cleanStickerIds = Array.from(new Set((Array.isArray(stickerIds) ? stickerIds : []).filter(Boolean)));
|
|
890
638
|
const centroidVector = buildPackCentroidVector(cleanStickerIds, classificationByAssetId);
|
|
891
639
|
const matrixScores = cleanStickerIds.map((stickerId) =>
|
|
@@ -894,14 +642,18 @@ const computePackProfile = ({
|
|
|
894
642
|
packStickerIds: cleanStickerIds,
|
|
895
643
|
classificationByAssetId,
|
|
896
644
|
centroidVector,
|
|
897
|
-
})
|
|
645
|
+
}),
|
|
646
|
+
);
|
|
898
647
|
const meanStickerScore = meanArray(matrixScores);
|
|
899
|
-
const semanticCohesion =
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
648
|
+
const semanticCohesion =
|
|
649
|
+
cleanStickerIds.length <= 1
|
|
650
|
+
? 1
|
|
651
|
+
: meanArray(
|
|
652
|
+
cleanStickerIds.map((stickerId) => {
|
|
653
|
+
const classification = classificationByAssetId.get(stickerId);
|
|
654
|
+
return cosineSimilarity(buildStickerFeatureVector(classification), centroidVector);
|
|
655
|
+
}),
|
|
656
|
+
);
|
|
905
657
|
const parsedThemeKey = parseThemeKey(themeKey);
|
|
906
658
|
const meanAssetQuality = meanArray(
|
|
907
659
|
cleanStickerIds.map((stickerId) => {
|
|
@@ -927,22 +679,13 @@ const computePackProfile = ({
|
|
|
927
679
|
pairCount += 1;
|
|
928
680
|
const leftClassification = classificationByAssetId.get(cleanStickerIds[i]);
|
|
929
681
|
const rightClassification = classificationByAssetId.get(cleanStickerIds[j]);
|
|
930
|
-
const sim = cosineSimilarity(
|
|
931
|
-
buildStickerFeatureVector(leftClassification),
|
|
932
|
-
buildStickerFeatureVector(rightClassification),
|
|
933
|
-
);
|
|
682
|
+
const sim = cosineSimilarity(buildStickerFeatureVector(leftClassification), buildStickerFeatureVector(rightClassification));
|
|
934
683
|
if (sim >= DEDUPE_SIMILARITY_THRESHOLD) duplicatePairs += 1;
|
|
935
684
|
}
|
|
936
685
|
}
|
|
937
686
|
const duplicationRatio = pairCount > 0 ? duplicatePairs / pairCount : 0;
|
|
938
687
|
|
|
939
|
-
const qualityRaw =
|
|
940
|
-
PACK_QUALITY_W1 * meanStickerScore
|
|
941
|
-
+ PACK_QUALITY_W2 * semanticCohesion
|
|
942
|
-
+ PACK_QUALITY_W3 * topicDominance
|
|
943
|
-
+ PACK_QUALITY_W4 * volumeScore
|
|
944
|
-
- PACK_QUALITY_W5 * internalVariance
|
|
945
|
-
- PACK_QUALITY_W6 * duplicationRatio;
|
|
688
|
+
const qualityRaw = PACK_QUALITY_W1 * meanStickerScore + PACK_QUALITY_W2 * semanticCohesion + PACK_QUALITY_W3 * topicDominance + PACK_QUALITY_W4 * volumeScore - PACK_QUALITY_W5 * internalVariance - PACK_QUALITY_W6 * duplicationRatio;
|
|
946
689
|
const packQuality = clampNumber(qualityRaw, 0, 2.5);
|
|
947
690
|
|
|
948
691
|
return {
|
|
@@ -962,8 +705,16 @@ const computePackProfile = ({
|
|
|
962
705
|
};
|
|
963
706
|
|
|
964
707
|
const computePackOverlap = (leftProfile, rightProfile) => {
|
|
965
|
-
const leftTags = new Set(
|
|
966
|
-
|
|
708
|
+
const leftTags = new Set(
|
|
709
|
+
String(leftProfile?.themeKey || '')
|
|
710
|
+
.split(':')
|
|
711
|
+
.filter(Boolean),
|
|
712
|
+
);
|
|
713
|
+
const rightTags = new Set(
|
|
714
|
+
String(rightProfile?.themeKey || '')
|
|
715
|
+
.split(':')
|
|
716
|
+
.filter(Boolean),
|
|
717
|
+
);
|
|
967
718
|
const intersection = Array.from(leftTags).filter((tag) => rightTags.has(tag)).length;
|
|
968
719
|
const union = new Set([...leftTags, ...rightTags]).size;
|
|
969
720
|
const jaccard = union > 0 ? intersection / union : 0;
|
|
@@ -1221,15 +972,7 @@ const deriveThemeFromClassification = (classification) => {
|
|
|
1221
972
|
const primary = semanticClusterSlug || categoryTag || fallbackPrimary || `cluster-${semanticClusterId}`;
|
|
1222
973
|
const secondary = topTags.find((entry) => entry.tag !== primary && entry.tag !== 'nsfw')?.tag || '';
|
|
1223
974
|
const semanticThemeKey = buildThemeKey(primary, `cluster-${semanticClusterId}`);
|
|
1224
|
-
const semanticTopTags = withThemeInTopTags(
|
|
1225
|
-
topTags,
|
|
1226
|
-
primary,
|
|
1227
|
-
Math.max(
|
|
1228
|
-
Number(classification?.confidence || 0),
|
|
1229
|
-
Number(topTags.find((entry) => entry.tag === primary)?.score || 0),
|
|
1230
|
-
MOVE_IN_THEME_SCORE_THRESHOLD,
|
|
1231
|
-
),
|
|
1232
|
-
);
|
|
975
|
+
const semanticTopTags = withThemeInTopTags(topTags, primary, Math.max(Number(classification?.confidence || 0), Number(topTags.find((entry) => entry.tag === primary)?.score || 0), MOVE_IN_THEME_SCORE_THRESHOLD));
|
|
1233
976
|
return {
|
|
1234
977
|
theme: primary,
|
|
1235
978
|
subtheme: secondary,
|
|
@@ -1243,15 +986,7 @@ const deriveThemeFromClassification = (classification) => {
|
|
|
1243
986
|
|
|
1244
987
|
const primary = (ENABLE_SEMANTIC_CLUSTERING ? categoryTag : '') || fallbackPrimary;
|
|
1245
988
|
const secondary = topTags.find((entry) => entry.tag !== primary && entry.tag !== 'nsfw')?.tag || '';
|
|
1246
|
-
const fallbackTopTags = withThemeInTopTags(
|
|
1247
|
-
topTags,
|
|
1248
|
-
primary,
|
|
1249
|
-
Math.max(
|
|
1250
|
-
Number(classification?.confidence || 0),
|
|
1251
|
-
Number(topTags.find((entry) => entry.tag === primary)?.score || 0),
|
|
1252
|
-
MOVE_IN_THEME_SCORE_THRESHOLD,
|
|
1253
|
-
),
|
|
1254
|
-
);
|
|
989
|
+
const fallbackTopTags = withThemeInTopTags(topTags, primary, Math.max(Number(classification?.confidence || 0), Number(topTags.find((entry) => entry.tag === primary)?.score || 0), MOVE_IN_THEME_SCORE_THRESHOLD));
|
|
1255
990
|
return {
|
|
1256
991
|
theme: primary,
|
|
1257
992
|
subtheme: secondary,
|
|
@@ -1269,11 +1004,15 @@ const dedupeCandidatesByEmbedding = (candidates, { embeddingByImageHash = new Ma
|
|
|
1269
1004
|
const deduped = [];
|
|
1270
1005
|
let dropped = 0;
|
|
1271
1006
|
for (const candidate of candidates) {
|
|
1272
|
-
const candidateImageHash = String(candidate?.classification?.image_hash || '')
|
|
1007
|
+
const candidateImageHash = String(candidate?.classification?.image_hash || '')
|
|
1008
|
+
.trim()
|
|
1009
|
+
.toLowerCase();
|
|
1273
1010
|
const candidateDense = candidateImageHash ? embeddingByImageHash.get(candidateImageHash) : null;
|
|
1274
1011
|
const candidateSparse = candidate?.classification?.all_scores || {};
|
|
1275
1012
|
const isDuplicate = deduped.some((entry) => {
|
|
1276
|
-
const entryImageHash = String(entry?.classification?.image_hash || '')
|
|
1013
|
+
const entryImageHash = String(entry?.classification?.image_hash || '')
|
|
1014
|
+
.trim()
|
|
1015
|
+
.toLowerCase();
|
|
1277
1016
|
const entryDense = entryImageHash ? embeddingByImageHash.get(entryImageHash) : null;
|
|
1278
1017
|
if (candidateDense && entryDense) {
|
|
1279
1018
|
return cosineSimilarityDense(candidateDense, entryDense) >= DEDUPE_SIMILARITY_THRESHOLD;
|
|
@@ -1315,11 +1054,7 @@ const computeAssetQualityForTheme = ({ classification, theme, subtheme, topTags
|
|
|
1315
1054
|
}, 0);
|
|
1316
1055
|
const rankedThemeScore = Number((Array.isArray(topTags) ? topTags : []).find((entry) => entry.tag === theme)?.score || 0);
|
|
1317
1056
|
const thematicAlignment = clampNumber(Math.max(rankedThemeScore, topLabelThemeScore), 0, 1.2);
|
|
1318
|
-
const assetQuality =
|
|
1319
|
-
ASSET_QUALITY_W1 * confidence
|
|
1320
|
-
+ ASSET_QUALITY_W2 * (1 - entropyNormalized)
|
|
1321
|
-
+ ASSET_QUALITY_W3 * affinityWeight
|
|
1322
|
-
+ ASSET_QUALITY_W4 * thematicAlignment;
|
|
1057
|
+
const assetQuality = ASSET_QUALITY_W1 * confidence + ASSET_QUALITY_W2 * (1 - entropyNormalized) + ASSET_QUALITY_W3 * affinityWeight + ASSET_QUALITY_W4 * thematicAlignment;
|
|
1323
1058
|
|
|
1324
1059
|
return {
|
|
1325
1060
|
confidence,
|
|
@@ -1331,11 +1066,7 @@ const computeAssetQualityForTheme = ({ classification, theme, subtheme, topTags
|
|
|
1331
1066
|
};
|
|
1332
1067
|
|
|
1333
1068
|
const scoreCandidate = ({ classification, theme, subtheme, topTags, qualityScore }) => {
|
|
1334
|
-
const {
|
|
1335
|
-
affinityWeight,
|
|
1336
|
-
entropyNormalized,
|
|
1337
|
-
assetQuality,
|
|
1338
|
-
} = computeAssetQualityForTheme({ classification, theme, subtheme, topTags });
|
|
1069
|
+
const { affinityWeight, entropyNormalized, assetQuality } = computeAssetQualityForTheme({ classification, theme, subtheme, topTags });
|
|
1339
1070
|
const confidenceMargin = Math.max(0, Number(classification?.confidence_margin || 0));
|
|
1340
1071
|
const ambiguityPenalty = (classification?.ambiguous ? AMBIGUOUS_FLAG_PENALTY : 0) + entropyNormalized * ENTROPY_WEIGHT;
|
|
1341
1072
|
|
|
@@ -1348,13 +1079,7 @@ const scoreCandidate = ({ classification, theme, subtheme, topTags, qualityScore
|
|
|
1348
1079
|
|
|
1349
1080
|
const adaptiveBonus = affinityWeight * ADAPTIVE_BONUS_WEIGHT;
|
|
1350
1081
|
const marginBonus = confidenceMargin * MARGIN_BONUS_WEIGHT;
|
|
1351
|
-
const finalScore =
|
|
1352
|
-
assetQuality * 0.65
|
|
1353
|
-
+ Number(qualityScore || 0) * 0.2
|
|
1354
|
-
+ adaptiveBonus
|
|
1355
|
-
+ marginBonus
|
|
1356
|
-
- ambiguityPenalty
|
|
1357
|
-
- similarImagesPenalty;
|
|
1082
|
+
const finalScore = assetQuality * 0.65 + Number(qualityScore || 0) * 0.2 + adaptiveBonus + marginBonus - ambiguityPenalty - similarImagesPenalty;
|
|
1358
1083
|
return Number(clampNumber(finalScore, 0, 1.2).toFixed(6));
|
|
1359
1084
|
};
|
|
1360
1085
|
|
|
@@ -1455,25 +1180,7 @@ const collectCuratableCandidates = async ({ includePacked = true, includeUnpacke
|
|
|
1455
1180
|
return current;
|
|
1456
1181
|
};
|
|
1457
1182
|
|
|
1458
|
-
const registerCandidate = ({
|
|
1459
|
-
asset,
|
|
1460
|
-
classification,
|
|
1461
|
-
passIndex,
|
|
1462
|
-
theme,
|
|
1463
|
-
subtheme,
|
|
1464
|
-
themeKey,
|
|
1465
|
-
topTags,
|
|
1466
|
-
qualityScore,
|
|
1467
|
-
themeScore,
|
|
1468
|
-
score,
|
|
1469
|
-
nsfwScore,
|
|
1470
|
-
nsfwLevel,
|
|
1471
|
-
entropy,
|
|
1472
|
-
confidenceMargin,
|
|
1473
|
-
affinityWeight,
|
|
1474
|
-
ambiguous,
|
|
1475
|
-
similarPenalty,
|
|
1476
|
-
}) => {
|
|
1183
|
+
const registerCandidate = ({ asset, classification, passIndex, theme, subtheme, themeKey, topTags, qualityScore, themeScore, score, nsfwScore, nsfwLevel, entropy, confidenceMargin, affinityWeight, ambiguous, similarPenalty }) => {
|
|
1477
1184
|
const assetStats = ensureAssetStats(asset, classification);
|
|
1478
1185
|
const themeStats = ensureThemeStats(assetStats, { themeKey, theme, subtheme });
|
|
1479
1186
|
const passWeight = resolvePassScoreWeight(asset.id, passIndex);
|
|
@@ -1545,14 +1252,7 @@ const collectCuratableCandidates = async ({ includePacked = true, includeUnpacke
|
|
|
1545
1252
|
continue;
|
|
1546
1253
|
}
|
|
1547
1254
|
|
|
1548
|
-
const {
|
|
1549
|
-
theme,
|
|
1550
|
-
subtheme,
|
|
1551
|
-
topTags,
|
|
1552
|
-
nsfwScore,
|
|
1553
|
-
nsfwLevel,
|
|
1554
|
-
semanticThemeKey = '',
|
|
1555
|
-
} = deriveThemeFromClassification(classification);
|
|
1255
|
+
const { theme, subtheme, topTags, nsfwScore, nsfwLevel, semanticThemeKey = '' } = deriveThemeFromClassification(classification);
|
|
1556
1256
|
if (!theme) {
|
|
1557
1257
|
stats.assets_rejected_no_theme += 1;
|
|
1558
1258
|
continue;
|
|
@@ -1598,10 +1298,7 @@ const collectCuratableCandidates = async ({ includePacked = true, includeUnpacke
|
|
|
1598
1298
|
entropy: entropyNormalized,
|
|
1599
1299
|
confidenceMargin: Number(classification?.confidence_margin || 0),
|
|
1600
1300
|
affinityWeight: normalizeAffinityWeight(classification?.affinity_weight),
|
|
1601
|
-
ambiguous:
|
|
1602
|
-
classification?.ambiguous === true
|
|
1603
|
-
|| classification?.ambiguous === 1
|
|
1604
|
-
|| entropyNormalized > ENTROPY_NORMALIZED_THRESHOLD,
|
|
1301
|
+
ambiguous: classification?.ambiguous === true || classification?.ambiguous === 1 || entropyNormalized > ENTROPY_NORMALIZED_THRESHOLD,
|
|
1605
1302
|
similarPenalty: maxSimilarity * SIMILAR_IMAGES_PENALTY_WEIGHT,
|
|
1606
1303
|
});
|
|
1607
1304
|
}
|
|
@@ -1621,9 +1318,7 @@ const collectCuratableCandidates = async ({ includePacked = true, includeUnpacke
|
|
|
1621
1318
|
|
|
1622
1319
|
if (REVIEW_VERSION_TARGET) {
|
|
1623
1320
|
while (scannedInPass < effectiveCapPerPass) {
|
|
1624
|
-
const remaining = Number.isFinite(effectiveCapPerPass)
|
|
1625
|
-
? Math.max(0, effectiveCapPerPass - scannedInPass)
|
|
1626
|
-
: pageLimit;
|
|
1321
|
+
const remaining = Number.isFinite(effectiveCapPerPass) ? Math.max(0, effectiveCapPerPass - scannedInPass) : pageLimit;
|
|
1627
1322
|
const limit = Math.max(1, Math.min(pageLimit, remaining || pageLimit));
|
|
1628
1323
|
const page = await listClassifiedStickerAssetsForCuration({
|
|
1629
1324
|
limit,
|
|
@@ -1645,9 +1340,7 @@ const collectCuratableCandidates = async ({ includePacked = true, includeUnpacke
|
|
|
1645
1340
|
}
|
|
1646
1341
|
|
|
1647
1342
|
while (scannedInPass < effectiveCapPerPass) {
|
|
1648
|
-
const remaining = Number.isFinite(effectiveCapPerPass)
|
|
1649
|
-
? Math.max(0, effectiveCapPerPass - scannedInPass)
|
|
1650
|
-
: pageLimit;
|
|
1343
|
+
const remaining = Number.isFinite(effectiveCapPerPass) ? Math.max(0, effectiveCapPerPass - scannedInPass) : pageLimit;
|
|
1651
1344
|
const limit = Math.max(1, Math.min(pageLimit, remaining || pageLimit));
|
|
1652
1345
|
const page = await listClassifiedStickerAssetsForCuration({
|
|
1653
1346
|
limit,
|
|
@@ -1678,8 +1371,7 @@ const collectCuratableCandidates = async ({ includePacked = true, includeUnpacke
|
|
|
1678
1371
|
stats.pass_assets_unique.push(passResult.uniqueSeenInPass);
|
|
1679
1372
|
}
|
|
1680
1373
|
|
|
1681
|
-
const meanPassScan =
|
|
1682
|
-
stats.pass_assets_scanned.reduce((sum, value) => sum + Number(value || 0), 0) / Math.max(1, stats.pass_assets_scanned.length);
|
|
1374
|
+
const meanPassScan = stats.pass_assets_scanned.reduce((sum, value) => sum + Number(value || 0), 0) / Math.max(1, stats.pass_assets_scanned.length);
|
|
1683
1375
|
stats.assets_scanned_avg_per_pass = Number(meanPassScan.toFixed(2));
|
|
1684
1376
|
stats.assets_unique_scanned = globalSeenAssetIds.size;
|
|
1685
1377
|
|
|
@@ -1687,15 +1379,13 @@ const collectCuratableCandidates = async ({ includePacked = true, includeUnpacke
|
|
|
1687
1379
|
const themeEntries = Array.from(assetStats.themes.values());
|
|
1688
1380
|
if (!themeEntries.length) continue;
|
|
1689
1381
|
|
|
1690
|
-
const dominantTheme = themeEntries
|
|
1691
|
-
.
|
|
1692
|
-
.
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
return right.themeScoreSum - left.themeScoreSum;
|
|
1698
|
-
})[0];
|
|
1382
|
+
const dominantTheme = themeEntries.slice().sort((left, right) => {
|
|
1383
|
+
if (right.votes !== left.votes) return right.votes - left.votes;
|
|
1384
|
+
const leftMean = left.scoreSum / Math.max(1, left.votes);
|
|
1385
|
+
const rightMean = right.scoreSum / Math.max(1, right.votes);
|
|
1386
|
+
if (rightMean !== leftMean) return rightMean - leftMean;
|
|
1387
|
+
return right.themeScoreSum - left.themeScoreSum;
|
|
1388
|
+
})[0];
|
|
1699
1389
|
|
|
1700
1390
|
if (!dominantTheme || dominantTheme.votes <= 0) continue;
|
|
1701
1391
|
|
|
@@ -1727,28 +1417,13 @@ const collectCuratableCandidates = async ({ includePacked = true, includeUnpacke
|
|
|
1727
1417
|
const avgSimilarPenalty = dominantTheme.similarPenaltySum / acceptedVotes;
|
|
1728
1418
|
const ambiguousRatio = dominantTheme.ambiguityVotes / acceptedVotes;
|
|
1729
1419
|
const stabilityFactor = Math.sqrt(clampNumber(acceptanceRate, 0, 1));
|
|
1730
|
-
const harmonicSignal = 3 / (
|
|
1731
|
-
|
|
1732
|
-
+ (1 / Math.max(0.01, avgThemeScore))
|
|
1733
|
-
+ (1 / Math.max(0.01, avgConfidence))
|
|
1734
|
-
);
|
|
1735
|
-
const robustScoreRaw =
|
|
1736
|
-
lowerBoundScore * 0.46
|
|
1737
|
-
+ meanScore * 0.16
|
|
1738
|
-
+ avgThemeScore * 0.14
|
|
1739
|
-
+ avgConfidence * 0.08
|
|
1740
|
-
+ harmonicSignal * 0.16
|
|
1741
|
-
+ avgConfidenceMargin * MARGIN_BONUS_WEIGHT * 0.45
|
|
1742
|
-
+ avgAffinityWeight * ADAPTIVE_BONUS_WEIGHT * 0.4
|
|
1743
|
-
- Math.min(0.42, avgEntropy * ENTROPY_WEIGHT)
|
|
1744
|
-
- ambiguousRatio * AMBIGUOUS_FLAG_PENALTY
|
|
1745
|
-
- avgSimilarPenalty * 0.5;
|
|
1420
|
+
const harmonicSignal = 3 / (1 / Math.max(0.01, avgQuality) + 1 / Math.max(0.01, avgThemeScore) + 1 / Math.max(0.01, avgConfidence));
|
|
1421
|
+
const robustScoreRaw = lowerBoundScore * 0.46 + meanScore * 0.16 + avgThemeScore * 0.14 + avgConfidence * 0.08 + harmonicSignal * 0.16 + avgConfidenceMargin * MARGIN_BONUS_WEIGHT * 0.45 + avgAffinityWeight * ADAPTIVE_BONUS_WEIGHT * 0.4 - Math.min(0.42, avgEntropy * ENTROPY_WEIGHT) - ambiguousRatio * AMBIGUOUS_FLAG_PENALTY - avgSimilarPenalty * 0.5;
|
|
1746
1422
|
const stabilityMultiplier = 0.72 + stabilityFactor * 0.28;
|
|
1747
1423
|
const variancePenalty = Math.max(0.4, 1 - Math.min(0.55, stdDev * EFFECTIVE_SCORE_STDDEV_PENALTY));
|
|
1748
1424
|
const robustScore = clampNumber(robustScoreRaw * stabilityMultiplier * variancePenalty, 0, 1.2);
|
|
1749
1425
|
|
|
1750
|
-
const dominantSubtheme = Array.from(dominantTheme.subthemeVotes.entries())
|
|
1751
|
-
.sort((left, right) => right[1] - left[1])[0]?.[0] || dominantTheme.subtheme || '';
|
|
1426
|
+
const dominantSubtheme = Array.from(dominantTheme.subthemeVotes.entries()).sort((left, right) => right[1] - left[1])[0]?.[0] || dominantTheme.subtheme || '';
|
|
1752
1427
|
const topTags = buildTopTags(assetStats.classification);
|
|
1753
1428
|
if (!topTags.some((entry) => entry?.tag === dominantTheme.theme)) {
|
|
1754
1429
|
topTags.unshift({ tag: dominantTheme.theme, score: avgThemeScore });
|
|
@@ -1792,7 +1467,11 @@ const collectCuratableCandidates = async ({ includePacked = true, includeUnpacke
|
|
|
1792
1467
|
new Set(
|
|
1793
1468
|
Array.from(grouped.values())
|
|
1794
1469
|
.flat()
|
|
1795
|
-
.map((candidate) =>
|
|
1470
|
+
.map((candidate) =>
|
|
1471
|
+
String(candidate?.classification?.image_hash || '')
|
|
1472
|
+
.trim()
|
|
1473
|
+
.toLowerCase(),
|
|
1474
|
+
)
|
|
1796
1475
|
.filter((hash) => hash.length === 64),
|
|
1797
1476
|
),
|
|
1798
1477
|
);
|
|
@@ -1800,7 +1479,9 @@ const collectCuratableCandidates = async ({ includePacked = true, includeUnpacke
|
|
|
1800
1479
|
if (imageHashes.length) {
|
|
1801
1480
|
const rows = await listClipImageEmbeddingsByImageHashes(imageHashes);
|
|
1802
1481
|
for (const row of rows) {
|
|
1803
|
-
const imageHash = String(row?.image_hash || '')
|
|
1482
|
+
const imageHash = String(row?.image_hash || '')
|
|
1483
|
+
.trim()
|
|
1484
|
+
.toLowerCase();
|
|
1804
1485
|
if (!imageHash) continue;
|
|
1805
1486
|
const embedding = parseFloat32EmbeddingBuffer(row?.embedding, Number(row?.embedding_dim || 0));
|
|
1806
1487
|
if (!embedding?.length) continue;
|
|
@@ -1841,20 +1522,20 @@ const computeGroupMetrics = (themeKey, candidates) => {
|
|
|
1841
1522
|
return { theme, subtheme, themeKey, groupScore: 0, cohesion: 0, avgConfidence: 0, avgQuality: 0 };
|
|
1842
1523
|
}
|
|
1843
1524
|
|
|
1844
|
-
const avgConfidence =
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1525
|
+
const avgConfidence = candidates.reduce((sum, candidate) => sum + Number(candidate.classification?.confidence || 0), 0) / size;
|
|
1526
|
+
const avgEntropy =
|
|
1527
|
+
candidates.reduce(
|
|
1528
|
+
(sum, candidate) =>
|
|
1529
|
+
sum +
|
|
1530
|
+
normalizeEntropy({
|
|
1531
|
+
entropy: candidate.classification?.entropy,
|
|
1532
|
+
entropyNormalized: candidate.classification?.entropy_normalized,
|
|
1533
|
+
topLabelCount: Array.isArray(candidate.classification?.top_labels) ? candidate.classification.top_labels.length : 0,
|
|
1534
|
+
}),
|
|
1535
|
+
0,
|
|
1536
|
+
) / size;
|
|
1854
1537
|
const avgMargin = candidates.reduce((sum, candidate) => sum + Number(candidate.classification?.confidence_margin || 0), 0) / size;
|
|
1855
|
-
const avgAffinity = candidates.reduce((sum, candidate) => (
|
|
1856
|
-
sum + normalizeAffinityWeight(candidate.classification?.affinity_weight)
|
|
1857
|
-
), 0) / size;
|
|
1538
|
+
const avgAffinity = candidates.reduce((sum, candidate) => sum + normalizeAffinityWeight(candidate.classification?.affinity_weight), 0) / size;
|
|
1858
1539
|
const avgQuality = candidates.reduce((sum, candidate) => sum + Number(candidate.qualityScore || 0), 0) / size;
|
|
1859
1540
|
const avgDuplicateRate = candidates.reduce((sum, candidate) => sum + Number(candidate.duplicateRate || 0), 0) / size;
|
|
1860
1541
|
let semanticSimilaritySum = 0;
|
|
@@ -1868,9 +1549,7 @@ const computeGroupMetrics = (themeKey, candidates) => {
|
|
|
1868
1549
|
const semanticCohesion = semanticPairs > 0 ? semanticSimilaritySum / semanticPairs : 1;
|
|
1869
1550
|
const cooccurrence = new Map();
|
|
1870
1551
|
for (const candidate of candidates) {
|
|
1871
|
-
const localSecondary = (candidate.topTags || [])
|
|
1872
|
-
.map((entry) => entry.tag)
|
|
1873
|
-
.find((tag) => tag && tag !== theme && tag !== 'nsfw');
|
|
1552
|
+
const localSecondary = (candidate.topTags || []).map((entry) => entry.tag).find((tag) => tag && tag !== theme && tag !== 'nsfw');
|
|
1874
1553
|
if (!localSecondary) continue;
|
|
1875
1554
|
cooccurrence.set(localSecondary, (cooccurrence.get(localSecondary) || 0) + 1);
|
|
1876
1555
|
}
|
|
@@ -1883,9 +1562,7 @@ const computeGroupMetrics = (themeKey, candidates) => {
|
|
|
1883
1562
|
traitVotes.set(token, (traitVotes.get(token) || 0) + 1);
|
|
1884
1563
|
}
|
|
1885
1564
|
}
|
|
1886
|
-
const strongestTraitRatio = size
|
|
1887
|
-
? Math.max(0, ...Array.from(traitVotes.values()).map((value) => value / size))
|
|
1888
|
-
: 0;
|
|
1565
|
+
const strongestTraitRatio = size ? Math.max(0, ...Array.from(traitVotes.values()).map((value) => value / size)) : 0;
|
|
1889
1566
|
const semanticBoost = strongestTraitRatio * LLM_TRAIT_WEIGHT;
|
|
1890
1567
|
const subthemeFromCooccurrence = Array.from(cooccurrence.entries()).sort((left, right) => right[1] - left[1])[0]?.[0] || subtheme;
|
|
1891
1568
|
const volumeBoost = Math.min(1, size / Math.max(MIN_GROUP_SIZE, TARGET_PACK_SIZE));
|
|
@@ -1893,17 +1570,7 @@ const computeGroupMetrics = (themeKey, candidates) => {
|
|
|
1893
1570
|
const entropyPenalty = Math.min(0.35, avgEntropy * ENTROPY_WEIGHT);
|
|
1894
1571
|
const marginBoost = Math.max(0, avgMargin * MARGIN_BONUS_WEIGHT);
|
|
1895
1572
|
const affinityBoost = Math.max(0, avgAffinity * ADAPTIVE_BONUS_WEIGHT);
|
|
1896
|
-
const groupScore = Number(
|
|
1897
|
-
(
|
|
1898
|
-
avgConfidence
|
|
1899
|
-
* (0.55 + cohesion * 0.45 + semanticBoost)
|
|
1900
|
-
* avgQuality
|
|
1901
|
-
* (0.75 + volumeBoost * 0.25 + marginBoost)
|
|
1902
|
-
* duplicatePenalty
|
|
1903
|
-
* (1 + affinityBoost)
|
|
1904
|
-
* Math.max(0.45, 1 - entropyPenalty)
|
|
1905
|
-
).toFixed(6),
|
|
1906
|
-
);
|
|
1573
|
+
const groupScore = Number((avgConfidence * (0.55 + cohesion * 0.45 + semanticBoost) * avgQuality * (0.75 + volumeBoost * 0.25 + marginBoost) * duplicatePenalty * (1 + affinityBoost) * Math.max(0.45, 1 - entropyPenalty)).toFixed(6));
|
|
1907
1574
|
|
|
1908
1575
|
return {
|
|
1909
1576
|
theme,
|
|
@@ -2128,8 +1795,7 @@ const runRetroConsolidationCycle = async ({ ownerPool }) => {
|
|
|
2128
1795
|
let themeLimitReached = false;
|
|
2129
1796
|
let mutationLimitReached = false;
|
|
2130
1797
|
|
|
2131
|
-
const themeEntries = Array.from(packsByTheme.entries())
|
|
2132
|
-
.sort((left, right) => right[1].length - left[1].length);
|
|
1798
|
+
const themeEntries = Array.from(packsByTheme.entries()).sort((left, right) => right[1].length - left[1].length);
|
|
2133
1799
|
|
|
2134
1800
|
for (const [themeKey, themePacksRaw] of themeEntries) {
|
|
2135
1801
|
if (processedThemes >= RETRO_CONSOLIDATION_THEME_LIMIT) {
|
|
@@ -2161,17 +1827,12 @@ const runRetroConsolidationCycle = async ({ ownerPool }) => {
|
|
|
2161
1827
|
|
|
2162
1828
|
const anchorPack = themePacks[0];
|
|
2163
1829
|
const anchorItemsInitial = itemsByPackId.get(anchorPack.id) || [];
|
|
2164
|
-
const donorPacks = themePacks.filter((pack) => pack.id !== anchorPack.id && (
|
|
2165
|
-
|
|
2166
|
-
));
|
|
2167
|
-
|
|
2168
|
-
const desiredAnchorIds = Array.from(new Set([
|
|
2169
|
-
...anchorItemsInitial.map((item) => item.sticker_id).filter(Boolean),
|
|
2170
|
-
...donorPacks.flatMap((pack) => (itemsByPackId.get(pack.id) || []).map((item) => item.sticker_id).filter(Boolean)),
|
|
2171
|
-
])).slice(0, TARGET_PACK_SIZE);
|
|
1830
|
+
const donorPacks = themePacks.filter((pack) => pack.id !== anchorPack.id && (smallPacks.some((entry) => entry.id === pack.id) || overflowPacks.some((entry) => entry.id === pack.id)));
|
|
1831
|
+
|
|
1832
|
+
const desiredAnchorIds = Array.from(new Set([...anchorItemsInitial.map((item) => item.sticker_id).filter(Boolean), ...donorPacks.flatMap((pack) => (itemsByPackId.get(pack.id) || []).map((item) => item.sticker_id).filter(Boolean))])).slice(0, TARGET_PACK_SIZE);
|
|
2172
1833
|
const desiredAnchorSet = new Set(desiredAnchorIds);
|
|
2173
1834
|
|
|
2174
|
-
let anchorItems = itemsByPackId.get(anchorPack.id) || await listStickerPackItems(anchorPack.id);
|
|
1835
|
+
let anchorItems = itemsByPackId.get(anchorPack.id) || (await listStickerPackItems(anchorPack.id));
|
|
2175
1836
|
const anchorCurrentSet = new Set(anchorItems.map((item) => item.sticker_id).filter(Boolean));
|
|
2176
1837
|
|
|
2177
1838
|
for (const item of anchorItems) {
|
|
@@ -2235,10 +1896,7 @@ const runRetroConsolidationCycle = async ({ ownerPool }) => {
|
|
|
2235
1896
|
itemsByPackId.set(anchorPack.id, anchorItems);
|
|
2236
1897
|
const anchorOrder = anchorItems.map((item) => item.sticker_id);
|
|
2237
1898
|
const finalDesiredOrder = desiredAnchorIds.filter((stickerId) => anchorOrder.includes(stickerId));
|
|
2238
|
-
const needsReorder =
|
|
2239
|
-
finalDesiredOrder.length > 1 &&
|
|
2240
|
-
(finalDesiredOrder.length !== anchorOrder.length
|
|
2241
|
-
|| finalDesiredOrder.some((stickerId, index) => anchorOrder[index] !== stickerId));
|
|
1899
|
+
const needsReorder = finalDesiredOrder.length > 1 && (finalDesiredOrder.length !== anchorOrder.length || finalDesiredOrder.some((stickerId, index) => anchorOrder[index] !== stickerId));
|
|
2242
1900
|
if (needsReorder) {
|
|
2243
1901
|
try {
|
|
2244
1902
|
await stickerPackService.reorderPackItems({
|
|
@@ -2275,7 +1933,7 @@ const runRetroConsolidationCycle = async ({ ownerPool }) => {
|
|
|
2275
1933
|
}
|
|
2276
1934
|
}
|
|
2277
1935
|
|
|
2278
|
-
anchorItems = itemsByPackId.get(anchorPack.id) || await listStickerPackItems(anchorPack.id);
|
|
1936
|
+
anchorItems = itemsByPackId.get(anchorPack.id) || (await listStickerPackItems(anchorPack.id));
|
|
2279
1937
|
const anchorCount = anchorItems.length;
|
|
2280
1938
|
if (anchorCount < HARD_MIN_PACK_ITEMS) {
|
|
2281
1939
|
if (mutations < RETRO_CONSOLIDATION_MUTATION_LIMIT) {
|
|
@@ -2331,12 +1989,7 @@ const runRetroConsolidationCycle = async ({ ownerPool }) => {
|
|
|
2331
1989
|
};
|
|
2332
1990
|
};
|
|
2333
1991
|
|
|
2334
|
-
const optimizePackEcosystem = ({
|
|
2335
|
-
operations,
|
|
2336
|
-
itemsByPackId,
|
|
2337
|
-
classificationByAssetId,
|
|
2338
|
-
packEngagementByPackId = new Map(),
|
|
2339
|
-
}) => {
|
|
1992
|
+
const optimizePackEcosystem = ({ operations, itemsByPackId, classificationByAssetId, packEngagementByPackId = new Map() }) => {
|
|
2340
1993
|
if (!ENABLE_GLOBAL_OPTIMIZATION) {
|
|
2341
1994
|
return {
|
|
2342
1995
|
enabled: false,
|
|
@@ -2360,9 +2013,7 @@ const optimizePackEcosystem = ({
|
|
|
2360
2013
|
};
|
|
2361
2014
|
}
|
|
2362
2015
|
|
|
2363
|
-
const scopedOps = (Array.isArray(operations) ? operations : [])
|
|
2364
|
-
.filter((op) => op?.type === 'reconcile_volume' && op?.existingPackId)
|
|
2365
|
-
.sort((left, right) => String(left.sort_key || '').localeCompare(String(right.sort_key || '')));
|
|
2016
|
+
const scopedOps = (Array.isArray(operations) ? operations : []).filter((op) => op?.type === 'reconcile_volume' && op?.existingPackId).sort((left, right) => String(left.sort_key || '').localeCompare(String(right.sort_key || '')));
|
|
2366
2017
|
|
|
2367
2018
|
if (!scopedOps.length) {
|
|
2368
2019
|
return {
|
|
@@ -2391,44 +2042,50 @@ const optimizePackEcosystem = ({
|
|
|
2391
2042
|
scopedOps.map((op) => {
|
|
2392
2043
|
const initialItems = itemsByPackId.get(op.existingPackId) || [];
|
|
2393
2044
|
const stickers = new Set(initialItems.map((item) => item?.sticker_id).filter(Boolean));
|
|
2394
|
-
return [
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2045
|
+
return [
|
|
2046
|
+
op.existingPackId,
|
|
2047
|
+
{
|
|
2048
|
+
packId: op.existingPackId,
|
|
2049
|
+
op,
|
|
2050
|
+
themeKey: String(op.themeKey || ''),
|
|
2051
|
+
stickers,
|
|
2052
|
+
tier: 'BRONZE',
|
|
2053
|
+
},
|
|
2054
|
+
];
|
|
2401
2055
|
}),
|
|
2402
2056
|
);
|
|
2403
2057
|
|
|
2404
2058
|
const computeProfiles = () => {
|
|
2405
2059
|
const profiles = new Map();
|
|
2406
2060
|
for (const [packId, state] of stateByPackId.entries()) {
|
|
2407
|
-
profiles.set(
|
|
2061
|
+
profiles.set(
|
|
2408
2062
|
packId,
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2063
|
+
computePackProfile({
|
|
2064
|
+
packId,
|
|
2065
|
+
stickerIds: Array.from(state.stickers),
|
|
2066
|
+
themeKey: state.themeKey,
|
|
2067
|
+
classificationByAssetId,
|
|
2068
|
+
}),
|
|
2069
|
+
);
|
|
2413
2070
|
}
|
|
2414
2071
|
return profiles;
|
|
2415
2072
|
};
|
|
2416
2073
|
|
|
2417
2074
|
const getEngagementScore = (packId) => computePackEngagementScore(packEngagementByPackId.get(packId));
|
|
2418
|
-
const engagementScoreByPackId = new Map(
|
|
2419
|
-
Array.from(stateByPackId.keys()).map((packId) => [packId, Number(getEngagementScore(packId) || 0)]),
|
|
2420
|
-
);
|
|
2075
|
+
const engagementScoreByPackId = new Map(Array.from(stateByPackId.keys()).map((packId) => [packId, Number(getEngagementScore(packId) || 0)]));
|
|
2421
2076
|
const engagementZscoreByPackId = buildNormalizedZScoreMap(engagementScoreByPackId);
|
|
2422
2077
|
const getEngagementZscore = (packId) => Number(engagementZscoreByPackId.get(packId) || 0);
|
|
2423
2078
|
|
|
2424
|
-
const scoreProfile = (profile) =>
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2079
|
+
const scoreProfile = (profile) =>
|
|
2080
|
+
computePackObjectiveScore({
|
|
2081
|
+
profile,
|
|
2082
|
+
engagementScore: Number(getEngagementScore(profile?.packId) || 0),
|
|
2083
|
+
});
|
|
2084
|
+
const scoreQualityProfile = (profile) =>
|
|
2085
|
+
computePackOfficialQualityScore({
|
|
2086
|
+
profile,
|
|
2087
|
+
engagementZscore: getEngagementZscore(profile?.packId),
|
|
2088
|
+
});
|
|
2432
2089
|
|
|
2433
2090
|
const buildProfileScoreMap = (profiles) => {
|
|
2434
2091
|
const map = new Map();
|
|
@@ -2585,10 +2242,7 @@ const optimizePackEcosystem = ({
|
|
|
2585
2242
|
if (!sourceProfile || !Number.isFinite(sourceScore) || !Number.isFinite(sourceQuality)) continue;
|
|
2586
2243
|
|
|
2587
2244
|
const recipientCandidates = packStates
|
|
2588
|
-
.filter((recipient) =>
|
|
2589
|
-
recipient.packId !== source.packId
|
|
2590
|
-
&& !recipient.stickers.has(stickerId)
|
|
2591
|
-
&& recipient.stickers.size < TARGET_PACK_SIZE)
|
|
2245
|
+
.filter((recipient) => recipient.packId !== source.packId && !recipient.stickers.has(stickerId) && recipient.stickers.size < TARGET_PACK_SIZE)
|
|
2592
2246
|
.map((recipient) => {
|
|
2593
2247
|
const recipientProfile = profiles.get(recipient.packId);
|
|
2594
2248
|
const recipientScore = Number(profileScores.get(recipient.packId) || 0);
|
|
@@ -2601,10 +2255,7 @@ const optimizePackEcosystem = ({
|
|
|
2601
2255
|
if (!sameTheme && semanticSimilarity < EFFECTIVE_TRANSFER_CANDIDATE_SIMILARITY_FLOOR) {
|
|
2602
2256
|
return null;
|
|
2603
2257
|
}
|
|
2604
|
-
const candidateRank =
|
|
2605
|
-
semanticSimilarity * 0.85
|
|
2606
|
-
+ (sameTheme ? 0.15 : 0)
|
|
2607
|
-
+ Math.max(0, recipientQuality - sourceQuality) * 0.1;
|
|
2258
|
+
const candidateRank = semanticSimilarity * 0.85 + (sameTheme ? 0.15 : 0) + Math.max(0, recipientQuality - sourceQuality) * 0.1;
|
|
2608
2259
|
return {
|
|
2609
2260
|
recipient,
|
|
2610
2261
|
recipientScore,
|
|
@@ -2810,9 +2461,7 @@ const optimizePackEcosystem = ({
|
|
|
2810
2461
|
});
|
|
2811
2462
|
const nextScore = Number(scoreProfile(nextProfile).toFixed(6));
|
|
2812
2463
|
const nextQuality = Number(scoreQualityProfile(nextProfile).toFixed(6));
|
|
2813
|
-
const changes = new Map([
|
|
2814
|
-
[state.packId, { profile: nextProfile, score: nextScore }],
|
|
2815
|
-
]);
|
|
2464
|
+
const changes = new Map([[state.packId, { profile: nextProfile, score: nextScore }]]);
|
|
2816
2465
|
const deltaPreview = computePackEnergyDelta({
|
|
2817
2466
|
baseEnergySnapshot: energySnapshot,
|
|
2818
2467
|
profiles,
|
|
@@ -2889,9 +2538,7 @@ const optimizePackEcosystem = ({
|
|
|
2889
2538
|
const desiredSet = new Set(op.desiredAssetIds);
|
|
2890
2539
|
const removedByOptimization = Array.from(currentSet).filter((stickerId) => !desiredSet.has(stickerId));
|
|
2891
2540
|
if (removedByOptimization.length) {
|
|
2892
|
-
op.forceRemoveAssetIds = Array.from(
|
|
2893
|
-
new Set([...(Array.isArray(op.forceRemoveAssetIds) ? op.forceRemoveAssetIds : []), ...removedByOptimization]),
|
|
2894
|
-
);
|
|
2541
|
+
op.forceRemoveAssetIds = Array.from(new Set([...(Array.isArray(op.forceRemoveAssetIds) ? op.forceRemoveAssetIds : []), ...removedByOptimization]));
|
|
2895
2542
|
}
|
|
2896
2543
|
if (state.tier === 'ARCHIVE') {
|
|
2897
2544
|
op.desiredAssetIds = [];
|
|
@@ -2902,9 +2549,7 @@ const optimizePackEcosystem = ({
|
|
|
2902
2549
|
}
|
|
2903
2550
|
}
|
|
2904
2551
|
|
|
2905
|
-
const entropyMeanGlobal = Number(
|
|
2906
|
-
computeMeanNormalizedEntropy(collectStickerIds(), classificationByAssetId).toFixed(6),
|
|
2907
|
-
);
|
|
2552
|
+
const entropyMeanGlobal = Number(computeMeanNormalizedEntropy(collectStickerIds(), classificationByAssetId).toFixed(6));
|
|
2908
2553
|
|
|
2909
2554
|
return {
|
|
2910
2555
|
enabled: true,
|
|
@@ -2979,15 +2624,8 @@ const buildCurationExecutionPlan = async ({ curatedGroups, ownerPool, enableAddi
|
|
|
2979
2624
|
return extractVolumeFromPack(left) - extractVolumeFromPack(right);
|
|
2980
2625
|
});
|
|
2981
2626
|
const retainedThemePacks = rankedThemePacks.slice(0, MAX_PACKS_PER_THEME);
|
|
2982
|
-
const packCountById = new Map(
|
|
2983
|
-
|
|
2984
|
-
);
|
|
2985
|
-
const packItemsById = new Map(
|
|
2986
|
-
retainedThemePacks.map((pack) => [
|
|
2987
|
-
pack.id,
|
|
2988
|
-
new Set((itemsByPackId.get(pack.id) || []).map((item) => item.sticker_id).filter(Boolean)),
|
|
2989
|
-
]),
|
|
2990
|
-
);
|
|
2627
|
+
const packCountById = new Map(retainedThemePacks.map((pack) => [pack.id, Number(itemsByPackId.get(pack.id)?.length || 0)]));
|
|
2628
|
+
const packItemsById = new Map(retainedThemePacks.map((pack) => [pack.id, new Set((itemsByPackId.get(pack.id) || []).map((item) => item.sticker_id).filter(Boolean))]));
|
|
2991
2629
|
const incompleteExistingCount = retainedThemePacks.reduce((sum, pack) => {
|
|
2992
2630
|
const count = Number(packCountById.get(pack.id) || 0);
|
|
2993
2631
|
return sum + (count < TARGET_PACK_SIZE ? 1 : 0);
|
|
@@ -3001,19 +2639,14 @@ const buildCurationExecutionPlan = async ({ curatedGroups, ownerPool, enableAddi
|
|
|
3001
2639
|
return extractVolumeFromPack(left) - extractVolumeFromPack(right);
|
|
3002
2640
|
})
|
|
3003
2641
|
: [];
|
|
3004
|
-
const volumeCandidateChunks = chunkArray(
|
|
3005
|
-
group.candidates.map((candidate) => candidate.asset.id).filter(Boolean),
|
|
3006
|
-
TARGET_PACK_SIZE,
|
|
3007
|
-
);
|
|
2642
|
+
const volumeCandidateChunks = chunkArray(group.candidates.map((candidate) => candidate.asset.id).filter(Boolean), TARGET_PACK_SIZE);
|
|
3008
2643
|
const groupFillAssetIds = group.candidates.map((candidate) => candidate.asset.id).filter(Boolean);
|
|
3009
2644
|
|
|
3010
2645
|
const ownerCreateCapacity = ownerStates.reduce((sum, owner) => sum + Math.max(0, Number(owner.available || 0)), 0);
|
|
3011
2646
|
const hasIncompleteExisting = incompleteExistingCount > 0;
|
|
3012
2647
|
const themeCreateCapacity = Math.max(0, MAX_PACKS_PER_THEME - retainedThemePacks.length);
|
|
3013
2648
|
const globalCreateCapacity = Math.max(0, GLOBAL_AUTO_PACK_LIMIT - (autoPacks.length + plannedCreates));
|
|
3014
|
-
const maxCreatableForGroup = enableAdditions && !hasIncompleteExisting
|
|
3015
|
-
? Math.max(0, Math.min(ownerCreateCapacity, themeCreateCapacity, globalCreateCapacity))
|
|
3016
|
-
: 0;
|
|
2649
|
+
const maxCreatableForGroup = enableAdditions && !hasIncompleteExisting ? Math.max(0, Math.min(ownerCreateCapacity, themeCreateCapacity, globalCreateCapacity)) : 0;
|
|
3017
2650
|
if (enableAdditions && !hasIncompleteExisting && themeCreateCapacity > 0 && globalCreateCapacity <= 0) {
|
|
3018
2651
|
creationBlockedByGlobalCap += 1;
|
|
3019
2652
|
}
|
|
@@ -3035,14 +2668,7 @@ const buildCurationExecutionPlan = async ({ curatedGroups, ownerPool, enableAddi
|
|
|
3035
2668
|
|
|
3036
2669
|
for (let volumeIndex = 0; volumeIndex < targetVolumeCount; volumeIndex += 1) {
|
|
3037
2670
|
const volume = volumeIndex + 1;
|
|
3038
|
-
const existingPack = prioritizeGroupCompletion
|
|
3039
|
-
? completionPriorityPacks[volumeIndex]
|
|
3040
|
-
|| retainedThemePacks.find((pack) => extractVolumeFromPack(pack) === volume)
|
|
3041
|
-
|| retainedThemePacks[volumeIndex]
|
|
3042
|
-
|| null
|
|
3043
|
-
: retainedThemePacks.find((pack) => extractVolumeFromPack(pack) === volume)
|
|
3044
|
-
|| retainedThemePacks[volumeIndex]
|
|
3045
|
-
|| null;
|
|
2671
|
+
const existingPack = prioritizeGroupCompletion ? completionPriorityPacks[volumeIndex] || retainedThemePacks.find((pack) => extractVolumeFromPack(pack) === volume) || retainedThemePacks[volumeIndex] || null : retainedThemePacks.find((pack) => extractVolumeFromPack(pack) === volume) || retainedThemePacks[volumeIndex] || null;
|
|
3046
2672
|
if (existingPack?.id) {
|
|
3047
2673
|
selectedExistingPackIds.add(existingPack.id);
|
|
3048
2674
|
}
|
|
@@ -3078,9 +2704,7 @@ const buildCurationExecutionPlan = async ({ curatedGroups, ownerPool, enableAddi
|
|
|
3078
2704
|
fillAssetIds: groupFillAssetIds,
|
|
3079
2705
|
existingPackId: existingPack?.id || null,
|
|
3080
2706
|
ownerJid: existingPack?.owner_jid || createOwnerJid || null,
|
|
3081
|
-
ownerCandidates: existingPack
|
|
3082
|
-
? [existingPack.owner_jid].filter(Boolean)
|
|
3083
|
-
: [createOwnerJid, ...ownerPool.filter((owner) => owner && owner !== createOwnerJid)].filter(Boolean),
|
|
2707
|
+
ownerCandidates: existingPack ? [existingPack.owner_jid].filter(Boolean) : [createOwnerJid, ...ownerPool.filter((owner) => owner && owner !== createOwnerJid)].filter(Boolean),
|
|
3084
2708
|
});
|
|
3085
2709
|
}
|
|
3086
2710
|
|
|
@@ -3124,9 +2748,7 @@ const buildCurationExecutionPlan = async ({ curatedGroups, ownerPool, enableAddi
|
|
|
3124
2748
|
const recipientPackId = recipientOp.existingPackId;
|
|
3125
2749
|
const recipientCount = Number(packCountById.get(recipientPackId) || 0);
|
|
3126
2750
|
if (recipientCount <= 0) continue;
|
|
3127
|
-
const recipientDesired = new Set(
|
|
3128
|
-
(Array.isArray(recipientOp.desiredAssetIds) ? recipientOp.desiredAssetIds : []).filter(Boolean),
|
|
3129
|
-
);
|
|
2751
|
+
const recipientDesired = new Set((Array.isArray(recipientOp.desiredAssetIds) ? recipientOp.desiredAssetIds : []).filter(Boolean));
|
|
3130
2752
|
if (!recipientDesired.size) continue;
|
|
3131
2753
|
|
|
3132
2754
|
for (const assetId of recipientDesired) {
|
|
@@ -3141,13 +2763,9 @@ const buildCurationExecutionPlan = async ({ curatedGroups, ownerPool, enableAddi
|
|
|
3141
2763
|
const donorItems = packItemsById.get(donorPackId);
|
|
3142
2764
|
if (!donorItems || !donorItems.has(assetId)) continue;
|
|
3143
2765
|
|
|
3144
|
-
donorOp.forceRemoveAssetIds = Array.from(
|
|
3145
|
-
|
|
3146
|
-
);
|
|
3147
|
-
donorOp.desiredAssetIds = (Array.isArray(donorOp.desiredAssetIds) ? donorOp.desiredAssetIds : [])
|
|
3148
|
-
.filter((id) => id !== assetId);
|
|
3149
|
-
donorOp.fillAssetIds = (Array.isArray(donorOp.fillAssetIds) ? donorOp.fillAssetIds : [])
|
|
3150
|
-
.filter((id) => id !== assetId);
|
|
2766
|
+
donorOp.forceRemoveAssetIds = Array.from(new Set([...(Array.isArray(donorOp.forceRemoveAssetIds) ? donorOp.forceRemoveAssetIds : []), assetId]));
|
|
2767
|
+
donorOp.desiredAssetIds = (Array.isArray(donorOp.desiredAssetIds) ? donorOp.desiredAssetIds : []).filter((id) => id !== assetId);
|
|
2768
|
+
donorOp.fillAssetIds = (Array.isArray(donorOp.fillAssetIds) ? donorOp.fillAssetIds : []).filter((id) => id !== assetId);
|
|
3151
2769
|
packCountById.set(donorPackId, Math.max(0, donorCount - 1));
|
|
3152
2770
|
groupTransfers += 1;
|
|
3153
2771
|
break;
|
|
@@ -3195,9 +2813,7 @@ const buildCurationExecutionPlan = async ({ curatedGroups, ownerPool, enableAddi
|
|
|
3195
2813
|
autoPackIndex,
|
|
3196
2814
|
stats: {
|
|
3197
2815
|
owner_pool_size: ownerPool.length,
|
|
3198
|
-
owner_available_total: ownerStates.some((owner) => !Number.isFinite(Number(owner.available)))
|
|
3199
|
-
? 'unlimited'
|
|
3200
|
-
: ownerStates.reduce((sum, owner) => sum + Math.max(0, Number(owner.available || 0)), 0),
|
|
2816
|
+
owner_available_total: ownerStates.some((owner) => !Number.isFinite(Number(owner.available))) ? 'unlimited' : ownerStates.reduce((sum, owner) => sum + Math.max(0, Number(owner.available || 0)), 0),
|
|
3201
2817
|
planned_creates: plannedCreates,
|
|
3202
2818
|
completion_priority_groups: completionPriorityGroups,
|
|
3203
2819
|
completion_transfers_planned: plannedCompletionTransfers,
|
|
@@ -3240,7 +2856,10 @@ const buildCurationExecutionPlan = async ({ curatedGroups, ownerPool, enableAddi
|
|
|
3240
2856
|
};
|
|
3241
2857
|
|
|
3242
2858
|
const updateAutoPackMetadata = async (packId, payload) => {
|
|
3243
|
-
const normalizedPackStatus =
|
|
2859
|
+
const normalizedPackStatus =
|
|
2860
|
+
String(payload?.pack_status || 'building')
|
|
2861
|
+
.trim()
|
|
2862
|
+
.toLowerCase() || 'building';
|
|
3244
2863
|
const resolvedWebStatus = String(payload?.status || (normalizedPackStatus === 'ready' ? 'published' : 'draft'))
|
|
3245
2864
|
.trim()
|
|
3246
2865
|
.toLowerCase();
|
|
@@ -3262,14 +2881,7 @@ const updateAutoPackMetadata = async (packId, payload) => {
|
|
|
3262
2881
|
return updateStickerPackFields(packId, fields);
|
|
3263
2882
|
};
|
|
3264
2883
|
|
|
3265
|
-
const createAutoPackVolume = async ({
|
|
3266
|
-
ownerJid,
|
|
3267
|
-
theme,
|
|
3268
|
-
subtheme,
|
|
3269
|
-
themeKey,
|
|
3270
|
-
groupScore,
|
|
3271
|
-
volume,
|
|
3272
|
-
}) => {
|
|
2884
|
+
const createAutoPackVolume = async ({ ownerJid, theme, subtheme, themeKey, groupScore, volume }) => {
|
|
3273
2885
|
return stickerPackService.createPack({
|
|
3274
2886
|
ownerJid,
|
|
3275
2887
|
name: buildAutoPackName(theme, subtheme, volume),
|
|
@@ -3287,14 +2899,7 @@ const createAutoPackVolume = async ({
|
|
|
3287
2899
|
|
|
3288
2900
|
const getThemeScoreForPack = (classification, theme) => getScoreByTag(classification, theme);
|
|
3289
2901
|
|
|
3290
|
-
const reconcileAutoPackVolume = async ({
|
|
3291
|
-
op,
|
|
3292
|
-
enableAdditions,
|
|
3293
|
-
enableRebuild,
|
|
3294
|
-
budgets,
|
|
3295
|
-
itemsByPackId,
|
|
3296
|
-
classificationByAssetId,
|
|
3297
|
-
}) => {
|
|
2902
|
+
const reconcileAutoPackVolume = async ({ op, enableAdditions, enableRebuild, budgets, itemsByPackId, classificationByAssetId }) => {
|
|
3298
2903
|
let pack = op.existingPackId ? await findStickerPackById(op.existingPackId) : null;
|
|
3299
2904
|
|
|
3300
2905
|
if (!pack && op.type === 'reconcile_volume') {
|
|
@@ -3344,8 +2949,7 @@ const reconcileAutoPackVolume = async ({
|
|
|
3344
2949
|
}
|
|
3345
2950
|
|
|
3346
2951
|
const desiredPrimaryIds = Array.from(new Set((Array.isArray(op.desiredAssetIds) ? op.desiredAssetIds : []).filter(Boolean)));
|
|
3347
|
-
const fillPoolIds = Array.from(new Set((Array.isArray(op.fillAssetIds) ? op.fillAssetIds : []).filter(Boolean)))
|
|
3348
|
-
.filter((assetId) => !desiredPrimaryIds.includes(assetId));
|
|
2952
|
+
const fillPoolIds = Array.from(new Set((Array.isArray(op.fillAssetIds) ? op.fillAssetIds : []).filter(Boolean))).filter((assetId) => !desiredPrimaryIds.includes(assetId));
|
|
3349
2953
|
const plannedIds = desiredPrimaryIds.slice();
|
|
3350
2954
|
if (plannedIds.length < TARGET_PACK_SIZE) {
|
|
3351
2955
|
for (const assetId of fillPoolIds) {
|
|
@@ -3361,7 +2965,9 @@ const reconcileAutoPackVolume = async ({
|
|
|
3361
2965
|
const created = op.existingPackId ? 0 : 1;
|
|
3362
2966
|
const feedbackPromises = [];
|
|
3363
2967
|
const queueFeedback = ({ classification, accepted, assetId }) => {
|
|
3364
|
-
const imageHash = String(classification?.image_hash || '')
|
|
2968
|
+
const imageHash = String(classification?.image_hash || '')
|
|
2969
|
+
.trim()
|
|
2970
|
+
.toLowerCase();
|
|
3365
2971
|
if (!imageHash) return;
|
|
3366
2972
|
feedbackPromises.push(
|
|
3367
2973
|
submitStickerClassificationFeedback({
|
|
@@ -3382,15 +2988,11 @@ const reconcileAutoPackVolume = async ({
|
|
|
3382
2988
|
cover_sticker_id: pack.cover_sticker_id || null,
|
|
3383
2989
|
});
|
|
3384
2990
|
|
|
3385
|
-
let currentItems = itemsByPackId.get(pack.id) || await listStickerPackItems(pack.id);
|
|
2991
|
+
let currentItems = itemsByPackId.get(pack.id) || (await listStickerPackItems(pack.id));
|
|
3386
2992
|
const currentById = new Map(currentItems.map((item) => [item.sticker_id, item]));
|
|
3387
2993
|
const forceRemoveSet = new Set((Array.isArray(op.forceRemoveAssetIds) ? op.forceRemoveAssetIds : []).filter(Boolean));
|
|
3388
2994
|
|
|
3389
|
-
const shouldRebuildVolume =
|
|
3390
|
-
enableRebuild
|
|
3391
|
-
|| op.type === 'archive_volume'
|
|
3392
|
-
|| Number(op.cohesion || 0) < COHESION_REBUILD_THRESHOLD
|
|
3393
|
-
|| forceRemoveSet.size > 0;
|
|
2995
|
+
const shouldRebuildVolume = enableRebuild || op.type === 'archive_volume' || Number(op.cohesion || 0) < COHESION_REBUILD_THRESHOLD || forceRemoveSet.size > 0;
|
|
3394
2996
|
if (shouldRebuildVolume && budgets.removed < MAX_REMOVALS_PER_CYCLE) {
|
|
3395
2997
|
for (const item of currentItems) {
|
|
3396
2998
|
if (budgets.removed >= MAX_REMOVALS_PER_CYCLE) break;
|
|
@@ -3503,14 +3105,8 @@ const reconcileAutoPackVolume = async ({
|
|
|
3503
3105
|
const finalDesiredOrder = plannedIds.filter((assetId) => currentById.has(assetId));
|
|
3504
3106
|
const currentOrder = currentItems.map((item) => item.sticker_id);
|
|
3505
3107
|
const desiredReorderSet = new Set(finalDesiredOrder);
|
|
3506
|
-
const projectedOrder = [
|
|
3507
|
-
|
|
3508
|
-
...currentOrder.filter((assetId) => !desiredReorderSet.has(assetId)),
|
|
3509
|
-
];
|
|
3510
|
-
const needsReorder =
|
|
3511
|
-
projectedOrder.length > 1
|
|
3512
|
-
&& projectedOrder.length === currentOrder.length
|
|
3513
|
-
&& projectedOrder.some((assetId, index) => currentOrder[index] !== assetId);
|
|
3108
|
+
const projectedOrder = [...finalDesiredOrder, ...currentOrder.filter((assetId) => !desiredReorderSet.has(assetId))];
|
|
3109
|
+
const needsReorder = projectedOrder.length > 1 && projectedOrder.length === currentOrder.length && projectedOrder.some((assetId, index) => currentOrder[index] !== assetId);
|
|
3514
3110
|
|
|
3515
3111
|
if (needsReorder) {
|
|
3516
3112
|
try {
|
|
@@ -3532,7 +3128,7 @@ const reconcileAutoPackVolume = async ({
|
|
|
3532
3128
|
}
|
|
3533
3129
|
}
|
|
3534
3130
|
|
|
3535
|
-
const finalItems = itemsByPackId.get(pack.id) || await listStickerPackItems(pack.id);
|
|
3131
|
+
const finalItems = itemsByPackId.get(pack.id) || (await listStickerPackItems(pack.id));
|
|
3536
3132
|
const finalCount = finalItems.length;
|
|
3537
3133
|
const finalCover = finalItems[0]?.sticker_id || null;
|
|
3538
3134
|
const finalDesiredPresentCount = finalItems.filter((item) => desiredSet.has(item.sticker_id)).length;
|
|
@@ -3541,17 +3137,9 @@ const reconcileAutoPackVolume = async ({
|
|
|
3541
3137
|
const allowExtraItemsForReady = !enableRebuild && op.type === 'reconcile_volume';
|
|
3542
3138
|
const meetsHardMinimum = finalCount >= HARD_MIN_PACK_ITEMS;
|
|
3543
3139
|
const meetsReadyMinimum = finalCount >= READY_PACK_MIN_ITEMS;
|
|
3544
|
-
const packStatus =
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
: allDesiredPresent && (allowExtraItemsForReady || !hasExtraItems) && meetsReadyMinimum
|
|
3548
|
-
? 'ready'
|
|
3549
|
-
: meetsHardMinimum
|
|
3550
|
-
? 'building'
|
|
3551
|
-
: 'archived';
|
|
3552
|
-
|
|
3553
|
-
const shouldDeletePack =
|
|
3554
|
-
packStatus === 'archived' && (op.type === 'archive_volume' || finalCount < HARD_MIN_PACK_ITEMS);
|
|
3140
|
+
const packStatus = finalCount === 0 ? 'archived' : allDesiredPresent && (allowExtraItemsForReady || !hasExtraItems) && meetsReadyMinimum ? 'ready' : meetsHardMinimum ? 'building' : 'archived';
|
|
3141
|
+
|
|
3142
|
+
const shouldDeletePack = packStatus === 'archived' && (op.type === 'archive_volume' || finalCount < HARD_MIN_PACK_ITEMS);
|
|
3555
3143
|
if (shouldDeletePack) {
|
|
3556
3144
|
try {
|
|
3557
3145
|
await deleteAutoPackWithItems(pack.id, itemsByPackId);
|
|
@@ -3635,8 +3223,7 @@ const resolveNextCycleDelayMs = () => {
|
|
|
3635
3223
|
return EFFECTIVE_INTERVAL_MIN_MS;
|
|
3636
3224
|
}
|
|
3637
3225
|
|
|
3638
|
-
return EFFECTIVE_INTERVAL_MIN_MS
|
|
3639
|
-
+ Math.floor(Math.random() * (EFFECTIVE_INTERVAL_MAX_MS - EFFECTIVE_INTERVAL_MIN_MS + 1));
|
|
3226
|
+
return EFFECTIVE_INTERVAL_MIN_MS + Math.floor(Math.random() * (EFFECTIVE_INTERVAL_MAX_MS - EFFECTIVE_INTERVAL_MIN_MS + 1));
|
|
3640
3227
|
};
|
|
3641
3228
|
|
|
3642
3229
|
const scheduleNextCycle = () => {
|
|
@@ -3662,10 +3249,7 @@ const scheduleNextCycle = () => {
|
|
|
3662
3249
|
}
|
|
3663
3250
|
};
|
|
3664
3251
|
|
|
3665
|
-
export const runStickerAutoPackByTagsCycle = async ({
|
|
3666
|
-
enableAdditions = true,
|
|
3667
|
-
enableRebuild = REBUILD_ENABLED,
|
|
3668
|
-
} = {}) => {
|
|
3252
|
+
export const runStickerAutoPackByTagsCycle = async ({ enableAdditions = true, enableRebuild = REBUILD_ENABLED } = {}) => {
|
|
3669
3253
|
if (running) {
|
|
3670
3254
|
return {
|
|
3671
3255
|
executed: false,
|
|
@@ -3719,9 +3303,7 @@ export const runStickerAutoPackByTagsCycle = async ({
|
|
|
3719
3303
|
};
|
|
3720
3304
|
const classifiedWithoutPackBefore = await countClassifiedWithoutPackSafely({ phase: 'before_cycle' });
|
|
3721
3305
|
const finalizeCycleResult = async (payload) => {
|
|
3722
|
-
const withoutPackBefore = Number.isFinite(classifiedWithoutPackBefore)
|
|
3723
|
-
? Number(classifiedWithoutPackBefore)
|
|
3724
|
-
: null;
|
|
3306
|
+
const withoutPackBefore = Number.isFinite(classifiedWithoutPackBefore) ? Number(classifiedWithoutPackBefore) : null;
|
|
3725
3307
|
if (!Number.isFinite(withoutPackBefore)) {
|
|
3726
3308
|
return {
|
|
3727
3309
|
...payload,
|
|
@@ -3732,12 +3314,8 @@ export const runStickerAutoPackByTagsCycle = async ({
|
|
|
3732
3314
|
}
|
|
3733
3315
|
|
|
3734
3316
|
const classifiedWithoutPackAfter = await countClassifiedWithoutPackSafely({ phase: 'after_cycle' });
|
|
3735
|
-
const withoutPackAfter = Number.isFinite(classifiedWithoutPackAfter)
|
|
3736
|
-
|
|
3737
|
-
: null;
|
|
3738
|
-
const withoutPackDelta = Number.isFinite(withoutPackAfter)
|
|
3739
|
-
? withoutPackBefore - withoutPackAfter
|
|
3740
|
-
: null;
|
|
3317
|
+
const withoutPackAfter = Number.isFinite(classifiedWithoutPackAfter) ? Number(classifiedWithoutPackAfter) : null;
|
|
3318
|
+
const withoutPackDelta = Number.isFinite(withoutPackAfter) ? withoutPackBefore - withoutPackAfter : null;
|
|
3741
3319
|
|
|
3742
3320
|
return {
|
|
3743
3321
|
...payload,
|
|
@@ -3816,10 +3394,7 @@ export const runStickerAutoPackByTagsCycle = async ({
|
|
|
3816
3394
|
if (result?.status === 'archived') archivedPacks += 1;
|
|
3817
3395
|
}
|
|
3818
3396
|
|
|
3819
|
-
const scanReferenceCount = Math.max(
|
|
3820
|
-
1,
|
|
3821
|
-
Number(stats.assets_unique_scanned || stats.assets_total_seen || stats.assets_scanned || 0),
|
|
3822
|
-
);
|
|
3397
|
+
const scanReferenceCount = Math.max(1, Number(stats.assets_unique_scanned || stats.assets_total_seen || stats.assets_scanned || 0));
|
|
3823
3398
|
const rejectionReferenceCount = Math.max(1, Number(stats.assets_scanned || 0));
|
|
3824
3399
|
const duplicateRate = Number(stats.assets_deduped || 0) / scanReferenceCount;
|
|
3825
3400
|
const rejectedCount = Number(stats.assets_rejected_quality || 0) + Number(stats.assets_rejected_no_theme || 0);
|