Phase6/7 runtime + Gitea smoke gate setup #1
@@ -1392,9 +1392,11 @@ async def api_aurora_compare(job_id: str) -> Dict[str, Any]:
|
||||
"download_url": (result_file or {}).get("url"),
|
||||
}
|
||||
|
||||
output_media_path: Optional[Path] = None
|
||||
if result_file and output_dir:
|
||||
out_path = Path(output_dir) / result_file["name"]
|
||||
if out_path.exists():
|
||||
output_media_path = out_path
|
||||
after["file_size_mb"] = round(out_path.stat().st_size / (1024 * 1024), 2)
|
||||
_probe = _ffprobe_quick(out_path)
|
||||
if _probe:
|
||||
@@ -1419,6 +1421,14 @@ async def api_aurora_compare(job_id: str) -> Dict[str, Any]:
|
||||
"time_ms": step.get("time_ms"),
|
||||
})
|
||||
|
||||
frame_preview = _aurora_ensure_compare_frame_preview(
|
||||
job_id=job_id,
|
||||
media_type=str(status.get("media_type") or ""),
|
||||
input_path=Path(input_path) if input_path else None,
|
||||
output_path=output_media_path,
|
||||
output_dir=Path(output_dir) if output_dir else None,
|
||||
)
|
||||
|
||||
return {
|
||||
"job_id": job_id,
|
||||
"status": status.get("status"),
|
||||
@@ -1429,11 +1439,97 @@ async def api_aurora_compare(job_id: str) -> Dict[str, Any]:
|
||||
"after": after,
|
||||
"faces_detected": faces_total,
|
||||
"enhance_steps": enhance_steps,
|
||||
"frame_preview": frame_preview,
|
||||
"folder_path": output_dir,
|
||||
"input_path": input_path,
|
||||
}
|
||||
|
||||
|
||||
def _aurora_extract_frame_preview(source: Path, target: Path, *, second: float = 1.0) -> bool:
|
||||
"""Write a JPEG preview frame for image/video sources."""
|
||||
if not source.exists():
|
||||
return False
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
ext = source.suffix.lower()
|
||||
if ext in {".jpg", ".jpeg", ".png", ".webp", ".bmp", ".tif", ".tiff"}:
|
||||
try:
|
||||
target.write_bytes(source.read_bytes())
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
ffmpeg = [
|
||||
"ffmpeg",
|
||||
"-hide_banner",
|
||||
"-loglevel",
|
||||
"error",
|
||||
"-y",
|
||||
"-ss",
|
||||
f"{max(0.0, float(second)):.3f}",
|
||||
"-i",
|
||||
str(source),
|
||||
"-frames:v",
|
||||
"1",
|
||||
"-q:v",
|
||||
"2",
|
||||
str(target),
|
||||
]
|
||||
try:
|
||||
run = subprocess.run(ffmpeg, capture_output=True, text=True, timeout=20)
|
||||
if run.returncode == 0 and target.exists() and target.stat().st_size > 0:
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Fallback for short videos / odd timestamps.
|
||||
ffmpeg_fallback = ffmpeg[:]
|
||||
ffmpeg_fallback[6] = "0.0"
|
||||
try:
|
||||
run = subprocess.run(ffmpeg_fallback, capture_output=True, text=True, timeout=20)
|
||||
return run.returncode == 0 and target.exists() and target.stat().st_size > 0
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def _aurora_ensure_compare_frame_preview(
|
||||
*,
|
||||
job_id: str,
|
||||
media_type: str,
|
||||
input_path: Optional[Path],
|
||||
output_path: Optional[Path],
|
||||
output_dir: Optional[Path],
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
if not output_dir or not output_dir.exists():
|
||||
return None
|
||||
if not input_path or not input_path.exists():
|
||||
return None
|
||||
if not output_path or not output_path.exists():
|
||||
return None
|
||||
|
||||
before_name = "_compare_before.jpg"
|
||||
after_name = "_compare_after.jpg"
|
||||
before_path = output_dir / before_name
|
||||
after_path = output_dir / after_name
|
||||
ts = 1.0 if media_type == "video" else 0.0
|
||||
|
||||
if not before_path.exists() or before_path.stat().st_size == 0:
|
||||
_aurora_extract_frame_preview(input_path, before_path, second=ts)
|
||||
if not after_path.exists() or after_path.stat().st_size == 0:
|
||||
_aurora_extract_frame_preview(output_path, after_path, second=ts)
|
||||
|
||||
if not before_path.exists() or not after_path.exists():
|
||||
return None
|
||||
if before_path.stat().st_size <= 0 or after_path.stat().st_size <= 0:
|
||||
return None
|
||||
|
||||
quoted_job = quote(job_id, safe="")
|
||||
return {
|
||||
"timestamp_sec": ts,
|
||||
"before_url": f"/api/aurora/files/{quoted_job}/{quote(before_name, safe='')}",
|
||||
"after_url": f"/api/aurora/files/{quoted_job}/{quote(after_name, safe='')}",
|
||||
}
|
||||
|
||||
|
||||
def _ffprobe_quick(filepath: Path) -> Dict[str, Any]:
|
||||
"""Quick ffprobe for resolution, codec, duration, fps, frame count."""
|
||||
if not filepath.exists():
|
||||
|
||||
8467
services/sofiia-console/static/index.html
Normal file
8467
services/sofiia-console/static/index.html
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user