# -*- coding: utf-8 -*- from typing import List, Optional, Tuple def smooth_scores(time_scores: List[Tuple[float, float]], window: int = 3) -> List[Tuple[float, float]]: if len(time_scores) <= 1 or window <= 1: return time_scores half = window // 2 smoothed = [] for i, (t, _) in enumerate(time_scores): lo = max(0, i - half) hi = min(len(time_scores), i + half + 1) avg = sum(s for _, s in time_scores[lo:hi]) / (hi - lo) smoothed.append((t, avg)) return smoothed def find_peak( time_scores: List[Tuple[float, float]], min_time: float = 0.0, min_confidence: float = 0.3, ) -> Optional[Tuple[float, float]]: if not time_scores: return None candidates = [(t, s) for t, s in time_scores if t >= min_time and s >= min_confidence] if not candidates: candidates = time_scores best = max(candidates, key=lambda x: x[1]) if best[1] < 0.1: return None return best def find_peaks_ordered( sf_scores: List[Tuple[float, float]], ho_scores: List[Tuple[float, float]], duration: float, min_gap: float = 30.0, ) -> Tuple[Optional[Tuple[float, float]], Optional[Tuple[float, float]]]: sf = find_peak(smooth_scores(sf_scores)) min_ho = (sf[0] + min_gap) if sf else 0.0 ho = find_peak(smooth_scores(ho_scores), min_time=min_ho) if sf and ho and ho[0] <= sf[0]: ho = find_peak(smooth_scores(ho_scores), min_time=sf[0] + 1.0) if sf and not ho and duration > sf[0] + min_gap: ho = find_peak(smooth_scores(ho_scores), min_time=sf[0] + min_gap) return sf, ho