fix(#2184): VLM <people>标签解析+扩展外貌属性,修复信任链第4处断链
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 59s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m57s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m25s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m58s
AI Code Review / AI Code Review (pull_request) Successful in 6m59s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 8m52s
CI/CD Pipeline / Validate - Style (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 59s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m57s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m25s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m58s
AI Code Review / AI Code Review (pull_request) Successful in 6m59s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 8m52s
CI/CD Pipeline / Validate - Style (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
问题根因:#2177 XML重构后VLM prompt契约改为顶层<people has_person count gender age_range pose expression/>标签, 人物信息不再是<product portrait_prompt=...>属性。worker的_xml_to_product只读product属性, VLM输出<people has_person="true" ...>被忽略,所有人物判断走默认"无人像", 导致:preheat跳过→现场t2i跳过→真人图直传Seedance→400 portrait_intercept→降级纯t2v(无参考图→人物相似度仅30-40%) 修复: 1. _xml_to_product解析顶层<people>标签,拼装portrait_prompt供信任链使用 2. 扩展VLM <people>标签新增外貌属性:hair/skin_tone/face_shape/outfit(原6属性→10属性) 提供足够细节(60-100字外貌描述)给Seedream t2i生成还原度高的AI人像 3. 同步更新example为新属性格式 4. 兼容旧schema:product属性仍有portrait_prompt时优先使用 5. 无product标签但<people has_person=true>时也构造结果,不丢人物信息
This commit is contained in:
@@ -404,6 +404,50 @@ def _analyze_single_image(
|
||||
product_nodes = [n for n in nodes if n["tag"] == "product"]
|
||||
scene = xp.text_of(raw_text, "scene") or "通用"
|
||||
mood = xp.text_of(raw_text, "mood") or ""
|
||||
# #2184: #2177 XML 重构后人物信息放在顶层 <people has_person count gender age_range pose expression/>,
|
||||
# 不再是 <product> 的 portrait_prompt 属性。需从顶层 people 标签提取并拼装 portrait_prompt。
|
||||
portrait_prompt = "无人像"
|
||||
try:
|
||||
people_node = xp.find_first(raw_text, "people")
|
||||
if people_node:
|
||||
_pa = people_node.get("attrs") or {}
|
||||
_has_person = xp.attr_bool(_pa.get("has_person"), False)
|
||||
if _has_person:
|
||||
_gender = _pa.get("gender", "无法判断") or "无法判断"
|
||||
_age = _pa.get("age_range", "无法判断") or "无法判断"
|
||||
_hair = _pa.get("hair", "无法判断") or "无法判断"
|
||||
_skin = _pa.get("skin_tone", "无法判断") or "无法判断"
|
||||
_face = _pa.get("face_shape", "无法判断") or "无法判断"
|
||||
_outfit = _pa.get("outfit", "无法判断") or "无法判断"
|
||||
_pose = _pa.get("pose", "无法判断") or "无法判断"
|
||||
_expr = _pa.get("expression", "无法判断") or "无法判断"
|
||||
_count = xp.attr_int(_pa.get("count"), 1)
|
||||
_parts = []
|
||||
if _gender != "无法判断":
|
||||
_g = _gender + ("性" if not _gender.endswith("性") else "")
|
||||
_parts.append(_g)
|
||||
if _age != "无法判断":
|
||||
_parts.append(_age)
|
||||
_parts.append("人物")
|
||||
if _hair != "无法判断":
|
||||
_parts.append(_hair)
|
||||
if _skin != "无法判断":
|
||||
_parts.append(f"{_skin}肤色")
|
||||
if _face != "无法判断":
|
||||
_parts.append(f"{_face}脸型")
|
||||
if _outfit != "无法判断":
|
||||
_parts.append(f"身着{_outfit}")
|
||||
if _pose != "无法判断":
|
||||
_parts.append(f"姿态{_pose}")
|
||||
if _expr != "无法判断":
|
||||
_parts.append(f"表情{_expr}")
|
||||
portrait_prompt = ",".join(_parts)
|
||||
logger.info(
|
||||
"[爆款视频] 图片 #%d 解析<people>: count=%d gender=%s age=%s hair=%s skin=%s face=%s outfit=%s pose=%s expr=%s → %s",
|
||||
idx, _count, _gender, _age, _hair, _skin, _face, _outfit, _pose, _expr, portrait_prompt,
|
||||
)
|
||||
except Exception as _pe:
|
||||
logger.warning("[爆款视频] 图片 #%d 解析<people>标签异常: %s,回退无人像", idx, _pe)
|
||||
for p in product_nodes:
|
||||
a = p["attrs"]
|
||||
text_on_pkg = a.get("text_on_package", "")
|
||||
@@ -419,6 +463,10 @@ def _analyze_single_image(
|
||||
appearance = a.get("appearance", "") or "无法判断"
|
||||
packaging = a.get("packaging", "") or "无法判断"
|
||||
summary = a.get("summary", "") or f"{brand} {name}"
|
||||
# 优先取 product 属性上的 portrait_prompt(兼容旧schema),否则用顶层 <people> 解析结果
|
||||
_pp_from_attr = a.get("portrait_prompt", "")
|
||||
if _pp_from_attr and _pp_from_attr != "无人像":
|
||||
portrait_prompt = _pp_from_attr
|
||||
return {
|
||||
"name": name,
|
||||
"brand": brand,
|
||||
@@ -429,10 +477,26 @@ def _analyze_single_image(
|
||||
"key_features": feat_list or [features] if features else ["无法判断"],
|
||||
"scene": scene,
|
||||
"mood": mood,
|
||||
"portrait_prompt": a.get("portrait_prompt", "无人像"),
|
||||
"portrait_prompt": portrait_prompt,
|
||||
"summary": summary,
|
||||
"_source": "xml",
|
||||
}
|
||||
# 没有 product 标签但有 <people has_person="true"> 也要能取到人物描述(兜底)
|
||||
if portrait_prompt != "无人像":
|
||||
return {
|
||||
"name": "未识别",
|
||||
"brand": "无法判断",
|
||||
"category": "无法判断",
|
||||
"appearance": "无法判断",
|
||||
"packaging": "无法判断",
|
||||
"text_on_package": [],
|
||||
"key_features": ["无法判断"],
|
||||
"scene": scene,
|
||||
"mood": mood,
|
||||
"portrait_prompt": portrait_prompt,
|
||||
"summary": "未识别",
|
||||
"_source": "xml_no_product",
|
||||
}
|
||||
return _vision_fallback(idx, "no_product_tag")
|
||||
|
||||
def _normalize(raw, source: str) -> dict:
|
||||
|
||||
@@ -50,7 +50,7 @@ _IMAGE_ANALYSIS_SYSTEM = f"""你是电商商品视觉分析师,负责从商品
|
||||
请严格按下面的标签格式输出,标签名一个都不能改,不要输出任何解释,不要用代码块:
|
||||
<products> 下面每个产品用一个 <product> 标签,属性 name 是产品名、features 是外观特征、position 是 main 或 secondary、image_index 是第几张图(从0开始)。
|
||||
<colors> 下面每个主要颜色用一个 <color> 标签,属性 hex 是色值、name 是颜色名、coverage 是占比小数。
|
||||
<people> 用一个标签,属性 has_person、count、gender、age_range、pose、expression 分别描述人物情况。
|
||||
<people> 用一个标签,属性 has_person、count、gender、age_range、hair(发型发色)、skin_tone(肤色)、face_shape(脸型)、outfit(穿着)、pose(姿态)、expression(表情)分别描述人物外貌。有人物时属性尽量具体(如hair="黑色长直发"、outfit="白色衬衫"),无人像时除has_person=false外其他填"无法判断"。
|
||||
<mood> 标签写画面整体情绪氛围。
|
||||
<visible_text> 下面每处可见文字用一个 <text_item> 标签,属性 text 是文字内容、position 是位置。
|
||||
<scene> 标签写场景描述。
|
||||
@@ -73,7 +73,7 @@ _IMAGE_ANALYSIS_EXAMPLE = """<products>
|
||||
<color hex="#D32F2F" name="红色" coverage="0.4"/>
|
||||
<color hex="#FFFFFF" name="白色" coverage="0.5"/>
|
||||
</colors>
|
||||
<people has_person="false" count="0" gender="无法判断" age_range="无法判断" pose="无法判断" expression="无法判断"/>
|
||||
<people has_person="false" count="0" gender="无法判断" age_range="无法判断" hair="无法判断" skin_tone="无法判断" face_shape="无法判断" outfit="无法判断" pose="无法判断" expression="无法判断"/>
|
||||
<mood>干净、实用</mood>
|
||||
<visible_text>
|
||||
<text_item text="多功能油污净" position="瓶身正面"/>
|
||||
|
||||
Reference in New Issue
Block a user