54 lines
2.2 KiB
Python
54 lines
2.2 KiB
Python
"""tts 수동 확인용.
|
|
|
|
사용: uv run python -m tests.poster_alive.test_tts <포스터경로>
|
|
test_result/<이름>.narration.txt 가 있으면 재사용하고, 없으면 앞 단계부터 돌린다.
|
|
결과는 <이름>.tts.mp3(합쳐진 나레이션)와 <이름>.tts.txt(타임라인)로 떨어진다.
|
|
"""
|
|
import asyncio
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from answers.narration_answer import NarrationAnswer
|
|
from services.narration import generate_narration
|
|
from services.tts import synthesize
|
|
from tests.poster_alive.test_narration import load_regions
|
|
|
|
TEST_RESULT_DIR = Path(__file__).parent.parent / "test_result" / "poster_alive"
|
|
|
|
|
|
async def load_narration(poster_path: Path, output_base: Path) -> NarrationAnswer:
|
|
narration_path = output_base.with_suffix(".narration.txt")
|
|
if narration_path.exists():
|
|
return NarrationAnswer.model_validate_json(narration_path.read_text(encoding="utf-8"))
|
|
regions = await load_regions(poster_path, output_base.with_suffix(".detect.txt"))
|
|
answer = await generate_narration(poster_path, regions)
|
|
narration_path.write_text(answer.model_dump_json(indent=2), encoding="utf-8")
|
|
return answer
|
|
|
|
|
|
async def main() -> None:
|
|
poster_path = Path(sys.argv[1])
|
|
TEST_RESULT_DIR.mkdir(exist_ok=True)
|
|
output_base = TEST_RESULT_DIR / poster_path.stem
|
|
|
|
answer = await load_narration(poster_path, output_base)
|
|
audio = await synthesize(answer.narration, answer.voice)
|
|
|
|
mp3_path = output_base.with_suffix(".tts.mp3")
|
|
timeline_path = output_base.with_suffix(".tts.txt")
|
|
mp3_path.write_bytes(audio.mp3)
|
|
timeline_path.write_text(audio.timeline.model_dump_json(indent=2), encoding="utf-8")
|
|
|
|
print(f"engine={audio.timeline.engine} voice={audio.timeline.voice}")
|
|
for cue in audio.timeline.cues:
|
|
print(f" [{cue.index}] {cue.start:5.2f}s +{cue.duration:4.2f}s {cue.text}")
|
|
print(f"\n나레이션 종료 {audio.timeline.cues[-1].end:.2f}s "
|
|
f"+ 여백 {audio.timeline.tail}s → 영상 길이 {audio.timeline.total}s")
|
|
if audio.timeline.total > 8:
|
|
print("※ 8초를 넘는다 — 영상이 8초 고정이라 나레이션이 잘린다")
|
|
print(f"\n{mp3_path}\n{timeline_path}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|