baseline: Clover 独立仓库首次基线提交

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

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
yangqianqian
2026-06-16 11:30:22 +08:00
commit 6a2632da70
253 changed files with 27467 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
"""
app/workers/replenish_task.py — 文案后台补充任务S1: 先展示后台补铁律)
合格文案(passed且score>=90且非hard_block)不足用户目标条数时,
run_generation_pipeline 已先展示合格的; 此任务异步补齐到目标数或达上限。
只接收 task_id(基石B)。复用 pipeline_io.run_text_generation 的生成+过滤。
"""
import logging
from app.workers.celery_app import celery_app
logger = logging.getLogger(__name__)
# 补充上限:避免合格率低时无限补。最多补 MAX_REPLENISH_ROUNDS 轮。
MAX_REPLENISH_ROUNDS = 3
@celery_app.task(
bind=True,
name="app.workers.tasks.replenish_text_candidates",
max_retries=2,
default_retry_delay=30,
queue="generation",
)
def replenish_text_candidates(self, task_id: int) -> dict:
"""后台补充合格文案到目标条数(或达补充上限)。
每轮调用 run_text_generation 续生成,过滤后累加入库;
已合格数 >= text_count 即停; 达 MAX_REPLENISH_ROUNDS 仍不足也停(不卡用户)。
"""
from app.workers.tasks import _get_db, _push_event_sync
from app.workers.pipeline_io import run_text_generation
from app.workers.pipeline_steps import (
load_task_and_product,
decrypt_user_key,
build_clients_and_clear_key,
build_product_dict,
load_flywheel_context,
)
from app.models.task import TextCandidate
db = _get_db()
try:
task, product = load_task_and_product(db, task_id)
if not task:
logger.warning("补充任务找不到 task_id=%s", task_id)
return {"task_id": task_id, "replenished": 0, "reason": "task_not_found"}
# 已合格数(按入库的合格候选计)
existing = db.query(TextCandidate).filter(
TextCandidate.task_id == task_id
).count()
target = task.text_count
if existing >= target:
return {"task_id": task_id, "replenished": 0, "reason": "already_enough"}
workspace_id = task.workspace_id
plain_key = decrypt_user_key(db, task.operator_id, workspace_id)
clients = build_clients_and_clear_key(plain_key)
plain_key = None # 用完即清除基石B
product_dict = build_product_dict(product)
flywheel_fragment, _ = load_flywheel_context(
db, workspace_id, task.product_id, product_dict
)
seq = 9000 # 补充事件 seq 段,避开主流程
rounds = 0
# 真实入库合格数以 DB count 为准,绝不用 len(raw)(那是原始生成数含被过滤的低分条)。
# task47 实测踩坑len(raw)=2 但 saved=0(都没过90),误判达标提前停,库里仍缺。
current = existing
while current < target and rounds < MAX_REPLENISH_ROUNDS:
rounds += 1
run_text_generation(
db, clients, task, product_dict, flywheel_fragment,
_push_event_sync, workspace_id, seq,
)
# run_text_generation 内部已把本轮合格候选写库,这里重查真实库内条数
db.expire_all()
current = db.query(TextCandidate).filter(
TextCandidate.task_id == task_id
).count()
seq += 100
logger.info(
"补充轮 %d: task_id=%s 库内合格=%d/%d",
rounds, task_id, current, target,
)
return {
"task_id": task_id,
"replenished": current - existing,
"rounds": rounds,
"final": current,
"target": target,
}
except Exception as exc:
logger.error("replenish_text_candidates failed: task_id=%s err=%s", task_id, exc)
raise self.retry(exc=exc)
finally:
db.close()