"""GPT 图像模型(gpt-image-2 / gpt-image-2-vip,RightAPI 中转)提示词。 语义:/v1/images/edits —— 输入图是"被编辑的照片",prompt 是编辑指令; 与通义/豆包的"主体参考"语义完全不同:参考图不是商品锚,模型会按文字指令 重新渲染整张图。此前与国产模型共用场景提示词,再用文字锚定商品并要求输出 "匹配商品描述",导致模型把商品改造成营销关键词描述的样子(必现商品被改)。 本模块写法原则: 1. 商品只由 Image 1 定义;标题/参数仅作识别背景并声明"以图为准", 绝不要求输出匹配文字描述(那等于授权模型改商品); 2. 指令只说"改什么"(背景/场景/排版/文案),不描述商品外观; 3. 分节精简、首尾重申保真;不用负面清单(gpt 无 negative_prompt 参数, 罗列畸形反而往上下文植入概念); 4. sku 合集 / 多拼图明确"复制同一件商品,禁止发明新配色或变体"。 """ from __future__ import annotations from .common import TEXT_RENDER, requirements_block, resolve_style, selling_point_lines # 保真锁:商品由 Image 1 唯一定义,其余指令一律不得触碰商品本体 _PRESERVE = ( "PRESERVE (absolute, overrides every other instruction below): the product shown in Image 1. " "Reuse the photographed product exactly as it is — identical shape, silhouette, proportions, " "colors, print/pattern, logo and label text, materials, stitching and surface details. " "Do not redesign, restyle, recolor, re-pattern, tidy up or substitute the product, " "and do not let any style or text instruction below alter it. Image 2 is a secondary " "view of the same product for reference only." ) _STYLE = ( "SCENE STYLE (applies to background, scene, props and lighting only — never to the product): " ) _QUALITY = ( "OUTPUT: photorealistic commercial e-commerce photography, ultra-detailed, " "natural light and shadow, professional retouching." ) _REMINDER = ( "FINAL CHECK: the product itself must remain exactly as photographed in Image 1 — " "only its surroundings, composition, lighting and overlay graphics may differ." ) # 图内文案:明确是"排版图层",不落在商品本体上 _TEXT_SCOPE = ( "TEXT OVERLAY (a graphic layer on the composition, never printed on the product): " ) def _anchor(ctx: dict) -> str: """商品文字锚定:仅供识别,明确声明以图为准。 只放标题 + 参数、不放营销描述——描述里的卖点词("卡通""加固""防水"等) 在 edits 语义下会被执行到商品上;官逆通道(-vip)参考图被弱化时, 文字锚定用于帮模型认出"是哪件商品",而不是"长什么样"。 """ line = f"CONTEXT (identification only): the product is \"{ctx['title']}\"" if ctx.get("params_line"): line += f" ({ctx['params_line']})" return ( line + ". Image 1 — not this text — defines the product's appearance; " "if they ever conflict, follow Image 1." ) # ── 各图类型的编辑指令(只描述改动,不描述商品)──────────────────────────── def _task_white_bg(ctx: dict, lang: str) -> str: return ( "TASK: Clean up this product photo for a marketplace listing. Replace the entire " "background with seamless pure white (RGB 255,255,255); recompose with the product " "centered in front view filling about 85% of the frame; keep only a faint natural " "contact shadow. No props, no text, no background elements." ) def _task_key_features(ctx: dict, lang: str) -> str: sp = selling_point_lines(ctx, lang) or ctx["title"] return ( "TASK: Feature infographic on a square canvas. Keep the product unchanged on the left " "two-thirds; build the right third as a clean info panel listing 3 feature callouts with " f"minimal line icons and thin leader lines pointing at parts of the product. Callout copy: {sp}." ) def _task_selling_pt(ctx: dict, lang: str) -> str: sp = selling_point_lines(ctx, lang, 1) or ctx["title"] return ( "TASK: Single-selling-point poster. Hero close-up of the unchanged product at a dynamic " f"angle, generous negative space, one large bold headline about \"{sp}\", plus one small " "magnified circle zooming into an existing detail of the product (zoom only — do not " "invent details that are not in the photo)." ) def _task_material(ctx: dict, lang: str) -> str: return ( "TASK: Material close-up. Zoom tightly into an existing area of the product's surface and " "show its true texture — fabric weave, surface finish, stitching — exactly as it appears in " "Image 1; shallow depth of field, raking light across the surface; small caption label in a corner." ) def _task_lifestyle(ctx: dict, lang: str) -> str: return ( "TASK: Lifestyle scene. Place the unchanged product into a realistic everyday environment " "where it would naturally be used: human-scale surroundings, soft daylight, authentic candid " "mood, matched shadows and color temperature, the product remaining the clear visual focus." ) def _task_multi_scene(ctx: dict, lang: str) -> str: sp = selling_point_lines(ctx, lang) task = ( "TASK: Triptych showcase. Build three vertical panels separated by thin gutters; every panel " "contains an IDENTICAL copy of the product from Image 1 (do not re-render it differently per " "panel) placed in a different usage scene (e.g. home interior / outdoor street / office desk), " "with consistent color grading across panels." ) if sp: task += f" Panel captions: {sp}." return task def _task_ecommerce_detail(ctx: dict, lang: str) -> str: sp = selling_point_lines(ctx, lang) or ctx["title"] params = ctx["params_line"] return ( "TASK: Detail-page hero section on a square canvas. Top half: hero banner with the unchanged " "product at a 3/4 angle. Bottom half: clean spec card with 3 feature rows and line icons" + (f" (specs: {params})" if params else "") + f", one highlighted row: {sp}." ) def _task_size_chart(ctx: dict, lang: str) -> str: dims = ctx["params_line"] return ( "TASK: Measurement chart. Show the unchanged product in clean front and side views on a light " "background; overlay thin technical annotation lines (arrows) marking length, width and height " "with measurement values rendered beside each line" + (f" (known specs: {dims})" if dims else "") + "; precise technical-drawing aesthetic, small caption row." ) def _task_sku_collection(ctx: dict, lang: str) -> str: # 关键差异:不允许像国产模型那样展开"全部配色"——edits 语义下那会凭空造出新商品 return ( "TASK: Product lineup. Arrange several IDENTICAL copies of the product from Image 1 in a neat " "equal grid (2-4 per row) with a small label chip below each copy; identical lighting and scale " "across copies. Every copy must show this exact product — do NOT invent other colorways, " "variants or versions." ) _TASK_BUILDERS = { "white_bg": (_task_white_bg, False), "key_features": (_task_key_features, True), "selling_pt": (_task_selling_pt, True), "material": (_task_material, True), "lifestyle": (_task_lifestyle, True), "multi_scene": (_task_multi_scene, True), "ecommerce_detail": (_task_ecommerce_detail, True), "size_chart": (_task_size_chart, True), "sku_collection": (_task_sku_collection, True), } 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: """构造指定图类型的 edits 语义 prompt:要求块 → 编辑指令 → 保真锁 → 锚定 → 风格 → 文案 → 画质 → 终检。""" style = resolve_style(style_set, style_prompt) extra = extra or {} hint = (extra.get("prompt_hint") or "").strip() if type_id == "custom": purpose = extra.get("title") or "" detail = extra.get("detail") or "" task = "TASK: Create an e-commerce marketing image featuring the product from Image 1" task += f" — {purpose}" if purpose else "" task += f": {detail}" if detail else "" task += "." wants_text = True else: entry = _TASK_BUILDERS.get(type_id) if entry is None: raise ValueError(f"未知图类型: {type_id}") builder, wants_text = entry task = builder(ctx, lang) if hint: task += f" Composition guidance: {hint}." parts = [p for p in (requirements_block(requirements),) if p] parts.append(task) parts.append(_PRESERVE) parts.append(_anchor(ctx)) parts.append(f"{_STYLE}{style['tone']}.") if wants_text: parts.append(f"{_TEXT_SCOPE}{TEXT_RENDER[lang]}") parts.append(_QUALITY) parts.append(_REMINDER) return "\n\n".join(parts)