Spaces:
Sleeping
Sleeping
| """ | |
| Voice Transcription & Content Generation System | |
| Developer: Najaf Ali Sharqi | |
| """ | |
| import gradio as gr | |
| import os | |
| from groq import Groq | |
| from docx import Document | |
| from docx.shared import Pt, Inches | |
| from docx.enum.text import WD_ALIGN_PARAGRAPH | |
| from docx.oxml import OxmlElement | |
| from docx.oxml.ns import qn | |
| from pptx import Presentation | |
| from pptx.util import Inches as PptxInches, Pt as PptxPt | |
| from pptx.enum.text import PP_ALIGN | |
| from pptx.dml.color import RGBColor as PptxRGBColor | |
| from datetime import datetime | |
| import re, traceback, math | |
| GROQ_API_KEY = os.environ.get("GROQ_API_KEY") | |
| if not GROQ_API_KEY: | |
| raise ValueError("❌ GROQ_API_KEY not set") | |
| client = Groq(api_key=GROQ_API_KEY) | |
| TRANSCRIPTION_MODEL = "whisper-large-v3-turbo" | |
| CHAT_MODEL = "llama-3.3-70b-versatile" | |
| MAX_AUDIO_SIZE = 24 * 1024 * 1024 | |
| def remove_emojis_and_special_chars(text): | |
| emoji_pattern = re.compile("[" | |
| u"\U0001F600-\U0001F64F"u"\U0001F300-\U0001F5FF"u"\U0001F680-\U0001F6FF" | |
| u"\U0001F1E0-\U0001F1FF"u"\U00002702-\U000027B0"u"\U000024C2-\U0001F251" | |
| u"\U0001F900-\U0001F9FF"u"\U0001FA00-\U0001FA6F" | |
| "]+", flags=re.UNICODE) | |
| text = emoji_pattern.sub(r'', text) | |
| text = re.sub(r'[^\w\s\-.,;:!?()\[\]{}\'\"\/\n\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF]', '', text) | |
| return text | |
| def add_page_numbers(section): | |
| footer = section.footer | |
| footer_para = footer.paragraphs[0] | |
| footer_para.alignment = WD_ALIGN_PARAGRAPH.CENTER | |
| run = footer_para.add_run() | |
| fldChar1 = OxmlElement('w:fldChar') | |
| fldChar1.set(qn('w:fldCharType'), 'begin') | |
| instrText = OxmlElement('w:instrText') | |
| instrText.set(qn('xml:space'), 'preserve') | |
| instrText.text = "PAGE" | |
| fldChar2 = OxmlElement('w:fldChar') | |
| fldChar2.set(qn('w:fldCharType'), 'end') | |
| run._r.append(fldChar1) | |
| run._r.append(instrText) | |
| run._r.append(fldChar2) | |
| def is_urdu_text(text): | |
| urdu_pattern = re.compile(r'[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF]') | |
| return bool(urdu_pattern.search(text)) | |
| def transcribe_single_audio(audio_path): | |
| with open(audio_path, "rb") as audio_file: | |
| transcription = client.audio.transcriptions.create( | |
| file=(audio_path, audio_file.read()), | |
| model=TRANSCRIPTION_MODEL, | |
| temperature=0.0, | |
| response_format="verbose_json" | |
| ) | |
| text = transcription.text.strip() | |
| if not text: | |
| return None, "❌ Transcription returned empty text" | |
| rewrite_prompt = f"""Rewrite the following transcribed text with proper grammar, punctuation, and clarity. | |
| Maintain the original meaning and language (Urdu/English). | |
| If the text is in Urdu, use very short sentences. Break long sentences into smaller ones: | |
| {text}""" | |
| completion = client.chat.completions.create( | |
| model=CHAT_MODEL, | |
| messages=[{"role": "user", "content": rewrite_prompt}], | |
| temperature=0.5, | |
| max_tokens=8192 | |
| ) | |
| rewritten_text = completion.choices[0].message.content.strip() | |
| return rewritten_text, "✅ Transcription completed successfully" | |
| def transcribe_audio_chunked(audio_path): | |
| if not audio_path: | |
| return None, "⚠️ No audio file provided" | |
| try: | |
| file_size = os.path.getsize(audio_path) | |
| if file_size <= MAX_AUDIO_SIZE: | |
| return transcribe_single_audio(audio_path) | |
| print(f"Large audio file detected ({file_size / (1024*1024):.2f} MB). Processing in chunks...") | |
| with open(audio_path, "rb") as audio_file: | |
| audio_data = audio_file.read() | |
| num_chunks = math.ceil(file_size / MAX_AUDIO_SIZE) | |
| chunk_size = len(audio_data) // num_chunks | |
| all_transcriptions = [] | |
| for i in range(num_chunks): | |
| start_idx = i * chunk_size | |
| end_idx = start_idx + chunk_size if i < num_chunks - 1 else len(audio_data) | |
| chunk_data = audio_data[start_idx:end_idx] | |
| print(f"Processing chunk {i+1}/{num_chunks}...") | |
| try: | |
| transcription = client.audio.transcriptions.create( | |
| file=(f"chunk_{i}.mp3", chunk_data), | |
| model=TRANSCRIPTION_MODEL, | |
| temperature=0.0, | |
| response_format="verbose_json" | |
| ) | |
| chunk_text = transcription.text.strip() | |
| if chunk_text: | |
| all_transcriptions.append(chunk_text) | |
| except Exception as e: | |
| print(f"Error transcribing chunk {i+1}: {str(e)}") | |
| combined_text = " ".join(all_transcriptions) | |
| if not combined_text: | |
| return None, "❌ Transcription returned empty text" | |
| rewrite_prompt = f"""Rewrite the following transcribed text with proper grammar, punctuation, and clarity. | |
| Maintain the original meaning and language (Urdu/English). | |
| If the text is in Urdu, use very short sentences. Break long sentences into smaller ones. | |
| Ensure the text flows naturally and coherently: | |
| {combined_text}""" | |
| completion = client.chat.completions.create( | |
| model=CHAT_MODEL, | |
| messages=[{"role": "user", "content": rewrite_prompt}], | |
| temperature=0.5, | |
| max_tokens=8192 | |
| ) | |
| rewritten_text = completion.choices[0].message.content.strip() | |
| return rewritten_text, f"✅ Transcription completed successfully ({num_chunks} chunks processed)" | |
| except Exception as e: | |
| error_msg = f"❌ Transcription Error: {str(e)}" | |
| print(f"Transcription error details: {traceback.format_exc()}") | |
| return None, error_msg | |
| def generate_content(text, content_type, language="English"): | |
| if not text or text.strip() == "": | |
| return "❌ No transcribed text available. Please transcribe audio first." | |
| lang_instruction = "" | |
| if language == "Urdu": | |
| lang_instruction = """CRITICAL: You MUST write the entire response in Urdu language ONLY. | |
| Do not use ANY English words or phrases except for technical terms that have no Urdu equivalent. | |
| Use very short sentences in Urdu. Break long sentences into smaller ones. | |
| Write naturally in Urdu without mixing any English.""" | |
| else: | |
| lang_instruction = """CRITICAL: You MUST write the entire response in English language ONLY. | |
| Do not mix Urdu or any other language. Write everything in clear, proper English.""" | |
| prompts = { | |
| "themes_subthemes": f"""{lang_instruction} | |
| Act as a qualitative researcher. Analyze the text and identify all major themes and their subthemes. | |
| Present in a clear hierarchical structure. Start directly with the themes and subthemes without any introductory text. | |
| Text to analyze: {text}""", | |
| "summary": f"""{lang_instruction} | |
| Create a comprehensive summary of the text. Include key points and main ideas. | |
| Write the summary directly without any introductory phrases. Text to summarize: {text}""", | |
| "study_notes": f"""{lang_instruction} | |
| Create detailed study notes from the text. Organize with clear headings and key concepts. | |
| Present the notes directly without any introductory text. Text: {text}""", | |
| "tutorial_beginners": f"""{lang_instruction} | |
| Create a step-by-step tutorial for absolute beginners based on this content. | |
| Use simple language and clear instructions. Start directly with the tutorial steps without introduction. Content: {text}""", | |
| "infographic_content": f"""{lang_instruction} | |
| Create infographic-style content from the text. Use short phrases and clear structure. | |
| NO EMOJIS. NO SPECIAL CHARACTERS. Use plain text only. Make it organized and easy to read. Text: {text}""", | |
| "social_facebook": f"""{lang_instruction} | |
| Create an engaging Facebook post from this content. Make it conversational and relatable. | |
| Include relevant hashtags. Write the post directly without any introductory phrases. Content: {text}""", | |
| "social_linkedin": f"""{lang_instruction} | |
| Create a professional LinkedIn post from this content. Make it insightful and career-focused. | |
| Include relevant hashtags. Write the post directly without any introductory phrases. Content: {text}""", | |
| "quiz_mcqs": f"""{lang_instruction} | |
| Generate 10 multiple-choice questions from this text. Each question should have 4 options (A, B, C, D). | |
| Mark the correct answer with an asterisk (*) after the option letter. | |
| Format each question as: | |
| Question 1: [Question text] | |
| A) [Option A] | |
| B) [Option B] | |
| C) [Option C] | |
| D) [Option D] | |
| Correct Answer: [Letter]* | |
| Write questions directly without any introductory text. Text: {text}""", | |
| "quiz_truefalse": f"""{lang_instruction} | |
| Generate 10 True/False questions from this text. | |
| Format each question as: | |
| Question 1: [Statement] | |
| Answer: True / False | |
| Provide the correct answer for each question. Write questions directly without any introductory text. Text: {text}""", | |
| "quiz_fillblanks": f"""{lang_instruction} | |
| Generate 10 fill-in-the-blank questions from this text. | |
| Format each question as: | |
| Question 1: [Sentence with _____ for blank] | |
| Answer: [Correct word/phrase] | |
| Provide correct answers for each question. Write questions directly without any introductory text. Text: {text}""", | |
| "quiz_matching": f"""{lang_instruction} | |
| Create a matching exercise with 10 items in Column A and their matches in Column B. | |
| Format as: | |
| Column A: | |
| 1. [Item 1] | |
| 2. [Item 2] | |
| ... | |
| Column B: | |
| a) [Match option a] | |
| b) [Match option b] | |
| ... | |
| Correct Matches: | |
| 1 - [letter] | |
| 2 - [letter] | |
| ... | |
| Present directly without any introductory text. Text: {text}""", | |
| "quiz_short": f"""{lang_instruction} | |
| Generate 10 short-answer questions from this text with brief model answers. | |
| Format each question as: | |
| Question 1: [Question text] | |
| Model Answer: [2-3 sentence answer] | |
| Write questions directly without any introductory text. Text: {text}""", | |
| "quiz_essay": f"""{lang_instruction} | |
| Generate 5 essay-type questions from this text with key points to cover. | |
| Format each question as: | |
| Question 1: [Essay question] | |
| Key Points to Cover: | |
| - Point 1 | |
| - Point 2 | |
| - Point 3 | |
| Write questions directly without any introductory text. Text: {text}""", | |
| "chapter": f"""{lang_instruction} | |
| Create a comprehensive book chapter from this content. Include: | |
| - Chapter title | |
| - Introduction (2-3 paragraphs) | |
| - Main sections with headings (3-5 sections) | |
| - Each section should have multiple paragraphs | |
| - Conclusion (2 paragraphs) | |
| - Key takeaways (5-7 bullet points) | |
| Write in an academic style suitable for a textbook. Present directly without any introductory text. Content: {text}""", | |
| "mindmap": f"""{lang_instruction} | |
| Create a text-based mind map structure from this content. | |
| Show central idea, main branches, and sub-branches clearly. Present directly without any introductory text. Content: {text}""", | |
| "meeting_minutes": f"""{lang_instruction} | |
| Create professional minutes of meeting from this text. Include: | |
| - Date and attendees | |
| - Agenda items | |
| - Decisions made | |
| - Action items | |
| Write directly without any introductory phrases. Text: {text}""", | |
| "powerpoint": f"""{lang_instruction} | |
| Create PowerPoint slide content. For each slide, provide: | |
| - Slide title | |
| - 3-5 bullet points | |
| - Brief speaker notes | |
| Create 8-10 slides covering all key points. Format each slide clearly with "Slide X:" as the heading. Content: {text}""" | |
| } | |
| prompt = prompts.get(content_type, f"{lang_instruction}\n\nProcess this text:\n\n{text}") | |
| try: | |
| completion = client.chat.completions.create( | |
| model=CHAT_MODEL, | |
| messages=[{"role": "user", "content": prompt}], | |
| temperature=0.7, | |
| max_tokens=8192 | |
| ) | |
| result = completion.choices[0].message.content.strip() | |
| intro_phrases = ["Here are", "Here is", "Here's", "Based on", "According to", "یہاں ہیں", "یہ ہے", "مندرجہ ذیل"] | |
| for phrase in intro_phrases: | |
| if result.lower().startswith(phrase.lower()): | |
| idx = result.find('\n') | |
| if idx > 0: | |
| result = result[idx+1:].strip() | |
| idx = result.find(':') | |
| if idx > 0 and idx < 100: | |
| result = result[idx+1:].strip() | |
| return result | |
| except Exception as e: | |
| error_msg = f"❌ Content Generation Error: {str(e)}" | |
| print(f"Content generation error: {traceback.format_exc()}") | |
| return error_msg | |
| def create_docx(content, title, institution_name="", writer_name="", language="English"): | |
| try: | |
| doc = Document() | |
| is_urdu = language == "Urdu" or is_urdu_text(content) | |
| style = doc.styles['Normal'] | |
| font = style.font | |
| font.name = 'Times New Roman' | |
| font.size = Pt(12) | |
| if institution_name: | |
| section = doc.sections[0] | |
| header = section.header | |
| header_para = header.paragraphs[0] | |
| header_para.text = institution_name.upper() | |
| header_para.alignment = WD_ALIGN_PARAGRAPH.CENTER | |
| header_para.runs[0].font.bold = True | |
| header_para.runs[0].font.size = Pt(14) | |
| if writer_name: | |
| writer_para = doc.add_paragraph() | |
| writer_run = writer_para.add_run(f"Writer: {writer_name}\n" if not is_urdu else f"مصنف: {writer_name}\n") | |
| writer_run.bold = True | |
| if is_urdu: | |
| writer_para.alignment = WD_ALIGN_PARAGRAPH.RIGHT | |
| date_para = doc.add_paragraph() | |
| date_text = f"Date: {datetime.now().strftime('%B %d, %Y')}\n" if not is_urdu else f"تاریخ: {datetime.now().strftime('%d/%m/%Y')}\n" | |
| date_run = date_para.add_run(date_text) | |
| date_run.bold = True | |
| if is_urdu: | |
| date_para.alignment = WD_ALIGN_PARAGRAPH.RIGHT | |
| title_para = doc.add_paragraph() | |
| title_run = title_para.add_run(title) | |
| title_run.font.size = Pt(24) | |
| title_run.font.bold = True | |
| title_run.font.name = 'Times New Roman' | |
| title_para.alignment = WD_ALIGN_PARAGRAPH.CENTER | |
| doc.add_paragraph() | |
| lines = content.split('\n') | |
| for line in lines: | |
| if line.strip(): | |
| para = doc.add_paragraph(line) | |
| para.paragraph_format.line_spacing = 1.5 | |
| if is_urdu or is_urdu_text(line): | |
| para.alignment = WD_ALIGN_PARAGRAPH.RIGHT | |
| pPr = para._element.get_or_add_pPr() | |
| bidi = OxmlElement('w:bidi') | |
| bidi.set(qn('w:val'), '1') | |
| pPr.append(bidi) | |
| if line.startswith('##'): | |
| para.runs[0].font.size = Pt(18) | |
| para.runs[0].font.bold = True | |
| elif line.startswith('#'): | |
| para.runs[0].font.size = Pt(18) | |
| para.runs[0].font.bold = True | |
| elif line.isupper() and len(line.split()) < 8: | |
| para.runs[0].font.size = Pt(18) | |
| para.runs[0].font.bold = True | |
| for section in doc.sections: | |
| add_page_numbers(section) | |
| for section in doc.sections: | |
| section.top_margin = Inches(1) | |
| section.bottom_margin = Inches(1) | |
| section.left_margin = Inches(1) | |
| section.right_margin = Inches(1) | |
| filename = f"{title.replace(' ', '_')}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.docx" | |
| doc.save(filename) | |
| return filename | |
| except Exception as e: | |
| print(f"DOCX creation error: {traceback.format_exc()}") | |
| raise e | |
| def create_pptx(content, title, language="English"): | |
| try: | |
| prs = Presentation() | |
| prs.slide_width = PptxInches(10) | |
| prs.slide_height = PptxInches(7.5) | |
| is_urdu = language == "Urdu" or is_urdu_text(content) | |
| title_slide_layout = prs.slide_layouts[0] | |
| slide = prs.slides.add_slide(title_slide_layout) | |
| slide.shapes.title.text = title | |
| title_frame = slide.shapes.title.text_frame | |
| title_frame.paragraphs[0].font.size = PptxPt(44) | |
| title_frame.paragraphs[0].font.bold = True | |
| title_frame.paragraphs[0].font.color.rgb = PptxRGBColor(25, 25, 112) | |
| subtitle = slide.placeholders[1] | |
| subtitle_text = f"Generated on {datetime.now().strftime('%B %d, %Y')}" | |
| if is_urdu: | |
| subtitle_text = f"تیار کردہ: {datetime.now().strftime('%d/%m/%Y')}" | |
| subtitle.text = subtitle_text | |
| for paragraph in subtitle.text_frame.paragraphs: | |
| paragraph.font.color.rgb = PptxRGBColor(70, 130, 180) | |
| paragraph.font.size = PptxPt(20) | |
| objectives_layout = prs.slide_layouts[1] | |
| obj_slide = prs.slides.add_slide(objectives_layout) | |
| obj_slide.shapes.title.text = "Session Objectives" if not is_urdu else "سیشن کے مقاصد" | |
| obj_title_frame = obj_slide.shapes.title.text_frame | |
| obj_title_frame.paragraphs[0].font.color.rgb = PptxRGBColor(220, 20, 60) | |
| obj_title_frame.paragraphs[0].font.bold = True | |
| obj_frame = obj_slide.shapes.placeholders[1].text_frame | |
| obj_frame.clear() | |
| objectives = ["Understand key concepts and main ideas", "Apply knowledge in practical scenarios", "Develop critical thinking skills"] | |
| if is_urdu: | |
| objectives = ["اہم تصورات اور بنیادی خیالات کو سمجھنا", "عملی منظرناموں میں علم کا اطلاق کرنا", "تنقیدی سوچ کی مہارت پیدا کرنا"] | |
| objective_colors = [PptxRGBColor(46, 139, 87), PptxRGBColor(255, 140, 0), PptxRGBColor(138, 43, 226)] | |
| for idx, obj_text in enumerate(objectives): | |
| p = obj_frame.add_paragraph() | |
| p.text = obj_text | |
| p.font.size = PptxPt(24) | |
| p.font.color.rgb = objective_colors[idx % len(objective_colors)] | |
| p.level = 0 | |
| if is_urdu: | |
| p.alignment = PP_ALIGN.RIGHT | |
| slides_content = [] | |
| current_slide = {"title": "", "points": []} | |
| lines = content.split('\n') | |
| for line in lines: | |
| line = line.strip() | |
| if not line: | |
| continue | |
| if line.startswith('Slide') or line.startswith('**') or (line.isupper() and len(line.split()) < 10): | |
| if current_slide["title"]: | |
| slides_content.append(current_slide) | |
| current_slide = {"title": line.replace('**', '').replace('Slide', '').replace(':', '').strip(), "points": []} | |
| elif line.startswith('-') or line.startswith('•') or line.startswith('*'): | |
| current_slide["points"].append(line.lstrip('-•* ')) | |
| elif current_slide["title"]: | |
| current_slide["points"].append(line) | |
| if current_slide["title"]: | |
| slides_content.append(current_slide) | |
| title_colors = [PptxRGBColor(0, 51, 102), PptxRGBColor(139, 0, 0), PptxRGBColor(0, 100, 0), PptxRGBColor(148, 0, 211), PptxRGBColor(255, 140, 0), PptxRGBColor(0, 139, 139)] | |
| text_colors = [PptxRGBColor(47, 79, 79), PptxRGBColor(105, 105, 105), PptxRGBColor(25, 25, 112)] | |
| for idx, slide_data in enumerate(slides_content): | |
| bullet_slide_layout = prs.slide_layouts[1] | |
| slide = prs.slides.add_slide(bullet_slide_layout) | |
| slide.shapes.title.text = slide_data["title"] | |
| title_frame = slide.shapes.title.text_frame | |
| title_frame.paragraphs[0].font.size = PptxPt(32) | |
| title_frame.paragraphs[0].font.bold = True | |
| title_frame.paragraphs[0].font.color.rgb = title_colors[idx % len(title_colors)] | |
| text_frame = slide.shapes.placeholders[1].text_frame | |
| text_frame.clear() | |
| for point_idx, point in enumerate(slide_data["points"][:6]): | |
| p = text_frame.add_paragraph() | |
| p.text = point | |
| p.level = 0 | |
| p.font.size = PptxPt(24) | |
| p.font.color.rgb = text_colors[point_idx % len(text_colors)] | |
| if is_urdu or is_urdu_text(point): | |
| p.alignment = PP_ALIGN.RIGHT | |
| conclusion_layout = prs.slide_layouts[1] | |
| conclusion_slide = prs.slides.add_slide(conclusion_layout) | |
| conclusion_slide.shapes.title.text = "Conclusion" if not is_urdu else "نتیجہ" | |
| conc_title_frame = conclusion_slide.shapes.title.text_frame | |
| conc_title_frame.paragraphs[0].font.color.rgb = PptxRGBColor(178, 34, 34) | |
| conc_title_frame.paragraphs[0].font.bold = True | |
| conc_frame = conclusion_slide.shapes.placeholders[1].text_frame | |
| conc_frame.clear() | |
| conclusion_text = ["Thank you for your attention", "Questions and Discussion", "Contact for further information"] | |
| if is_urdu: | |
| conclusion_text = ["آپ کی توجہ کا شکریہ", "سوالات اور بحث", "مزید معلومات کے لیے رابطہ کریں"] | |
| conclusion_colors = [PptxRGBColor(0, 128, 0), PptxRGBColor(255, 69, 0), PptxRGBColor(72, 61, 139)] | |
| for idx, text in enumerate(conclusion_text): | |
| p = conc_frame.add_paragraph() | |
| p.text = text | |
| p.font.size = PptxPt(28) | |
| p.font.bold = True | |
| p.font.color.rgb = conclusion_colors[idx] | |
| if is_urdu: | |
| p.alignment = PP_ALIGN.RIGHT | |
| filename = f"{title.replace(' ', '_')}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pptx" | |
| prs.save(filename) | |
| return filename | |
| except Exception as e: | |
| print(f"PPTX creation error: {traceback.format_exc()}") | |
| raise e | |
| def ui_transcribe(upload_audio, record_audio, lang_choice): | |
| audio = upload_audio or record_audio | |
| if not audio: | |
| return "", "⚠️ No audio provided" | |
| return transcribe_audio_chunked(audio) | |
| def ui_quick_generate_and_download(content_type, transcription_box, lang_choice, institution_input, writer_input): | |
| if not transcription_box: | |
| return "❌ No transcribed text available. Please transcribe audio first.", None, "" | |
| try: | |
| content = generate_content(transcription_box, content_type, lang_choice) | |
| if content.startswith("❌"): | |
| return content, None, content | |
| title_map = { | |
| "themes_subthemes": "Themes and Subthemes Analysis" if lang_choice == "English" else "موضوعات اور ذیلی موضوعات کا تجزیہ", | |
| "summary": "Summary" if lang_choice == "English" else "خلاصہ", | |
| "study_notes": "Study Notes" if lang_choice == "English" else "مطالعاتی نوٹس", | |
| "tutorial_beginners": "Tutorial for Beginners" if lang_choice == "English" else "ابتدائی افراد کے لیے ٹیوٹوریل", | |
| "infographic_content": "Infographic Content" if lang_choice == "English" else "انفوگرافک مواد", | |
| "social_facebook": "Facebook Post" if lang_choice == "English" else "فیس بک پوسٹ", | |
| "social_linkedin": "LinkedIn Post" if lang_choice == "English" else "لنکڈان پوسٹ", | |
| "quiz_mcqs": "Multiple Choice Questions" if lang_choice == "English" else "کثیر الانتخابی سوالات", | |
| "quiz_truefalse": "True False Questions" if lang_choice == "English" else "درست غلط سوالات", | |
| "quiz_fillblanks": "Fill in the Blanks" if lang_choice == "English" else "خالی جگہ پر کریں", | |
| "quiz_matching": "Matching Exercise" if lang_choice == "English" else "ملاپ کی مشق", | |
| "quiz_short": "Short Answer Questions" if lang_choice == "English" else "مختصر جوابی سوالات", | |
| "quiz_essay": "Essay Questions" if lang_choice == "English" else "مضمون کے سوالات", | |
| "mindmap": "Mind Map" if lang_choice == "English" else "ذہنی نقشہ", | |
| "meeting_minutes": "Minutes of Meeting" if lang_choice == "English" else "اجلاس کی کارروائی", | |
| "chapter": "Book Chapter" if lang_choice == "English" else "کتاب کا باب" | |
| } | |
| title = title_map.get(content_type, "Generated Content") | |
| content_clean = remove_emojis_and_special_chars(content) | |
| filename = create_docx(content_clean, title, institution_input, writer_input, lang_choice) | |
| return f"✅ {title} generated successfully!", filename, content | |
| except Exception as e: | |
| error_msg = f"❌ Error: {str(e)}" | |
| print(f"Quick generation error: {traceback.format_exc()}") | |
| return error_msg, None, error_msg | |
| def ui_generate_pptx(transcription_box, lang_choice, institution_input, writer_input): | |
| if not transcription_box: | |
| return None, "❌ No transcribed text available" | |
| try: | |
| content = generate_content(transcription_box, "powerpoint", lang_choice) | |
| if content.startswith("❌"): | |
| return None, content | |
| ppt_title = "Presentation" if lang_choice == "English" else "پیشکش" | |
| filename = create_pptx(content, ppt_title, lang_choice) | |
| return filename, "✅ PowerPoint presentation created" | |
| except Exception as e: | |
| error_msg = f"❌ Error: {str(e)}" | |
| print(f"PowerPoint generation error: {traceback.format_exc()}") | |
| return None, error_msg | |
| with gr.Blocks(title="Voice Transcription & Content Generation") as app: | |
| gr.Markdown(""" | |
| # 🎙️ Professional Voice Transcription & Content Generation System | |
| ### Transform your audio into professional documents, presentations, and educational content | |
| **Supports:** Urdu & English | **Features:** 15+ Content Types | **Export:** DOCX & PPTX | |
| **Developer:** Najaf Ali Sharqi | |
| --- | |
| ### 🌍 **Empowering Education in Low-Resource Countries** | |
| This application bridges the digital divide in academia, particularly in developing nations like Pakistan. By providing: | |
| - **Free multilingual transcription** (Urdu/English) for lectures and seminars | |
| - **Automated content generation** for study materials, eliminating hours of manual work | |
| - **Professional document creation** without expensive software licenses | |
| - **Accessible AI tools** for educators and students with limited resources | |
| This tool democratizes educational content creation, enabling teachers in remote areas to produce high-quality materials, | |
| students to convert lectures into study notes, and researchers to document their work professionally—all without financial barriers. | |
| --- | |
| """) | |
| with gr.Row(): | |
| with gr.Column(scale=6): | |
| gr.Markdown("### 1") | |
| gr.Markdown("### 1) Audio Input") | |
| upload_audio = gr.Audio(sources=["upload"], type="filepath", label="Upload Audio (MP3/WAV)") | |
| record_audio = gr.Audio(sources=["microphone"], type="filepath", label="Record Audio (Microphone)") | |
| lang_choice = gr.Dropdown(["English", "Urdu"], value="English", label="Transcription / Output Language") | |
| transcribe_btn = gr.Button("🔍 Transcribe Audio", variant="primary") | |
| trans_status = gr.Textbox(label="Status", interactive=False) | |
| transcription_box = gr.Textbox(label="Transcribed Text", lines=12) | |
| clear_btn = gr.Button("🔄 Clear", variant="secondary") | |
| with gr.Column(scale=6): | |
| gr.Markdown("### 2) Content Generation & Downloads") | |
| institution_input = gr.Textbox(label="Institution Name (optional)", lines=1) | |
| writer_input = gr.Textbox(label="Writer Name (optional)", lines=1) | |
| gr.Markdown("### 📄 Generate PowerPoint Presentation") | |
| generate_pptx_btn = gr.Button("🖥️ Generate & Download PPTX", variant="primary", size="lg") | |
| pptx_status = gr.Textbox(label="PPTX Status", interactive=False) | |
| pptx_file = gr.File(label="Download PPTX") | |
| gr.Markdown("### ⚡ Quick Actions - Generate & Download Content") | |
| gr.Markdown("*Click any button to instantly generate content and download as Word document*") | |
| with gr.Row(): | |
| qa_summary = gr.Button("📝 Summary", variant="secondary") | |
| qa_notes = gr.Button("📚 Study Notes", variant="secondary") | |
| qa_themes = gr.Button("🎯 Themes", variant="secondary") | |
| qa_chapter = gr.Button("📖 Chapter", variant="secondary") | |
| with gr.Row(): | |
| qa_tutorial = gr.Button("🎓 Tutorial", variant="secondary") | |
| qa_mindmap = gr.Button("🧠 Mind Map", variant="secondary") | |
| qa_infographic = gr.Button("📊 Infographic", variant="secondary") | |
| qa_minutes = gr.Button("📋 Meeting Minutes", variant="secondary") | |
| with gr.Row(): | |
| qa_mcqs = gr.Button("❓ MCQs", variant="secondary") | |
| qa_truefalse = gr.Button("✓✗ True/False", variant="secondary") | |
| qa_fillblanks = gr.Button("⬜ Fill Blanks", variant="secondary") | |
| qa_matching = gr.Button("🔗 Matching", variant="secondary") | |
| with gr.Row(): | |
| qa_short = gr.Button("✍️ Short Answer", variant="secondary") | |
| qa_essay = gr.Button("📄 Essay Questions", variant="secondary") | |
| qa_facebook = gr.Button("📱 Facebook Post", variant="secondary") | |
| qa_linkedin = gr.Button("💼 LinkedIn Post", variant="secondary") | |
| quick_status = gr.Textbox(label="Quick Action Status", interactive=False) | |
| quick_file = gr.File(label="Download Generated Document") | |
| quick_output = gr.Textbox(label="Generated Content Preview", lines=10) | |
| transcribe_btn.click(fn=ui_transcribe, inputs=[upload_audio, record_audio, lang_choice], outputs=[transcription_box, trans_status]) | |
| clear_btn.click(fn=lambda: (None, None, "", "", "", None, "", None, ""), inputs=None, outputs=[upload_audio, record_audio, transcription_box, trans_status, quick_status, quick_file, pptx_status, pptx_file, quick_output]) | |
| generate_pptx_btn.click(fn=ui_generate_pptx, inputs=[transcription_box, lang_choice, institution_input, writer_input], outputs=[pptx_file, pptx_status]) | |
| qa_summary.click(fn=lambda t, l, i, w: ui_quick_generate_and_download("summary", t, l, i, w), inputs=[transcription_box, lang_choice, institution_input, writer_input], outputs=[quick_status, quick_file, quick_output]) | |
| qa_notes.click(fn=lambda t, l, i, w: ui_quick_generate_and_download("study_notes", t, l, i, w), inputs=[transcription_box, lang_choice, institution_input, writer_input], outputs=[quick_status, quick_file, quick_output]) | |
| qa_themes.click(fn=lambda t, l, i, w: ui_quick_generate_and_download("themes_subthemes", t, l, i, w), inputs=[transcription_box, lang_choice, institution_input, writer_input], outputs=[quick_status, quick_file, quick_output]) | |
| qa_chapter.click(fn=lambda t, l, i, w: ui_quick_generate_and_download("chapter", t, l, i, w), inputs=[transcription_box, lang_choice, institution_input, writer_input], outputs=[quick_status, quick_file, quick_output]) | |
| qa_tutorial.click(fn=lambda t, l, i, w: ui_quick_generate_and_download("tutorial_beginners", t, l, i, w), inputs=[transcription_box, lang_choice, institution_input, writer_input], outputs=[quick_status, quick_file, quick_output]) | |
| qa_mindmap.click(fn=lambda t, l, i, w: ui_quick_generate_and_download("mindmap", t, l, i, w), inputs=[transcription_box, lang_choice, institution_input, writer_input], outputs=[quick_status, quick_file, quick_output]) | |
| qa_infographic.click(fn=lambda t, l, i, w: ui_quick_generate_and_download("infographic_content", t, l, i, w), inputs=[transcription_box, lang_choice, institution_input, writer_input], outputs=[quick_status, quick_file, quick_output]) | |
| qa_minutes.click(fn=lambda t, l, i, w: ui_quick_generate_and_download("meeting_minutes", t, l, i, w), inputs=[transcription_box, lang_choice, institution_input, writer_input], outputs=[quick_status, quick_file, quick_output]) | |
| qa_mcqs.click(fn=lambda t, l, i, w: ui_quick_generate_and_download("quiz_mcqs", t, l, i, w), inputs=[transcription_box, lang_choice, institution_input, writer_input], outputs=[quick_status, quick_file, quick_output]) | |
| qa_truefalse.click(fn=lambda t, l, i, w: ui_quick_generate_and_download("quiz_truefalse", t, l, i, w), inputs=[transcription_box, lang_choice, institution_input, writer_input], outputs=[quick_status, quick_file, quick_output]) | |
| qa_fillblanks.click(fn=lambda t, l, i, w: ui_quick_generate_and_download("quiz_fillblanks", t, l, i, w), inputs=[transcription_box, lang_choice, institution_input, writer_input], outputs=[quick_status, quick_file, quick_output]) | |
| qa_matching.click(fn=lambda t, l, i, w: ui_quick_generate_and_download("quiz_matching", t, l, i, w), inputs=[transcription_box, lang_choice, institution_input, writer_input], outputs=[quick_status, quick_file, quick_output]) | |
| qa_short.click(fn=lambda t, l, i, w: ui_quick_generate_and_download("quiz_short", t, l, i, w), inputs=[transcription_box, lang_choice, institution_input, writer_input], outputs=[quick_status, quick_file, quick_output]) | |
| qa_essay.click(fn=lambda t, l, i, w: ui_quick_generate_and_download("quiz_essay", t, l, i, w), inputs=[transcription_box, lang_choice, institution_input, writer_input], outputs=[quick_status, quick_file, quick_output]) | |
| qa_facebook.click(fn=lambda t, l, i, w: ui_quick_generate_and_download("social_facebook", t, l, i, w), inputs=[transcription_box, lang_choice, institution_input, writer_input], outputs=[quick_status, quick_file, quick_output]) | |
| qa_linkedin.click(fn=lambda t, l, i, w: ui_quick_generate_and_download("social_linkedin", t, l, i, w), inputs=[transcription_box, lang_choice, institution_input, writer_input], outputs=[quick_status, quick_file, quick_output]) | |
| if __name__ == "__main__": | |
| app.launch() |