Spaces:
Runtime error
Runtime error
Neal Caren
commited on
Commit
•
a507bd6
1
Parent(s):
72a5c50
Added some comments and medium model option.
Browse files
app.py
CHANGED
@@ -10,11 +10,14 @@ import tempfile
|
|
10 |
|
11 |
|
12 |
def create_download_link(val, filename, label):
|
|
|
13 |
b64 = base64.b64encode(val)
|
14 |
return f'<a href="data:application/octet-stream;base64,{b64.decode()}" download="{filename}">{label}</a>'
|
15 |
|
16 |
|
17 |
def segment(nu_speakers):
|
|
|
|
|
18 |
|
19 |
diar = Diarizer(embed_model='ecapa',cluster_method='sc')
|
20 |
segments = diar.diarize(temp_file, num_speakers=nu_speakers)
|
@@ -27,56 +30,63 @@ def segment(nu_speakers):
|
|
27 |
|
28 |
sdf['speaker'] = sdf['label'].replace(speaker_d)
|
29 |
return sdf
|
|
|
|
|
|
|
|
|
30 |
|
31 |
def audio_to_df(uploaded):
|
32 |
-
|
|
|
33 |
model = whisper.load_model(model_size)
|
34 |
result = model.transcribe(temp_file,
|
35 |
-
|
36 |
-
|
37 |
tdf = pd.DataFrame(result['segments'])
|
38 |
return tdf
|
39 |
|
40 |
-
|
41 |
-
cmd = f"ffmpeg -y -i {uploaded} -acodec pcm_s16le -ar 16000 -ac 1 {temp_file}"
|
42 |
-
subprocess.Popen(cmd, shell=True).wait()
|
43 |
|
44 |
def add_preface(row):
|
|
|
45 |
text = row['text'].replace('\n','')
|
46 |
speaker = row['speaker']
|
47 |
return f'Speaker {speaker}: {text}'
|
48 |
|
49 |
def transcribe(uploaded, nu_speakers):
|
|
|
50 |
with st.spinner(text="Converting file..."):
|
51 |
monotize('temp_audio')
|
52 |
|
|
|
53 |
audio_file = open(temp_file, 'rb')
|
54 |
audio_bytes = audio_file.read()
|
55 |
st.audio(temp_file, format='audio/wav')
|
56 |
|
|
|
57 |
with st.spinner(text=f"Transcribing using {model_size} model..."):
|
58 |
tdf = audio_to_df(uploaded)
|
|
|
59 |
with st.spinner(text="Segmenting..."):
|
60 |
sdf = segment(nu_speakers)
|
61 |
|
62 |
-
ns_list = sdf[['start','speaker']].to_dict(orient='records')
|
63 |
-
|
64 |
# Find the nearest transcript line to the start of each speaker
|
|
|
65 |
for row in ns_list:
|
66 |
input = row['start']
|
67 |
id = tdf.iloc[(tdf['start']-input).abs().argsort()[:1]]['id'].values[0]
|
68 |
tdf.loc[tdf['id'] ==id, 'speaker'] = row['speaker']
|
69 |
-
|
70 |
tdf['speaker'].fillna(method = 'ffill', inplace = True)
|
71 |
tdf['speaker'].fillna(method = 'bfill', inplace = True)
|
72 |
-
|
73 |
tdf['n1'] = tdf['speaker'] != tdf['speaker'].shift(1)
|
74 |
tdf['speach'] = tdf['n1'].cumsum()
|
75 |
-
binned_df = tdf.groupby(['speach', 'speaker'])['text'].apply('\n'.join).reset_index()
|
76 |
|
|
|
|
|
77 |
binned_df['speaker'] = binned_df['speaker'].astype(int)
|
78 |
binned_df['output'] = binned_df.apply(add_preface, axis=1)
|
79 |
|
|
|
80 |
lines = []
|
81 |
for row in binned_df['output'].values:
|
82 |
st.write(row)
|
@@ -106,7 +116,7 @@ uploaded = form.file_uploader("Choose a file")
|
|
106 |
nu_speakers = form.slider('Number of speakers in recording:', min_value=1, max_value=8, value=2, step=1)
|
107 |
models = form.selectbox(
|
108 |
'Which Whisper model?',
|
109 |
-
('Tiny (fast)', 'Base (good)', 'Small (great but slow)'), index=1)
|
110 |
translate = form.checkbox('Translate to English?')
|
111 |
submit = form.form_submit_button("Transcribe!")
|
112 |
|
@@ -118,6 +128,8 @@ if submit:
|
|
118 |
model_size ='base'
|
119 |
elif models == 'Small (great but slow)':
|
120 |
model_size = 'small'
|
|
|
|
|
121 |
|
122 |
if translate == True:
|
123 |
task = 'translate'
|
@@ -131,13 +143,18 @@ if submit:
|
|
131 |
bytes_data = uploaded.getvalue()
|
132 |
with open('temp_audio', 'wb') as outfile:
|
133 |
outfile.write(bytes_data)
|
|
|
|
|
|
|
134 |
transcript = transcribe('temp_audio', nu_speakers)
|
135 |
|
136 |
-
|
137 |
text = '\n'.join(transcript['text']).encode('utf-8')
|
138 |
download_url = create_download_link(text, 'transcript.txt', 'Download transcript as plain text.')
|
139 |
st.markdown(download_url, unsafe_allow_html=True)
|
140 |
|
|
|
|
|
141 |
download_url = create_download_link(csv, 'transcript.csv', 'Download transcript as CSV (with time codes)')
|
142 |
st.markdown(download_url, unsafe_allow_html=True)
|
143 |
tmp_dir.cleanup()
|
|
|
10 |
|
11 |
|
12 |
def create_download_link(val, filename, label):
|
13 |
+
'''Hack to have a stable download link in Streamlit'''
|
14 |
b64 = base64.b64encode(val)
|
15 |
return f'<a href="data:application/octet-stream;base64,{b64.decode()}" download="{filename}">{label}</a>'
|
16 |
|
17 |
|
18 |
def segment(nu_speakers):
|
19 |
+
'''Segment the audio using simple_diarizer.
|
20 |
+
Defaults to the speechbrain ECAPA-TDNN embeddings.'''
|
21 |
|
22 |
diar = Diarizer(embed_model='ecapa',cluster_method='sc')
|
23 |
segments = diar.diarize(temp_file, num_speakers=nu_speakers)
|
|
|
30 |
|
31 |
sdf['speaker'] = sdf['label'].replace(speaker_d)
|
32 |
return sdf
|
33 |
+
def monotize(uploaded):
|
34 |
+
'''Convert the upload file to audio file.'''
|
35 |
+
cmd = f"ffmpeg -y -i {uploaded} -acodec pcm_s16le -ar 16000 -ac 1 {temp_file}"
|
36 |
+
subprocess.Popen(cmd, shell=True).wait()
|
37 |
|
38 |
def audio_to_df(uploaded):
|
39 |
+
'''Turn the upload file in a segemented dataframe.'''
|
40 |
+
#monotize(uploaded)
|
41 |
model = whisper.load_model(model_size)
|
42 |
result = model.transcribe(temp_file,
|
43 |
+
without_timestamps=False,
|
44 |
+
task = task)
|
45 |
tdf = pd.DataFrame(result['segments'])
|
46 |
return tdf
|
47 |
|
48 |
+
|
|
|
|
|
49 |
|
50 |
def add_preface(row):
|
51 |
+
''' Add speaker prefix to transcript during transcribe().'''
|
52 |
text = row['text'].replace('\n','')
|
53 |
speaker = row['speaker']
|
54 |
return f'Speaker {speaker}: {text}'
|
55 |
|
56 |
def transcribe(uploaded, nu_speakers):
|
57 |
+
# Convert file to mono
|
58 |
with st.spinner(text="Converting file..."):
|
59 |
monotize('temp_audio')
|
60 |
|
61 |
+
# Make audio available to play in UI
|
62 |
audio_file = open(temp_file, 'rb')
|
63 |
audio_bytes = audio_file.read()
|
64 |
st.audio(temp_file, format='audio/wav')
|
65 |
|
66 |
+
# trancibe file
|
67 |
with st.spinner(text=f"Transcribing using {model_size} model..."):
|
68 |
tdf = audio_to_df(uploaded)
|
69 |
+
# segement file
|
70 |
with st.spinner(text="Segmenting..."):
|
71 |
sdf = segment(nu_speakers)
|
72 |
|
|
|
|
|
73 |
# Find the nearest transcript line to the start of each speaker
|
74 |
+
ns_list = sdf[['start','speaker']].to_dict(orient='records')
|
75 |
for row in ns_list:
|
76 |
input = row['start']
|
77 |
id = tdf.iloc[(tdf['start']-input).abs().argsort()[:1]]['id'].values[0]
|
78 |
tdf.loc[tdf['id'] ==id, 'speaker'] = row['speaker']
|
|
|
79 |
tdf['speaker'].fillna(method = 'ffill', inplace = True)
|
80 |
tdf['speaker'].fillna(method = 'bfill', inplace = True)
|
|
|
81 |
tdf['n1'] = tdf['speaker'] != tdf['speaker'].shift(1)
|
82 |
tdf['speach'] = tdf['n1'].cumsum()
|
|
|
83 |
|
84 |
+
# collaps the dataframe by speach turn.
|
85 |
+
binned_df = tdf.groupby(['speach', 'speaker'])['text'].apply('\n'.join).reset_index()
|
86 |
binned_df['speaker'] = binned_df['speaker'].astype(int)
|
87 |
binned_df['output'] = binned_df.apply(add_preface, axis=1)
|
88 |
|
89 |
+
# Display the transcript and prepare for export
|
90 |
lines = []
|
91 |
for row in binned_df['output'].values:
|
92 |
st.write(row)
|
|
|
116 |
nu_speakers = form.slider('Number of speakers in recording:', min_value=1, max_value=8, value=2, step=1)
|
117 |
models = form.selectbox(
|
118 |
'Which Whisper model?',
|
119 |
+
('Tiny (fast)', 'Base (good)', 'Small (great but slow)', 'Medium (greater but slower)'), index=1)
|
120 |
translate = form.checkbox('Translate to English?')
|
121 |
submit = form.form_submit_button("Transcribe!")
|
122 |
|
|
|
128 |
model_size ='base'
|
129 |
elif models == 'Small (great but slow)':
|
130 |
model_size = 'small'
|
131 |
+
elif models == 'Medium (greater but slower)':
|
132 |
+
model_size = 'medium'
|
133 |
|
134 |
if translate == True:
|
135 |
task = 'translate'
|
|
|
143 |
bytes_data = uploaded.getvalue()
|
144 |
with open('temp_audio', 'wb') as outfile:
|
145 |
outfile.write(bytes_data)
|
146 |
+
|
147 |
+
|
148 |
+
# Transcribe/translate and segment
|
149 |
transcript = transcribe('temp_audio', nu_speakers)
|
150 |
|
151 |
+
# Prepare text file for export.
|
152 |
text = '\n'.join(transcript['text']).encode('utf-8')
|
153 |
download_url = create_download_link(text, 'transcript.txt', 'Download transcript as plain text.')
|
154 |
st.markdown(download_url, unsafe_allow_html=True)
|
155 |
|
156 |
+
# prepare CSV file for expport.
|
157 |
+
csv = transcript['df'].to_csv( float_format='%.2f', index=False).encode('utf-8')
|
158 |
download_url = create_download_link(csv, 'transcript.csv', 'Download transcript as CSV (with time codes)')
|
159 |
st.markdown(download_url, unsafe_allow_html=True)
|
160 |
tmp_dir.cleanup()
|