fix(ai-outfit): 货号(B列)改为可选,空货号不再跳过整行 (§19.14)
用户表的「商品id(货号)」整列为空时,行有效性判定(标题+货号+图三者非空) 把每一行都判为不完整 → read_all_rows 与 load_outfit_tasks 都返回 0:预览下拉 只剩占位符,且「开始生成」也判定无待处理行。货号不进提示词、目录行输出名沿用 源图名,对该用法是多余约束。 - excel_service.py: read_all_rows / load_outfit_tasks 完整性判定改为只要求 标题 + 衣服图路径 非空,货号可空(状态过滤不变) - core/ai_outfit.py: 单文件行货号为空时输出名回退 Path(garment).stem (货号非空仍用 货号.jpg);目录行不变 - ai_outfit_panel.py: 样本下拉标签货号为空显示「(无货号)」 - tests: 空货号行被 read_all_rows/load_outfit_tasks 收录、单文件空货号按源图名命名 - docs/11 §4(表+规则)/§9(命名回退)、tasks.md §19.14 离屏冒烟:标题填/货号空/C=目录 → 预览下拉有行、生成产出到子目录、E=完成; 全套测试在 Python 3.7 全绿(test_config_service 的失败属并行的出厂模板工作,与本次无关)。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -687,8 +687,9 @@ class AiOutfitPanel(QWidget):
|
||||
self._sample_combo.clear()
|
||||
if tasks:
|
||||
for t in tasks:
|
||||
pid = t.product_id if (t.product_id and t.product_id.strip()) else "(无货号)"
|
||||
self._sample_combo.addItem(
|
||||
"第 {} 行 · {} · {}".format(t.row_index, t.product_id, t.title), t)
|
||||
"第 {} 行 · {} · {}".format(t.row_index, pid, t.title), t)
|
||||
else:
|
||||
self._sample_combo.addItem("(选 Excel 后显示替换效果)", None)
|
||||
self._sample_combo.blockSignals(False)
|
||||
|
||||
@@ -167,7 +167,10 @@ def generate_outfit_image(
|
||||
prompt = render_prompt(prompt_template, task, resolution=resolution)
|
||||
client = api_client or ImageApiClient(model_config)
|
||||
image_bytes = client.generate(prompt, task.garment_path, resolution=resolution)
|
||||
output_path = make_outfit_output_path(output_dir, task.product_id)
|
||||
# 货号可空:为空时输出名回退用源图名(docs/11 §9)。
|
||||
name = task.product_id if (task.product_id and str(task.product_id).strip()) \
|
||||
else Path(task.garment_path).stem
|
||||
output_path = make_outfit_output_path(output_dir, name)
|
||||
save_jpg_under_limit(image_bytes, output_path, quality=quality)
|
||||
logger.info("Generated outfit row %s -> %s", task.row_index, output_path)
|
||||
return OutfitResult(
|
||||
|
||||
@@ -72,8 +72,9 @@ def load_outfit_tasks(excel_path, retry_failed=False):
|
||||
A title, B product id, C garment path, D output path, E status, F error.
|
||||
|
||||
Rows start at 2. Completed rows are always skipped. Failed rows are included
|
||||
only when *retry_failed* is True. Rows missing title/product/path are skipped
|
||||
silently and are not written back.
|
||||
only when *retry_failed* is True. Row validity needs only 标题 + 衣服图路径;
|
||||
货号 (B) is optional (docs/11 §4). Rows missing title/path are skipped silently
|
||||
and are not written back.
|
||||
"""
|
||||
path = Path(excel_path)
|
||||
workbook = load_workbook(str(path))
|
||||
@@ -86,7 +87,8 @@ def load_outfit_tasks(excel_path, retry_failed=False):
|
||||
product_id = sheet.cell(row_index, COL_PRODUCT_ID).value
|
||||
garment_path = sheet.cell(row_index, COL_GARMENT_PATH).value
|
||||
|
||||
if _is_empty(title) or _is_empty(product_id) or _is_empty(garment_path):
|
||||
# 货号(B)可空:只要求 标题 + 衣服图路径 非空(docs/11 §4)。
|
||||
if _is_empty(title) or _is_empty(garment_path):
|
||||
logger.debug("Skipped incomplete outfit row %s in %s", row_index, path)
|
||||
continue
|
||||
|
||||
@@ -117,9 +119,9 @@ def read_all_rows(excel_path):
|
||||
"""Return an OutfitTask for every valid data row, ignoring E-column status.
|
||||
|
||||
Unlike load_outfit_tasks (which filters for *processable* rows), this returns
|
||||
all rows whose title/product/garment are filled — including 「完成」/「失败」 —
|
||||
for preview/sample purposes only (docs/11 §10.3). Rows missing any of those
|
||||
fields are skipped.
|
||||
all rows whose 标题 + 衣服图路径 are filled — including 「完成」/「失败」, and
|
||||
regardless of 货号 (which is optional, docs/11 §4) — for preview/sample purposes
|
||||
only (docs/11 §10.3). Rows missing title/garment are skipped.
|
||||
"""
|
||||
path = Path(excel_path)
|
||||
workbook = load_workbook(str(path))
|
||||
@@ -130,7 +132,7 @@ def read_all_rows(excel_path):
|
||||
title = sheet.cell(row_index, COL_TITLE).value
|
||||
product_id = sheet.cell(row_index, COL_PRODUCT_ID).value
|
||||
garment_path = sheet.cell(row_index, COL_GARMENT_PATH).value
|
||||
if _is_empty(title) or _is_empty(product_id) or _is_empty(garment_path):
|
||||
if _is_empty(title) or _is_empty(garment_path): # 货号可空
|
||||
continue
|
||||
raw_status = sheet.cell(row_index, COL_STATUS).value
|
||||
rows.append(
|
||||
|
||||
Reference in New Issue
Block a user