Files
beige/backend/app/models/fission.py
yangqianqian 285791c12f 裂变补图:中转站波动导致单张失败时只重生失败分镜
实测发现 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>
2026-06-18 11:30:41 +08:00

108 lines
4.0 KiB
Python
Raw Permalink 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.
"""
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起"
)
# 完整笔记包 JSONtitle/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"),
)