Files
Jyotisha/scripts/rectification/living_display_intervals.py
T
jesse-uxandGrok (agent loop) 56a3c08145 显示生时校正里还活着的时间段,不再把空档涂进目前范围。
交付卡、旁白和遥测在有簇区间时按段书写。打分、出题和进区间门槛未改;对半出题和门槛 6 因为没有真值保留回放而没有交付。

Co-Authored-By: Grok (agent loop)
2026-10-17 03:07:25 +08:00

80 lines
2.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Display-only merge of living candidate intervals.
Decision width stays on ``interval_union_width`` / ``unionWindowIntervals``.
This module is not part of the sealed scoring identity: scoring must not import it.
"""
from __future__ import annotations
from datetime import datetime
from typing import Any
LIVING_DISPLAY_MERGE_GAP_MINUTES = 4
LIVING_DISPLAY_MAX_SEGMENTS = 3
def _stamp(value: str) -> datetime:
return datetime.fromisoformat(value)
def merge_living_display_intervals(
intervals: list[dict[str, Any]],
gap_minutes: int = LIVING_DISPLAY_MERGE_GAP_MINUTES,
) -> list[dict[str, str]]:
"""Merge intervals whose gap is <= gap_minutes. Gap is the open minutes between them."""
rows = []
for row in intervals:
start, end = str(row.get("start_at") or ""), str(row.get("end_at") or "")
if len(start) < 16 or len(end) < 16 or start > end:
continue
try:
_stamp(start)
_stamp(end)
except ValueError:
continue
rows.append({"start_at": start[:16], "end_at": end[:16]})
rows.sort(key=lambda item: (item["start_at"], item["end_at"]))
merged: list[dict[str, str]] = []
for row in rows:
if not merged:
merged.append(row)
continue
previous = merged[-1]
gap = int((_stamp(row["start_at"]) - _stamp(previous["end_at"])).total_seconds() // 60) - 1
if gap <= gap_minutes:
if row["end_at"] > previous["end_at"]:
previous["end_at"] = row["end_at"]
else:
merged.append(row)
return merged
def inclusive_interval_minutes(intervals: list[dict[str, str]]) -> int:
total = 0
for row in intervals:
width = int((_stamp(row["end_at"]) - _stamp(row["start_at"])).total_seconds() // 60) + 1
if width > 0:
total += width
return total
def living_display_label(
intervals: list[dict[str, str]],
birth_date: str | None = None,
max_segments: int = LIVING_DISPLAY_MAX_SEGMENTS,
) -> str:
def label(value: str) -> str:
date, clock = value[:10], value[11:16]
if not birth_date:
return f"{date} {clock}"
if date == birth_date:
return clock
return f"{'前一天' if date < birth_date else '后一天'} {clock}"
def text(row: dict[str, str]) -> str:
return f"{label(row['start_at'])}–{label(row['end_at'])}"
if len(intervals) <= max_segments:
return "、".join(text(row) for row in intervals)
shown = "、".join(text(row) for row in intervals[:max_segments])
return f"{shown},等 {len(intervals)} 段,共约 {inclusive_interval_minutes(intervals)} 分钟"