robertselvam commited on
Commit
7f8dd93
·
1 Parent(s): 13b638a

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +335 -0
app.py ADDED
@@ -0,0 +1,335 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from stable_whisper import modify_model,results_to_word_srt, results_to_sentence_srt
2
+ import whisper
3
+ import pysrt
4
+ import re
5
+ import os
6
+ from copy import deepcopy
7
+ from typing import List
8
+ import os
9
+ from langchain import HuggingFaceHub, PromptTemplate, LLMChain
10
+ from langchain.document_loaders import UnstructuredPDFLoader
11
+ from nltk.corpus import stopwords
12
+ from nltk.tokenize import word_tokenize
13
+ from nltk import FreqDist
14
+ from nltk.metrics import jaccard_distance
15
+
16
+ from moviepy.video.io.VideoFileClip import VideoFileClip
17
+ from moviepy.video.VideoClip import ImageClip
18
+ from datetime import datetime
19
+ import gradio as gr
20
+ import nltk
21
+ nltk.download('stopwords')
22
+ nltk.download('punkt')
23
+
24
+ huggingfacehub_api_token = os.getenv("HF_TOKEN")
25
+
26
+ class VideoQA:
27
+ def __init__(self):
28
+ # self.loader = UnstructuredPDFLoader("/content/Document_ Introduction to Python (1).pdf")
29
+ # self.extracted_text=self.loader.load()
30
+
31
+ # self.huggingfacehub_api_token = # Replace with your Hugging Face token
32
+ self.repo_id = "mistralai/Mistral-7B-Instruct-v0.1"
33
+ self.llm = HuggingFaceHub(
34
+ huggingfacehub_api_token=huggingfacehub_api_token,
35
+ repo_id=self.repo_id,
36
+ model_kwargs={"temperature": 0.2, "max_new_tokens": 800}
37
+ )
38
+
39
+ def load_model(self,model_selected):
40
+ """
41
+ Load a pre-trained machine learning model specified by the `model_selected` parameter
42
+ using the `whisper` library and modify it to output word timestamps.
43
+
44
+ Parameters:
45
+ -----------
46
+ model_selected : str
47
+ A string specifying the name of the pre-trained machine learning model to load.
48
+
49
+ Returns:
50
+ --------
51
+ model : object
52
+ A modified version of the loaded pre-trained machine learning model that outputs
53
+ timestamps for individual words.
54
+
55
+ """
56
+ model = whisper.load_model(model_selected)
57
+ modify_model(model)
58
+ return model
59
+
60
+ def whisper_result_to_srt(self,result):
61
+ """
62
+ Convert the output of the Whisper speech recognition model into SubRip subtitle format.
63
+
64
+ Parameters:
65
+ -----------
66
+ result : dict
67
+ A dictionary containing the output of the Whisper speech recognition model, including word-level
68
+ timestamps.
69
+
70
+ Returns:
71
+ --------
72
+ srt : str
73
+ A string in SubRip subtitle format, containing the word-level transcriptions and timing information
74
+ from the Whisper output.
75
+
76
+ Notes:
77
+ ------
78
+ This function takes the output of the Whisper speech recognition model, which includes word-level timestamps
79
+ for each segment of the input audio file, and converts it into SubRip subtitle format. The resulting subtitle
80
+ file can be used to display captions or transcripts alongside a video recording of the original audio.
81
+ """
82
+ text = []
83
+ for i,s in enumerate(result['segments']):
84
+ text.append(str(i+1))
85
+ time_start = s['start']
86
+ hours, minutes, seconds = int(time_start/3600), (time_start/60) % 60, (time_start) % 60
87
+ timestamp_start = "%02d:%02d:%06.3f" % (hours, minutes, seconds)
88
+ timestamp_start = timestamp_start.replace('.',',')
89
+ time_end = s['end']
90
+ hours, minutes, seconds = int(time_end/3600), (time_end/60) % 60, (time_end) % 60
91
+ timestamp_end = "%02d:%02d:%06.3f" % (hours, minutes, seconds)
92
+ timestamp_end = timestamp_end.replace('.',',')
93
+ text.append(timestamp_start + " --> " + timestamp_end)
94
+ text.append(s['text'].strip() + "\n")
95
+ return "\n".join(text)
96
+
97
+ # model_selected = 'tiny'
98
+ def transcribe_video(self,vid, model_selected):
99
+ """
100
+ Transcribe the audio in a video file using a pre-trained machine learning model and return the transcription
101
+ and its corresponding timestamps in a subtitle format.
102
+
103
+ Parameters:
104
+ -----------
105
+ vid : str
106
+ A string specifying the path to the video file to be transcribed.
107
+ model_selected : str
108
+ A string specifying the name of the pre-trained machine learning model to use for transcription.
109
+
110
+ Returns:
111
+ --------
112
+ result : dict
113
+ A dictionary containing the transcription and its corresponding timestamps in a subtitle format.
114
+
115
+ """
116
+ model = self.load_model(model_selected)
117
+ options = whisper.DecodingOptions(fp16=False)
118
+ result = model.transcribe(vid, **options.__dict__)
119
+ result['srt'] = self.whisper_result_to_srt(result)
120
+ return result
121
+
122
+
123
+ def to_srt(self,lines: List[dict], strip=False) -> str:
124
+ """
125
+ lines: List[dict]
126
+ [{start:<start-timestamp-of-text>, end:<end-timestamp-of-text>, text:<str-of-text>}, ...]
127
+ """
128
+
129
+ def secs_to_hhmmss(secs):
130
+ mm, ss = divmod(secs, 60)
131
+ hh, mm = divmod(mm, 60)
132
+ return f'{hh:0>2.0f}:{mm:0>2.0f}:{ss:0>6.3f}'.replace(".", ",")
133
+
134
+ srt_str = '\n'.join(
135
+ f'{i}\n'
136
+ f'{secs_to_hhmmss(sub["start"])} --> {secs_to_hhmmss(sub["end"])}\n'
137
+ f'{sub["text"].strip() if strip else sub["text"]}\n'
138
+ for i, sub in enumerate(lines, 1))
139
+
140
+ # if save_path:
141
+ # with open(save_path, 'w', encoding='utf-8') as f:
142
+ # f.write(srt_str)
143
+ # print(f'Saved: {os.path.abspath(save_path)}')
144
+
145
+ return srt_str
146
+
147
+ def tighten_timestamps(self,res: dict, end_at_last_word=True, end_before_period=False, start_at_first_word=False) -> dict:
148
+ res = deepcopy(res)
149
+ for i in range(len(res['segments'])):
150
+ if start_at_first_word:
151
+ res['segments'][i]['start'] = res['segments'][i]['word_timestamps'][0]['timestamp']
152
+ if end_before_period and \
153
+ res['segments'][i]['word_timestamps'][-1] == '.' and \
154
+ len(res['segments'][i]['word_timestamps']) > 1:
155
+ res['segments'][i]['end'] = res['segments'][i]['word_timestamps'][-2]['timestamp']
156
+ elif end_at_last_word:
157
+ res['segments'][i]['end'] = res['segments'][i]['word_timestamps'][-1]['timestamp']
158
+
159
+ return res
160
+
161
+ def results_to_sentence_srt(self,res: dict,
162
+ end_at_last_word=False,
163
+ end_before_period=False,
164
+ start_at_first_word=False,
165
+ strip=False):
166
+ """
167
+
168
+ Parameters
169
+ ----------
170
+ res: dict
171
+ results from modified model
172
+ srt_path: str
173
+ output path of srt
174
+ end_at_last_word: bool
175
+ set end-of-sentence to timestamp-of-last-token
176
+ end_before_period: bool
177
+ set end-of-sentence to timestamp-of-last-non-period-token
178
+ start_at_first_word: bool
179
+ set start-of-sentence to timestamp-of-first-token
180
+ strip: bool
181
+ perform strip() on each sentence
182
+
183
+ """
184
+ strict = any((end_at_last_word, end_before_period, start_at_first_word))
185
+ segs = self.tighten_timestamps(res,
186
+ end_at_last_word=end_at_last_word,
187
+ end_before_period=end_before_period,
188
+ start_at_first_word=start_at_first_word)['segments'] \
189
+ if strict else res['segments']
190
+
191
+ max_idx = len(segs) - 1
192
+ i = 1
193
+ while i <= max_idx:
194
+ if not (segs[i]['end'] - segs[i]['start']):
195
+ if segs[i - 1]['end'] == segs[i]['end']:
196
+ segs[i - 1]['text'] += (' ' + segs[i]['text'].strip())
197
+ del segs[i]
198
+ max_idx -= 1
199
+ continue
200
+ else:
201
+ segs[i]['start'] = segs[i - 1]['end']
202
+ i += 1
203
+
204
+ srt = self.to_srt(segs, strip=strip)
205
+ return srt
206
+
207
+
208
+
209
+ def extract_timestamps_and_text(self,input_text):
210
+ timestamp_pattern = re.compile(r'(\d{2}:\d{2}:\d{2}.\d{3})\s*-->\s*(\d{2}:\d{2}:\d{2}.\d{3})\n(.+)')
211
+
212
+ matches = timestamp_pattern.findall(input_text)
213
+
214
+ data = []
215
+
216
+ for match in matches:
217
+ start_timestamp, end_timestamp, text = match
218
+ data.append({
219
+ 'start_timestamp': start_timestamp,
220
+ 'end_timestamp': end_timestamp,
221
+ 'text': text.strip()
222
+ })
223
+
224
+ return data
225
+
226
+
227
+ def generate_contract(self,text,question):
228
+
229
+
230
+ template = """you are the german language and universal language expert .your task is analyze the given text and user ask any question about given text answer to the user question.your returning answer must in user's language.otherwise reply i don't know.
231
+ extracted_text:{text}
232
+ user_question:{question}"""
233
+
234
+ prompt = PromptTemplate(template=template, input_variables=["text","question"])
235
+ llm_chain = LLMChain(prompt=prompt, verbose=True, llm=self.llm)
236
+
237
+ result = llm_chain.run({"text":text,"question":question})
238
+ print()
239
+ print()
240
+ print("this is answer:",result)
241
+ return result
242
+
243
+
244
+ def preprocess_sentence(self,sentence):
245
+ stop_words = set(stopwords.words('english'))
246
+ words = word_tokenize(sentence.lower())
247
+ filtered_words = [word for word in words if word.isalnum() and word not in stop_words]
248
+ return filtered_words
249
+
250
+ def compute_similarity(self,sentence1, sentence2):
251
+ words1 = self.preprocess_sentence(sentence1)
252
+ words2 = self.preprocess_sentence(sentence2)
253
+
254
+ freq_dist1 = FreqDist(words1)
255
+ freq_dist2 = FreqDist(words2)
256
+
257
+ jaccard = 1 - jaccard_distance(set(freq_dist1), set(freq_dist2))
258
+
259
+ return jaccard
260
+
261
+ def find_most_similar(self,sentence_list, target_sentence):
262
+ similarities = [self.compute_similarity(target_sentence, sentence) for sentence in sentence_list]
263
+
264
+ # Find the index of the most similar sentence
265
+ most_similar_index = similarities.index(max(similarities))
266
+
267
+ # Return the most similar sentence
268
+ return sentence_list[most_similar_index]
269
+
270
+
271
+ def start_end_timestamp(self,result,answer):
272
+ appended_text = []
273
+
274
+ for item in result:
275
+ appended_text.append(item['text'])
276
+
277
+ # Find the most similar sentence
278
+ matched_sentence = self.find_most_similar(appended_text, answer)
279
+ start_time=""
280
+ end_time=""
281
+ for entry in result:
282
+ if matched_sentence in entry['text']:
283
+ start_time = entry['start_timestamp']
284
+ end_time = entry['end_timestamp']
285
+ print(start_time+"\n"+end_time)
286
+ return start_time,end_time
287
+
288
+
289
+
290
+ def timestamp_to_seconds(self,timestamp):
291
+ time_format = "%H:%M:%S,%f"
292
+ dt = datetime.strptime(timestamp, time_format)
293
+ return dt.hour * 3600 + dt.minute * 60 + dt.second + dt.microsecond / 1e6
294
+
295
+ def cut_video(self,input_file, output_file, start_timestamp, end_timestamp):
296
+ # Convert timestamps to seconds
297
+ start_time = self.timestamp_to_seconds(start_timestamp)
298
+ end_time = self.timestamp_to_seconds(end_timestamp)
299
+
300
+ # Use moviepy to cut both video and audio
301
+ video_clip = VideoFileClip(input_file).subclip(start_time, end_time)
302
+ video_clip.write_videofile(output_file, codec='libx264', audio_codec='aac', temp_audiofile='temp-audio.m4a', remove_temp=True)
303
+
304
+ def main(self,input_video_path,question):
305
+
306
+ subtitle = self.transcribe_video(input_video_path,'medium')
307
+ text = subtitle['text']
308
+ answer = self.generate_contract(text,question)
309
+
310
+ subrip_text = self.results_to_sentence_srt(subtitle)
311
+ result = self.extract_timestamps_and_text(subrip_text)
312
+ start_time,end_time = self.start_end_timestamp(result,answer)
313
+ output_video_path = 'output_video.mp4'
314
+
315
+ self.cut_video(input_video_path, output_video_path, start_time, end_time)
316
+ return output_video_path
317
+
318
+ def gradio_interface(self):
319
+
320
+ with gr.Blocks() as demo:
321
+ gr.HTML("""<center><h1>Video Question Answering</h1></center>""")
322
+ with gr.Row():
323
+ video = gr.Video()
324
+ with gr.Row():
325
+ query = gr.Textbox("Query")
326
+ with gr.Row():
327
+ output_video = gr.Video()
328
+
329
+ query.submit(self.main,[video,query],output_video)
330
+ demo.launch(debug=True)
331
+
332
+ if __name__=="__main__":
333
+ video_qa = VideoQA()
334
+ video_qa.gradio_interface()
335
+