카테고리 없음

[음성 대본 추출] Whisper ai를 통한 .srt 파일 추출

박히응 2025. 9. 12. 18:31

whisper.ipynb
0.02MB

실행 목적

api 미사용(과금 가능성)으로 영상 파일을 대상으로 음성 대본(.srt) 추출

실제 경로 내 파일

실행 자체는 로컬환경 리소스 절약을 위해 Google Colab을 사용 (로컬환경에서도 실행 가능)

선행 조건

  1. 구글 코랩 또는 로컬 등 구동 가능한 환경
  2.  구글 드라이브 (경로 생성은 자동)

 

실행 순서

colab 환경에서 개별실행이 아니라면 모두 실행(빨간박스 표시)

  1. 기본 모듈 설치 및 마운트
  2. .srt 파일 추출
    • 추가 프롬프트 입력 (추출 전 프롬프트 질문 有, 고유명사 등을 입력 권장)

작성 내용

  • 기본 모듈 설치 및 마운트
# @title 1. 초기 설정(라이브러리 설치) 및 마운트
# 필수 패키지 설치 (ffmpeg, whisper, tqdm)
!apt -y install ffmpeg > /dev/null
!pip -q install git+https://github.com/openai/whisper.git tqdm

# 구글 드라이브 마운트
from google.colab import drive
drive.mount('/content/drive')

import os
import torch
import whisper
import subprocess
from pathlib import Path
from tqdm.notebook import tqdm

# GPU 사용 가능 여부 확인
device_check = "cuda" if torch.cuda.is_available() else "cpu"
print(f"\n✅ 설정 완료. (현재 디바이스: {device_check.upper()})")

 

  • .srt 파일 추출 (메인 실행)
# @title 2. Whisper 자막 추출 실행

# ==========================================
# A. 설정 및 경로 정의
# ==========================================
BASE_DIR = Path("/content/drive/MyDrive/whisper")
INPUT_DIR = BASE_DIR / "whisper_input"
OUTPUT_DIR = BASE_DIR / "whisper_output"
TMP_DIR = Path("/content/whisper_tmp")

for p in (INPUT_DIR, OUTPUT_DIR, TMP_DIR):
    p.mkdir(parents=True, exist_ok=True)

MODEL_SIZE = "medium"
VIDEO_EXTS = {".mp4", ".mov", ".mkv", ".m4v", ".avi", ".mp3", ".wav", ".m4a", ".flac", ".wma"}
USE_PREPROCESS = False
PREPROCESS_FILTER = "loudnorm,highpass=f=100"

# ==========================================
# B. 프롬프트 및 디바이스 설정
# ==========================================
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
FP16 = (DEVICE == "cuda")

print(f"🚀 작업 시작 (디바이스: {DEVICE.upper()})")

# 사용자 키워드 입력
print("\n" + "-"*40)
print("💡 [힌트] 영상의 주제, 고유명사, 전문용어를 입력하세요 (없으면 Enter)")
user_hint = input("키워드 입력 > ").strip()

# ▼ [수정됨] 인사말 제거 및 효율성 위주의 지시형 프롬프트
base_prompt = "한국어 자막을 생성합니다. 문장의 끝에는 반드시 마침표를 찍고, 문맥에 맞는 정확한 띄어쓰기와 맞춤법을 준수하세요."

final_prompt = base_prompt
if user_hint:
    final_prompt += f" 특히 다음 전문 용어의 표기를 정확히 지키세요: {user_hint}"

print(f"📋 적용된 프롬프트: \"{final_prompt}\"")
print("-"*40 + "\n")

# ==========================================
# C. 내부 처리 함수
# ==========================================
def format_timestamp(seconds: float):
    ms = int((seconds % 1) * 1000)
    seconds = int(seconds)
    hrs = seconds // 3600
    mins = (seconds % 3600) // 60
    secs = seconds % 60
    return f"{hrs:02d}:{mins:02d}:{secs:02d},{ms:03d}"

def write_srt(segments, file_path):
    with open(file_path, "w", encoding="utf-8") as f:
        for i, seg in enumerate(segments, start=1):
            start = format_timestamp(seg['start'])
            end = format_timestamp(seg['end'])
            text = seg['text'].strip()
            f.write(f"{i}\n{start} --> {end}\n{text}\n\n")

def preprocess_audio(src, dst):
    cmd = [
        "ffmpeg", "-y", "-i", str(src),
        "-vn", "-ac", "1", "-ar", "16000",
        "-af", PREPROCESS_FILTER,
        str(dst)
    ]
    subprocess.run(cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

# ==========================================
# D. 배치 실행 로직
# ==========================================
def run_batch():
    files = []
    for root, _, names in os.walk(INPUT_DIR):
        for n in names:
            if n.startswith(".") or n.endswith(".part"): continue
            if Path(n).suffix.lower() in VIDEO_EXTS:
                files.append(Path(root) / n)
    files.sort()

    if not files:
        print(f"❌ '{INPUT_DIR}' 폴더에 처리할 파일이 없습니다.")
        return

    print(f"⏳ 모델 로딩 중... ({MODEL_SIZE})")
    try:
        model = whisper.load_model(MODEL_SIZE, device=DEVICE)
    except Exception as e:
        print(f"❌ 모델 로드 실패: {e}")
        return
    print("✅ 모델 로드 완료.")

    for f in tqdm(files, desc="전체 진행률"):
        srt_out = OUTPUT_DIR / f"{f.stem}.srt"

        if srt_out.exists() and srt_out.stat().st_size > 100:
            print(f"⏩ 스킵: {f.name}")
            continue

        print(f"🎬 처리 중: {f.name}")
        
        src_file = f
        tmp_wav = None

        try:
            if USE_PREPROCESS:
                tmp_wav = TMP_DIR / f"{f.stem}_temp.wav"
                preprocess_audio(f, tmp_wav)
                src_file = tmp_wav

            # Whisper 추론 실행
            result = model.transcribe(
                str(src_file),
                language="ko",
                fp16=FP16,
                initial_prompt=final_prompt, # 수정된 프롬프트 적용
                verbose=False,
                condition_on_previous_text=False,
                temperature=(0.0, 0.2, 0.4, 0.6, 0.8, 1.0),
                compression_ratio_threshold=2.4,
                logprob_threshold=-1.0,
                no_speech_threshold=0.6
            )

            write_srt(result["segments"], srt_out)
            print(f"   -> 💾 저장 완료")

        except Exception as e:
            print(f"   -> ❌ 에러 발생: {e}")

        finally:
            if tmp_wav and tmp_wav.exists():
                try: tmp_wav.unlink()
                except: pass
    
    print("\n🎉 모든 작업이 완료되었습니다.")

if __name__ == "__main__":
    run_batch()

실행 결과

모든 음성 추출이 완벽하지않다