sesa-gpu / src /longform.py
John6666's picture
Upload 44 files
81ba775 verified
Raw
History Blame Contribute Delete
7.6 kB
from __future__ import annotations
import math
from dataclasses import asdict, dataclass
RANGE_MODE_FULL = "Full input"
RANGE_MODE_PREVIEW = "Preview range"
RANGE_MODE_CUSTOM = "Custom start/end"
RANGE_MODES = [RANGE_MODE_FULL, RANGE_MODE_PREVIEW, RANGE_MODE_CUSTOM]
CHUNK_MODE_AUTO = "Auto"
CHUNK_MODE_DISABLED = "Disabled"
CHUNK_MODE_FIXED = "Fixed"
CHUNK_MODES = [CHUNK_MODE_AUTO, CHUNK_MODE_DISABLED, CHUNK_MODE_FIXED]
CHUNK_CHOICES_SECONDS = (120, 300, 600)
DEFAULT_PREVIEW_SECONDS = 60
DEFAULT_FIXED_CHUNK_SECONDS = 300
LONG_FORM_THRESHOLD_SECONDS = 20 * 60
@dataclass(frozen=True)
class LongFormPlan:
range_mode: str
requested_start_seconds: float
requested_end_seconds: float | None
preview_seconds: float
selection_applied: bool
input_ranges: list[dict]
total_source_seconds: float
total_selected_seconds: float
longest_selected_seconds: float
chunk_mode: str
requested_chunk_seconds: int
resolved_chunk_seconds: int
chunk_count_total: int
auto_chunk_reason: str
chunk_merge_method: str
chunk_boundary_note: str
long_form: bool
estimated_prepared_pcm_bytes: int
def to_dict(self) -> dict:
return asdict(self)
def _number(value, default: float = 0.0) -> float:
try:
parsed = float(value)
except (TypeError, ValueError):
return default
if not math.isfinite(parsed):
return default
return parsed
def _normalize_range_mode(value) -> str:
text = str(value or RANGE_MODE_FULL)
return text if text in RANGE_MODES else RANGE_MODE_FULL
def _normalize_chunk_mode(value) -> str:
text = str(value or CHUNK_MODE_AUTO)
return text if text in CHUNK_MODES else CHUNK_MODE_AUTO
def _resolve_auto_chunk(longest_seconds: float, model_count: int) -> tuple[int, str]:
if longest_seconds <= LONG_FORM_THRESHOLD_SECONDS:
return 0, "Selected range is at most 20 minutes; package-level chunking is unnecessary."
if model_count > 1:
return 300, "Multiple models are selected; use conservative 5-minute chunks."
if longest_seconds > 3600:
return 600, "Selected range exceeds one hour; use the package-recommended 10-minute chunks."
return 300, "Selected range exceeds 20 minutes; use conservative 5-minute chunks."
def build_long_form_plan(
source_durations,
*,
range_mode=RANGE_MODE_FULL,
range_start_seconds=0,
range_end_seconds=0,
preview_seconds=DEFAULT_PREVIEW_SECONDS,
chunk_mode=CHUNK_MODE_AUTO,
fixed_chunk_seconds=DEFAULT_FIXED_CHUNK_SECONDS,
model_count=1,
additional_fixed_chunk_seconds=(),
) -> LongFormPlan:
durations = [_number(value) for value in list(source_durations or [])]
if not durations or any(value <= 0 for value in durations):
raise ValueError("Every input requires a positive probed duration.")
mode = _normalize_range_mode(range_mode)
start = max(0.0, _number(range_start_seconds))
requested_end_raw = _number(range_end_seconds)
requested_end = requested_end_raw if requested_end_raw > 0 else None
preview = max(5.0, min(600.0, _number(preview_seconds, DEFAULT_PREVIEW_SECONDS)))
if mode == RANGE_MODE_CUSTOM and requested_end is not None and requested_end <= start:
raise ValueError("Custom range end must be later than its start.")
ranges: list[dict] = []
total_selected = 0.0
longest_selected = 0.0
for index, source_duration in enumerate(durations):
if mode == RANGE_MODE_FULL:
item_start = 0.0
item_end = source_duration
else:
if start >= source_duration:
raise ValueError(
f"Range start {start:.3f}s is outside input {index + 1} ({source_duration:.3f}s)."
)
item_start = start
if mode == RANGE_MODE_PREVIEW:
item_end = min(source_duration, item_start + preview)
else:
item_end = min(source_duration, requested_end or source_duration)
if item_end <= item_start:
raise ValueError(f"Input {index + 1} has an empty selected range.")
effective = item_end - item_start
total_selected += effective
longest_selected = max(longest_selected, effective)
ranges.append(
{
"input_index": index,
"source_duration_seconds": round(source_duration, 6),
"start_seconds": round(item_start, 6),
"end_seconds": round(item_end, 6),
"selected_seconds": round(effective, 6),
"source_end_clamped": bool(
mode != RANGE_MODE_FULL
and (
(mode == RANGE_MODE_PREVIEW and item_start + preview > source_duration)
or (mode == RANGE_MODE_CUSTOM and requested_end is not None and requested_end > source_duration)
)
),
}
)
chunk_policy = _normalize_chunk_mode(chunk_mode)
requested_chunk = int(round(_number(fixed_chunk_seconds, DEFAULT_FIXED_CHUNK_SECONDS)))
if chunk_policy == CHUNK_MODE_DISABLED:
resolved_chunk = 0
auto_reason = "Chunking was explicitly disabled."
elif chunk_policy == CHUNK_MODE_FIXED:
additional: set[int] = set()
for value in additional_fixed_chunk_seconds or ():
try:
parsed = int(value)
except (TypeError, ValueError):
continue
if parsed > 0:
additional.add(parsed)
allowed_fixed_chunks = set(CHUNK_CHOICES_SECONDS) | additional
if requested_chunk not in allowed_fixed_chunks:
raise ValueError("Fixed chunk duration must be 120, 300, or 600 seconds.")
resolved_chunk = requested_chunk
auto_reason = "Fixed chunk duration selected by the user."
else:
resolved_chunk, auto_reason = _resolve_auto_chunk(longest_selected, max(1, int(model_count or 1)))
chunk_count = 0
for item in ranges:
selected = float(item["selected_seconds"])
item_chunks = math.ceil(selected / resolved_chunk) if resolved_chunk > 0 else 1
item["estimated_chunk_count"] = int(max(1, item_chunks))
chunk_count += int(max(1, item_chunks))
selection_applied = mode != RANGE_MODE_FULL
estimated_pcm = int(total_selected * 44100 * 2 * 2) if selection_applied else 0
return LongFormPlan(
range_mode=mode,
requested_start_seconds=round(start, 6),
requested_end_seconds=round(requested_end, 6) if requested_end is not None else None,
preview_seconds=round(preview, 6),
selection_applied=selection_applied,
input_ranges=ranges,
total_source_seconds=round(sum(durations), 6),
total_selected_seconds=round(total_selected, 6),
longest_selected_seconds=round(longest_selected, 6),
chunk_mode=chunk_policy,
requested_chunk_seconds=requested_chunk,
resolved_chunk_seconds=int(resolved_chunk),
chunk_count_total=int(chunk_count),
auto_chunk_reason=auto_reason,
chunk_merge_method="simple concatenation by audio-separator",
chunk_boundary_note=(
"Package chunks are concatenated without crossfade; rare boundary artifacts remain possible."
if resolved_chunk > 0
else "No package-level chunk merge is planned."
),
long_form=bool(longest_selected > LONG_FORM_THRESHOLD_SECONDS),
estimated_prepared_pcm_bytes=estimated_pcm,
)