A8多套打包+M4归档+R5多图:存量功能备份
A8 多套交付包(packaging_task.py): - 修复交付包只打第1条混乱note的bug,按ImageCandidate.strategy分A/B/C组 - 每组生独立note_0N夹(6图+文案.txt),同seq留最新去重,老数据兼容 - task74端到端验:3套各6图,独立agent7项交叉验证全过 M4 归档(tasks.py/exports.py/前端): - list_tasks加date_from/date_to/product_id筛选+product_name批量填(防N+1) - 新增exports.py:产品JSON导出+标杆CSV导出(UTF-8 BOM) - 前端HistoryFilters日期/产品筛选+产品列+打回原因红banner - response.py加raise_param_error;独立agent验A1/A2/A9通过 R5 产品多图(product_images.py/020迁移/前端): - product_images表+5端点(上传/列/改场景/设主图/删图) - 生图按ROLE_SCENE_PREFERENCE选对应场景图,回落primary - 前端ProductImageManager多图画廊 R6 账号config拆页(settings/): - 配置页按角色拆/settings(运营+组长+admin)+/config(仅admin) - Key只显末4位不显余额(守红线) 核销表对齐真实代码状态:D1改稿框/M7裂变/E12评图分纠偏为已完成(曾漏回写) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -58,6 +58,7 @@ def build_clients_and_clear_key(plain_key: str):
|
||||
def build_product_dict(product) -> dict:
|
||||
"""把 ORM product 转成 AI 引擎所需的 dict(不含任何 key)。"""
|
||||
return {
|
||||
"id": product.id,
|
||||
"name": product.name,
|
||||
"category": product.category or "通用好物",
|
||||
"selling_points": json.loads(product.selling_points or "[]"),
|
||||
@@ -66,10 +67,52 @@ def build_product_dict(product) -> dict:
|
||||
"custom_prompt": product.custom_prompt or "",
|
||||
"brand_keyword": product.brand_keyword or "", # S3: 品牌词透传进生成prompt(每条植入)
|
||||
"target_audience": product.target_audience or "", # 012: 人群透传进storyboard/文案prompt
|
||||
"image_path": product.image_path or "", # 产品参考图路径(前端上传后填入)
|
||||
"image_path": product.image_path or "", # 产品参考图路径(主图,向后兼容)
|
||||
# R5多图:每张产品图 {path, scene},生图按分镜role选对应场景图
|
||||
"images": [
|
||||
{"path": im.path, "scene": im.scene}
|
||||
for im in (getattr(product, "images", None) or [])
|
||||
],
|
||||
# 第2环标杆配方,默认空;走 AI 主链时由 load_benchmark_features 覆盖填充
|
||||
"benchmark_refs": [],
|
||||
}
|
||||
|
||||
|
||||
def load_benchmark_features(db, task, workspace_id: int) -> list[dict]:
|
||||
"""
|
||||
第2环→第5环接线:读 task.benchmark_ids → 查 analyze_status=done 的标杆 features_json。
|
||||
返回 8维配方 dict 列表(供 build_prompt 借方法层结构,禁抄竞品品牌/功效原话)。
|
||||
未选/未分析完/解析失败都安全返空,绝不阻断生成。
|
||||
"""
|
||||
from app.models.product import BenchmarkNote
|
||||
|
||||
raw_ids = getattr(task, "benchmark_ids", None)
|
||||
if not raw_ids:
|
||||
return []
|
||||
try:
|
||||
ids = [int(i) for i in json.loads(raw_ids)]
|
||||
except Exception:
|
||||
return []
|
||||
if not ids:
|
||||
return []
|
||||
|
||||
rows = db.query(BenchmarkNote).filter(
|
||||
BenchmarkNote.id.in_(ids),
|
||||
BenchmarkNote.workspace_id == workspace_id,
|
||||
BenchmarkNote.analyze_status == "done",
|
||||
).all()
|
||||
|
||||
feats: list[dict] = []
|
||||
for b in rows:
|
||||
if not b.features_json:
|
||||
continue
|
||||
try:
|
||||
feats.append(json.loads(b.features_json))
|
||||
except Exception:
|
||||
logger.warning("标杆 features_json 解析失败 id=%s", b.id)
|
||||
return feats
|
||||
|
||||
|
||||
def load_flywheel_context(db, workspace_id: int, product_id: int, product_dict: dict) -> tuple[str, dict]:
|
||||
"""
|
||||
查最近50条飞轮事件,聚合偏好上下文。
|
||||
|
||||
Reference in New Issue
Block a user