Files
beige/backend/app/services/ai_engine/prompt_composer.py
yangqianqian 6a2632da70 baseline: Clover 独立仓库首次基线提交
将 Clover 从上层产品包旧仓库中独立出来,建立专属版本控制。
当前状态=纵切片端到端已打通(登录→选品→出文出图→审核→下载包),
M1文案质量去套路化已验收。此提交作为后续按核销清单逐条修复的基线。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 11:30:22 +08:00

110 lines
4.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
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 — 产品档案 dictname/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)