""" Copy 任务处理器 ============== 管理 AnyToCopy 文案提取的提交与轮询。 """ import logging from typing import Any from app.scheduler.handlers.base import AsyncHandler from app.scheduler.models import StateChange from app.scheduler.registry import JobRegistry from app.scheduler.slot_manager import SlotManager from app.services.anytocopy_service import get_anytocopy_service logger = logging.getLogger(__name__) SLOT_KEY = "anytocopy:slots" MAX_SLOTS = 5 class CopyHandler(AsyncHandler): name = "copy" slot_key = SLOT_KEY max_slots = MAX_SLOTS async def tick( self, jobs: list[Any], registry: JobRegistry, slots: SlotManager ) -> list[StateChange]: changes: list[StateChange] = [] for job in jobs: params = job.params or {} anytocopy_task_id = params.get("anytocopy_task_id") video_url = params.get("url", params.get("video_url", "")) if anytocopy_task_id: try: service = get_anytocopy_service() result = await service.query_task(anytocopy_task_id) if result.get("code") != 200: continue data = result.get("data", {}) status = data.get("status") if status == "SUCCESS": result_data = { "video_url": video_url, "title": data.get("title", ""), "content": data.get("content", ""), "text_content": data.get("textContent", ""), "platform": data.get("platform", ""), "duration": data.get("duration", 0), } await slots.release(SLOT_KEY, job.job_id) changes.append( StateChange(job_id=job.job_id, field_path="status", value="completed") ) changes.append( StateChange( job_id=job.job_id, field_path="message", value="文案提取完成" ) ) changes.append( StateChange(job_id=job.job_id, field_path="completed", value=1) ) changes.append(StateChange(job_id=job.job_id, field_path="total", value=1)) changes.append( StateChange(job_id=job.job_id, field_path="result", value=result_data) ) elif status in ("FAILED", "FAILURE"): await slots.release(SLOT_KEY, job.job_id) changes.append( StateChange(job_id=job.job_id, field_path="status", value="failed") ) changes.append( StateChange( job_id=job.job_id, field_path="message", value=f"提取失败: {data.get('errorMessage', '未知错误')}", ) ) changes.append( StateChange( job_id=job.job_id, field_path="error", value=data.get("errorMessage", ""), ) ) except Exception as e: logger.error(f"[Copy {job.job_id}] poll error: {e}") continue acquired = await slots.acquire(SLOT_KEY, job.job_id, MAX_SLOTS) if not acquired: continue try: service = get_anytocopy_service() submit_result = await service.submit_task(video_url) if submit_result.get("code") != 200: raise Exception(f"提交失败: {submit_result.get('msg')}") anytocopy_task_id = submit_result["data"] params["anytocopy_task_id"] = anytocopy_task_id changes.append(StateChange(job_id=job.job_id, field_path="params", value=params)) changes.append( StateChange(job_id=job.job_id, field_path="message", value="文案提取任务已提交") ) except Exception as e: await slots.release(SLOT_KEY, job.job_id) changes.append(StateChange(job_id=job.job_id, field_path="status", value="failed")) changes.append( StateChange(job_id=job.job_id, field_path="message", value=str(e)[:200]) ) changes.append( StateChange(job_id=job.job_id, field_path="error", value=str(e)[:500]) ) return changes