"""阿里通义(wan* 万相 / qwen* 千问)提示词:国产"主体参考"语义。 生图 API 把参考图当商品锚(subject reference)、prompt 当场景描述, 风格词/文字商品描述不会反噬商品本体,负面清单也可以安全写入 prompt。 豆包(doubao.py)与此语义一致,直接复用本模块装配。 """ from __future__ import annotations from .common import ( STYLE_SETS, TEXT_RENDER, requirements_block, resolve_style, selling_point_lines, ) # ── 公共组件(主体参考语义专用)──────────────────────────────────────────── QUALITY = ( "Shot on Sony A7R V with 85mm lens at f/2.0, ultra-detailed, photorealistic, " "8K commercial image quality, professional retouching." ) PRODUCT_REF_LOCK = ( "CRITICAL: The product must look EXACTLY the same as in the reference image — " "identical silhouette, proportions, colors, print pattern, stitching and every design detail. " "Only the background, camera angle, lighting and styling may change. " "Do not redesign, add or remove any element of the product." ) DEFAULT_NEGATIVE_INTENT = ( "no AI-generated look, no CGI quality, no plastic appearance, no watermark, " "no distorted text, no deformed product, no extra limbs, no blurry areas" ) # ── 各图类型 Prompt ─────────────────────────────────────────────────────── def _prompt_white_bg(ctx: dict, style: dict, lang: str) -> str: return ( f"E-commerce main product image on pure white background (RGB 255,255,255), " f"product \"{ctx['title']}\" centered and filling about 85% of the frame, " f"front view, even shadowless studio lighting with a faint natural contact shadow, " f"{style['tone']}. No text, no props, no background elements. {QUALITY} {PRODUCT_REF_LOCK}" ) def _prompt_key_features(ctx: dict, style: dict, lang: str) -> str: sp = selling_point_lines(ctx, lang) or ctx["title"] return ( f"E-commerce key-features infographic for product \"{ctx['title']}\", square layout: " f"product on the left two-thirds ({style['bg']}), right column lists 3 feature callouts " f"with minimal line icons, thin leader lines pointing to product details. " f"Feature callouts: {sp}. {style['tone']}. {TEXT_RENDER[lang]} {QUALITY} {PRODUCT_REF_LOCK}" ) def _prompt_selling_pt(ctx: dict, style: dict, lang: str) -> str: sp = selling_point_lines(ctx, lang, 1) or ctx["title"] return ( f"Single-selling-point e-commerce poster for product \"{ctx['title']}\": " f"hero product close-up at dynamic angle ({style['bg']}), one large bold headline " f"about \"{sp}\", generous negative space, one small magnified detail circle " f"highlighting material or craft. {style['tone']}. {TEXT_RENDER[lang]} {QUALITY} {PRODUCT_REF_LOCK}" ) def _prompt_material(ctx: dict, style: dict, lang: str) -> str: return ( f"Macro material close-up of product \"{ctx['title']}\": extreme detail shot revealing " f"fabric weave / surface texture / stitching / finish, shallow depth of field, " f"raking light across the surface, {style['tone']}. Small caption label in corner. " f"{TEXT_RENDER[lang]} {QUALITY} {PRODUCT_REF_LOCK}" ) def _prompt_lifestyle(ctx: dict, style: dict, lang: str) -> str: bg = f" ({style['bg']})" if style.get("bg") else "" return ( f"Lifestyle in-context scene for product \"{ctx['title']}\": the product is naturally " f"used / placed in a real environment{bg}, realistic human-scale surroundings, " f"soft daylight, authentic candid mood, product remains the clear visual focus. " f"{style['tone']}. {TEXT_RENDER[lang]} {QUALITY} {PRODUCT_REF_LOCK}" ) def _prompt_multi_scene(ctx: dict, style: dict, lang: str) -> str: sp = selling_point_lines(ctx, lang) return ( f"Triptych multi-scene e-commerce image for product \"{ctx['title']}\": three vertical panels " f"separated by thin gutters, each panel shows the SAME product in a different usage scene " f"(e.g. home interior / outdoor street / office desk), consistent color grading across panels. " f"Panel captions: {sp}. {style['tone']}. {TEXT_RENDER[lang]} {QUALITY} {PRODUCT_REF_LOCK}" ) def _prompt_ecommerce_detail(ctx: dict, style: dict, lang: str) -> str: sp = selling_point_lines(ctx, lang) or ctx["title"] params = ctx["params_line"] return ( f"E-commerce detail-page hero section for product \"{ctx['title']}\", square layout: " f"top half is a hero banner with the product at a 3/4 angle ({style['bg']}); " f"bottom half is a clean spec card listing 3 feature rows with line icons" + (f" (specs: {params})" if params else "") + f" and one highlighted row: {sp}. {style['tone']}. {TEXT_RENDER[lang]} {QUALITY} {PRODUCT_REF_LOCK}" ) def _prompt_size_chart(ctx: dict, style: dict, lang: str) -> str: dims = ctx["params_line"] return ( f"Product size chart infographic for \"{ctx['title']}\": product shown in clean front and side views " f"on light background, with thin measurement annotation lines (arrows) marking length, width and height, " f"measurement values rendered next to each line" + (f" (known specs: {dims})" if dims else "") + f", small caption row, precise technical drawing aesthetic. {style['tone']}. " f"{TEXT_RENDER[lang]} {QUALITY} {PRODUCT_REF_LOCK}" ) def _prompt_sku_collection(ctx: dict, style: dict, lang: str) -> str: return ( f"Colorway collection image for product \"{ctx['title']}\": the SAME product in all its color/variant " f"options arranged in a neat equal grid (2-4 items per row), each colorway with a small label chip below it, " f"consistent lighting and scale across all items, clean e-commerce presentation. " f"{style['tone']}. {TEXT_RENDER[lang]} {QUALITY} {PRODUCT_REF_LOCK}" ) def _prompt_custom(ctx: dict, style: dict, lang: str, extra: dict) -> str: hint = (extra.get("prompt_hint") or "").strip() purpose = extra.get("title") or "" detail = extra.get("detail") or "" bg = f" {style['bg']} as environment." if style.get("bg") else "" composed = ( f"E-commerce marketing image for product \"{ctx['title']}\"" + (f" — {purpose}" if purpose else "") + (f": {detail}" if detail else "") + "." ) if hint: composed += f" Composition: {hint}." return f"{composed}{bg} {style['tone']}. {TEXT_RENDER[lang]} {QUALITY} {PRODUCT_REF_LOCK}" _PROMPT_BUILDERS = { "white_bg": _prompt_white_bg, "key_features": _prompt_key_features, "selling_pt": _prompt_selling_pt, "material": _prompt_material, "lifestyle": _prompt_lifestyle, "multi_scene": _prompt_multi_scene, "ecommerce_detail": _prompt_ecommerce_detail, "size_chart": _prompt_size_chart, "sku_collection": _prompt_sku_collection, } def build_prompt(type_id: str, ctx: dict, style_set: int, lang: str, extra: dict | None = None, style_prompt: str | None = None, requirements: str | None = None) -> str: """构造指定图类型的完整生图 prompt(主体参考语义)。 extra: 方案项信息 {title, detail, prompt_hint}——custom 类型必需, 预设类型也会把 prompt_hint 作为构图补充注入。 style_prompt: 用户改写的风格提示词,覆盖 style_set 内置模板(tone/bg 整体替换)。 requirements: 生图要求(最高优先级,强制约束),置于 prompt 最前面, 声明覆盖一切冲突指令,用户可在此输入强制要求。 """ style = resolve_style(style_set, style_prompt) extra = extra or {} if type_id == "custom": prompt = _prompt_custom(ctx, style, lang, extra) else: builder = _PROMPT_BUILDERS.get(type_id) if builder is None: raise ValueError(f"未知图类型: {type_id}") prompt = builder(ctx, style, lang) hint = (extra.get("prompt_hint") or "").strip() if hint: prompt = prompt.rstrip(".") + f". Additional composition guidance: {hint}." req = requirements_block(requirements) if req: prompt = f"{req} {prompt}" return prompt + ". " + DEFAULT_NEGATIVE_INTENT