hammamiomar commited on
Commit
da9fc8c
·
1 Parent(s): cd0c5d8
Files changed (10) hide show
  1. .DS_Store +0 -0
  2. .gitignore +8 -0
  3. app.py +57 -2
  4. downloader.py +75 -0
  5. movieCompile.py +61 -0
  6. moviecompile.ipynb +422 -0
  7. requirements.txt +9 -0
  8. speech2text.py +25 -0
  9. text2speech.py +62 -0
  10. text2text.py +52 -0
.DS_Store ADDED
Binary file (6.15 kB). View file
 
.gitignore ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ playlist10/
2
+ videos/
3
+ transcriptions/
4
+ captions/
5
+ translated/
6
+ audio/
7
+ output/
8
+ __pycache__
app.py CHANGED
@@ -1,3 +1,58 @@
1
  import streamlit as st
2
- x = st.slider('select a value')
3
- st.write(x,'squared is',x*x)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
+ import pandas as pd
3
+ import downloader
4
+ import speech2text
5
+ import text2speech
6
+ import text2text
7
+ import movieCompile
8
+ import os
9
+
10
+ st.title("Translate English Youtube Videos to German")
11
+ st.write("Input a youtube video URL, and if you wanna do another one click the reset button first.")
12
+
13
+ # Add a text field for inputting the YouTube video URL
14
+ youtube_url = st.text_input("YouTube URL")
15
+ if st.button("Submit"):
16
+ with st.status("Downloading video and captions")as status:
17
+ downloader.download_video(youtube_url, "videos", "captions")
18
+ status.update(label="Downloaded video and captions")
19
+ status.update(label="Transcribing video")
20
+ speech2text.transcribeAndSaveFolder("videos", "transcriptions")
21
+ status.update(label="Transcribed video")
22
+ status.update(label="Translating video")
23
+ text2text.translateTsvFolder("transcriptions", "translated")
24
+ status.update(label="Translated video")
25
+ status.update(label="Creating audio")
26
+
27
+ englishSubPath = os.path.join("transcriptions", f"{os.listdir('transcriptions')[0]}")
28
+ germanSubPath = os.path.join("translated", f"{os.listdir('translated')[0]}")
29
+ englishSub=pd.read_csv(englishSubPath,sep="\t")
30
+ germanSub=pd.read_csv(germanSubPath,sep="\t")
31
+
32
+ df=pd.merge(englishSub,germanSub,on=['start','end'],how='inner')
33
+ df['start']=df['start']/1000
34
+ df['end']=df['end']/1000
35
+ df.rename(columns={'text_x':'English','text_y':'German'},inplace=True)
36
+ text2speech.createAudioFolder("translated", "audio")
37
+ status.update(label="Created audio")
38
+ status.update(label="Creating video")
39
+ movieCompile.compileVideo("videos", "audio", "translated", "output")
40
+ status.update(label="Created video")
41
+
42
+ st.dataframe(df)
43
+ st.video("output/output_subtitled.mp4")
44
+
45
+
46
+ resetButton = st.button("Reset")
47
+ if resetButton:
48
+ os.system("rm -rf videos")
49
+ os.system("rm -rf captions")
50
+ os.system("rm -rf transcriptions")
51
+ os.system("rm -rf translated")
52
+ os.system("rm -rf audio")
53
+ os.system("rm -rf output")
54
+
55
+
56
+
57
+
58
+
downloader.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import argparse
3
+ from pytube import YouTube, Playlist
4
+ import json
5
+ # Credit: chatgpt assisted
6
+ def download_video(url, video_folder, caption_folder):
7
+ # Create video and caption folders if they don't exist
8
+ os.makedirs(video_folder, exist_ok=True)
9
+ os.makedirs(caption_folder, exist_ok=True)
10
+
11
+ # Initialize the YouTube object
12
+ yt = YouTube(url)
13
+
14
+ # Download the video
15
+
16
+ try:
17
+ video = yt.streams.get_highest_resolution()
18
+
19
+ except:
20
+ print("Age-restricted video. Skipping.")
21
+ return 1
22
+
23
+ video.download(output_path=video_folder,filename=yt.video_id+".mp4")
24
+ # Loop through available closed captions
25
+ for caption in yt.captions:
26
+ caption2=yt.captions.get_by_language_code(caption.code).json_captions
27
+ os.makedirs(os.path.join(caption_folder, yt.video_id), exist_ok=True)
28
+ caption_file = os.path.join(caption_folder, f"{yt.video_id}/{caption.code}.json")
29
+ with open(caption_file, 'w') as json_file:
30
+ json.dump(caption2, json_file)
31
+ return 0
32
+
33
+ def download_playlist(playlist_url, num_videos, video_folder, caption_folder):
34
+ # Create output folder if it doesn't exist
35
+ os.makedirs(video_folder, exist_ok=True)
36
+ os.makedirs(caption_folder, exist_ok=True)
37
+
38
+ # Initialize the playlist object
39
+ playlist = Playlist(playlist_url)
40
+
41
+ # Download each video in the playlist
42
+ iterations = 0
43
+ extraIteration = False
44
+ counter=0
45
+
46
+ while iterations < num_videos or extraIteration:
47
+ video = playlist.videos[iterations]
48
+ video_url = video.watch_url
49
+ skipCheck = download_video(video_url, video_folder, caption_folder)
50
+
51
+ if skipCheck == 1:
52
+ iterations += 1
53
+ extraIteration = True
54
+ else:
55
+ iterations += 1
56
+ counter+=1
57
+ if counter == num_videos:
58
+ extraIteration = False
59
+
60
+ if __name__ == "__main__":
61
+ parser = argparse.ArgumentParser(description="Pytube Video and Caption Downloader")
62
+ parser.add_argument("url", help="URL of the video to download")
63
+ parser.add_argument("video_folder", help="Folder to save downloaded videos")
64
+ parser.add_argument("caption_folder", help="Folder to save downloaded captions")
65
+ parser.add_argument("--playlist", help="URL of the playlist to download")
66
+ parser.add_argument("--num_videos", type=int, default=1, help="Number of videos to download from the playlist")
67
+ parser.add_argument("--output_folder", default="downloads", help="Folder to save downloaded playlist videos")
68
+
69
+ args = parser.parse_args()
70
+
71
+ if args.playlist:
72
+ download_playlist(args.playlist, args.num_videos, args.output_folder)
73
+ else:
74
+ download_video(args.url, args.video_folder, args.caption_folder)
75
+
movieCompile.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import re
3
+ import pandas as pd
4
+
5
+ import os
6
+ #credit to chatgpt for alot of help
7
+
8
+ def tsv_to_srt(input_file, output_file):
9
+ df = pd.read_csv(input_file, sep='\t')
10
+
11
+ with open(output_file, 'w', encoding='utf-8') as srt_file:
12
+ for index, row in df.iterrows():
13
+ start_time = row['start'] / 1000.0
14
+ end_time = row['end'] / 1000.0
15
+ text = row['text']
16
+
17
+ srt_file.write(f"{index + 1}\n")
18
+ srt_file.write(f"{convert_to_srt_time_format(start_time)} --> {convert_to_srt_time_format(end_time)}\n")
19
+ srt_file.write(f"{text}\n\n")
20
+
21
+ def convert_to_srt_time_format(seconds):
22
+ hours, remainder = divmod(seconds, 3600)
23
+ minutes, seconds = divmod(remainder, 60)
24
+ milliseconds = int((seconds - int(seconds)) * 1000)
25
+
26
+ return f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d},{milliseconds:03d}"
27
+
28
+ def replace_audio_and_add_subtitles(input_video, input_audio, output_video, subtitles_file):
29
+ # Replace audio
30
+ replace_audio_command = [
31
+ 'ffmpeg',
32
+ '-i', input_video,
33
+ '-i', input_audio,
34
+ '-c:v', 'copy',
35
+ '-c:a', 'aac',
36
+ '-strict', 'experimental',
37
+ '-map', '0:v:0',
38
+ '-map', '1:a:0',
39
+ '-max_muxing_queue_size', '9999',
40
+
41
+ output_video
42
+ ]
43
+ subprocess.run(replace_audio_command)
44
+
45
+ # Add subtitles
46
+ add_subtitles_command = [
47
+ 'ffmpeg',
48
+ '-i', output_video,
49
+ '-vf', f'subtitles={subtitles_file}',
50
+ output_video[:-4] + '_subtitled.mp4' # Output file with subtitles
51
+ ]
52
+ subprocess.run(add_subtitles_command)
53
+
54
+ def compileVideo(videoFolder,audioFolder,captionFolder,savepath):
55
+ audiopath =os.path.join(audioFolder,os.listdir(audioFolder)[0])
56
+ videopath = os.path.join(videoFolder,os.listdir(videoFolder)[0])
57
+ captionpath = os.path.join(captionFolder,os.listdir(captionFolder)[0])
58
+ os.makedirs(savepath,exist_ok=True)
59
+
60
+ tsv_to_srt(captionpath, os.path.join(savepath, 'subtitles.srt'))
61
+ replace_audio_and_add_subtitles(videopath, audiopath, os.path.join(savepath, 'output.mp4'), os.path.join(savepath, 'subtitles.srt'))
moviecompile.ipynb ADDED
@@ -0,0 +1,422 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "metadata": {},
7
+ "outputs": [],
8
+ "source": [
9
+ "from moviepy.editor import VideoFileClip, AudioFileClip, TextClip, CompositeVideoClip\n",
10
+ "from moviepy.video.io.VideoFileClip import VideoFileClip\n",
11
+ "import pandas as pd\n",
12
+ "from math import floor\n",
13
+ "import speech2text\n",
14
+ "\n",
15
+ "import os"
16
+ ]
17
+ },
18
+ {
19
+ "cell_type": "code",
20
+ "execution_count": 6,
21
+ "metadata": {},
22
+ "outputs": [],
23
+ "source": [
24
+ "def compileVideo(videoFolder,audioFolder,captionFolder,savepath):\n",
25
+ " audiopath =os.path.join(audioFolder,os.listdir(audioFolder)[0])\n",
26
+ " videopath = os.path.join(videoFolder,os.listdir(videoFolder)[0])\n",
27
+ " captionpath = os.path.join(captionFolder,os.listdir(captionFolder)[0])\n",
28
+ " os.makedirs(savepath,exist_ok=True)\n",
29
+ "\n",
30
+ " video=VideoFileClip(videopath)\n",
31
+ " video=video.set_duration(video.duration)\n",
32
+ " audio=AudioFileClip(audiopath)\n",
33
+ "\n",
34
+ " video=video.set_audio(audio)\n",
35
+ "\n",
36
+ " captions=pd.read_csv(captionpath,delimiter='\\t')\n",
37
+ " captions['start'] /= 1000\n",
38
+ " captions['end'] /= 1000\n",
39
+ "\n",
40
+ " captioned_clips=[]\n",
41
+ " for index,row in captions.iterrows():\n",
42
+ " text=row['text']\n",
43
+ " start=row['start']\n",
44
+ " end=row['end']\n",
45
+ "\n",
46
+ " # Create a TextClip with the caption\n",
47
+ " caption_clip = TextClip(text, fontsize=20, color='white', bg_color='black')\n",
48
+ "\n",
49
+ " # Add the caption to the video at the specified time\n",
50
+ " captioned_clip = CompositeVideoClip([video.subclip(start, end),\\\n",
51
+ " caption_clip.set_pos(('center', 'bottom'))])\n",
52
+ "\n",
53
+ " # Append the captioned clip to the list\n",
54
+ " captioned_clips.append(captioned_clip)\n",
55
+ "\n",
56
+ " # Concatenate all captioned clips\n",
57
+ " final_clip = CompositeVideoClip(captioned_clips)\n",
58
+ " final_clip = final_clip.set_duration(video.duration)\n",
59
+ "\n",
60
+ " # Write the final video with captions\n",
61
+ " final_clip.write_videofile(os.path.join(savepath,\"output.mp4\"), codec='libx264', audio_codec='aac',threads=8)"
62
+ ]
63
+ },
64
+ {
65
+ "cell_type": "code",
66
+ "execution_count": 29,
67
+ "metadata": {},
68
+ "outputs": [],
69
+ "source": [
70
+ "import subprocess\n",
71
+ "import tempfile\n",
72
+ "import re\n",
73
+ "def remove_weird_characters(text):\n",
74
+ " # Define the regular expression to match unwanted characters\n",
75
+ " pattern = r'[^a-zA-Z0-9 ]'\n",
76
+ " # Use str.replace() to replace matched characters with an empty string\n",
77
+ " cleaned_text = ''.join(re.sub(pattern, '', str(text)))\n",
78
+ " return cleaned_text\n",
79
+ "def compileVideo(videoFolder,audioFolder,captionFolder,savepath):\n",
80
+ " audiopath =os.path.join(audioFolder,os.listdir(audioFolder)[0])\n",
81
+ " videopath = os.path.join(videoFolder,os.listdir(videoFolder)[0])\n",
82
+ " captionpath = os.path.join(captionFolder,os.listdir(captionFolder)[0])\n",
83
+ " os.makedirs(savepath,exist_ok=True)\n",
84
+ "\n",
85
+ " \n",
86
+ "\n",
87
+ " captions=pd.read_csv(captionpath,delimiter='\\t')\n",
88
+ " captions['start'] /= 1000\n",
89
+ " captions['end'] /= 1000\n",
90
+ " captions['text'] = captions['text'].apply(remove_weird_characters)\n",
91
+ "\n",
92
+ " temp_subtitles_file_path = tempfile.mktemp(suffix='.srt')\n",
93
+ " temp_subtitles_file = open(temp_subtitles_file_path, 'w')\n",
94
+ "\n",
95
+ " for index,row in captions.iterrows():\n",
96
+ " text=row['text']\n",
97
+ " start=row['start']\n",
98
+ " end=row['end']\n",
99
+ " temp_subtitles_file.write(f\"{index + 1}\\n{start} --> {end}\\n{text}\\n\\n\")\n",
100
+ " temp_subtitles_file.close()\n",
101
+ "\n",
102
+ "# Run ffmpeg command to replace audio and add captions\n",
103
+ " ffmpeg_command = [\n",
104
+ " 'ffmpeg',\n",
105
+ " '-i', videopath,\n",
106
+ " '-i', audiopath,\n",
107
+ " '-vf', f\"subtitles={temp_subtitles_file_path}:force_style='Fontsize=20,PrimaryColour=&HFFFFFF,BackColour=&H000000'\",\n",
108
+ " '-c:v', 'libx264',\n",
109
+ " '-c:a', 'aac',\n",
110
+ " '-strict', 'experimental',\n",
111
+ " os.path.join(savepath,\"output.mp4\")\n",
112
+ "]\n",
113
+ "\n",
114
+ "\n",
115
+ " # Execute the ffmpeg command using subprocess\n",
116
+ " subprocess.run(ffmpeg_command)\n",
117
+ " os.remove(temp_subtitles_file.name)"
118
+ ]
119
+ },
120
+ {
121
+ "cell_type": "code",
122
+ "execution_count": 31,
123
+ "metadata": {},
124
+ "outputs": [
125
+ {
126
+ "name": "stderr",
127
+ "output_type": "stream",
128
+ "text": [
129
+ "ffmpeg version 6.0 Copyright (c) 2000-2023 the FFmpeg developers\n",
130
+ " built with clang version 15.0.7\n",
131
+ " configuration: --prefix=/Users/runner/miniforge3/conda-bld/ffmpeg_1696213807101/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_pl --cc=arm64-apple-darwin20.0.0-clang --cxx=arm64-apple-darwin20.0.0-clang++ --nm=arm64-apple-darwin20.0.0-nm --ar=arm64-apple-darwin20.0.0-ar --disable-doc --disable-openssl --enable-demuxer=dash --enable-hardcoded-tables --enable-libfreetype --enable-libfontconfig --enable-libopenh264 --enable-libdav1d --enable-cross-compile --arch=arm64 --target-os=darwin --cross-prefix=arm64-apple-darwin20.0.0- --host-cc=/Users/runner/miniforge3/conda-bld/ffmpeg_1696213807101/_build_env/bin/x86_64-apple-darwin13.4.0-clang --enable-neon --enable-gnutls --enable-libmp3lame --enable-libvpx --enable-libass --enable-pthreads --enable-gpl --enable-libx264 --enable-libx265 --enable-libaom --enable-libsvtav1 --enable-libxml2 --enable-pic --enable-shared --disable-static --enable-version3 --enable-zlib --enable-libopus --pkg-config=/Users/runner/miniforge3/conda-bld/ffmpeg_1696213807101/_build_env/bin/pkg-config\n",
132
+ " libavutil 58. 2.100 / 58. 2.100\n",
133
+ " libavcodec 60. 3.100 / 60. 3.100\n",
134
+ " libavformat 60. 3.100 / 60. 3.100\n",
135
+ " libavdevice 60. 1.100 / 60. 1.100\n",
136
+ " libavfilter 9. 3.100 / 9. 3.100\n",
137
+ " libswscale 7. 1.100 / 7. 1.100\n",
138
+ " libswresample 4. 10.100 / 4. 10.100\n",
139
+ " libpostproc 57. 1.100 / 57. 1.100\n",
140
+ "Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'videos/qrvK_KuIeJk.mp4':\n",
141
+ " Metadata:\n",
142
+ " major_brand : mp42\n",
143
+ " minor_version : 0\n",
144
+ " compatible_brands: isommp42\n",
145
+ " creation_time : 2023-10-09T21:47:52.000000Z\n",
146
+ " Duration: 00:13:11.89, start: 0.000000, bitrate: 347 kb/s\n",
147
+ " Stream #0:0[0x1](und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1280x720 [SAR 1:1 DAR 16:9], 215 kb/s, 29.97 fps, 29.97 tbr, 30k tbn (default)\n",
148
+ " Metadata:\n",
149
+ " creation_time : 2023-10-09T21:47:52.000000Z\n",
150
+ " handler_name : ISO Media file produced by Google Inc. Created on: 10/09/2023.\n",
151
+ " vendor_id : [0][0][0][0]\n",
152
+ " Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 127 kb/s (default)\n",
153
+ " Metadata:\n",
154
+ " creation_time : 2023-10-09T21:47:52.000000Z\n",
155
+ " handler_name : ISO Media file produced by Google Inc. Created on: 10/09/2023.\n",
156
+ " vendor_id : [0][0][0][0]\n",
157
+ "Guessed Channel Layout for Input Stream #1.0 : mono\n",
158
+ "Input #1, wav, from 'audio/merged_audio.wav':\n",
159
+ " Duration: 00:13:05.89, bitrate: 352 kb/s\n",
160
+ " Stream #1:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 22050 Hz, 1 channels, s16, 352 kb/s\n",
161
+ "Stream mapping:\n",
162
+ " Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))\n",
163
+ " Stream #0:1 -> #0:1 (aac (native) -> aac (native))\n",
164
+ "Press [q] to stop, [?] for help\n",
165
+ "[Parsed_subtitles_0 @ 0x125f05de0] libass API version: 0x1701000\n",
166
+ "[Parsed_subtitles_0 @ 0x125f05de0] libass source: tarball: 0.17.1\n",
167
+ "[Parsed_subtitles_0 @ 0x125f05de0] Shaper: FriBidi 1.0.10 (SIMPLE) HarfBuzz-ng 8.2.1 (COMPLEX)\n",
168
+ "[Parsed_subtitles_0 @ 0x125f05de0] Unable to open /var/folders/1t/_whn9tx16w5f68951h3wrfyr0000gn/T/tmpgueqw446.srt\n",
169
+ "[AVFilterGraph @ 0x125f05af0] Error initializing filters\n",
170
+ "Error reinitializing filters!\n",
171
+ "Failed to inject frame into filter network: Invalid data found when processing input\n",
172
+ "Error while processing the decoded data for stream #0:0\n",
173
+ "Conversion failed!\n"
174
+ ]
175
+ }
176
+ ],
177
+ "source": [
178
+ "compileVideo('videos','audio','translated','output')"
179
+ ]
180
+ },
181
+ {
182
+ "cell_type": "code",
183
+ "execution_count": 52,
184
+ "metadata": {},
185
+ "outputs": [
186
+ {
187
+ "name": "stderr",
188
+ "output_type": "stream",
189
+ "text": [
190
+ "ffmpeg version 6.0 Copyright (c) 2000-2023 the FFmpeg developers\n",
191
+ " built with clang version 15.0.7\n",
192
+ " configuration: --prefix=/Users/runner/miniforge3/conda-bld/ffmpeg_1696213807101/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_pl --cc=arm64-apple-darwin20.0.0-clang --cxx=arm64-apple-darwin20.0.0-clang++ --nm=arm64-apple-darwin20.0.0-nm --ar=arm64-apple-darwin20.0.0-ar --disable-doc --disable-openssl --enable-demuxer=dash --enable-hardcoded-tables --enable-libfreetype --enable-libfontconfig --enable-libopenh264 --enable-libdav1d --enable-cross-compile --arch=arm64 --target-os=darwin --cross-prefix=arm64-apple-darwin20.0.0- --host-cc=/Users/runner/miniforge3/conda-bld/ffmpeg_1696213807101/_build_env/bin/x86_64-apple-darwin13.4.0-clang --enable-neon --enable-gnutls --enable-libmp3lame --enable-libvpx --enable-libass --enable-pthreads --enable-gpl --enable-libx264 --enable-libx265 --enable-libaom --enable-libsvtav1 --enable-libxml2 --enable-pic --enable-shared --disable-static --enable-version3 --enable-zlib --enable-libopus --pkg-config=/Users/runner/miniforge3/conda-bld/ffmpeg_1696213807101/_build_env/bin/pkg-config\n",
193
+ " libavutil 58. 2.100 / 58. 2.100\n",
194
+ " libavcodec 60. 3.100 / 60. 3.100\n",
195
+ " libavformat 60. 3.100 / 60. 3.100\n",
196
+ " libavdevice 60. 1.100 / 60. 1.100\n",
197
+ " libavfilter 9. 3.100 / 9. 3.100\n",
198
+ " libswscale 7. 1.100 / 7. 1.100\n",
199
+ " libswresample 4. 10.100 / 4. 10.100\n",
200
+ " libpostproc 57. 1.100 / 57. 1.100\n",
201
+ "Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'videos/qrvK_KuIeJk.mp4':\n",
202
+ " Metadata:\n",
203
+ " major_brand : mp42\n",
204
+ " minor_version : 0\n",
205
+ " compatible_brands: isommp42\n",
206
+ " creation_time : 2023-10-09T21:47:52.000000Z\n",
207
+ " Duration: 00:13:11.89, start: 0.000000, bitrate: 347 kb/s\n",
208
+ " Stream #0:0[0x1](und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1280x720 [SAR 1:1 DAR 16:9], 215 kb/s, 29.97 fps, 29.97 tbr, 30k tbn (default)\n",
209
+ " Metadata:\n",
210
+ " creation_time : 2023-10-09T21:47:52.000000Z\n",
211
+ " handler_name : ISO Media file produced by Google Inc. Created on: 10/09/2023.\n",
212
+ " vendor_id : [0][0][0][0]\n",
213
+ " Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 127 kb/s (default)\n",
214
+ " Metadata:\n",
215
+ " creation_time : 2023-10-09T21:47:52.000000Z\n",
216
+ " handler_name : ISO Media file produced by Google Inc. Created on: 10/09/2023.\n",
217
+ " vendor_id : [0][0][0][0]\n",
218
+ "Guessed Channel Layout for Input Stream #1.0 : mono\n",
219
+ "Input #1, wav, from 'audio/merged_audio.wav':\n",
220
+ " Duration: 00:13:05.89, bitrate: 352 kb/s\n",
221
+ " Stream #1:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 22050 Hz, 1 channels, s16, 352 kb/s\n",
222
+ "Stream mapping:\n",
223
+ " Stream #0:0 -> #0:0 (copy)\n",
224
+ " Stream #1:0 -> #0:1 (pcm_s16le (native) -> aac (native))\n",
225
+ "Press [q] to stop, [?] for help\n",
226
+ "Output #0, mp4, to 'output/output_video.mp4':\n",
227
+ " Metadata:\n",
228
+ " major_brand : mp42\n",
229
+ " minor_version : 0\n",
230
+ " compatible_brands: isommp42\n",
231
+ " encoder : Lavf60.3.100\n",
232
+ " Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1280x720 [SAR 1:1 DAR 16:9], q=2-31, 215 kb/s, 29.97 fps, 29.97 tbr, 30k tbn (default)\n",
233
+ " Metadata:\n",
234
+ " creation_time : 2023-10-09T21:47:52.000000Z\n",
235
+ " handler_name : ISO Media file produced by Google Inc. Created on: 10/09/2023.\n",
236
+ " vendor_id : [0][0][0][0]\n",
237
+ " Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 22050 Hz, mono, fltp, 69 kb/s\n",
238
+ " Metadata:\n",
239
+ " encoder : Lavc60.3.100 aac\n",
240
+ "frame=23733 fps=4178 q=-1.0 Lsize= 27885kB time=00:13:11.82 bitrate= 288.5kbits/s speed= 139x \n",
241
+ "video:20816kB audio:6477kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 2.167844%\n",
242
+ "[aac @ 0x152709120] Qavg: 12239.573\n",
243
+ "ffmpeg version 6.0 Copyright (c) 2000-2023 the FFmpeg developers\n",
244
+ " built with clang version 15.0.7\n",
245
+ " configuration: --prefix=/Users/runner/miniforge3/conda-bld/ffmpeg_1696213807101/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_pl --cc=arm64-apple-darwin20.0.0-clang --cxx=arm64-apple-darwin20.0.0-clang++ --nm=arm64-apple-darwin20.0.0-nm --ar=arm64-apple-darwin20.0.0-ar --disable-doc --disable-openssl --enable-demuxer=dash --enable-hardcoded-tables --enable-libfreetype --enable-libfontconfig --enable-libopenh264 --enable-libdav1d --enable-cross-compile --arch=arm64 --target-os=darwin --cross-prefix=arm64-apple-darwin20.0.0- --host-cc=/Users/runner/miniforge3/conda-bld/ffmpeg_1696213807101/_build_env/bin/x86_64-apple-darwin13.4.0-clang --enable-neon --enable-gnutls --enable-libmp3lame --enable-libvpx --enable-libass --enable-pthreads --enable-gpl --enable-libx264 --enable-libx265 --enable-libaom --enable-libsvtav1 --enable-libxml2 --enable-pic --enable-shared --disable-static --enable-version3 --enable-zlib --enable-libopus --pkg-config=/Users/runner/miniforge3/conda-bld/ffmpeg_1696213807101/_build_env/bin/pkg-config\n",
246
+ " libavutil 58. 2.100 / 58. 2.100\n",
247
+ " libavcodec 60. 3.100 / 60. 3.100\n",
248
+ " libavformat 60. 3.100 / 60. 3.100\n",
249
+ " libavdevice 60. 1.100 / 60. 1.100\n",
250
+ " libavfilter 9. 3.100 / 9. 3.100\n",
251
+ " libswscale 7. 1.100 / 7. 1.100\n",
252
+ " libswresample 4. 10.100 / 4. 10.100\n",
253
+ " libpostproc 57. 1.100 / 57. 1.100\n",
254
+ "Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'output/output_video.mp4':\n",
255
+ " Metadata:\n",
256
+ " major_brand : isom\n",
257
+ " minor_version : 512\n",
258
+ " compatible_brands: isomiso2avc1mp41\n",
259
+ " encoder : Lavf60.3.100\n",
260
+ " Duration: 00:13:11.89, start: 0.000000, bitrate: 288 kb/s\n",
261
+ " Stream #0:0[0x1](und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1280x720 [SAR 1:1 DAR 16:9], 215 kb/s, 29.97 fps, 29.97 tbr, 30k tbn (default)\n",
262
+ " Metadata:\n",
263
+ " handler_name : ISO Media file produced by Google Inc. Created on: 10/09/2023.\n",
264
+ " vendor_id : [0][0][0][0]\n",
265
+ " Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 22050 Hz, mono, fltp, 67 kb/s (default)\n",
266
+ " Metadata:\n",
267
+ " handler_name : SoundHandler\n",
268
+ " vendor_id : [0][0][0][0]\n",
269
+ "Stream mapping:\n",
270
+ " Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))\n",
271
+ " Stream #0:1 -> #0:1 (aac (native) -> aac (native))\n",
272
+ "Press [q] to stop, [?] for help\n",
273
+ "[Parsed_subtitles_0 @ 0x125807250] libass API version: 0x1701000\n",
274
+ "[Parsed_subtitles_0 @ 0x125807250] libass source: tarball: 0.17.1\n",
275
+ "[Parsed_subtitles_0 @ 0x125807250] Shaper: FriBidi 1.0.10 (SIMPLE) HarfBuzz-ng 8.2.1 (COMPLEX)\n",
276
+ "[Parsed_subtitles_0 @ 0x125807250] Using font provider coretext\n",
277
+ "[Parsed_subtitles_0 @ 0x125807250] fontselect: (Arial, 400, 0) -> /System/Library/Fonts/Supplemental/Arial.ttf, -1, ArialMT\n",
278
+ "[libx264 @ 0x123f39fc0] using SAR=1/1\n",
279
+ "[libx264 @ 0x123f39fc0] using cpu capabilities: ARMv8 NEON\n",
280
+ "[libx264 @ 0x123f39fc0] profile High, level 3.1, 4:2:0, 8-bit\n",
281
+ "[libx264 @ 0x123f39fc0] 264 - core 164 r3095 baee400 - H.264/MPEG-4 AVC codec - Copyleft 2003-2022 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=15 lookahead_threads=2 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00\n",
282
+ "Output #0, mp4, to 'output/output_video_subtitled.mp4':\n",
283
+ " Metadata:\n",
284
+ " major_brand : isom\n",
285
+ " minor_version : 512\n",
286
+ " compatible_brands: isomiso2avc1mp41\n",
287
+ " encoder : Lavf60.3.100\n",
288
+ " Stream #0:0(und): Video: h264 (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1280x720 [SAR 1:1 DAR 16:9], q=2-31, 29.97 fps, 30k tbn (default)\n",
289
+ " Metadata:\n",
290
+ " handler_name : ISO Media file produced by Google Inc. Created on: 10/09/2023.\n",
291
+ " vendor_id : [0][0][0][0]\n",
292
+ " encoder : Lavc60.3.100 libx264\n",
293
+ " Side data:\n",
294
+ " cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A\n",
295
+ " Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 22050 Hz, mono, fltp, 69 kb/s (default)\n",
296
+ " Metadata:\n",
297
+ " handler_name : SoundHandler\n",
298
+ " vendor_id : [0][0][0][0]\n",
299
+ " encoder : Lavc60.3.100 aac\n",
300
+ "frame=23733 fps=436 q=-1.0 Lsize= 58121kB time=00:13:11.79 bitrate= 601.3kbits/s speed=14.6x \n",
301
+ "video:51102kB audio:6407kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 1.064471%\n",
302
+ "[libx264 @ 0x123f39fc0] frame I:106 Avg QP:15.86 size: 43407\n",
303
+ "[libx264 @ 0x123f39fc0] frame P:7968 Avg QP:20.48 size: 4366\n",
304
+ "[libx264 @ 0x123f39fc0] frame B:15659 Avg QP:22.31 size: 826\n",
305
+ "[libx264 @ 0x123f39fc0] consecutive B-frames: 0.9% 22.0% 34.2% 43.0%\n",
306
+ "[libx264 @ 0x123f39fc0] mb I I16..4: 25.1% 53.0% 21.9%\n",
307
+ "[libx264 @ 0x123f39fc0] mb P I16..4: 1.9% 3.3% 0.4% P16..4: 21.2% 3.8% 1.3% 0.0% 0.0% skip:68.1%\n",
308
+ "[libx264 @ 0x123f39fc0] mb B I16..4: 0.1% 0.2% 0.0% B16..8: 15.4% 0.5% 0.1% direct: 0.1% skip:83.7% L0:40.5% L1:57.9% BI: 1.5%\n",
309
+ "[libx264 @ 0x123f39fc0] 8x8 transform intra:57.0% inter:79.7%\n",
310
+ "[libx264 @ 0x123f39fc0] coded y,uvDC,uvAC intra: 32.1% 26.2% 6.0% inter: 1.7% 1.1% 0.0%\n",
311
+ "[libx264 @ 0x123f39fc0] i16 v,h,dc,p: 33% 25% 10% 31%\n",
312
+ "[libx264 @ 0x123f39fc0] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 31% 21% 30% 2% 3% 3% 3% 3% 3%\n",
313
+ "[libx264 @ 0x123f39fc0] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 31% 25% 15% 4% 6% 5% 6% 4% 4%\n",
314
+ "[libx264 @ 0x123f39fc0] i8c dc,h,v,p: 69% 15% 13% 3%\n",
315
+ "[libx264 @ 0x123f39fc0] Weighted P-Frames: Y:1.1% UV:0.4%\n",
316
+ "[libx264 @ 0x123f39fc0] ref P L0: 67.2% 12.6% 14.7% 5.5% 0.0%\n",
317
+ "[libx264 @ 0x123f39fc0] ref B L0: 81.9% 15.7% 2.4%\n",
318
+ "[libx264 @ 0x123f39fc0] ref B L1: 97.7% 2.3%\n",
319
+ "[libx264 @ 0x123f39fc0] kb/s:528.63\n",
320
+ "[aac @ 0x123f38490] Qavg: 12473.627\n"
321
+ ]
322
+ }
323
+ ],
324
+ "source": [
325
+ "def replace_audio_and_add_subtitles(input_video, input_audio, output_video, subtitles_file):\n",
326
+ " # Replace audio\n",
327
+ " replace_audio_command = [\n",
328
+ " 'ffmpeg',\n",
329
+ " '-i', input_video,\n",
330
+ " '-i', input_audio,\n",
331
+ " '-c:v', 'copy',\n",
332
+ " '-c:a', 'aac',\n",
333
+ " '-strict', 'experimental',\n",
334
+ " '-map', '0:v:0',\n",
335
+ " '-map', '1:a:0',\n",
336
+ " '-max_muxing_queue_size', '9999',\n",
337
+ "\n",
338
+ " output_video\n",
339
+ " ]\n",
340
+ " subprocess.run(replace_audio_command)\n",
341
+ "\n",
342
+ " # Add subtitles\n",
343
+ " add_subtitles_command = [\n",
344
+ " 'ffmpeg',\n",
345
+ " '-i', output_video,\n",
346
+ " '-vf', f'subtitles={subtitles_file}', \n",
347
+ " output_video[:-4] + '_subtitled.mp4' # Output file with subtitles\n",
348
+ " ]\n",
349
+ " subprocess.run(add_subtitles_command)\n",
350
+ "\n",
351
+ "input_video = 'videos/qrvK_KuIeJk.mp4'\n",
352
+ "input_audio = 'audio/merged_audio.wav'\n",
353
+ "output_video = 'output/output_video.mp4'\n",
354
+ "subtitles_file = 'translated/German_qrvK_KuIeJk.srt'\n",
355
+ "\n",
356
+ "replace_audio_and_add_subtitles(input_video, input_audio, output_video, subtitles_file)"
357
+ ]
358
+ },
359
+ {
360
+ "cell_type": "code",
361
+ "execution_count": 51,
362
+ "metadata": {},
363
+ "outputs": [],
364
+ "source": [
365
+ "def tsv_to_srt(input_file, output_file):\n",
366
+ " df = pd.read_csv(input_file, sep='\\t')\n",
367
+ " \n",
368
+ " with open(output_file, 'w', encoding='utf-8') as srt_file:\n",
369
+ " for index, row in df.iterrows():\n",
370
+ " start_time = row['start'] / 1000.0\n",
371
+ " end_time = row['end'] / 1000.0\n",
372
+ " text = row['text']\n",
373
+ "\n",
374
+ " srt_file.write(f\"{index + 1}\\n\")\n",
375
+ " srt_file.write(f\"{convert_to_srt_time_format(start_time)} --> {convert_to_srt_time_format(end_time)}\\n\")\n",
376
+ " srt_file.write(f\"{text}\\n\\n\")\n",
377
+ "\n",
378
+ "def convert_to_srt_time_format(seconds):\n",
379
+ " hours, remainder = divmod(seconds, 3600)\n",
380
+ " minutes, seconds = divmod(remainder, 60)\n",
381
+ " milliseconds = int((seconds - int(seconds)) * 1000)\n",
382
+ "\n",
383
+ " return f\"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d},{milliseconds:03d}\"\n",
384
+ "\n",
385
+ "\n",
386
+ "\n",
387
+ "tsv_file = 'translated/German_qrvK_KuIeJk.tsv'\n",
388
+ "srt_file = 'translated/German_qrvK_KuIeJk.srt'\n",
389
+ "\n",
390
+ "tsv_to_srt(tsv_file, srt_file)\n"
391
+ ]
392
+ },
393
+ {
394
+ "cell_type": "code",
395
+ "execution_count": null,
396
+ "metadata": {},
397
+ "outputs": [],
398
+ "source": []
399
+ }
400
+ ],
401
+ "metadata": {
402
+ "kernelspec": {
403
+ "display_name": "sports",
404
+ "language": "python",
405
+ "name": "python3"
406
+ },
407
+ "language_info": {
408
+ "codemirror_mode": {
409
+ "name": "ipython",
410
+ "version": 3
411
+ },
412
+ "file_extension": ".py",
413
+ "mimetype": "text/x-python",
414
+ "name": "python",
415
+ "nbconvert_exporter": "python",
416
+ "pygments_lexer": "ipython3",
417
+ "version": "3.9.16"
418
+ }
419
+ },
420
+ "nbformat": 4,
421
+ "nbformat_minor": 2
422
+ }
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ pytube
2
+ whisper
3
+ torch
4
+ transformers
5
+ TTS
6
+ pydub
7
+ soundfile
8
+ pyrubberband
9
+ moviepy
speech2text.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os, re
2
+
3
+ import whisper
4
+ from whisper.utils import get_writer
5
+
6
+ model=whisper.load_model("base").to('cpu')
7
+
8
+ def get_file_stem(file_name):
9
+ # Use a regular expression to match and extract the file stem
10
+ match = re.match(r'^(.*/)?([^.]+)\.\w+$', file_name)
11
+ if match:
12
+ return match.group(2)
13
+ else:
14
+ return None
15
+
16
+ def transcribeAndSave(file,outputPath):
17
+ result = model.transcribe(file)
18
+ writer = get_writer('tsv',outputPath)
19
+ writer(result,get_file_stem(file),None)
20
+
21
+ def transcribeAndSaveFolder(fileFolder,outputpath):
22
+ os.makedirs(outputpath, exist_ok=True)
23
+ for file in os.listdir(fileFolder):
24
+ filepath=os.path.join(fileFolder,file)
25
+ transcribeAndSave(filepath,outputpath)
text2speech.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from pyrubberband import time_stretch
3
+ from TTS.api import TTS
4
+ import torch
5
+ import pandas as pd
6
+ from pydub import AudioSegment
7
+ import soundfile as sf
8
+
9
+
10
+
11
+ def mergeAudio(outputFolder,length):
12
+ audio_files = [f'{outputFolder}/adjusted_audio_{i}.wav' for i in range(length)]
13
+ combined = AudioSegment.from_wav(audio_files[0])
14
+
15
+ for file in audio_files[1:]:
16
+ segment = AudioSegment.from_wav(file)
17
+ combined = combined + segment
18
+ #remove all files in the folder
19
+ for file in audio_files:
20
+ os.remove(file)
21
+ combined.export(f'{outputFolder}/merged_audio.wav', format='wav')
22
+
23
+
24
+ def generate_audio(tsvFile, outputFolder):
25
+ os.makedirs(outputFolder, exist_ok=True)
26
+ df = pd.read_csv(tsvFile, sep='\t')
27
+ tts = TTS("tts_models/de/thorsten/vits").to("cpu")
28
+ for index, row in df.iterrows():
29
+ start_time = int(row['start'])
30
+ end_time = int(row['end'])
31
+ text = row['text']
32
+
33
+ tts.tts_to_file(text=text, file_path=f'{outputFolder}/audio_{index}.wav')
34
+ audio =AudioSegment.from_wav(f'{outputFolder}/audio_{index}.wav')
35
+
36
+ y,sr = sf.read(f'{outputFolder}/audio_{index}.wav')
37
+
38
+ speed_ratio = len(audio) / (end_time - start_time)
39
+
40
+
41
+ # Time-stretch using pyrubberband
42
+ y_stretch = time_stretch(y, sr, speed_ratio)
43
+
44
+ # Create a new AudioSegment from the stretched audio data
45
+ # Save the adjusted audio
46
+ sf.write(f'{outputFolder}/adjusted_audio_{index}.wav',y_stretch,sr)
47
+ os.remove(f'{outputFolder}/audio_{index}.wav')
48
+ # Play the audio for verification
49
+ mergeAudio(outputFolder,len(df))
50
+
51
+
52
+
53
+
54
+ def createAudioFolder(tsvFolder, outputFolder):
55
+ os.makedirs(outputFolder, exist_ok=True)
56
+ for file in os.listdir(tsvFolder):
57
+ filepath = os.path.join(tsvFolder, file)
58
+ generate_audio(filepath, outputFolder)
59
+
60
+
61
+
62
+
text2text.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from transformers import T5Tokenizer, T5ForConditionalGeneration
3
+
4
+
5
+ def unpackTsv(tsvFile):
6
+ with open(tsvFile, 'r') as f:
7
+ lines = f.readlines()
8
+ lines = [l.strip().split('\t') for l in lines]
9
+ return lines
10
+
11
+
12
+
13
+ def translateSentences(sentences,languageSecond="German",languageFirst="English"):
14
+ tokenizer = T5Tokenizer.from_pretrained("t5-small")
15
+ model = T5ForConditionalGeneration.from_pretrained("t5-small")
16
+
17
+ task_prefix = f"translate {languageFirst} to {languageSecond}: "
18
+ # use different length sentences to test batching
19
+
20
+ inputs = tokenizer([task_prefix + sentence for sentence in sentences], return_tensors="pt", padding=True)
21
+
22
+ output_sequences = model.generate(
23
+ input_ids=inputs["input_ids"],
24
+ attention_mask=inputs["attention_mask"],
25
+ do_sample=False, # disable sampling to test if batching affects output
26
+ )
27
+
28
+ return (tokenizer.batch_decode(output_sequences, skip_special_tokens=True))
29
+
30
+ def translateTsv(tsvFile,languageSecond="German",languageFirst="English"):
31
+ lines=unpackTsv(tsvFile)
32
+ sentences=[l[2] for l in lines[1:]]
33
+ translatedSentences=translateSentences(sentences,languageSecond,languageFirst)
34
+ for i in range(1,len(lines)):
35
+ lines[i][2]=translatedSentences[i-1]
36
+ return lines
37
+
38
+ def writeTsv(lines,outputFile):
39
+ with open(outputFile, 'w') as f:
40
+ for l in lines:
41
+ f.write('\t'.join(l)+'\n')
42
+
43
+ def translateTsvFile(tsvFile, outputFile, languageSecond="German", languageFirst="English"):
44
+ lines = translateTsv(tsvFile, languageSecond, languageFirst)
45
+ outputFilePath = os.path.join(outputFile, f"{languageSecond}_{os.path.basename(tsvFile)}")
46
+ writeTsv(lines, outputFilePath)
47
+
48
+ def translateTsvFolder(tsvFolder, outputFolder, languageSecond="German", languageFirst="English"):
49
+ os.makedirs(outputFolder, exist_ok=True)
50
+ for file in os.listdir(tsvFolder):
51
+ filepath = os.path.join(tsvFolder, file)
52
+ translateTsvFile(filepath, outputFolder, languageSecond, languageFirst)