Files
microdao-daarion/services/aurora-service/app/analysis.py
Apple 129e4ea1fc feat(platform): add new services, tools, tests and crews modules
New router intelligence modules (26 files): alert_ingest/store, audit_store,
architecture_pressure, backlog_generator/store, cost_analyzer, data_governance,
dependency_scanner, drift_analyzer, incident_* (5 files), llm_enrichment,
platform_priority_digest, provider_budget, release_check_runner, risk_* (6 files),
signature_state_store, sofiia_auto_router, tool_governance

New services:
- sofiia-console: Dockerfile, adapters/, monitor/nodes/ops/voice modules, launchd, react static
- memory-service: integration_endpoints, integrations, voice_endpoints, static UI
- aurora-service: full app suite (analysis, job_store, orchestrator, reporting, schemas, subagents)
- sofiia-supervisor: new supervisor service
- aistalk-bridge-lite: Telegram bridge lite
- calendar-service: CalDAV calendar service with reminders
- mlx-stt-service / mlx-tts-service: Apple Silicon speech services
- binance-bot-monitor: market monitor service
- node-worker: STT/TTS memory providers

New tools (9): agent_email, browser_tool, contract_tool, observability_tool,
oncall_tool, pr_reviewer_tool, repo_tool, safe_code_executor, secure_vault

New crews: agromatrix_crew (10 modules: depth_classifier, doc_facts, doc_focus,
farm_state, light_reply, llm_factory, memory_manager, proactivity, reflection_engine,
session_context, style_adapter, telemetry)

Tests: 85+ test files for all new modules
Made-with: Cursor
2026-03-03 07:14:14 -08:00

418 lines
13 KiB
Python

from __future__ import annotations
import json
import math
import statistics
import subprocess
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
try:
import cv2 # type: ignore[import-untyped]
except Exception: # pragma: no cover
cv2 = None
def _safe_float(value: Any, default: float = 0.0) -> float:
try:
return float(value)
except Exception:
return default
def _safe_int(value: Any, default: int = 0) -> int:
try:
return int(float(value))
except Exception:
return default
def _iso_clamp(v: int, lo: int, hi: int) -> int:
return max(lo, min(hi, v))
def _detect_faces(gray_img) -> List[Dict[str, Any]]:
if cv2 is None:
return []
cascade_path = str(Path(cv2.data.haarcascades) / "haarcascade_frontalface_default.xml")
detector = cv2.CascadeClassifier(cascade_path)
if detector.empty():
return []
faces = detector.detectMultiScale(
gray_img,
scaleFactor=1.1,
minNeighbors=4,
minSize=(20, 20),
)
out: List[Dict[str, Any]] = []
for (x, y, w, h) in faces:
out.append(
{
"bbox": [int(x), int(y), int(w), int(h)],
"confidence": 0.75,
}
)
return out
def _detect_plates(gray_img) -> List[Dict[str, Any]]:
if cv2 is None:
return []
cascade_path = str(Path(cv2.data.haarcascades) / "haarcascade_russian_plate_number.xml")
if not Path(cascade_path).exists():
return []
detector = cv2.CascadeClassifier(cascade_path)
if detector.empty():
return []
plates = detector.detectMultiScale(
gray_img,
scaleFactor=1.1,
minNeighbors=3,
minSize=(28, 10),
)
out: List[Dict[str, Any]] = []
for (x, y, w, h) in plates:
out.append(
{
"bbox": [int(x), int(y), int(w), int(h)],
"confidence": 0.65,
"text": None,
}
)
return out
def _noise_label(noise_sigma: float) -> str:
if noise_sigma >= 28:
return "high"
if noise_sigma >= 14:
return "medium"
return "low"
def _brightness_label(brightness: float) -> str:
if brightness < 75:
return "low"
if brightness > 180:
return "high"
return "medium"
def _blur_label(laplacian_var: float) -> str:
if laplacian_var < 45:
return "high"
if laplacian_var < 120:
return "medium"
return "low"
def _analyze_quality(gray_img) -> Dict[str, Any]:
if cv2 is None:
return {
"noise_level": "unknown",
"brightness": "unknown",
"blur_level": "unknown",
"brightness_value": None,
"noise_sigma": None,
"laplacian_var": None,
}
brightness = float(gray_img.mean())
noise_sigma = float(gray_img.std())
lap_var = float(cv2.Laplacian(gray_img, cv2.CV_64F).var())
return {
"noise_level": _noise_label(noise_sigma),
"brightness": _brightness_label(brightness),
"blur_level": _blur_label(lap_var),
"brightness_value": round(brightness, 2),
"noise_sigma": round(noise_sigma, 2),
"laplacian_var": round(lap_var, 2),
}
def _aggregate_quality(samples: List[Dict[str, Any]]) -> Dict[str, Any]:
if not samples:
return {
"noise_level": "unknown",
"brightness": "unknown",
"blur_level": "unknown",
"brightness_value": None,
"noise_sigma": None,
"laplacian_var": None,
}
brightness_values = [float(s["brightness_value"]) for s in samples if s.get("brightness_value") is not None]
noise_values = [float(s["noise_sigma"]) for s in samples if s.get("noise_sigma") is not None]
lap_values = [float(s["laplacian_var"]) for s in samples if s.get("laplacian_var") is not None]
brightness = statistics.mean(brightness_values) if brightness_values else 0.0
noise_sigma = statistics.mean(noise_values) if noise_values else 0.0
lap_var = statistics.mean(lap_values) if lap_values else 0.0
return {
"noise_level": _noise_label(noise_sigma),
"brightness": _brightness_label(brightness),
"blur_level": _blur_label(lap_var),
"brightness_value": round(brightness, 2),
"noise_sigma": round(noise_sigma, 2),
"laplacian_var": round(lap_var, 2),
}
def probe_video_metadata(path: Path) -> Dict[str, Any]:
cmd = [
"ffprobe",
"-v",
"error",
"-select_streams",
"v:0",
"-show_entries",
"stream=width,height,nb_frames,r_frame_rate,duration",
"-show_entries",
"format=duration",
"-of",
"json",
str(path),
]
try:
p = subprocess.run(cmd, check=False, capture_output=True, text=True)
if p.returncode != 0 or not p.stdout:
return {}
payload = json.loads(p.stdout)
except Exception:
return {}
stream = (payload.get("streams") or [{}])[0] if isinstance(payload, dict) else {}
fmt = payload.get("format") or {}
width = _safe_int(stream.get("width"))
height = _safe_int(stream.get("height"))
nb_frames = _safe_int(stream.get("nb_frames"))
fps_raw = str(stream.get("r_frame_rate") or "0/1")
duration = _safe_float(stream.get("duration")) or _safe_float(fmt.get("duration"))
fps = 0.0
if "/" in fps_raw:
num_s, den_s = fps_raw.split("/", 1)
num = _safe_float(num_s)
den = _safe_float(den_s, 1.0)
if den > 0:
fps = num / den
elif fps_raw:
fps = _safe_float(fps_raw)
if nb_frames <= 0 and duration > 0 and fps > 0:
nb_frames = int(duration * fps)
return {
"width": width,
"height": height,
"fps": round(fps, 3) if fps > 0 else None,
"frame_count": nb_frames if nb_frames > 0 else None,
"duration_seconds": round(duration, 3) if duration > 0 else None,
}
def estimate_processing_seconds(
*,
media_type: str,
mode: str,
width: int = 0,
height: int = 0,
frame_count: int = 0,
) -> Optional[int]:
if media_type == "video":
if frame_count <= 0:
return None
megapixels = max(0.15, (max(1, width) * max(1, height)) / 1_000_000.0)
per_frame = 0.8 * megapixels if mode == "tactical" else 1.35 * megapixels
per_frame = max(0.08, min(9.0, per_frame))
overhead = 6 if mode == "tactical" else 12
return int(math.ceil(frame_count * per_frame + overhead))
if media_type == "photo":
megapixels = max(0.15, (max(1, width) * max(1, height)) / 1_000_000.0)
base = 3.0 if mode == "tactical" else 6.0
return int(math.ceil(base + megapixels * (3.0 if mode == "tactical" else 5.0)))
return None
def _recommendations(
*,
faces_count: int,
plates_count: int,
quality: Dict[str, Any],
media_type: str,
) -> Tuple[List[str], str]:
recs: List[str] = []
noise_level = quality.get("noise_level")
brightness = quality.get("brightness")
blur_level = quality.get("blur_level")
if noise_level == "high":
recs.append("Enable denoise (FastDVDnet/SCUNet) before enhancement.")
if brightness == "low":
recs.append("Apply low-light normalization before super-resolution.")
if blur_level in {"medium", "high"}:
recs.append("Enable sharpening after upscaling to recover edges.")
if faces_count > 0:
recs.append("Run face restoration (GFPGAN) as priority stage.")
if plates_count > 0:
recs.append("Run license-plate ROI enhancement with focused sharpening.")
if not recs:
recs.append("Balanced enhancement pipeline is sufficient for this media.")
if faces_count > 0 and faces_count >= plates_count:
priority = "faces"
elif plates_count > 0:
priority = "plates"
elif media_type == "photo":
priority = "details"
else:
priority = "balanced"
return recs, priority
def _suggested_export(media_type: str, quality: Dict[str, Any], width: int, height: int) -> Dict[str, Any]:
if media_type == "video":
if width >= 3840 or height >= 2160:
resolution = "original"
elif width >= 1920 or height >= 1080:
resolution = "4k"
else:
resolution = "1080p"
codec = "mp4_h264" if quality.get("noise_level") != "high" else "mp4_h265"
return {
"resolution": resolution,
"format": codec,
"roi": "auto_faces",
}
return {
"resolution": "original",
"format": "png",
"roi": "full_frame",
}
def analyze_photo(path: Path) -> Dict[str, Any]:
if cv2 is None:
raise RuntimeError("opencv-python-headless is not installed")
frame = cv2.imread(str(path), cv2.IMREAD_COLOR)
if frame is None:
raise RuntimeError("Cannot decode uploaded image")
h, w = frame.shape[:2]
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = _detect_faces(gray)
plates = _detect_plates(gray)
quality = _analyze_quality(gray)
recs, priority = _recommendations(
faces_count=len(faces),
plates_count=len(plates),
quality=quality,
media_type="photo",
)
return {
"media_type": "photo",
"frame_sampled": 1,
"resolution": {"width": w, "height": h},
"faces": faces,
"license_plates": plates,
"quality_analysis": quality,
"recommendations": recs,
"suggested_priority": priority,
"suggested_export": _suggested_export("photo", quality, w, h),
"estimated_processing_seconds": estimate_processing_seconds(
media_type="photo",
mode="tactical",
width=w,
height=h,
frame_count=1,
),
}
def _sample_video_frames(path: Path, max_samples: int = 24) -> Tuple[List[Tuple[int, Any]], Dict[str, Any]]:
if cv2 is None:
raise RuntimeError("opencv-python-headless is not installed")
cap = cv2.VideoCapture(str(path))
if not cap.isOpened():
raise RuntimeError("Cannot open uploaded video")
frame_count = _safe_int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
fps = _safe_float(cap.get(cv2.CAP_PROP_FPS))
width = _safe_int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = _safe_int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
indices: List[int] = []
if frame_count > 0:
sample_count = min(max_samples, frame_count)
if sample_count <= 1:
indices = [0]
else:
indices = sorted({int(i * (frame_count - 1) / (sample_count - 1)) for i in range(sample_count)})
else:
indices = list(range(max_samples))
sampled: List[Tuple[int, Any]] = []
for idx in indices:
if frame_count > 0:
cap.set(cv2.CAP_PROP_POS_FRAMES, idx)
ok, frame = cap.read()
if not ok or frame is None:
continue
sampled.append((idx, frame))
cap.release()
duration = (frame_count / fps) if (frame_count > 0 and fps > 0) else None
meta = {
"frame_count": frame_count if frame_count > 0 else None,
"fps": round(fps, 3) if fps > 0 else None,
"width": width,
"height": height,
"duration_seconds": round(duration, 3) if duration else None,
}
return sampled, meta
def analyze_video(path: Path) -> Dict[str, Any]:
sampled, meta = _sample_video_frames(path, max_samples=24)
if not sampled:
raise RuntimeError("Cannot sample frames from uploaded video")
all_faces: List[Dict[str, Any]] = []
all_plates: List[Dict[str, Any]] = []
quality_samples: List[Dict[str, Any]] = []
for frame_idx, frame in sampled:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # type: ignore[union-attr]
faces = _detect_faces(gray)
plates = _detect_plates(gray)
for f in faces:
f["frame_index"] = frame_idx
all_faces.append(f)
for p in plates:
p["frame_index"] = frame_idx
all_plates.append(p)
quality_samples.append(_analyze_quality(gray))
quality = _aggregate_quality(quality_samples)
recs, priority = _recommendations(
faces_count=len(all_faces),
plates_count=len(all_plates),
quality=quality,
media_type="video",
)
width = _safe_int(meta.get("width"))
height = _safe_int(meta.get("height"))
frame_count = _safe_int(meta.get("frame_count"))
return {
"media_type": "video",
"frame_sampled": len(sampled),
"video_metadata": meta,
"faces": all_faces[:120],
"license_plates": all_plates[:120],
"quality_analysis": quality,
"recommendations": recs,
"suggested_priority": priority,
"suggested_export": _suggested_export("video", quality, width, height),
"estimated_processing_seconds": estimate_processing_seconds(
media_type="video",
mode="tactical",
width=width,
height=height,
frame_count=frame_count,
),
}