实测发现 codeproxy 偶发不稳,单套中某张图重试3次仍失败会记 error。
本次加按需补图:只重生标 error 的分镜,成功的图与 token 不浪费。
- 019迁移+模型:fission_tasks 加 source_task_id(新架构不扇出GenerationTask,
补图需复刻首轮上下文:产品/operator key/张数,故落库回查)
- fission_image_retry:只补失败 role(引擎 target_role 单张重生,R2零改动),
merge 回 images_json,全恢复则 status=image_done
- tasks.py:retry_fission_images Celery task,key归属源任务operator(基石B),
幂等锁防重复补图
- api:POST /fission/{id}/notes/{seq}/retry-images,无失败分镜守卫 queued=false
- 前端:FissionNoteCard 失败提示改"重试补图"按钮+loading,父页轮询刷新
实测task5 seq1(hook图首轮codeproxy重试3次失败)补图跑通:只补hook(1024×1536
去AI化)、applied_proof原图不动、recovered=1 still_failed=0、status=image_done;
apiports503回落codeproxy gpt-5.5强档兜底;seq0无失败图守卫queued=false
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
108 lines
4.0 KiB
Python
108 lines
4.0 KiB
Python
"""
|
||
app/models/fission.py — fission_tasks
|
||
Alembic 010 第11环裂变引擎(1爆款→N套完整笔记包)
|
||
|
||
reference_level: low/mid/high(参考程度)
|
||
status: pending/generating/done/failed
|
||
"""
|
||
|
||
from datetime import datetime
|
||
|
||
from sqlalchemy import (
|
||
BigInteger, DateTime, ForeignKey,
|
||
Index, Integer, String, Text, func,
|
||
)
|
||
from sqlalchemy.orm import Mapped, mapped_column
|
||
|
||
from app.core.database import Base
|
||
|
||
|
||
class FissionTask(Base):
|
||
"""裂变任务:1爆款→N套完整笔记包(第11环),在工作台内呈现。"""
|
||
__tablename__ = "fission_tasks"
|
||
|
||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||
workspace_id: Mapped[int] = mapped_column(
|
||
BigInteger, ForeignKey("workspaces.id", ondelete="CASCADE"), nullable=False
|
||
)
|
||
# 爆款源笔记内容(文案+图描述),JSON存储
|
||
source_note: Mapped[str | None] = mapped_column(
|
||
Text, comment="爆款源笔记内容(文案+图描述,JSON存储)"
|
||
)
|
||
# 源生成任务ID:补图/重生需复刻首轮上下文(产品+operator key+张数)时回查
|
||
source_task_id: Mapped[int | None] = mapped_column(
|
||
BigInteger, nullable=True, comment="源 GenerationTask id(补图复刻上下文用)"
|
||
)
|
||
# 参考程度:low/mid/high
|
||
reference_level: Mapped[str] = mapped_column(
|
||
String(10), default="mid", nullable=False,
|
||
comment="参考程度: low/mid/high"
|
||
)
|
||
# 裂变套数(默认3套)
|
||
fanout_count: Mapped[int] = mapped_column(
|
||
Integer, default=3, nullable=False,
|
||
comment="裂变套数(默认3套)"
|
||
)
|
||
# 状态机
|
||
status: Mapped[str] = mapped_column(
|
||
String(20), default="pending", nullable=False,
|
||
comment="状态: pending/generating/done/failed"
|
||
)
|
||
created_at: Mapped[datetime] = mapped_column(
|
||
DateTime, server_default=func.now(), nullable=False
|
||
)
|
||
|
||
__table_args__ = (
|
||
Index("idx_fission_tasks_workspace_id", "workspace_id"),
|
||
)
|
||
|
||
|
||
class FissionNote(Base):
|
||
"""裂变产出的单套完整笔记包(一次LLM出N套,每套落一行)。
|
||
|
||
对齐上线版 split.js handleContentSplit:每套含 标题/正文/标签/封面/imagePlan,
|
||
带评分+裂变维度+生图结果。北哥在独立展示页查看。
|
||
"""
|
||
__tablename__ = "fission_notes"
|
||
|
||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||
fission_id: Mapped[int] = mapped_column(
|
||
BigInteger, ForeignKey("fission_tasks.id", ondelete="CASCADE"), nullable=False
|
||
)
|
||
workspace_id: Mapped[int] = mapped_column(
|
||
BigInteger, ForeignKey("workspaces.id", ondelete="CASCADE"), nullable=False
|
||
)
|
||
seq: Mapped[int] = mapped_column(
|
||
Integer, default=0, nullable=False, comment="第几套(0起)"
|
||
)
|
||
# 完整笔记包 JSON:title/content/tags/coverTitle/imagePlan/dimension/audience/scene/painPoint/keywords
|
||
note_json: Mapped[str | None] = mapped_column(
|
||
Text, comment="完整笔记包JSON"
|
||
)
|
||
# 生图结果 JSON:[{role,name,image_url,error}...]
|
||
images_json: Mapped[str | None] = mapped_column(
|
||
Text, comment="生图结果JSON"
|
||
)
|
||
score: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
||
passed: Mapped[bool] = mapped_column(
|
||
Integer, default=0, nullable=False, comment="是否过线(>=80)"
|
||
)
|
||
needs_optimization: Mapped[bool] = mapped_column(
|
||
Integer, default=0, nullable=False, comment="不达标降级草稿标记"
|
||
)
|
||
dimension: Mapped[str | None] = mapped_column(
|
||
String(64), comment="裂变维度: 换角度/换痛点/换人群"
|
||
)
|
||
status: Mapped[str] = mapped_column(
|
||
String(20), default="pending", nullable=False,
|
||
comment="状态: pending/scored/image_done/failed"
|
||
)
|
||
created_at: Mapped[datetime] = mapped_column(
|
||
DateTime, server_default=func.now(), nullable=False
|
||
)
|
||
|
||
__table_args__ = (
|
||
Index("idx_fission_notes_fission_id", "fission_id"),
|
||
Index("idx_fission_notes_workspace_id", "workspace_id"),
|
||
)
|