将 Clover 从上层产品包旧仓库中独立出来,建立专属版本控制。 当前状态=纵切片端到端已打通(登录→选品→出文出图→审核→下载包), M1文案质量去套路化已验收。此提交作为后续按核销清单逐条修复的基线。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
110 lines
4.1 KiB
Python
110 lines
4.1 KiB
Python
"""
|
||
prompt_composer.py — 统一 prompt 组装入口(≤100行)
|
||
扒自:banana prompts/service.py + worker/src/copy.js prompt 逻辑
|
||
Lead 指名接口:compose_variants / compose_preference_context
|
||
|
||
组装逻辑委托:
|
||
_text_prompt.py → build_prompt (文案 prompt 主体)
|
||
preference_aggregator.py → aggregate_preference_context (飞轮上下文)
|
||
|
||
原则:prompt 组装从这里进,不散落在 text_variants / generate_text_variants 里。
|
||
"""
|
||
from __future__ import annotations
|
||
import logging
|
||
from typing import Any
|
||
|
||
from ._text_prompt import build_prompt, COPY_SYSTEM
|
||
from .preference_aggregator import aggregate_preference_context
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
# ── 主接口 ────────────────────────────────────────────────────────────────────
|
||
|
||
def compose_variants(
|
||
product: dict,
|
||
count: int,
|
||
flywheel_context: str = "",
|
||
extra_rules: str = "",
|
||
) -> tuple[str, str]:
|
||
"""
|
||
一次出 count 角度文案的完整 prompt。
|
||
|
||
返回 (system_prompt, user_prompt)。
|
||
飞轮片段追加到 user_prompt 末尾(不改 system,避免覆盖质量红线)。
|
||
|
||
参数:
|
||
product — 产品档案 dict(name/selling_points/text_angles/custom_prompt 等)
|
||
count — 需要几条
|
||
flywheel_context— 由 compose_preference_context 返回的 prompt_fragment
|
||
extra_rules — 额外规则(优化循环重生成时传 hint)
|
||
"""
|
||
combined_extra = "\n".join(filter(None, [flywheel_context, extra_rules]))
|
||
user_prompt = build_prompt(product, count, extra_rules=combined_extra)
|
||
logger.debug(
|
||
"compose_variants: product=%s count=%d flywheel_len=%d",
|
||
product.get("name", "?"), count, len(flywheel_context),
|
||
)
|
||
return COPY_SYSTEM, user_prompt
|
||
|
||
|
||
def compose_preference_context(
|
||
events: list[dict],
|
||
product: dict,
|
||
workspace_id: int,
|
||
product_id: int,
|
||
) -> dict:
|
||
"""
|
||
聚合偏好事件 → 可注入 prompt 的飞轮上下文。
|
||
|
||
返回结构(对齐 API契约 GET /tasks/{id}/preference/context):
|
||
{
|
||
recent_preference: str, # 人类可读摘要(前端"本次已注入"显示)
|
||
reject_reasons: list, # 最近打回原因
|
||
injected_count: int, # 有效信号数
|
||
prompt_fragment: str, # 注入 compose_variants flywheel_context 的字符串
|
||
}
|
||
|
||
信号不足 FLYWHEEL_COLD_START 条时用产品档案冷启动。
|
||
按 workspace_id + product_id 双维过滤(素颜霜偏好不串精华)。
|
||
"""
|
||
return aggregate_preference_context(events, product, workspace_id, product_id)
|
||
|
||
|
||
# ── 辅助:解析模型返回的 JSON(给 text_variants 调用,集中不散) ──────────────
|
||
|
||
def parse_model_output(raw: str) -> list[dict]:
|
||
"""从 LLM 原始输出提取 JSON 数组(容错 markdown 包裹)"""
|
||
from ._text_prompt import parse_json_array
|
||
return parse_json_array(raw)
|
||
|
||
|
||
# ── 辅助:图片 prompt 组装入口(预留,联调时填充)─────────────────────────────
|
||
|
||
def compose_image_prompt(
|
||
role_name: str,
|
||
visual_system: dict,
|
||
product: dict,
|
||
extra: str = "",
|
||
) -> str:
|
||
"""
|
||
单张分镜 prompt 组装(供 image_gen.generate_one_image 调用)。
|
||
TODO: 联调后从 storyboard.plan_image_set 取 base_prompt 注入。
|
||
|
||
role_name — 分镜角色(hook / pain_scene / closer 等)
|
||
visual_system— build_visual_system 返回的视觉系统 dict
|
||
extra — 追加约束(飞轮图片偏好片段,二期接入)
|
||
"""
|
||
name = product.get("name", "产品")
|
||
style = visual_system.get("style", "")
|
||
palette = visual_system.get("color_palette", "")
|
||
base = visual_system.get("base_prompt", "")
|
||
lines = [
|
||
f"[{role_name}] 为产品「{name}」生成种草图。",
|
||
base and f"视觉基调:{base}",
|
||
style and f"摄影风格:{style}",
|
||
palette and f"色调:{palette}",
|
||
extra,
|
||
]
|
||
return "\n".join(l for l in lines if l)
|