속삭임을 사용하여 YouTube 동영상을 전사하는 방법

20058 단어
내 블로그에서 이 게시물을 참조하십시오.

요약



YouTube 동영상에 대본을 추가하려면 속삭임을 사용할 수 있습니다. Whispers는 openai의 새로운 전사 도구입니다. 먼저 YouTube 비디오를 다운로드한 다음 ffmpeg를 사용하여 오디오를 mp3로 변환할 수 있습니다. 그런 다음 속삭임 라이브러리를 사용하여 오디오를 전사할 수 있습니다. 귓속말은 mp4 파일에서도 작동하며 ffmpeg를 설치해야 합니다.

fdrrt 프로젝트의 일부 기능을 재사용했기 때문에 코드가 약간 지저분합니다. 앞으로 정리하겠습니다.

def get_video_metadata(video_url: str = "https://www.youtube.com/watch?v=21X5lGlDOfg&ab_channel=NASA")-> dict:
    with youtube_dl.YoutubeDL({'outtmpl': '%(id)s.%(ext)s'}) as ydl:
        info_dict = ydl.extract_info(video_url, download=False)
        video_title = info_dict.get('title', None)
        uploader_id = info_dict.get('uploader_id', None)
        print(f"[youtube] {video_title}: {uploader_id}")
    return info_dict


def parse_metadata(metadata) -> dict:
    """
    Parse metadata and send to discord.
    After a video is done recording, 
    it will have both the livestream format and the mp4 format.
    """
    # send metadata to discord
    formats = metadata.get("formats", [])
    # filter for ext = mp4
    mp4_formats = [f for f in formats if f.get("ext", "") == "mp4"]
    format_ids = [int(f.get("format_id", 0)) for f in mp4_formats]
    if livestream_entries := list(
        set(format_ids).intersection(youtube_livestream_codes)
    ):
        # get the first one
        livestream_entries.sort()
        selected_id = livestream_entries[0]

    video_entries = sorted(set(format_ids).intersection(youtube_mp4_codes))

    is_livestream = True
    if len(video_entries) > 0:
        # use video format id over livestream id if available
        selected_id = video_entries[0]
        is_livestream = False

    # TODO use video format if available
    return {
        "selected_id": selected_id,
        "is_livestream": is_livestream,
    }

youtube-dl를 사용하여 비디오에서 메타데이터를 추출한 다음 메타데이터를 구문 분석하여 비디오의 형식 ID를 가져옵니다. 그런 다음 해당 형식 ID를 사용하여 비디오를 다운로드합니다.


def get_video(url: str, config: dict):
    """
    Get video from start time.
    """
    # result = subprocess.run()
    # could delay start time by a few seconds to just sync up and capture the full video length
    # but would need to time how long it takes to fetch the video using youtube-dl and other adjustments and start a bit before
    filename = config.get("filename", "livestream01.mp4")
    end = config.get("end", "00:00:10")
    overlay_file = ffmpeg.input(filename)
    (
        ffmpeg
        .input(url, t=end)
        .output(filename)
        .run()
    )

def get_all_files(url: str, end: str = "00:01:30"):
    metadata = get_video_metadata(url)
    temp_dict = parse_metadata(metadata)
    selected_id = temp_dict.get("selected_id", 0)
    formats = metadata.get("formats", [])
    selected_format = [f for f in formats if f.get("format_id", "") == str(selected_id)][0]
    format_url = selected_format.get("url", "")
    filename = f"{metadata.get('id', '')}.mp4"
    filename = filename.replace("-", "")
    get_video(format_url, {"filename": filename, "end": "00:01:30"})

ffmpegyoutube-dl(오래된)보다 비디오를 다운로드하는 데 훨씬 더 효율적입니다. 라이브러리youtube-dl는 새로운 YouTube 형식에 최적화되지 않았습니다.

파일에서 오디오 콘텐츠를 추출하고 mp3로 저장하는 표준ffmpeg 명령은 다음과 같습니다.

ffmpeg -i input.mp4 -vn output.mp3


YouTube 동영상에서 오디오를 추출하려면 스크립트의 표준(srt) 형식에서 귓속말의 타임스탬프 형식을 적절하게 지정해야 합니다.

import whisper

def main():
    model = whisper.load_model("small")
    options = dict(language="Japanese")
    transcribe_options = dict(task="translate", **options)
    result = model.transcribe("a4Vi7YUp9ws.mp3", **transcribe_options)
    return result


위의 코드는 귓속말 모델을 로드하고 결과를 반환합니다. 그런 다음 결과를 구문 분석하여 타임스탬프와 텍스트를 얻을 수 있습니다.

위의 코드는 타임스탬프를 srt 형식으로 변환합니다. 출력은 다음과 같습니다.

0
00:00:00,000 --> 00:00:06,500
I'm a person, I wonder what troubles you?


모든 텍스트를 분할하고, 시작 및 종료 시간을 가져오고, 시작 및 종료 시간의 형식을 지정한 다음 파일에 씁니다.

def second_to_timecode(x: float) -> str:
    hour, x = divmod(x, 3600)
    minute, x = divmod(x, 60)
    second, x = divmod(x, 1)
    millisecond = int(x * 1000.)

    return '%.2d:%.2d:%.2d,%.3d' % (hour, minute, second, millisecond)

if __name__ == "__main__":
    result = main()
    lines = []
    for count, segment in enumerate(result.get("segments")):
        # print(segment)
        start = segment.get("start")
        end = segment.get("end")
        lines.append(f"{count}")
        lines.append(f"{second_to_timecode(start)} --> {second_to_timecode(end)}")
        lines.append(segment.get("text", "").strip())
        lines.append('')
    words = '\n'.join(lines)
    with open("transcript.srt", "w") as f:
        f.write(words)


마지막으로 ffmpeg를 사용하여 동영상에 대본을 추가할 수 있습니다.

ffmpeg -i <file_name>.mp4 -vf subtitles=transcript.srt mysubtitledmovie.mp4


샘플 비디오의 경우 여기에서 출력을 볼 수 있습니다.

다음 포스팅에서는 리모콘을 이용하여 동영상을 만드는 방법에 대해 다루도록 하겠습니다.

참조



다음 기사에서는 tkinter를 사용하여 YouTube 동영상을 기록하는 간단한 데스크톱 앱을 만드는 방법을 보여 드리겠습니다. 기본 UI(파일 업로더)가 있어야 합니다.

  • 좋은 웹페이지 즐겨찾기