-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcreate_voice_profile.py
More file actions
164 lines (124 loc) · 4.78 KB
/
create_voice_profile.py
File metadata and controls
164 lines (124 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#!/usr/bin/env python3
"""
Create a voice profile from a reference video.
This extracts your voice from the specified timestamp in the reference video
and creates an embedding that can be used to identify your voice in other videos.
"""
import os
import sys
from pathlib import Path
from dotenv import load_dotenv
import yt_dlp
import numpy as np
import pickle
from pydub import AudioSegment
# Load environment variables
load_dotenv()
REFERENCE_VIDEO_URL = os.getenv('REFERENCE_VIDEO_URL', 'https://www.youtube.com/watch?v=HN_hOuyXUkc')
REFERENCE_START_TIME = os.getenv('REFERENCE_START_TIME', '0:29')
# Directories
DOWNLOADS_DIR = Path('downloads')
VOICE_PROFILES_DIR = Path('voice_profiles')
DOWNLOADS_DIR.mkdir(exist_ok=True)
VOICE_PROFILES_DIR.mkdir(exist_ok=True)
def parse_time_to_seconds(time_str):
"""Convert time string like '0:29' or '1:23:45' to seconds."""
parts = time_str.split(':')
if len(parts) == 2:
minutes, seconds = map(int, parts)
return minutes * 60 + seconds
elif len(parts) == 3:
hours, minutes, seconds = map(int, parts)
return hours * 3600 + minutes * 60 + seconds
else:
return int(parts[0])
def download_reference_video():
"""Download the reference video."""
print(f"Downloading reference video: {REFERENCE_VIDEO_URL}")
audio_path = DOWNLOADS_DIR / 'reference_video.wav'
# Check if already downloaded
if audio_path.exists():
print(f"Reference audio already exists: {audio_path}")
return audio_path
ydl_opts = {
'format': 'bestaudio/best',
'outtmpl': str(DOWNLOADS_DIR / 'reference_video.%(ext)s'),
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'wav',
}],
'quiet': False,
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
ydl.download([REFERENCE_VIDEO_URL])
if not audio_path.exists():
raise FileNotFoundError(f"Failed to download and convert reference video")
return audio_path
def extract_voice_segment(audio_path, start_time_str, duration=30):
"""
Extract a segment of audio starting from the specified time.
Duration in seconds (default 30 seconds for voice profiling).
"""
print(f"Extracting voice segment from {start_time_str} for {duration} seconds")
start_seconds = parse_time_to_seconds(start_time_str)
# Load audio using pydub
audio = AudioSegment.from_wav(str(audio_path))
# Extract segment (pydub uses milliseconds)
start_ms = start_seconds * 1000
end_ms = start_ms + (duration * 1000)
segment = audio[start_ms:end_ms]
# Convert to mono if stereo
if segment.channels > 1:
segment = segment.set_channels(1)
# Resample to 16kHz (required by resemblyzer)
segment = segment.set_frame_rate(16000)
# Save segment
segment_path = VOICE_PROFILES_DIR / 'jon_radoff_voice_segment.wav'
segment.export(str(segment_path), format='wav')
print(f"Saved voice segment to {segment_path}")
return segment_path
def create_voice_embedding(audio_path):
"""
Create a voice embedding using Resemblyzer.
This embedding can be used to identify the speaker in other audio files.
"""
print("Creating voice embedding using Resemblyzer...")
from resemblyzer import VoiceEncoder, preprocess_wav
# Load the voice encoder
encoder = VoiceEncoder()
# Load and preprocess audio
wav = preprocess_wav(audio_path)
# Generate embedding
embedding = encoder.embed_utterance(wav)
# Save embedding
profile_path = VOICE_PROFILES_DIR / 'jon_radoff_voice_profile.pkl'
with open(profile_path, 'wb') as f:
pickle.dump({
'embedding': embedding,
'name': 'Jon Radoff',
'source_video': REFERENCE_VIDEO_URL,
'timestamp': REFERENCE_START_TIME
}, f)
print(f"Voice profile saved to {profile_path}")
print(f"Embedding shape: {embedding.shape}")
return embedding
def main():
print("=" * 60)
print("Creating Voice Profile for Jon Radoff")
print("=" * 60)
print()
# Step 1: Download reference video
audio_path = download_reference_video()
# Step 2: Extract voice segment
segment_path = extract_voice_segment(audio_path, REFERENCE_START_TIME)
# Step 3: Create voice embedding
embedding = create_voice_embedding(segment_path)
print()
print("=" * 60)
print("Voice profile created successfully!")
print("=" * 60)
print(f"Profile location: {VOICE_PROFILES_DIR / 'jon_radoff_voice_profile.pkl'}")
print()
print("You can now run transcribe_channel.py to transcribe your videos")
if __name__ == '__main__':
main()