File size: 9,795 Bytes
cec74c1 7af809b cec74c1 113eac1 cec74c1 113eac1 cec74c1 55943c4 113eac1 cec74c1 3a785ad cec74c1 3a785ad cec74c1 55943c4 593b83c 7af809b 55943c4 cec74c1 113eac1 cec74c1 113eac1 7af809b 113eac1 7af809b 113eac1 cec74c1 7af809b cec74c1 7af809b cec74c1 7af809b cec74c1 7af809b 55943c4 7af809b 55943c4 cec74c1 3a785ad 3f39059 7af809b 3f39059 7af809b 55943c4 7af809b 55943c4 7af809b d180905 7af809b d180905 3a785ad cec74c1 3a785ad 7af809b dc7f33e cec74c1 dc7f33e cec74c1 113eac1 7af809b 593b83c cec74c1 9765bc3 cec74c1 593b83c cec74c1 593b83c cec74c1 593b83c 9765bc3 593b83c cec74c1 593b83c 9765bc3 dc7f33e cec74c1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | """
AI Graduate Job-Matching Platform
Production-Safe Version with Retry & Chunk Handling
Developer: Najaf Ali Sharqi
MoviePy-free (uses ffmpeg + tempfile)
"""
import os
import gradio as gr
import tempfile
import subprocess
import math
import time
from groq import Groq
# ============================================================================
# CONFIGURATION
# ============================================================================
client = Groq(api_key=os.getenv("GROQ_API_KEY"))
TRANSCRIPTION_MODEL = "whisper-large-v3"
REWRITE_MODEL = "openai/gpt-oss-120b"
CHUNK_SIZE = 300 # 5 min chunks for transcription to avoid rate limit
REWRITE_CHUNK_SIZE = 4000 # words per rewrite chunk
MAX_RETRIES = 5 # retries for 429 errors
# ============================================================================
# UTILITY FUNCTIONS
# ============================================================================
def get_video_duration(video_path):
"""Get video duration using ffprobe"""
try:
result = subprocess.run(
["ffprobe", "-v", "error", "-show_entries",
"format=duration", "-of",
"default=noprint_wrappers=1:nokey=1", video_path],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True
)
duration = float(result.stdout.strip())
return duration
except Exception as e:
raise RuntimeError(f"Failed to get video duration: {str(e)}")
def extract_audio_chunks(video_path, chunk_size=CHUNK_SIZE):
"""Extract audio from video and split into chunks"""
try:
duration = get_video_duration(video_path)
num_chunks = math.ceil(duration / chunk_size)
audio_chunks = []
# extract full audio first
temp_audio_full = tempfile.NamedTemporaryFile(suffix=".mp3", delete=False)
audio_full_path = temp_audio_full.name
temp_audio_full.close()
os.system(f"ffmpeg -y -i \"{video_path}\" -q:a 0 -map a \"{audio_full_path}\"")
# split audio into chunks
for i in range(num_chunks):
start = i * chunk_size
end = min((i + 1) * chunk_size, duration)
temp_chunk = tempfile.NamedTemporaryFile(suffix=".mp3", delete=False)
chunk_path = temp_chunk.name
temp_chunk.close()
os.system(f"ffmpeg -y -i \"{audio_full_path}\" -ss {start} -to {end} -c copy \"{chunk_path}\"")
audio_chunks.append(chunk_path)
# remove full audio file
if os.path.exists(audio_full_path):
os.unlink(audio_full_path)
return audio_chunks
except Exception as e:
raise RuntimeError(f"Audio extraction failed: {str(e)}")
# ============================================================================
# TRANSCRIPTION WITH RETRY
# ============================================================================
def transcribe_audio_chunks(audio_chunks, language="English"):
transcript_text = ""
for chunk in audio_chunks:
for attempt in range(MAX_RETRIES):
try:
with open(chunk, "rb") as audio_file:
transcription = client.audio.transcriptions.create(
file=(os.path.basename(chunk), audio_file.read()),
model=TRANSCRIPTION_MODEL,
temperature=0,
response_format="verbose_json",
language="en" if language=="English" else "ur"
)
transcript_text += transcription.text + "\n\n"
break # success
except Exception as e:
err_str = str(e)
if "Rate limit reached" in err_str or "429" in err_str:
wait_time = 5 + attempt * 5
print(f"Rate limit hit. Waiting {wait_time}s before retrying...")
time.sleep(wait_time)
else:
transcript_text += f"[Error in chunk transcription: {err_str}]\n\n"
break
if os.path.exists(chunk):
os.unlink(chunk)
return transcript_text.strip()
# ============================================================================
# GRAMMAR & PUNCTUATION CORRECTION (Chunked)
# ============================================================================
def rewrite_transcript_chunked(text, language="English", chunk_size=REWRITE_CHUNK_SIZE):
"""Rewrite transcript in smaller chunks to avoid token limits"""
try:
words = text.split()
rewritten_chunks = []
for i in range(0, len(words), chunk_size):
chunk_text = " ".join(words[i:i+chunk_size])
prompt = f"Correct grammar, punctuation, and make it readable. Language: {language}\n\n{chunk_text}"
for attempt in range(MAX_RETRIES):
try:
response = client.chat.completions.create(
model=REWRITE_MODEL,
messages=[{"role": "user", "content": prompt}],
temperature=0
)
rewritten_chunks.append(response.choices[0].message.content)
break
except Exception as e:
err_str = str(e)
if "Rate limit reached" in err_str or "429" in err_str:
wait_time = 5 + attempt*5
print(f"Rewrite rate limit hit. Waiting {wait_time}s before retrying...")
time.sleep(wait_time)
else:
rewritten_chunks.append(f"[Error rewriting chunk: {err_str}]")
break
return "\n\n".join(rewritten_chunks)
except Exception as e:
return f"[Error rewriting transcript: {str(e)}]"
def correct_transcript(transcript_text, language):
lang = "English" if "English" in language else "Urdu"
if not transcript_text:
return "", "Please generate transcript first." if lang=="English" else "پہلے ٹرانسکرپٹ بنائیں۔"
rewritten_text = rewrite_transcript_chunked(transcript_text, language=lang)
return rewritten_text, "✅ Grammar & punctuation corrected / گرامر اور پنکچویشن درست کی گئی"
# ============================================================================
# PROCESS VIDEO
# ============================================================================
def generate_transcript(video_file, language):
lang = "English" if "English" in language else "Urdu"
if not video_file:
return "", "Please upload a video file." if lang=="English" else "براہ کرم ایک ویڈیو فائل اپ لوڈ کریں۔"
try:
audio_chunks = extract_audio_chunks(video_file.name)
transcript = transcribe_audio_chunks(audio_chunks, language=lang)
return transcript, "✅ Transcription completed / ٹرانسکرپشن مکمل"
except Exception as e:
error_msg = str(e)
return "", error_msg if lang=="English" else "خرابی: " + error_msg
# ============================================================================
# DOWNLOAD FUNCTION
# ============================================================================
def download_transcript(text, language):
lang_suffix = "en" if "English" in language else "ur"
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=f"_{lang_suffix}.txt")
temp_file.write(text.encode("utf-8"))
temp_file.close()
return temp_file.name
# ============================================================================
# GRADIO UI
# ============================================================================
def create_ui():
with gr.Blocks(title="AI Graduate Job Matcher") as demo:
gr.HTML("<h1>🎓 AI Graduate Job-Matching Platform</h1><p>Developer: Najaf Ali Sharqi</p>")
video_input = gr.File(label="Upload Video / ویڈیو اپ لوڈ کریں", file_types=[".mp4", ".mov", ".avi"])
language_dropdown = gr.Dropdown(choices=["English", "Urdu / اردو"], value="English", label="Output Language / آؤٹ پٹ زبان")
transcript_output = gr.Textbox(label="Transcript / ٹرانسکرپٹ", lines=20)
status_output = gr.Textbox(label="Status / حیثیت", lines=1)
# Buttons
transcribe_btn = gr.Button("🚀 Generate Transcript / ٹرانسکرپٹ بنائیں")
rewrite_btn = gr.Button("✏️ Correct Grammar & Punctuation / گرامر درست کریں")
download_btn = gr.Button("💾 Download Transcript / ٹرانسکرپٹ ڈاؤن لوڈ کریں")
# Transcription click
transcribe_btn.click(
fn=generate_transcript,
inputs=[video_input, language_dropdown],
outputs=[transcript_output, status_output]
)
# Grammar correction click
rewrite_btn.click(
fn=correct_transcript,
inputs=[transcript_output, language_dropdown],
outputs=[transcript_output, status_output]
)
# Download click
download_btn.click(
fn=download_transcript,
inputs=[transcript_output, language_dropdown],
outputs=gr.File(label="Download your transcript")
)
return demo
# ============================================================================
# MAIN
# ============================================================================
if __name__ == "__main__":
if not os.getenv("GROQ_API_KEY"):
print("⚠️ WARNING: GROQ_API_KEY not found!")
demo = create_ui()
demo.launch(server_name="0.0.0.0", server_port=7860)
|