Turbiling commited on
Commit
55943c4
·
verified ·
1 Parent(s): 0b0005c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +95 -81
app.py CHANGED
@@ -1,6 +1,6 @@
1
  """
2
- AI Graduate Job-Matching Platform
3
- Complete Hugging Face Spaces Deployment Version
4
  Developer: Najaf Ali Sharqi
5
  MoviePy-free (uses ffmpeg + tempfile)
6
  """
@@ -10,23 +10,23 @@ import gradio as gr
10
  import tempfile
11
  import subprocess
12
  import math
 
13
  from groq import Groq
14
 
15
  # ============================================================================
16
  # CONFIGURATION
17
  # ============================================================================
18
-
19
  client = Groq(api_key=os.getenv("GROQ_API_KEY"))
20
 
21
- TRANSCRIPTION_MODEL = "whisper-large-v3" # transcription model
22
  REWRITE_MODEL = "openai/gpt-oss-120b"
23
- CHUNK_SIZE = 600 # 10 min in seconds for audio splitting
24
- REWRITE_CHUNK_WORDS = 4000 # number of words per GPT rewrite chunk
 
25
 
26
  # ============================================================================
27
  # UTILITY FUNCTIONS
28
  # ============================================================================
29
-
30
  def get_video_duration(video_path):
31
  try:
32
  result = subprocess.run(
@@ -37,108 +37,125 @@ def get_video_duration(video_path):
37
  stderr=subprocess.STDOUT,
38
  text=True
39
  )
40
- duration = float(result.stdout.strip())
41
- return duration
42
  except Exception as e:
43
  raise RuntimeError(f"Failed to get video duration: {str(e)}")
44
 
45
  def extract_audio_chunks(video_path, chunk_size=CHUNK_SIZE):
46
- try:
47
- duration = get_video_duration(video_path)
48
- num_chunks = math.ceil(duration / chunk_size)
49
- audio_chunks = []
50
 
51
- temp_audio_full = tempfile.NamedTemporaryFile(suffix=".mp3", delete=False)
52
- audio_full_path = temp_audio_full.name
53
- temp_audio_full.close()
54
 
55
- os.system(f"ffmpeg -y -i \"{video_path}\" -q:a 0 -map a \"{audio_full_path}\"")
56
 
57
- for i in range(num_chunks):
58
- start = i * chunk_size
59
- end = min((i + 1) * chunk_size, duration)
60
- temp_chunk = tempfile.NamedTemporaryFile(suffix=".mp3", delete=False)
61
- chunk_path = temp_chunk.name
62
- temp_chunk.close()
63
- os.system(f"ffmpeg -y -i \"{audio_full_path}\" -ss {start} -to {end} -c copy \"{chunk_path}\"")
64
- audio_chunks.append(chunk_path)
65
 
66
- if os.path.exists(audio_full_path):
67
- os.unlink(audio_full_path)
68
 
69
- return audio_chunks
70
- except Exception as e:
71
- raise RuntimeError(f"Audio extraction failed: {str(e)}")
72
 
73
  # ============================================================================
74
- # TRANSCRIPTION
75
  # ============================================================================
76
-
77
- def transcribe_audio_chunks(audio_chunks, language="English"):
78
  transcript_text = ""
79
- for chunk in audio_chunks:
80
- try:
81
- with open(chunk, "rb") as audio_file:
82
- transcription = client.audio.transcriptions.create(
83
- file=(os.path.basename(chunk), audio_file.read()),
84
- model=TRANSCRIPTION_MODEL,
85
- temperature=0,
86
- response_format="verbose_json",
87
- language="en" if language=="English" else "ur"
88
- )
89
- transcript_text += transcription.text + "\n\n"
90
- except Exception as e:
91
- transcript_text += f"[Error in chunk transcription: {str(e)}]\n\n"
92
- finally:
93
- if os.path.exists(chunk):
94
- os.unlink(chunk)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  return transcript_text.strip()
96
 
97
  # ============================================================================
98
- # GRAMMAR & PUNCTUATION CORRECTION (CHUNKED)
99
  # ============================================================================
 
 
 
 
100
 
101
- def rewrite_transcript_chunked(text, language="English", chunk_words=REWRITE_CHUNK_WORDS):
102
- """
103
- Rewrite transcript in smaller word-based chunks to avoid token limits
104
- """
105
- try:
106
- words = text.split()
107
- rewritten_chunks = []
108
-
109
- for i in range(0, len(words), chunk_words):
110
- chunk_text = " ".join(words[i:i+chunk_words])
111
- prompt = f"Correct grammar, punctuation, and make it readable. Language: {language}\n\n{chunk_text}"
112
- response = client.chat.completions.create(
113
- model=REWRITE_MODEL,
114
- messages=[{"role": "user", "content": prompt}],
115
- temperature=0
116
- )
117
- rewritten_chunks.append(response.choices[0].message.content)
118
-
119
- rewritten_text = "\n\n".join(rewritten_chunks)
120
- return rewritten_text
121
- except Exception as e:
122
- return f"[Error rewriting transcript: {str(e)}]"
123
-
124
- def correct_transcript(transcript_text, language):
 
 
 
 
125
  lang = "English" if "English" in language else "Urdu"
126
  if not transcript_text:
127
  return "", "Please generate transcript first." if lang=="English" else "پہلے ٹرانسکرپٹ بنائیں۔"
128
- rewritten_text = rewrite_transcript_chunked(transcript_text, language=lang)
129
  return rewritten_text, "✅ Grammar & punctuation corrected / گرامر اور پنکچویشن درست کی گئی"
130
 
131
  # ============================================================================
132
  # PROCESS VIDEO
133
  # ============================================================================
134
-
135
- def generate_transcript(video_file, language):
136
  lang = "English" if "English" in language else "Urdu"
137
  if not video_file:
138
  return "", "Please upload a video file." if lang=="English" else "براہ کرم ایک ویڈیو فائل اپ لوڈ کریں۔"
139
  try:
140
  audio_chunks = extract_audio_chunks(video_file.name)
141
- transcript = transcribe_audio_chunks(audio_chunks, language=lang)
142
  return transcript, "✅ Transcription completed / ٹرانسکرپشن مکمل"
143
  except Exception as e:
144
  error_msg = str(e)
@@ -147,7 +164,6 @@ def generate_transcript(video_file, language):
147
  # ============================================================================
148
  # DOWNLOAD FUNCTION
149
  # ============================================================================
150
-
151
  def download_transcript(text, language):
152
  lang_suffix = "en" if "English" in language else "ur"
153
  temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=f"_{lang_suffix}.txt")
@@ -158,7 +174,6 @@ def download_transcript(text, language):
158
  # ============================================================================
159
  # GRADIO UI
160
  # ============================================================================
161
-
162
  def create_ui():
163
  with gr.Blocks(title="AI Graduate Job Matcher") as demo:
164
  gr.HTML("<h1>🎓 AI Graduate Job-Matching Platform</h1><p>Developer: Najaf Ali Sharqi</p>")
@@ -200,7 +215,6 @@ def create_ui():
200
  # ============================================================================
201
  # MAIN
202
  # ============================================================================
203
-
204
  if __name__ == "__main__":
205
  if not os.getenv("GROQ_API_KEY"):
206
  print("⚠️ WARNING: GROQ_API_KEY not found!")
 
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
  """
 
10
  import tempfile
11
  import subprocess
12
  import math
13
+ import time
14
  from groq import Groq
15
 
16
  # ============================================================================
17
  # CONFIGURATION
18
  # ============================================================================
 
19
  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
 
27
  # ============================================================================
28
  # UTILITY FUNCTIONS
29
  # ============================================================================
 
30
  def get_video_duration(video_path):
31
  try:
32
  result = subprocess.run(
 
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:
80
+ transcription = client.audio.transcriptions.create(
81
+ file=(os.path.basename(chunk), audio_file.read()),
82
+ model=TRANSCRIPTION_MODEL,
83
+ temperature=0,
84
+ response_format="verbose_json",
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:
92
+ wait_time = 5 + attempt * 5
93
+ print(f"Rate limit hit. Waiting {wait_time}s before retrying...")
94
+ time.sleep(wait_time)
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)
 
164
  # ============================================================================
165
  # DOWNLOAD FUNCTION
166
  # ============================================================================
 
167
  def download_transcript(text, language):
168
  lang_suffix = "en" if "English" in language else "ur"
169
  temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=f"_{lang_suffix}.txt")
 
174
  # ============================================================================
175
  # GRADIO UI
176
  # ============================================================================
 
177
  def create_ui():
178
  with gr.Blocks(title="AI Graduate Job Matcher") as demo:
179
  gr.HTML("<h1>🎓 AI Graduate Job-Matching Platform</h1><p>Developer: Najaf Ali Sharqi</p>")
 
215
  # ============================================================================
216
  # MAIN
217
  # ============================================================================
 
218
  if __name__ == "__main__":
219
  if not os.getenv("GROQ_API_KEY"):
220
  print("⚠️ WARNING: GROQ_API_KEY not found!")