diff --git a/app/main.py b/app/main.py index b510617..ec8d45c 100644 --- a/app/main.py +++ b/app/main.py @@ -166,6 +166,8 @@ def process_job(job_id): "--min-duration", str(job.get("min_duration", 20)), "--output", str(analysis_path), ] + if job.get("include_prebuild"): + cmd += ["--include-prebuild"] # lang: če None ali 'auto', pusti analyze.py auto-detect if job.get("lang") and job["lang"] not in ("auto", ""): cmd += ["--lang", job["lang"]] @@ -188,7 +190,15 @@ def process_job(job_id): "fade": fade, "chorus_preview": analysis["chorus"]["best"]["text_preview"] if analysis.get("chorus") and analysis["chorus"].get("best") else None, + "video_duration": analysis.get("video_duration"), + "candidates": analysis["chorus"].get("all_candidates", [])[:5] + if analysis.get("chorus") else [], }, + # Cel transkript shranimo za UI prikaz + full_transcript=[ + {"start": s["start"], "end": s["end"], "text": s["text"]} + for s in analysis.get("transcript", {}).get("segments", []) + ], start=cr["start"], duration=cr["duration"], fade_in=fade["fade_in"], @@ -299,9 +309,10 @@ class StartJobIn(BaseModel): mode: str = "track" lang: Optional[str] = None # None/auto = Whisper auto-detect auto_chorus: bool = True + include_prebuild: bool = False # vključi pre-chorus build-up start: Optional[float] = None duration: Optional[float] = 30 - max_duration: Optional[float] = 45 # Smart selection lahko gre do 45s + max_duration: Optional[float] = 45 min_duration: Optional[float] = 20 no_subs: bool = False subtitle_style: str = "reels" @@ -401,6 +412,7 @@ async def start_processing( mode=payload.mode, lang=payload.lang, auto_chorus=payload.auto_chorus, + include_prebuild=payload.include_prebuild, start=payload.start, duration=payload.duration, max_duration=payload.max_duration, diff --git a/scripts/analyze.py b/scripts/analyze.py index 85c5cec..db4beb1 100644 --- a/scripts/analyze.py +++ b/scripts/analyze.py @@ -346,31 +346,46 @@ def smart_clip_range(chorus, transcript, video_duration, } -def detect_audio_fade(clip_range, transcript): - """Določi fade-in/fade-out trajanje. +def detect_audio_fade(clip_range, transcript, video_duration=None): + """Določi fade-in/fade-out trajanje + ev. razširi clip range, da fade + ne reže besedila na koncu refrena. Logika: - Če clip začne sredi vokala → 0.5s fade in - - Če se konča sredi vokala → 1.0s fade out + - Če se konča sredi vokala → razširi clip do konca segmenta (+ buffer), + potem 1.0s fade out - Sicer manj fade """ cs, ce = clip_range["start"], clip_range["end"] - # Vokal pri začetku? + # Najdi segment, ki konča znotraj clip-a (ali je clip end znotraj segmenta) starts_in_vocal = False ends_in_vocal = False + end_segment = None for seg in transcript["segments"]: - # Začetek clip-a znotraj segmenta if seg["start"] <= cs <= seg["end"]: starts_in_vocal = True - # Konec clip-a znotraj segmenta if seg["start"] <= ce <= seg["end"]: ends_in_vocal = True + end_segment = seg - fade_in = 0.5 if starts_in_vocal else 0.2 - fade_out = 1.5 if ends_in_vocal else 0.3 + # Če clip konča znotraj segmenta, razširi do konca segmenta + 0.5s buffer + extended_end = ce + if end_segment: + extended_end = end_segment["end"] + 0.5 + if video_duration is not None: + extended_end = min(extended_end, video_duration) - return {"fade_in": fade_in, "fade_out": fade_out} + fade_in = 0.4 if starts_in_vocal else 0.2 + # Krajši fade out (0.5s) ker zdaj clip konča po koncu vokala + fade_out = 0.5 if ends_in_vocal else 0.3 + + return { + "fade_in": fade_in, + "fade_out": fade_out, + "extended_end": round(extended_end, 2), + "ends_in_vocal": ends_in_vocal, + } def analyze_with_claude(transcript, video_duration, target_duration=30): @@ -612,10 +627,19 @@ def main(): f"(duration: {clip_range['duration']}s, source: {clip_range.get('source')})", file=sys.stderr) - # 7. Fade params - fade = detect_audio_fade(clip_range, transcript) + # 7. Fade params (lahko razširi clip end če konča sredi vokala) + fade = detect_audio_fade(clip_range, transcript, video_duration=duration) print(f"🎚 Fade: in={fade['fade_in']}s, out={fade['fade_out']}s", file=sys.stderr) + # Če fade detection razširi end (ker clip konča sredi vokala), apply + if fade.get("extended_end") and fade["extended_end"] > clip_range["end"]: + old_end = clip_range["end"] + new_end = min(fade["extended_end"], clip_range["start"] + args.max_duration) + clip_range["end"] = round(new_end, 2) + clip_range["duration"] = round(new_end - clip_range["start"], 2) + print(f" ↳ Razširjen za {new_end - old_end:.1f}s (zaključek besedila)", + file=sys.stderr) + result = { "video": str(video), "video_duration": duration, diff --git a/scripts/subtitle.py b/scripts/subtitle.py index 0ff8e2d..75a38ab 100644 --- a/scripts/subtitle.py +++ b/scripts/subtitle.py @@ -133,7 +133,7 @@ ScaledBorderAndShadow: yes [V4+ Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding -Style: Default,Arial,56,{primary},&H00FFFFFF,&H00000000,&H00000000,1,0,0,0,100,100,0,0,1,5,1,2,80,80,400,1 +Style: Default,DejaVu Sans,56,{primary},&H00FFFFFF,&H00000000,&H00000000,1,0,0,0,100,100,0,0,1,5,1,2,80,80,400,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text diff --git a/templates/index.html b/templates/index.html index 2dd1b86..b8513e3 100644 --- a/templates/index.html +++ b/templates/index.html @@ -233,9 +233,9 @@ @@ -245,9 +245,16 @@ Pametna izbira odseka (Whisper + energy → najde refren)