Files
yingqing/core/backend/tryon_underwear_test.py
zyc de4b20cc7b 模特上身图提示词重构 + 图片创作页 UI 调整
后端(模特上身图提示词):
- build_model_tryon_prompt_refs 重写:穿戴/非穿戴分流(穿戴=真实穿身替换原衣,
  非穿戴=手持/佩戴/使用不动原衣)、每张按 index 变化动作/场景/镜头、负面词尾接、
  多图参考序号自适应(参考图1~N=商品,参考图N+1=模特)
- 新增 _product_reference_urls:商品参考图真实上传图优先、排除 AI 生成图、可多张(≤3),
  无真实图回落 cover
- worker run_standalone_image_task 模特分支改用多图取图 + 传 index/n_product

前端(图片创作/工作室):
- 生成数量改 1/2/4;图片比例新增「手动输入」(宽:高 两输入框)
- 临时隐藏「商品库」按钮
- 模特卡:去掉 // 真人模特,标题改图片底部白字遮罩层 + 单行省略
- 工作室壳负边距对齐 .content padding,修复上下被遮挡/裁切

其他:并入此前未提交的商品页改动、脚本 Agent/格式实测文档与 demo
2026-06-27 09:31:44 +08:00

87 lines
4.2 KiB
Python

"""内衣品类(文胸)测试:对比两条路线能不能出图。
路线A · 真人上身(穿戴类) —— 验证 gpt-image-2 内容审核会不会拦(safety=[sexual])
路线B · 隐形人台/平铺(无真人) —— 验证绕开审核的安全做法
跑法: .venv/bin/python tryon_underwear_test.py
产物: /Users/maidong/Desktop/zyc/underwear_test
"""
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "airshelf.settings.development")
django.setup()
from apps.products.models import Product # noqa: E402
from apps.assets.models import Asset # noqa: E402
from apps.ai.models import ModelConfig # noqa: E402
from apps.ai.services import ( # noqa: E402
get_default_model, get_image_provider, _asset_preview_url, _ratio_to_image_size,
)
from apps.ai.providers.volcano import VolcanoArkProvider # noqa: E402
PRODUCT_ID = "42078cdc-8714-4fc7-be5c-6aa42b7fc995" # 棉居莫代尔无痕内衣(真实主图)
MODEL_ID = "ad362810-cf3e-49c0-9426-8142a74b75b2" # 一位真人模特
RATIO = "3:4"
OUT_DIR = "/Users/maidong/Desktop/zyc/underwear_test"
# 路线A · 真人上身(穿戴类从句)
PROMPT_ON_BODY = (
"参考图1是「{name}」的真实商品图,是商品外观的唯一依据。参考图2是出镜模特。"
"请生成参考图2中这位模特真实穿着参考图1中这件内衣的电商详情页效果图,得体、健康、非裸露,"
"覆盖充分,运动内衣风格,商品的颜色、版型、领口、肩带、纹样、Logo 必须与参考图1严格一致。"
"模特五官/发型/肤色/身形与参考图2一致,不要换人。真实电商摄影,自然光,干净背景,单人,{ratio} 构图。"
" 请规避:不要裸露,不要性暗示,不要换人,不要改商品设计与颜色,不要乱码文字,不要水印。"
)
# 路线B · 隐形人台 / 平铺(无真人,绕开审核)
PROMPT_GHOST = (
"参考图1是「{name}」的真实商品图。请生成该内衣的电商主图:采用隐形人台(ghost mannequin)立体悬浮效果,"
"衣服呈现被穿着时的自然立体版型与轮廓,但画面中没有真人、没有人体、不出现任何皮肤或身体部位。"
"商品的颜色、版型、肩带、领口、纹理、Logo 必须与参考图1严格一致,不要重新设计。"
"柔和自然光,干净纯净背景,商品居中,细节清晰,高分辨率,{ratio} 构图。"
" 请规避:不要出现人、不要皮肤、不要模特、不要改商品颜色与版型、不要乱码文字、不要水印。"
)
def run(provider, model_name, label, prompt, images, size):
print(f"\n━━━ {label} ━━━\n{prompt}\n图数={len(images)}")
try:
resp = provider.image_edit(model=model_name, prompt=prompt, images=images, size=size)
media = provider.extract_first_media_url(resp)
fileobj, ct = VolcanoArkProvider.media_to_bytes(media)
ext = ".jpg" if "jpeg" in ct else (".webp" if "webp" in ct else ".png")
path = os.path.join(OUT_DIR, f"{label}{ext}")
with open(path, "wb") as f:
f.write(fileobj.getvalue())
print(f"✅ 出图成功 → {path}")
except Exception as exc: # noqa: BLE001
msg = str(exc)
flagged = any(k in msg.lower() for k in ("moderation", "safety", "sexual", "blocked", "content_policy", "rejected"))
print(f"❌ 失败{' · 命中内容审核' if flagged else ''}: {msg[:600]}")
def main():
os.makedirs(OUT_DIR, exist_ok=True)
p = Product.objects.get(id=PRODUCT_ID)
product_url = _asset_preview_url(p.cover_asset)
model_url = _asset_preview_url(Asset.objects.get(id=MODEL_ID))
mc = get_default_model(ModelConfig.Capability.IMAGE)
provider = get_image_provider(mc)
size = _ratio_to_image_size(RATIO)
print(f"商品: {p.title} | 类目: {p.category}")
print(f"模型: {mc.provider.name}:{mc.name}")
print(f"商品图: {product_url[:80]}")
# 路线A:真人上身(商品图 + 模特图)
run(provider, mc.name, "A_真人上身", PROMPT_ON_BODY.format(name=p.title, ratio=RATIO),
[product_url, model_url], size)
# 路线B:隐形人台(仅商品图)
run(provider, mc.name, "B_隐形人台", PROMPT_GHOST.format(name=p.title, ratio=RATIO),
[product_url], size)
print(f"\n完成。产物: {OUT_DIR}")
if __name__ == "__main__":
main()