process_paste를 paste_analyze/paste_draft 두 조각으로 분할
댓글 매칭을 받아쓰기(asr_bottom) 다음에 넣으려면 파이프라인이 "받아쓰기까지" 상태에서 한 번 멈출 수 있어야 한다. 앞서 process_bg_template에 적용한 것과 같은 패턴(analyze/draft 분리 + state 이벤트 + 얇은 래퍼)을 process_paste에도 적용했다. 로직은 옮기기만 했고 바꾸지 않았다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
475b7b0f71
commit
e79f2dfaa3
@ -460,26 +460,30 @@ def _template_pos(white: bool = False):
|
|||||||
return frame, bg, pos
|
return frame, bg, pos
|
||||||
|
|
||||||
|
|
||||||
async def process_paste(
|
def paste_steps(asr_bottom: bool) -> List[Dict[str, str]]:
|
||||||
|
"""붙여넣기 파이프라인의 manifest 스텝."""
|
||||||
|
steps = [{"id": "download", "label": "컷 정밀 다운로드·병합"}]
|
||||||
|
if asr_bottom:
|
||||||
|
steps.append({"id": "asr", "label": "받아쓰기 (Whisper)"})
|
||||||
|
steps.append({"id": "draft", "label": "템플릿 드래프트 생성"})
|
||||||
|
return steps
|
||||||
|
|
||||||
|
|
||||||
|
async def paste_analyze(
|
||||||
payload: dict,
|
payload: dict,
|
||||||
draft_name: str,
|
draft_name: str,
|
||||||
*,
|
*,
|
||||||
video_scale: float = 1.0,
|
|
||||||
flip_horizontal: bool = False,
|
|
||||||
scene_split: bool = False,
|
|
||||||
comments_dir: str = "",
|
|
||||||
cards_fixed: bool = False,
|
|
||||||
card_cuts: Optional[List[int]] = None,
|
|
||||||
bg_white: bool = False,
|
|
||||||
remove_silence: bool = False,
|
remove_silence: bool = False,
|
||||||
asr_bottom: bool = False,
|
asr_bottom: bool = False,
|
||||||
name_suffix: str = "",
|
name_suffix: str = "",
|
||||||
) -> AsyncIterator[dict]:
|
) -> AsyncIterator[dict]:
|
||||||
"""붙여넣기(JSON) 파이프라인: 컷 정밀 다운로드·병합 → 공급된 자막 2트랙으로 드래프트.
|
"""붙여넣기 파이프라인 앞부분: 컷 정밀 다운로드·병합 → probe → 컷 배치·자막 계산 →
|
||||||
|
[무음 제거] → [asr_bottom 받아쓰기].
|
||||||
|
|
||||||
자막 배치 시간 = 컷 순서 누적. asr_bottom=True 면 JSON bottom 대신 병합본을
|
자막 배치 시간 = 컷 순서 누적. asr_bottom=True 면 JSON bottom 대신 병합본을
|
||||||
Whisper로 받아써 실제 발화 타이밍에 맞춘 하단 자막을 생성(effect/제목은 JSON 유지).
|
Whisper로 받아써 실제 발화 타이밍에 맞춘 하단 자막을 생성(effect/제목은 JSON 유지).
|
||||||
payload: paste.parse_paste 결과 dict.
|
payload: paste.parse_paste 결과 dict.
|
||||||
|
마지막에 `paste_draft` 로 이어줄 `{"type": "state", ...}` 를 낸다.
|
||||||
"""
|
"""
|
||||||
t_all = time.perf_counter()
|
t_all = time.perf_counter()
|
||||||
cuts = payload["cuts"] # [(s, e, bottom, effect)]
|
cuts = payload["cuts"] # [(s, e, bottom, effect)]
|
||||||
@ -488,12 +492,6 @@ async def process_paste(
|
|||||||
title_main = payload.get("title_main", "")
|
title_main = payload.get("title_main", "")
|
||||||
channel = payload.get("channel", "")
|
channel = payload.get("channel", "")
|
||||||
|
|
||||||
steps = [{"id": "download", "label": "컷 정밀 다운로드·병합"}]
|
|
||||||
if asr_bottom:
|
|
||||||
steps.append({"id": "asr", "label": "받아쓰기 (Whisper)"})
|
|
||||||
steps.append({"id": "draft", "label": "템플릿 드래프트 생성"})
|
|
||||||
yield {"type": "manifest", "steps": steps}
|
|
||||||
|
|
||||||
# ── 컷 정밀 다운로드 + 병합 ──
|
# ── 컷 정밀 다운로드 + 병합 ──
|
||||||
yield {"type": "step", "id": "download", "status": "start"}
|
yield {"type": "step", "id": "download", "status": "start"}
|
||||||
yield {"type": "log", "msg": f"{len(cuts)}개 컷 정밀 다운로드·병합 중… (프레임 정확 컷)"}
|
yield {"type": "log", "msg": f"{len(cuts)}개 컷 정밀 다운로드·병합 중… (프레임 정확 컷)"}
|
||||||
@ -587,6 +585,47 @@ async def process_paste(
|
|||||||
"elapsed": round(time.perf_counter() - t, 1),
|
"elapsed": round(time.perf_counter() - t, 1),
|
||||||
"detail": f"{method} · 자막 {len(bottom_caps)}개"}
|
"detail": f"{method} · 자막 {len(bottom_caps)}개"}
|
||||||
|
|
||||||
|
yield {"type": "state", "state": {
|
||||||
|
"video_path": video_path, "meta": meta, "dur": dur, "cuts": cuts,
|
||||||
|
"placements": placements, "card_places": card_places,
|
||||||
|
"video_clips": video_clips, "timeline_dur": timeline_dur,
|
||||||
|
"bottom_caps": bottom_caps, "eff_caps": eff_caps,
|
||||||
|
"draft_name": draft_name, "title_top": title_top, "title_main": title_main,
|
||||||
|
"channel": channel, "t_all": t_all,
|
||||||
|
}}
|
||||||
|
|
||||||
|
|
||||||
|
async def paste_draft(
|
||||||
|
state: dict,
|
||||||
|
*,
|
||||||
|
video_scale: float = 1.0,
|
||||||
|
flip_horizontal: bool = False,
|
||||||
|
scene_split: bool = False,
|
||||||
|
comments_dir: str = "",
|
||||||
|
cards_fixed: bool = False,
|
||||||
|
card_cuts: Optional[List[int]] = None,
|
||||||
|
bg_white: bool = False,
|
||||||
|
) -> AsyncIterator[dict]:
|
||||||
|
"""붙여넣기 파이프라인 뒷부분: [장면분할] → 댓글 카드 → 드래프트 생성 → result.
|
||||||
|
|
||||||
|
`paste_analyze` 가 낸 `state` 를 이어받는다.
|
||||||
|
"""
|
||||||
|
video_path = state["video_path"]
|
||||||
|
meta = state["meta"]
|
||||||
|
dur = state["dur"]
|
||||||
|
cuts = state["cuts"]
|
||||||
|
placements = state["placements"]
|
||||||
|
card_places = state["card_places"]
|
||||||
|
video_clips = state["video_clips"]
|
||||||
|
timeline_dur = state["timeline_dur"]
|
||||||
|
bottom_caps = state["bottom_caps"]
|
||||||
|
eff_caps = state["eff_caps"]
|
||||||
|
draft_name = state["draft_name"]
|
||||||
|
title_top = state["title_top"]
|
||||||
|
title_main = state["title_main"]
|
||||||
|
channel = state["channel"]
|
||||||
|
t_all = state["t_all"]
|
||||||
|
|
||||||
# ── draft ──
|
# ── draft ──
|
||||||
yield {"type": "step", "id": "draft", "status": "start"}
|
yield {"type": "step", "id": "draft", "status": "start"}
|
||||||
t = time.perf_counter()
|
t = time.perf_counter()
|
||||||
@ -646,6 +685,31 @@ async def process_paste(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def process_paste(payload, draft_name, *, video_scale=1.0, flip_horizontal=False,
|
||||||
|
scene_split=False, comments_dir="", cards_fixed=False,
|
||||||
|
card_cuts=None, bg_white=False, remove_silence=False,
|
||||||
|
asr_bottom=False, name_suffix="") -> AsyncIterator[dict]:
|
||||||
|
"""붙여넣기(JSON) 파이프라인 — 기존 호출부용 얇은 래퍼.
|
||||||
|
|
||||||
|
analyze/draft 두 조각을 연달아 부른다. `state` 이벤트는 밖으로 안 흘린다.
|
||||||
|
"""
|
||||||
|
yield {"type": "manifest", "steps": paste_steps(asr_bottom)}
|
||||||
|
state = None
|
||||||
|
async for ev in paste_analyze(payload, draft_name, remove_silence=remove_silence,
|
||||||
|
asr_bottom=asr_bottom, name_suffix=name_suffix):
|
||||||
|
if ev.get("type") == "state":
|
||||||
|
state = ev["state"]
|
||||||
|
continue
|
||||||
|
yield ev
|
||||||
|
if state is None:
|
||||||
|
return
|
||||||
|
async for ev in paste_draft(state, video_scale=video_scale,
|
||||||
|
flip_horizontal=flip_horizontal, scene_split=scene_split,
|
||||||
|
comments_dir=comments_dir, cards_fixed=cards_fixed,
|
||||||
|
card_cuts=card_cuts, bg_white=bg_white):
|
||||||
|
yield ev
|
||||||
|
|
||||||
|
|
||||||
STEPS: List[Dict[str, str]] = [
|
STEPS: List[Dict[str, str]] = [
|
||||||
{"id": "silence", "label": "무음·발화 분석"},
|
{"id": "silence", "label": "무음·발화 분석"},
|
||||||
{"id": "draft", "label": "점프컷 드래프트 생성"},
|
{"id": "draft", "label": "점프컷 드래프트 생성"},
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user