from evanescere.schemas import ClipCandidate from evanescere.services.llm import ( TranscriptChunk, candidate_quota_per_chunk, dedupe_and_rank_candidates, parse_clip_response, render_user_prompt, ) def test_parse_clip_response(): candidates = parse_clip_response( """ { "clips": [ { "start_sec": 10, "end_sec": 60, "title_zh": "标题", "summary_zh": "摘要", "reason": "有趣", "score": 0.9, "tags": ["反应"], "subtitle_priority": "high" } ] } """ ) assert candidates[0].title_zh == "标题" def test_parse_clip_response_accepts_candidates_key_and_score_out_of_ten(): candidates = parse_clip_response( """ { "candidates": [ { "start_sec": 10, "end_sec": 60, "title_zh": "标题", "summary_zh": "摘要", "reason": "有趣", "score": 8.5, "tags": ["反应"], "subtitle_priority": "high" } ] } """ ) assert candidates[0].score == 0.85 def test_parse_clip_response_normalizes_score_out_of_hundred(): candidates = parse_clip_response( """ { "clips": [ { "start_sec": 10, "end_sec": 60, "title_zh": "标题", "summary_zh": "摘要", "reason": "有趣", "score": 92, "tags": ["反应"], "subtitle_priority": "high" } ] } """ ) assert candidates[0].score == 0.92 def test_dedupe_and_rank_candidates_filters_short_and_overlapping(): candidates = [ ClipCandidate( start_sec=0, end_sec=20, title_zh="too short", summary_zh="", reason="", score=1, ), ClipCandidate( start_sec=0, end_sec=60, title_zh="best", summary_zh="", reason="", score=0.9, ), ClipCandidate( start_sec=10, end_sec=65, title_zh="overlap", summary_zh="", reason="", score=0.8, ), ClipCandidate( start_sec=120, end_sec=180, title_zh="second", summary_zh="", reason="", score=0.7, ), ] ranked = dedupe_and_rank_candidates(candidates) assert [candidate.title_zh for candidate in ranked] == ["best", "second"] def test_candidate_quota_uses_total_budget_across_chunks(): assert candidate_quota_per_chunk(1, 20) == 20 assert candidate_quota_per_chunk(4, 20) == 5 assert candidate_quota_per_chunk(0, 20) == 0 def test_dedupe_respects_configured_duration_and_total_cap(): candidates = [ ClipCandidate( start_sec=index * 240, end_sec=index * 240 + duration, title_zh=f"clip-{index}", summary_zh="", reason="", score=1 - index / 100, ) for index, duration in enumerate([60, 180, 181, 90]) ] ranked = dedupe_and_rank_candidates( candidates, min_clip_seconds=30, max_clip_seconds=180, max_candidates_total=2, ) assert [candidate.title_zh for candidate in ranked] == ["clip-0", "clip-1"] def test_render_user_prompt_inserts_configured_values(): prompt = render_user_prompt( "{max_candidates}|{min_clip_seconds}|{max_clip_seconds}|{chunk_start_sec}|{chunk_end_sec}|{transcript}", chunk=TranscriptChunk(12.25, 42.75, "hello"), max_candidates=20, min_clip_seconds=30, max_clip_seconds=180, ) assert prompt == "20|30|180|12.2|42.8|hello" def test_render_user_prompt_rejects_unknown_placeholder(): try: render_user_prompt( "{unknown}", chunk=TranscriptChunk(0, 1, "hello"), max_candidates=20, min_clip_seconds=30, max_clip_seconds=180, ) except ValueError as exc: assert "Unknown placeholder" in str(exc) else: raise AssertionError("Expected unknown placeholder to fail")