Files
meijiaka-zy/python-api/app/scheduler/handlers/script_handler.py
T

142 lines
5.1 KiB
Python

"""
Script 任务处理器
================
管理脚本生成的执行。
不占用 Kling/Volc 槽位,使用独立的 script 槽位池。
"""
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
from app.services.script_service import ScriptService
logger = logging.getLogger(__name__)
SLOT_KEY = "script:slots"
MAX_SLOTS = 10
class ScriptHandler(AsyncHandler):
name = "script"
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:
acquired = await slots.acquire(SLOT_KEY, job.job_id, MAX_SLOTS)
if not acquired:
continue
try:
changes.extend(await self._process_job(job, registry, slots))
except Exception as e:
logger.exception(f"[Script {job.job_id}] failed")
changes.append(StateChange(job_id=job.job_id, field_path="status", value="failed"))
changes.append(
StateChange(job_id=job.job_id, field_path="error", value=str(e)[:500])
)
finally:
await slots.release(SLOT_KEY, job.job_id)
return changes
async def _process_job(
self, job: Any, registry: JobRegistry, slots: SlotManager
) -> list[StateChange]:
changes: list[StateChange] = []
params = job.params or {}
topic = params.get("topic", "")
style = params.get("style", "default")
duration = params.get("duration", 60)
await registry.update(
job.job_id,
status="running",
progress=10,
message="分析需求中...",
completed=0,
total=1,
)
try:
await __import__("asyncio").sleep(2)
anytocopy = get_anytocopy_service()
extract_result = await anytocopy.extract_text_from_input(topic)
extracted_info = None
actual_topic = topic
is_video_url = extract_result.get("is_video_url", False)
if is_video_url:
await registry.update(
job.job_id,
progress=30,
message="提取视频素材中...",
)
video_info = extract_result.get("video_info")
if video_info:
extracted_info = {
"title": video_info.title,
"content": video_info.content,
"text_content": video_info.text_content,
"platform": video_info.platform,
"duration": video_info.duration,
"original_url": topic,
}
actual_topic = extract_result.get("extracted_text") or topic
await registry.update(
job.job_id,
progress=60,
message="生成脚本中...",
)
else:
await registry.update(
job.job_id,
progress=40,
message="构思脚本中...",
)
service = ScriptService()
shots = await service.generate_script(
topic=actual_topic, script_type=style, duration=duration
)
# 计算分镜真实总时长
total_duration = sum(s.duration for s in shots if s.duration)
result_data = {
"title": actual_topic[:50],
"scenes": [s.model_dump() for s in shots],
"total_duration": total_duration,
"style": style,
"shot_count": len(shots),
"extracted_info": extracted_info,
}
changes.append(StateChange(job_id=job.job_id, field_path="status", value="completed"))
changes.append(StateChange(job_id=job.job_id, field_path="progress", value=100))
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))
except Exception as exc:
logger.exception(f"[ScriptTask {job.job_id}] Failed")
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(exc)[:200])
)
changes.append(StateChange(job_id=job.job_id, field_path="error", value=str(exc)[:500]))
return changes