속삭임을 사용하여 YouTube 동영상을 전사하는 방법
요약
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"})
ffmpeg
는 youtube-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(파일 업로더)가 있어야 합니다.
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,
}
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"})
ffmpeg -i input.mp4 -vn output.mp3
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
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 -i <file_name>.mp4 -vf subtitles=transcript.srt mysubtitledmovie.mp4
Reference
이 문제에 관하여(속삭임을 사용하여 YouTube 동영상을 전사하는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/friendlyuser/how-to-transcribe-youtube-videos-using-whispers-3hbp텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)