- pipeline_io.py/replenish_task.py 注释写90与代码实际80打架,统一为80(红线) - 核销表纠正:文案先展示后台补=真做了/合格线80/M1本体已做 - M6标杆M7裂变改'草案先提炼再请北哥'(不干等),过滤策略条作废
101 lines
3.8 KiB
Python
101 lines
3.8 KiB
Python
"""
|
||
app/workers/replenish_task.py — 文案后台补充任务(S1: 先展示后台补铁律)
|
||
|
||
合格文案(passed且score>=QUALITY_PASS_SCORE(80,红线)且非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()
|