auto-save 2026-05-17 19:32 (~4)

This commit is contained in:
2026-05-17 19:32:19 +08:00
parent a9d5962496
commit 96c998c04d
4 changed files with 244 additions and 130 deletions

View File

@@ -4274,12 +4274,54 @@ PRODUCT_VIEW_LABELS = {
"back_bottom": "背面/底部",
}
PRODUCT_BACKGROUND_VALUES = ["white", "black", "simple", "complex", "unknown"]
PRODUCT_USE_TAG_VALUES = [
"hero_packshot",
"wearing_scale",
"inner_contact",
"side_thickness",
"asymmetry",
"button_detail",
"back_bottom",
"material_texture",
]
def default_product_use_tags(view: str) -> list[str]:
defaults = {
"front": ["hero_packshot", "asymmetry"],
"left_45": ["hero_packshot", "asymmetry", "button_detail"],
"right_45": ["hero_packshot", "asymmetry", "button_detail"],
"side_thickness": ["side_thickness", "wearing_scale"],
"inner_contacts": ["inner_contact", "wearing_scale"],
"back_bottom": ["back_bottom", "material_texture"],
}
return defaults.get(view, ["hero_packshot"])
def normalize_product_use_tags(tags: object, view: str) -> list[str]:
if isinstance(tags, str):
raw_tags = re.split(r"[,/、\s]+", tags)
elif isinstance(tags, list):
raw_tags = [str(x) for x in tags]
else:
raw_tags = []
result = []
for tag in raw_tags + default_product_use_tags(view):
tag = str(tag).strip()
if tag in PRODUCT_USE_TAG_VALUES and tag not in result:
result.append(tag)
return result[:4]
def fallback_product_view(index: int) -> dict:
view = PRODUCT_VIEW_VALUES[min(index, len(PRODUCT_VIEW_VALUES) - 1)]
return {
"view": view,
"background": "unknown",
"use_tags": default_product_use_tags(view),
"note": f"{PRODUCT_VIEW_LABELS.get(view, view)}参考;模型识别不可用时按上传顺序自动标注,请人工只检查备注。",
"risk": "模型识别不可用,按上传顺序兜底",
"confidence": 0.25,
}
@@ -4300,21 +4342,37 @@ def parse_product_view_response(raw: str, index: int) -> dict:
flags=re.I,
)
confidence_match = re.search(r'["\']?confidence["\']?\s*[:]\s*["\']?([0-9.]+)', text, flags=re.I)
background_match = re.search(r'["\']?background["\']?\s*[:]\s*["\']?([a-z0-9_]+)', text, flags=re.I)
tags_match = re.search(r'["\']?use_tags["\']?\s*[:]\s*\[([\s\S]*?)\]', text, flags=re.I)
risk_match = re.search(
r'["\']?risk["\']?\s*[:]\s*["\']?([\s\S]*?)(?:["\']?\s*[,}]\s*$)',
text,
flags=re.I,
)
data = {
"view": view_match.group(1) if view_match else "",
"background": background_match.group(1) if background_match else "unknown",
"use_tags": re.findall(r"[a-z_]+", tags_match.group(1)) if tags_match else [],
"note": note_match.group(1) if note_match else "",
"risk": risk_match.group(1) if risk_match else "",
"confidence": confidence_match.group(1) if confidence_match else 0.45,
}
view = str(data.get("view") or "").strip().strip('"\' ,。')
if view not in PRODUCT_VIEW_VALUES:
return fallback_product_view(index)
background = str(data.get("background") or "unknown").strip().strip('"\' ,。')
if background not in PRODUCT_BACKGROUND_VALUES:
background = "unknown"
use_tags = normalize_product_use_tags(data.get("use_tags"), view)
note = str(data.get("note") or "").strip().strip('"\' ,,。')
note = re.sub(r"\s+", " ", note)[:220] or f"{PRODUCT_VIEW_LABELS.get(view, view)}参考"
risk = str(data.get("risk") or "").strip().strip('"\' ,,。')
risk = re.sub(r"\s+", " ", risk)[:120]
try:
confidence = max(0.0, min(1.0, float(data.get("confidence", 0.5))))
except Exception:
confidence = 0.5
return {"view": view, "note": note, "confidence": confidence}
return {"view": view, "background": background, "use_tags": use_tags, "note": note, "risk": risk, "confidence": confidence}
def analyze_product_view(ref_path: Path, index: int) -> dict:
@@ -4324,10 +4382,13 @@ def analyze_product_view(ref_path: Path, index: int) -> dict:
prompt = (
"You are inspecting a product reference image for a SKG neck-and-shoulder wearable massage device. The background may be white, black, or simple studio color. "
"Classify the camera/view angle into exactly one enum: front, left_45, right_45, side_thickness, inner_contacts, back_bottom. "
"Also write a concise Chinese note for video generation, focused on visible structure, asymmetry, thickness, inner massage contacts, buttons, opening width, and shoulder-neck wearing scale. "
"Classify background into exactly one enum: white, black, simple, complex, unknown. Do not request or perform background conversion. "
"Add use_tags from this enum only: hero_packshot, wearing_scale, inner_contact, side_thickness, asymmetry, button_detail, back_bottom, material_texture. "
"Also write a concise Chinese note for video generation, focused on visible structure, asymmetry, thickness, inner massage contacts, buttons, opening width, shoulder-neck wearing scale, and what this image is best used for in video generation. "
"Write risk in Chinese only if this reference may mislead video generation, such as cropped product, hand blocking, low detail, strong reflection, or background confusion; otherwise use empty string. "
"If uncertain, choose the closest useful view; do not ask the user. "
"Output one-line strict JSON only. Do not use markdown or line breaks. "
"{\"view\":\"front|left_45|right_45|side_thickness|inner_contacts|back_bottom\", \"note\":\"中文备注\", \"confidence\":0.0}."
"{\"view\":\"front|left_45|right_45|side_thickness|inner_contacts|back_bottom\", \"background\":\"white|black|simple|complex|unknown\", \"use_tags\":[\"hero_packshot\"], \"note\":\"中文备注\", \"risk\":\"\", \"confidence\":0.0}."
)
try:
resp = llm().chat.completions.create(
@@ -4364,7 +4425,10 @@ def analyze_product_views(job_id: str, req: AnalyzeProductViewsReq) -> dict:
items.append({
"index": index,
"view": result["view"],
"background": result.get("background", "unknown"),
"use_tags": result.get("use_tags", default_product_use_tags(result["view"])),
"note": result["note"],
"risk": result.get("risk", ""),
"confidence": result["confidence"],
})
used = {item["view"] for item in items}