Turbiling commited on
Commit
7af809b
·
verified ·
1 Parent(s): 55943c4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +73 -73
app.py CHANGED
@@ -1,6 +1,6 @@
1
  """
2
- Video Transcription APP
3
- Production-Safe Version with Retry, Chunk Handling & Progress Bar
4
  Developer: Najaf Ali Sharqi
5
  MoviePy-free (uses ffmpeg + tempfile)
6
  """
@@ -20,7 +20,7 @@ client = Groq(api_key=os.getenv("GROQ_API_KEY"))
20
 
21
  TRANSCRIPTION_MODEL = "whisper-large-v3"
22
  REWRITE_MODEL = "openai/gpt-oss-120b"
23
- CHUNK_SIZE = 300 # 5 min chunks for transcription
24
  REWRITE_CHUNK_SIZE = 4000 # words per rewrite chunk
25
  MAX_RETRIES = 5 # retries for 429 errors
26
 
@@ -28,6 +28,7 @@ MAX_RETRIES = 5 # retries for 429 errors
28
  # UTILITY FUNCTIONS
29
  # ============================================================================
30
  def get_video_duration(video_path):
 
31
  try:
32
  result = subprocess.run(
33
  ["ffprobe", "-v", "error", "-show_entries",
@@ -37,43 +38,49 @@ def get_video_duration(video_path):
37
  stderr=subprocess.STDOUT,
38
  text=True
39
  )
40
- return float(result.stdout.strip())
 
41
  except Exception as e:
42
  raise RuntimeError(f"Failed to get video duration: {str(e)}")
43
 
44
  def extract_audio_chunks(video_path, chunk_size=CHUNK_SIZE):
45
- duration = get_video_duration(video_path)
46
- num_chunks = math.ceil(duration / chunk_size)
47
- audio_chunks = []
48
-
49
- temp_audio_full = tempfile.NamedTemporaryFile(suffix=".mp3", delete=False)
50
- audio_full_path = temp_audio_full.name
51
- temp_audio_full.close()
52
-
53
- os.system(f"ffmpeg -y -i \"{video_path}\" -q:a 0 -map a \"{audio_full_path}\"")
54
-
55
- for i in range(num_chunks):
56
- start = i * chunk_size
57
- end = min((i + 1) * chunk_size, duration)
58
- temp_chunk = tempfile.NamedTemporaryFile(suffix=".mp3", delete=False)
59
- chunk_path = temp_chunk.name
60
- temp_chunk.close()
61
- os.system(f"ffmpeg -y -i \"{audio_full_path}\" -ss {start} -to {end} -c copy \"{chunk_path}\"")
62
- audio_chunks.append(chunk_path)
63
-
64
- if os.path.exists(audio_full_path):
65
- os.unlink(audio_full_path)
66
-
67
- return audio_chunks
 
 
 
 
 
 
 
68
 
69
  # ============================================================================
70
- # TRANSCRIPTION WITH RETRY & PROGRESS
71
  # ============================================================================
72
- def transcribe_audio_chunks(audio_chunks, language="English", progress_fn=None):
73
  transcript_text = ""
74
- total_chunks = len(audio_chunks)
75
-
76
- for idx, chunk in enumerate(audio_chunks, start=1):
77
  for attempt in range(MAX_RETRIES):
78
  try:
79
  with open(chunk, "rb") as audio_file:
@@ -85,7 +92,7 @@ def transcribe_audio_chunks(audio_chunks, language="English", progress_fn=None):
85
  language="en" if language=="English" else "ur"
86
  )
87
  transcript_text += transcription.text + "\n\n"
88
- break
89
  except Exception as e:
90
  err_str = str(e)
91
  if "Rate limit reached" in err_str or "429" in err_str:
@@ -95,67 +102,60 @@ def transcribe_audio_chunks(audio_chunks, language="English", progress_fn=None):
95
  else:
96
  transcript_text += f"[Error in chunk transcription: {err_str}]\n\n"
97
  break
98
-
99
- if progress_fn:
100
- progress_fn(idx / total_chunks, f"Transcribing audio chunk {idx}/{total_chunks}...")
101
-
102
  if os.path.exists(chunk):
103
  os.unlink(chunk)
104
-
105
  return transcript_text.strip()
106
 
107
  # ============================================================================
108
- # GRAMMAR & PUNCTUATION CORRECTION (Chunked) WITH PROGRESS
109
  # ============================================================================
110
- def rewrite_transcript_chunked(text, language="English", chunk_size=REWRITE_CHUNK_SIZE, progress_fn=None):
111
- words = text.split()
112
- rewritten_chunks = []
113
- total_chunks = math.ceil(len(words) / chunk_size)
114
-
115
- for idx in range(0, len(words), chunk_size):
116
- chunk_text = " ".join(words[idx:idx+chunk_size])
117
- prompt = f"Correct grammar, punctuation, and make it readable. Language: {language}\n\n{chunk_text}"
118
- for attempt in range(MAX_RETRIES):
119
- try:
120
- response = client.chat.completions.create(
121
- model=REWRITE_MODEL,
122
- messages=[{"role": "user", "content": prompt}],
123
- temperature=0
124
- )
125
- rewritten_chunks.append(response.choices[0].message.content)
126
- break
127
- except Exception as e:
128
- err_str = str(e)
129
- if "Rate limit reached" in err_str or "429" in err_str:
130
- wait_time = 5 + attempt*5
131
- print(f"Rewrite rate limit hit. Waiting {wait_time}s before retrying...")
132
- time.sleep(wait_time)
133
- else:
134
- rewritten_chunks.append(f"[Error rewriting chunk: {err_str}]")
135
  break
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
- if progress_fn:
138
- progress_fn((idx // chunk_size + 1) / total_chunks, f"Rewriting text chunk {(idx // chunk_size + 1)}/{total_chunks}...")
139
-
140
- return "\n\n".join(rewritten_chunks)
141
-
142
- def correct_transcript(transcript_text, language, progress=gr.Progress()):
143
  lang = "English" if "English" in language else "Urdu"
144
  if not transcript_text:
145
  return "", "Please generate transcript first." if lang=="English" else "پہلے ٹرانسکرپٹ بنائیں۔"
146
- rewritten_text = rewrite_transcript_chunked(transcript_text, language=lang, progress_fn=progress.update)
147
  return rewritten_text, "✅ Grammar & punctuation corrected / گرامر اور پنکچویشن درست کی گئی"
148
 
149
  # ============================================================================
150
  # PROCESS VIDEO
151
  # ============================================================================
152
- def generate_transcript(video_file, language, progress=gr.Progress()):
153
  lang = "English" if "English" in language else "Urdu"
154
  if not video_file:
155
  return "", "Please upload a video file." if lang=="English" else "براہ کرم ایک ویڈیو فائل اپ لوڈ کریں۔"
156
  try:
157
  audio_chunks = extract_audio_chunks(video_file.name)
158
- transcript = transcribe_audio_chunks(audio_chunks, language=lang, progress_fn=progress.update)
159
  return transcript, "✅ Transcription completed / ٹرانسکرپشن مکمل"
160
  except Exception as e:
161
  error_msg = str(e)
 
1
  """
2
+ AI Graduate Job-Matching Platform
3
+ Production-Safe Version with Retry & Chunk Handling
4
  Developer: Najaf Ali Sharqi
5
  MoviePy-free (uses ffmpeg + tempfile)
6
  """
 
20
 
21
  TRANSCRIPTION_MODEL = "whisper-large-v3"
22
  REWRITE_MODEL = "openai/gpt-oss-120b"
23
+ CHUNK_SIZE = 300 # 5 min chunks for transcription to avoid rate limit
24
  REWRITE_CHUNK_SIZE = 4000 # words per rewrite chunk
25
  MAX_RETRIES = 5 # retries for 429 errors
26
 
 
28
  # UTILITY FUNCTIONS
29
  # ============================================================================
30
  def get_video_duration(video_path):
31
+ """Get video duration using ffprobe"""
32
  try:
33
  result = subprocess.run(
34
  ["ffprobe", "-v", "error", "-show_entries",
 
38
  stderr=subprocess.STDOUT,
39
  text=True
40
  )
41
+ duration = float(result.stdout.strip())
42
+ return duration
43
  except Exception as e:
44
  raise RuntimeError(f"Failed to get video duration: {str(e)}")
45
 
46
  def extract_audio_chunks(video_path, chunk_size=CHUNK_SIZE):
47
+ """Extract audio from video and split into chunks"""
48
+ try:
49
+ duration = get_video_duration(video_path)
50
+ num_chunks = math.ceil(duration / chunk_size)
51
+ audio_chunks = []
52
+
53
+ # extract full audio first
54
+ temp_audio_full = tempfile.NamedTemporaryFile(suffix=".mp3", delete=False)
55
+ audio_full_path = temp_audio_full.name
56
+ temp_audio_full.close()
57
+
58
+ os.system(f"ffmpeg -y -i \"{video_path}\" -q:a 0 -map a \"{audio_full_path}\"")
59
+
60
+ # split audio into chunks
61
+ for i in range(num_chunks):
62
+ start = i * chunk_size
63
+ end = min((i + 1) * chunk_size, duration)
64
+ temp_chunk = tempfile.NamedTemporaryFile(suffix=".mp3", delete=False)
65
+ chunk_path = temp_chunk.name
66
+ temp_chunk.close()
67
+ os.system(f"ffmpeg -y -i \"{audio_full_path}\" -ss {start} -to {end} -c copy \"{chunk_path}\"")
68
+ audio_chunks.append(chunk_path)
69
+
70
+ # remove full audio file
71
+ if os.path.exists(audio_full_path):
72
+ os.unlink(audio_full_path)
73
+
74
+ return audio_chunks
75
+ except Exception as e:
76
+ raise RuntimeError(f"Audio extraction failed: {str(e)}")
77
 
78
  # ============================================================================
79
+ # TRANSCRIPTION WITH RETRY
80
  # ============================================================================
81
+ def transcribe_audio_chunks(audio_chunks, language="English"):
82
  transcript_text = ""
83
+ for chunk in audio_chunks:
 
 
84
  for attempt in range(MAX_RETRIES):
85
  try:
86
  with open(chunk, "rb") as audio_file:
 
92
  language="en" if language=="English" else "ur"
93
  )
94
  transcript_text += transcription.text + "\n\n"
95
+ break # success
96
  except Exception as e:
97
  err_str = str(e)
98
  if "Rate limit reached" in err_str or "429" in err_str:
 
102
  else:
103
  transcript_text += f"[Error in chunk transcription: {err_str}]\n\n"
104
  break
 
 
 
 
105
  if os.path.exists(chunk):
106
  os.unlink(chunk)
 
107
  return transcript_text.strip()
108
 
109
  # ============================================================================
110
+ # GRAMMAR & PUNCTUATION CORRECTION (Chunked)
111
  # ============================================================================
112
+ def rewrite_transcript_chunked(text, language="English", chunk_size=REWRITE_CHUNK_SIZE):
113
+ """Rewrite transcript in smaller chunks to avoid token limits"""
114
+ try:
115
+ words = text.split()
116
+ rewritten_chunks = []
117
+ for i in range(0, len(words), chunk_size):
118
+ chunk_text = " ".join(words[i:i+chunk_size])
119
+ prompt = f"Correct grammar, punctuation, and make it readable. Language: {language}\n\n{chunk_text}"
120
+ for attempt in range(MAX_RETRIES):
121
+ try:
122
+ response = client.chat.completions.create(
123
+ model=REWRITE_MODEL,
124
+ messages=[{"role": "user", "content": prompt}],
125
+ temperature=0
126
+ )
127
+ rewritten_chunks.append(response.choices[0].message.content)
 
 
 
 
 
 
 
 
 
128
  break
129
+ except Exception as e:
130
+ err_str = str(e)
131
+ if "Rate limit reached" in err_str or "429" in err_str:
132
+ wait_time = 5 + attempt*5
133
+ print(f"Rewrite rate limit hit. Waiting {wait_time}s before retrying...")
134
+ time.sleep(wait_time)
135
+ else:
136
+ rewritten_chunks.append(f"[Error rewriting chunk: {err_str}]")
137
+ break
138
+ return "\n\n".join(rewritten_chunks)
139
+ except Exception as e:
140
+ return f"[Error rewriting transcript: {str(e)}]"
141
 
142
+ def correct_transcript(transcript_text, language):
 
 
 
 
 
143
  lang = "English" if "English" in language else "Urdu"
144
  if not transcript_text:
145
  return "", "Please generate transcript first." if lang=="English" else "پہلے ٹرانسکرپٹ بنائیں۔"
146
+ rewritten_text = rewrite_transcript_chunked(transcript_text, language=lang)
147
  return rewritten_text, "✅ Grammar & punctuation corrected / گرامر اور پنکچویشن درست کی گئی"
148
 
149
  # ============================================================================
150
  # PROCESS VIDEO
151
  # ============================================================================
152
+ def generate_transcript(video_file, language):
153
  lang = "English" if "English" in language else "Urdu"
154
  if not video_file:
155
  return "", "Please upload a video file." if lang=="English" else "براہ کرم ایک ویڈیو فائل اپ لوڈ کریں۔"
156
  try:
157
  audio_chunks = extract_audio_chunks(video_file.name)
158
+ transcript = transcribe_audio_chunks(audio_chunks, language=lang)
159
  return transcript, "✅ Transcription completed / ٹرانسکرپشن مکمل"
160
  except Exception as e:
161
  error_msg = str(e)