import os import tempfile import random import requests from urllib.parse import quote_plus from PIL import Image, ImageDraw, ImageFont import pytesseract from gtts import gTTS from moviepy.editor import ImageClip, AudioFileClip, concatenate_videoclips import gradio as gr # =========================== # Environment Variables # =========================== GROQ_API_KEY = os.getenv("GROQ_API_KEY", "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") GROQ_MODEL = "llama-3.3-70b-versatile" if not GROQ_API_KEY: print("⚠️ WARNING: GROQ_API_KEY is missing. Add it in HuggingFace Secrets!") # =========================== # Users Database # =========================== users_db = {} verification_codes = {} # =========================== # Authentication Functions # =========================== def signup_user(username, email, password, contact): if email in users_db: return "Email already registered.", "" code = str(random.randint(100000, 999999)) verification_codes[email] = code users_db[email] = { "username": username, "password": password, "contact": contact, "verified": False } return "Signup successful! Verification code:", code def verify_user(email, code): if email not in users_db: return "Email not registered." if users_db[email]["verified"]: return "Already verified." if verification_codes.get(email) == code: users_db[email]["verified"] = True verification_codes.pop(email) return "Verification successful!" return "Invalid verification code." def login_user(email, password): user = users_db.get(email) if not user: return False, "User not found." if not user["verified"]: return False, "Account not verified." if user["password"] != password: return False, "Incorrect password." return True, f"Welcome {user['username']}!" # =========================== # Groq API Call # =========================== def call_groq(prompt, max_tokens=500): if not GROQ_API_KEY: return "❌ Missing GROQ_API_KEY in environment variables." url = "https://api.groq.com/openai/v1/chat/completions" headers = {"Authorization": f"Bearer {GROQ_API_KEY}", "Content-Type": "application/json"} payload = { "model": GROQ_MODEL, "messages": [{"role": "user", "content": prompt}], "max_tokens": max_tokens } try: r = requests.post(url, json=payload, headers=headers, timeout=20) if r.status_code == 200: return r.json()["choices"][0]["message"]["content"] return f"API Error {r.status_code}: {r.text}" except Exception as e: return f"API Exception: {e}" # =========================== # AI Helper Functions # =========================== def generate_mcqs_from_text(text, n=5): prompt = f"Create {n} MCQs with 4 options and answers:\n\n{text}" return call_groq(prompt) def answer_text_query(query): prompt = f"Answer clearly:\n\n{query}" return call_groq(prompt) # =========================== # Video Generator # =========================== def create_video_simple(text, tts_lang="en", preview=False): if not text.strip(): return None tmp = tempfile.gettempdir() lines = [l.strip() for l in text.split(".") if l.strip()] if preview: lines = lines[:1] # one slide preview clips = [] for i, chunk in enumerate(lines): slide_path = os.path.join(tmp, f"slide_{i}.png") # Create slide img = Image.new("RGB", (480, 320), (255, 182, 193)) draw = ImageDraw.Draw(img) font = ImageFont.load_default() draw.text((20, 20), "AI Generated Slide", fill="blue", font=font) draw.text((20, 80), chunk[:220], fill="black", font=font) img.save(slide_path) # Audio audio_path = os.path.join(tmp, f"audio_{i}.mp3") gTTS(text=chunk, lang=tts_lang).save(audio_path) # Clip clip = ImageClip(slide_path).set_duration(4) clip = clip.set_audio(AudioFileClip(audio_path)) clips.append(clip) output_path = os.path.join(tmp, f"video_preview.mp4" if preview else "video_full.mp4") video = concatenate_videoclips(clips) video.write_videofile(output_path, fps=24, codec="libx264", audio_codec="aac") return output_path # =========================== # Notes + Flowchart # =========================== def generate_notes_flowchart(text): notes = call_groq(f"Summarize into clean notes:\n\n{text}") img = Image.new("RGB", (500, 350), (180, 250, 180)) draw = ImageDraw.Draw(img) font = ImageFont.load_default() y = 20 for line in notes.split("\n"): draw.text((10, y), line[:60], fill="black", font=font) y += 18 if y > 300: break return notes, img # =========================== # Quick Search Links # =========================== def get_links(topic): yt = f"https://www.youtube.com/results?search_query={quote_plus(topic)}" gg = f"https://www.google.com/search?q={quote_plus(topic)}" return yt, gg # =========================== # UI # =========================== with gr.Blocks(title="AI Study Wizard") as demo: gr.Markdown("# 🎓 AI Study Wizard — Full Assistant") # Signup with gr.Tab("Sign Up"): name = gr.Textbox(label="Name") email = gr.Textbox(label="Email") pwd = gr.Textbox(label="Password", type="password") contact = gr.Textbox(label="Contact") btn = gr.Button("Create Account") msg = gr.Textbox(label="Message") code_out = gr.Textbox(label="Verification Code (demo)") btn.click(signup_user, [name, email, pwd, contact], [msg, code_out]) # Verify with gr.Tab("Verify"): v_email = gr.Textbox(label="Email") v_code = gr.Textbox(label="Code") v_btn = gr.Button("Verify") v_msg = gr.Textbox(label="Status") v_btn.click(verify_user, [v_email, v_code], v_msg) # Login with gr.Tab("Login"): l_email = gr.Textbox(label="Email") l_pass = gr.Textbox(label="Password", type="password") l_btn = gr.Button("Login") l_msg = gr.Textbox(label="Message") l_btn.click(lambda e, p: login_user(e, p), [l_email, l_pass], l_msg) # Ask Question with gr.Tab("Ask AI"): q = gr.Textbox(label="Your Question") ans = gr.Textbox(label="Answer", lines=8) mcq = gr.Textbox(label="MCQs", lines=8) pv = gr.Video(label="Preview Video") fv = gr.Video(label="Full Video") b = gr.Button("Generate") def process_query(q): a = answer_text_query(q) m = generate_mcqs_from_text(a) prev = create_video_simple(a, preview=True) full = create_video_simple(a, preview=False) return a, m, prev, full b.click(process_query, q, [ans, mcq, pv, fv]) # Upload Notes with gr.Tab("Upload Image"): file = gr.File(label="Upload Image") lang = gr.Dropdown(["en", "ur", "hi"], value="en") out_text = gr.Textbox(label="Extracted Text", lines=6) out_mcq = gr.Textbox(label="MCQs", lines=6) out_notes = gr.Textbox(label="Notes", lines=6) out_flow = gr.Image(label="Flowchart") out_prev = gr.Video(label="Preview Video") out_full = gr.Video(label="Full Video") def process_upload(f, language): try: text = pytesseract.image_to_string(Image.open(f.name)) except: text = "" mcqs = generate_mcqs_from_text(text) if text else "" notes, img = generate_notes_flowchart(text) if text else ("", None) prev = create_video_simple(text, tts_lang=language, preview=True) if text else None full = create_video_simple(text, tts_lang=language, preview=False) if text else None return text, mcqs, notes, img, prev, full btn = gr.Button("Process") btn.click(process_upload, [file, lang], [out_text, out_mcq, out_notes, out_flow, out_prev, out_full]) # Search Links with gr.Tab("Search"): topic = gr.Textbox(label="Topic") yt = gr.Textbox(label="YouTube", interactive=False) gg = gr.Textbox(label="Google", interactive=False) btn = gr.Button("Search") btn.click(get_links, topic, [yt, gg]) demo.launch()