172 lines
7.5 KiB
Java
172 lines
7.5 KiB
Java
package com.nanri.aiimage.config;
|
||
|
||
import lombok.Data;
|
||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||
|
||
@Data
|
||
@ConfigurationProperties(prefix = "aiimage.similar-asin")
|
||
public class SimilarAsinProperties {
|
||
/**
|
||
* P0-1:单次提交 LLM 批次的 row 数量。
|
||
* 历史值 10,在含 puzzle 多图行的场景下频繁触发 720712008
|
||
* "node executed out of limit: 1000"。降到 3 以避免节点上限被打爆。
|
||
* 出现持续 720712008 时还会被 P1-1 滑窗自适应再降到 1。
|
||
*/
|
||
private int llmBatchSize = 3;
|
||
/**
|
||
* img_switch=false 时单次提交 LLM 的 row 数。
|
||
* 不走图片检测时压力小,恢复到 10 行一批以提高吞吐;开启图片检测时仍使用 llmBatchSize。
|
||
*/
|
||
private int llmTextOnlyBatchSize = 10;
|
||
private long dbTaskTouchIntervalMillis = 120000L;
|
||
private long dbJobTouchIntervalMillis = 60000L;
|
||
private int staleTimeoutMinutes = 30;
|
||
private String staleFinalizeCron = "0 */2 * * * *";
|
||
|
||
/**
|
||
* 末尾零头 batch 的强制 flush 阈值(分钟):当不足 llmBatchSize 的零头 row
|
||
* 长时间挂着(Python 慢回传)时触发提交。
|
||
* 任务级实测:345 行 / 4h 总耗时中,约 2-3 小时是 batch 永远凑不满 batchSize 在等下一波回传,
|
||
* 把阈值从 15 调到 1:最多 60s 后 1-2 行也强制提交,让 LLM 提交侧持续进票,
|
||
* 总耗时降到与 Python 回传节奏接近。
|
||
*/
|
||
private int llmFlushPendingMinutes = 1;
|
||
|
||
/**
|
||
* 图片下载、解码和缩放共享该池;4 核生产机默认 2,避免图片任务占满整机 CPU。
|
||
*/
|
||
private int imageDownloadPoolSize = 2;
|
||
|
||
/**
|
||
* 单张图片下载超时(秒)。
|
||
* P2-10:放宽到 8 + retry=1 在快源(aiproxy/m.media-amazon)下没问题,
|
||
* 但慢源(cbu01.alicdn)会一直挂 8s 才进入 retry,整体串行时间放大。
|
||
* 调到 5s + retry=2,让慢源更早重试新连接,单图最坏耗时 ≈ 5s * (1+2) = 15s。
|
||
*/
|
||
private int imageDownloadTimeoutSeconds = 5;
|
||
|
||
/** 单个结果文件整批图片预取预算,耗尽后缺图单元格降级为 URL。 */
|
||
private int imagePrefetchTimeoutSeconds = 1800;
|
||
|
||
/** 多源结果文件组装的单任务硬上限;运行期间由文件任务 heartbeat 保活。 */
|
||
private int resultFileTimeoutMinutes = 90;
|
||
|
||
/**
|
||
* Assemble each source workbook from chunk-scoped result maps. Keeping a
|
||
* switch makes rollback possible for an existing deployment while the new
|
||
* bounded path is observed in production.
|
||
*/
|
||
private boolean boundedResultAssemblyEnabled = true;
|
||
|
||
/**
|
||
* assemble 阶段 taskImageCache 的字节上限。
|
||
* 默认 256MB:5000 行 × 3 列 × 平均 100KB = 1.5GB 远超 2GB 堆,
|
||
* 用 BoundedImageCache 按字节累计 LRU 淘汰避免爆堆。
|
||
* 由于 embed() 写完即 remove(),活跃图片字节通常 ≤ 100MB,仅在极端 prefetch 领先场景才会触发淘汰。
|
||
* 出现淘汰过频影响命中率时可上调到 512MB;2GB 堆约束下不建议超过 768MB。
|
||
*/
|
||
private long imageCacheMaxBytes = 256L * 1024L * 1024L;
|
||
private String imageLocalCacheDir = "";
|
||
private boolean imageDbCacheEnabled = false;
|
||
|
||
/**
|
||
* 是否启用 merge 增量缓冲:每个 batch DONE 时仅缓冲 llmRows,
|
||
* 不立即合并到 chunk;finalize 前一次性按 chunkScopeHash 分组合并,
|
||
* 把 OSS chunk 读写从 1000+ 次降到 chunk 数量级。
|
||
*/
|
||
private boolean llmResultBufferEnabled = true;
|
||
|
||
/**
|
||
* 解析接口返回的预览行/预览组数量上限。
|
||
* 响应体只携带预览行(默认 100),全量行仅写入后端任务载荷。
|
||
* 有效范围 [1, 1000];0/负值回退默认,超上限 clamp 到 1000。
|
||
*/
|
||
private int parseResponsePreviewLimit = 100;
|
||
|
||
/**
|
||
* Task 7:单个源文件大小上限(字节)。超过则拒绝解析,防止无界文件增长。
|
||
*/
|
||
private long maxSourceFileBytes = 50L * 1024L * 1024L;
|
||
|
||
/**
|
||
* Task 7:单次解析最大有效行数。超过则拒绝解析,防止任务无界增长。
|
||
*/
|
||
private int maxParseRows = 50000;
|
||
|
||
/**
|
||
* Task 7:单字段最大长度(字符)。超过的字段值截断到该上限,防止内存无界增长。
|
||
*/
|
||
private int maxFieldLength = 2000;
|
||
|
||
/**
|
||
* Task 8:xlsx(zip) 最大条目数。受控读取在 WorkBookFactory 打开前探测,
|
||
* 超过则拒绝,防止 zip bomb / 超大工作簿拖垮内存。
|
||
*/
|
||
private int maxWorkbookZipEntries = 20000;
|
||
|
||
/**
|
||
* Task 8:xlsx(zip) 解压后总字节数上限。同样在打开前探测,超过则拒绝。
|
||
*/
|
||
private long maxWorkbookUncompressedBytes = 512L * 1024L * 1024L;
|
||
|
||
/**
|
||
* Task 13:单次 chunk 合并后的最大行数。mergeChunkPayload 合并后总行数超过该上限时,
|
||
* 从最旧行开始降级到 orphan 兜底(assemble 阶段 putIfAbsent 合并回结果),chunk 不无界增长。
|
||
* 默认与 maxParseRows 一致(50000)。
|
||
*/
|
||
private int chunkMergeMaxRows = 50000;
|
||
|
||
/**
|
||
* Task 13:单次 chunk 合并后 payload 的字节上限。合并后序列化字节超过该上限时,
|
||
* 从最旧行开始降级到 orphan 兜底;单行本身超过该上限时抛异常拒绝合并。
|
||
* 默认 16MB:50000 行 × 平均 300B/行 ≈ 15MB,留余量。
|
||
*/
|
||
private long chunkMergePayloadMaxBytes = 16L * 1024L * 1024L;
|
||
|
||
/**
|
||
* Task 15:图片缓存 last_used_at 异步批量刷新的缓冲阈值。
|
||
* lookup 命中先入内存缓冲(按 url_hash 去重),达到该阈值时立即批量 touch;
|
||
* 其余由定时 flush 兜底,把逐图 UPDATE 合并为批量 UPDATE。
|
||
*/
|
||
private int imageCacheTouchFlushThreshold = 1000;
|
||
|
||
/**
|
||
* Task 16:图片预取短预算(秒)。assemble 阶段预取在预算内 best-effort
|
||
* 尽力完成,预算耗尽即取消在途任务并回退 URL,避免整批预取拖垮结果组装。
|
||
* 该值仅作用于 assemble 阶段预取;后台预热仍使用 imagePrefetchTimeoutSeconds。
|
||
*/
|
||
private int imagePrefetchBudgetSeconds = 60;
|
||
|
||
/**
|
||
* 货源查询直连 LLM 模式开关(默认 true:新任务与存量 PENDING 批次都走直连 LLM,
|
||
* 不再经过工作流中转)。
|
||
*/
|
||
private boolean directLlmEnabled = true;
|
||
|
||
/** 直连 LLM 的 base url(OpenAI 兼容 /v1/chat/completions)。 */
|
||
private String llmHost = "https://ai.t8star.org";
|
||
|
||
/** 直连 LLM 的 Bearer token;前端未传 api_key 时兜底使用。 */
|
||
private String llmApiKey = "";
|
||
|
||
/** 类目匹配(一级/二级)使用的小模型。 */
|
||
private String llmCategoryModel = "glm-5.3-flash";
|
||
|
||
/** 合规检查(is_conform/reason/category)使用的小模型。 */
|
||
private String llmConformModel = "glm-5.3-flash";
|
||
|
||
/** 图片相似度对比(主图 vs 拼接图)使用的模型。 */
|
||
private String llmImageCompareModel = "glm-5.3-flash";
|
||
|
||
private int llmMaxTokens = 64000;
|
||
private int llmConnectTimeoutMillis = 10000;
|
||
private int llmReadTimeoutMillis = 180000;
|
||
private int llmRetryTimes = 3;
|
||
|
||
/** 批内行级并发上限:每行最多 2 次图片对比 + 1 次合规 + 3 次类目匹配。 */
|
||
private int llmRowConcurrency = 5;
|
||
|
||
/** 拼接图/主图下载超时(秒),慢源图片较多时放大该值。 */
|
||
private int llmImageDownloadTimeoutSeconds = 10;
|
||
}
|