From 5482efa045619f6134c9e642434d3885d1934399 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Mon, 5 Oct 2026 00:46:24 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(#2186):=20=E6=99=BA=E8=83=BD=E5=9B=9E?= =?UTF-8?q?=E5=A1=ABportrait=5Fprompt+few-shot=E7=A4=BA=E4=BE=8B,=E6=9C=8D?= =?UTF-8?q?=E8=A3=85=E5=8F=91=E5=9E=8B=E8=BF=98=E5=8E=9F=E5=A2=9E=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #2185后VLM仍省略hair/outfit四属性(只输出6个旧属性,连"无法判断"都不写), worker兜底用通用值导致服装还原失败(翻领衬衫→浅米色针织上衣)。 双层增强: 1. 智能回填(worker): - outfit兜底不再固定"日常服装",从product.name+features中匹配服装关键词 (衬衫/T恤/毛衣/针织/外套/西装/连衣裙/牛仔裤等30+类),提取前后短语作为具体服装描述 - hair兜底不再固定"自然发型",从color标签中识别小面积发色(占比<0.3的黑/棕/金/栗等颜色) 自动填充发色+"头发" - 回填后重新拼装_parts,保证portrait_prompt信息密度 - 回填不覆盖VLM正确输出的值,只补全缺失/通用值 2. few-shot示例(prompt): - image_analysis system prompt新增有人物场景的完整10属性输出示例 - 明确"必须写全10个属性,禁止省略" 预期:原米色翻领衬衫人像→outfit回填为"米色翻领衬衫"、hair从颜色提取"黑色头发" →Seedream t2i还原服装款式→整体人物相似度稳超85%且服装更准 --- apps/worker/worker_app/tasks/viral_video.py | 72 ++++++++++++++++++++- packages/application/viral_video/prompts.py | 5 +- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/apps/worker/worker_app/tasks/viral_video.py b/apps/worker/worker_app/tasks/viral_video.py index 678c3b8d0..2f8f8b82a 100644 --- a/apps/worker/worker_app/tasks/viral_video.py +++ b/apps/worker/worker_app/tasks/viral_video.py @@ -444,6 +444,76 @@ def _analyze_single_image( _parts.append(f"{_skin}肤色") _parts.append(f"{_face}脸型") _parts.append(f"身着{_outfit}") + if _pose != "无法判断": + _parts.append(f"姿态{_pose}") + if _expr != "无法判断": + _parts.append(f"表情{_expr}") + else: + _parts.append("表情自然") + # #2186: 智能回填——VLM有时省略hair/outfit等外貌属性,但product.name/features/colors里已有相关信息 + # 从product名字和features中提取服装关键词回填outfit + if _outfit in ("日常服装", "无法判断"): + for _ppn in product_nodes: + _pn = (_ppn.get("attrs") or {}).get("name", "") or "" + _pf = (_ppn.get("attrs") or {}).get("features", "") or "" + _ptxt = _pn + " " + _pf + # 服装关键词识别(常见上装/下装/裙装/套装) + _cloth_kws = ["衬衫","T恤","毛衣","针织衫","卫衣","外套","西装","夹克","风衣", + "大衣","羽绒服","马甲","背心","连衣裙","半身裙","短裙","长裙", + "牛仔裤","休闲裤","西裤","运动裤","短裤","旗袍","汉服","制服", + "polo衫","POLO衫","针织","毛衫","开衫","帽衫","皮夹克","皮衣"] + for _ckw in _cloth_kws: + if _ckw in _ptxt: + # 提取含关键词的短语(关键词前后4字) + _ci = _ptxt.find(_ckw) + _start = max(0, _ci-6) + _end = min(len(_ptxt), _ci+len(_ckw)+2) + _outfit_extract = _ptxt[_start:_end].strip(" ,,。.、") + # 清理掉品牌名/产品名词的干扰(只取服装描述部分) + _outfit_extract = re.sub(r"^[\w一-龥]{0,2}(牌|品牌|的|款|女|男|新|装|大|小|长|短|厚|薄)", "", _outfit_extract) + if len(_outfit_extract) >= 2: + _outfit = _outfit_extract + break + if _outfit not in ("日常服装", "无法判断"): + break + # 从color标签中提取头发颜色回填hair + if _hair in ("自然发型", "无法判断"): + _hair_color = "" + _color_nodes = [n for n in nodes if n["tag"] == "color"] + _hair_kws_map = {"黑":"黑色","棕":"棕色","金":"金色","栗":"栗色","红":"红色", + "白":"白色","灰":"灰色","蓝":"蓝色","黄":"黄色","紫":"紫色"} + for _cn in _color_nodes: + _cname = (_cn.get("attrs") or {}).get("name","") or "" + # 小占比颜色更可能是发色(非主色的小面积色),且名称含头发/黑/棕/金等 + _ccov = 0.0 + try: + _ccov = float((_cn.get("attrs") or {}).get("coverage","0") or 0) + except Exception: + pass + for _hk, _hv in _hair_kws_map.items(): + if _hk in _cname and _ccov < 0.3: + _hair_color = _hv + break + if _hair_color: + break + if _hair_color: + _hair = f"{_hair_color}头发" + else: + _hair = "自然发型" + # 重新拼装_parts(回填后) + _parts = [] + if _gender != "无法判断": + _g = _gender + ("性" if not _gender.endswith("性") else "") + _parts.append(_g) + else: + _parts.append("成年人") + if _age != "无法判断": + _parts.append(_age) + _parts.append("人物") + _parts.append(_hair) + _parts.append(f"{_skin}肤色") + _parts.append(f"{_face}脸型") + _parts.append(f"身着{_outfit}") if _pose != "无法判断": _parts.append(f"姿态{_pose}") if _expr != "无法判断": @@ -452,7 +522,7 @@ def _analyze_single_image( _parts.append("表情自然") portrait_prompt = ",".join(_parts) logger.info( - "[爆款视频] 图片 #%d 解析: count=%d gender=%s age=%s hair=%s skin=%s face=%s outfit=%s pose=%s expr=%s → %s", + "[爆款视频] 图片 #%d 解析(回填后): count=%d gender=%s age=%s hair=%s skin=%s face=%s outfit=%s pose=%s expr=%s → %s", idx, _count, _gender, diff --git a/packages/application/viral_video/prompts.py b/packages/application/viral_video/prompts.py index 4e41733a9..bf131b1e1 100644 --- a/packages/application/viral_video/prompts.py +++ b/packages/application/viral_video/prompts.py @@ -65,7 +65,10 @@ hair/skin_tone/face_shape/outfit四项绝对禁止填“无法判断”,必须 - outfit:必须描述可见穿着,如“米色翻领衬衫”“白色T恤”“黑色连衣裙” 即使局部被遮挡也要根据可见部分合理推断;确实看不清时按最接近的直观印象描述。 -其他非人物属性看不到或无法判断时填“无法判断”,布尔值填false,不要留空标签。""" +其他非人物属性看不到或无法判断时填“无法判断”,布尔值填false,不要留空标签。 + +【有人物场景输出参考(女性手持商品示例,必须写全10个属性,禁止省略)】 +""" _IMAGE_ANALYSIS_USER = """请分析以下商品图片,共 {image_count} 张。 所属行业:{industry} -- 2.54.0 From b21e8e16590105a4ea7dc8b4e5b4b9489b8ce4e4 Mon Sep 17 00:00:00 2001 From: CI Bot Date: Sun, 4 Oct 2026 16:57:02 +0000 Subject: [PATCH 2/2] style: auto-format with black + isort + ruff + prettier [skip ci-format-check] --- apps/worker/worker_app/tasks/viral_video.py | 67 +++++++++++++++++---- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/apps/worker/worker_app/tasks/viral_video.py b/apps/worker/worker_app/tasks/viral_video.py index 2f8f8b82a..58272d7eb 100644 --- a/apps/worker/worker_app/tasks/viral_video.py +++ b/apps/worker/worker_app/tasks/viral_video.py @@ -458,19 +458,54 @@ def _analyze_single_image( _pf = (_ppn.get("attrs") or {}).get("features", "") or "" _ptxt = _pn + " " + _pf # 服装关键词识别(常见上装/下装/裙装/套装) - _cloth_kws = ["衬衫","T恤","毛衣","针织衫","卫衣","外套","西装","夹克","风衣", - "大衣","羽绒服","马甲","背心","连衣裙","半身裙","短裙","长裙", - "牛仔裤","休闲裤","西裤","运动裤","短裤","旗袍","汉服","制服", - "polo衫","POLO衫","针织","毛衫","开衫","帽衫","皮夹克","皮衣"] + _cloth_kws = [ + "衬衫", + "T恤", + "毛衣", + "针织衫", + "卫衣", + "外套", + "西装", + "夹克", + "风衣", + "大衣", + "羽绒服", + "马甲", + "背心", + "连衣裙", + "半身裙", + "短裙", + "长裙", + "牛仔裤", + "休闲裤", + "西裤", + "运动裤", + "短裤", + "旗袍", + "汉服", + "制服", + "polo衫", + "POLO衫", + "针织", + "毛衫", + "开衫", + "帽衫", + "皮夹克", + "皮衣", + ] for _ckw in _cloth_kws: if _ckw in _ptxt: # 提取含关键词的短语(关键词前后4字) _ci = _ptxt.find(_ckw) - _start = max(0, _ci-6) - _end = min(len(_ptxt), _ci+len(_ckw)+2) + _start = max(0, _ci - 6) + _end = min(len(_ptxt), _ci + len(_ckw) + 2) _outfit_extract = _ptxt[_start:_end].strip(" ,,。.、") # 清理掉品牌名/产品名词的干扰(只取服装描述部分) - _outfit_extract = re.sub(r"^[\w一-龥]{0,2}(牌|品牌|的|款|女|男|新|装|大|小|长|短|厚|薄)", "", _outfit_extract) + _outfit_extract = re.sub( + r"^[\w一-龥]{0,2}(牌|品牌|的|款|女|男|新|装|大|小|长|短|厚|薄)", + "", + _outfit_extract, + ) if len(_outfit_extract) >= 2: _outfit = _outfit_extract break @@ -480,14 +515,24 @@ def _analyze_single_image( if _hair in ("自然发型", "无法判断"): _hair_color = "" _color_nodes = [n for n in nodes if n["tag"] == "color"] - _hair_kws_map = {"黑":"黑色","棕":"棕色","金":"金色","栗":"栗色","红":"红色", - "白":"白色","灰":"灰色","蓝":"蓝色","黄":"黄色","紫":"紫色"} + _hair_kws_map = { + "黑": "黑色", + "棕": "棕色", + "金": "金色", + "栗": "栗色", + "红": "红色", + "白": "白色", + "灰": "灰色", + "蓝": "蓝色", + "黄": "黄色", + "紫": "紫色", + } for _cn in _color_nodes: - _cname = (_cn.get("attrs") or {}).get("name","") or "" + _cname = (_cn.get("attrs") or {}).get("name", "") or "" # 小占比颜色更可能是发色(非主色的小面积色),且名称含头发/黑/棕/金等 _ccov = 0.0 try: - _ccov = float((_cn.get("attrs") or {}).get("coverage","0") or 0) + _ccov = float((_cn.get("attrs") or {}).get("coverage", "0") or 0) except Exception: pass for _hk, _hv in _hair_kws_map.items(): -- 2.54.0