返回 Pixelle-Video
history_persistence.py
根目录 / web / utils / history_persistence.py
1 """Persistence helpers for Web-only generation workflows."""
2
3 from __future__ import annotations
4
5 import subprocess
6 from datetime import datetime
7 from pathlib import Path
8 from typing import Any
9
10 from loguru import logger
11
12
13 def _probe_video_duration(video_path: str) -> float:
14 cmd = [
15 "ffprobe",
16 "-v",
17 "error",
18 "-show_entries",
19 "format=duration",
20 "-of",
21 "default=noprint_wrappers=1:nokey=1",
22 video_path,
23 ]
24 try:
25 result = subprocess.run(cmd, capture_output=True, text=True, check=True)
26 return float(result.stdout.strip())
27 except Exception as exc:
28 logger.warning(f"Failed to probe video duration for {video_path}: {exc}")
29 return 0.0
30
31
32 async def save_web_generation_history(
33 pixelle_video: Any,
34 *,
35 task_id: str,
36 video_path: str,
37 pipeline: str,
38 input_params: dict,
39 title: str | None = None,
40 n_frames: int = 1,
41 ) -> None:
42 """Save a minimal history record for workflows implemented directly in Web UI."""
43 if not getattr(pixelle_video, "persistence", None):
44 logger.warning("Pixelle persistence service is not initialized; skipping history save")
45 return
46
47 path = Path(video_path)
48 if not task_id:
49 task_id = path.parent.name
50 if not path.exists():
51 logger.warning(f"Cannot save history; video file does not exist: {video_path}")
52 return
53
54 created_at = datetime.fromtimestamp(path.parent.stat().st_ctime).isoformat()
55 completed_at = datetime.fromtimestamp(path.stat().st_mtime).isoformat()
56 duration = _probe_video_duration(str(path))
57
58 normalized_input = dict(input_params)
59 normalized_input.setdefault("mode", pipeline)
60 normalized_input.setdefault("title", title or pipeline)
61 if title:
62 normalized_input["title"] = title
63
64 metadata = {
65 "task_id": task_id,
66 "created_at": created_at,
67 "completed_at": completed_at,
68 "status": "completed",
69 "input": normalized_input,
70 "result": {
71 "video_path": str(path),
72 "duration": duration,
73 "file_size": path.stat().st_size,
74 "n_frames": n_frames,
75 },
76 "config": {
77 "llm_model": pixelle_video.config.get("llm", {}).get("model", "unknown"),
78 "llm_base_url": pixelle_video.config.get("llm", {}).get("base_url", "unknown"),
79 "source": "web",
80 },
81 }
82
83 await pixelle_video.persistence.save_task_metadata(task_id, metadata)
84 logger.info(f"Saved web workflow history: {task_id}")
85
85 lines PYTHON