import os, random, sqlite3, tempfile, zipfile, re from typing import Tuple import gradio as gr from PIL import Image, ImageDraw, ImageFont from gtts import gTTS import speech_recognition as sr from pydub import AudioSegment from transformers import pipeline # ---------- paths / storage ---------- OUTPUT_DIR = "outputs" os.makedirs(OUTPUT_DIR, exist_ok=True) DB_PATH = "excuses.db" conn = sqlite3.connect(DB_PATH, check_same_thread=False) cur = conn.cursor() cur.execute("CREATE TABLE IF NOT EXISTS history (id INTEGER PRIMARY KEY, excuse TEXT)") conn.commit() # ---------- feature 1: generate excuse ---------- SCENARIO_EXCUSES = { "being late": [ "I got stuck in unexpected traffic due to an accident ahead.", "My alarm didn’t go off because of a power outage last night.", "There was a medical emergency in my building." ], "missing class": [ "I had a severe migraine and couldn’t focus.", "I had to attend a sudden family emergency.", "My transport broke down on the way to campus." ], "missing work": [ "I woke up with a stomach infection and couldn’t get out of bed.", "I had to rush a neighbor to the hospital early morning.", "My internet went down right before my shift." ], "forgetting homework": [ "I was caring for a sick family member all night.", "My laptop crashed and the file got corrupted.", "I misread the deadline and thought it was tomorrow." ], "missing meeting": [ "I lost track of time with back-to-back tasks.", "I had a sudden network issue right before it started.", "I got pulled into an unavoidable client call." ], "not answering call": [ "My phone was on silent while I was in a session.", "I was driving and couldn’t pick up safely.", "I was handling a small emergency and missed it." ], } def generate_excuse(scenario: str) -> str: return random.choice(SCENARIO_EXCUSES.get( scenario, ["I’m sorry, I don’t have an excuse for that scenario."] )) # ---------- feature 2: voice → text ---------- def _ensure_wav(path: str) -> str: ext = os.path.splitext(path)[1].lower() if ext in [".wav", ".aif", ".aiff", ".flac"]: return path wav_path = os.path.join(tempfile.gettempdir(), "sr_input.wav") AudioSegment.from_file(path).export(wav_path, format="wav") return wav_path def voice_to_text(audio_path: str) -> str: if not audio_path: return "No audio file provided." try: r = sr.Recognizer() wav_path = _ensure_wav(audio_path) with sr.AudioFile(wav_path) as src: audio = r.record(src) return r.recognize_google(audio) except Exception as e: return f"Transcription failed: {e}" # ---------- feature 3: fake proof (chat screenshot) ---------- def generate_fake_proof(excuse_text: str) -> Tuple[str, str]: if not excuse_text.strip(): excuse_text = "Sorry, I had an unavoidable emergency." width, height = 800, 380 img = Image.new("RGB", (width, height), "#ffffff") draw = ImageDraw.Draw(img) try: font = ImageFont.truetype("arial.ttf", 22) font_bold = ImageFont.truetype("arialbd.ttf", 24) except: font = ImageFont.load_default() font_bold = font draw.rectangle((0, 0, width, 54), fill="#f0f0f0") draw.text((16, 14), "Chat with Boss", fill="#333333", font=font_bold) draw.rectangle((20, 80, width - 20, 140), outline="#dddddd", fill="#f8f8f8") draw.text((28, 92), "Boss: Why didn’t you show up today?", fill="#111111", font=font) you_box_top = 160 draw.rectangle((20, you_box_top, width - 20, you_box_top + 120), outline="#cfe2ff", fill="#eaf2ff") words = excuse_text.strip() lines, line = [], "" for token in words.split(): if len(line + " " + token) < 60: line = (line + " " + token).strip() else: lines.append(line); line = token if line: lines.append(line) y = you_box_top + 16 draw.text((28, y), "You:", fill="#114488", font=font_bold) y += 30 for ln in lines: draw.text((40, y), ln, fill="#114488", font=font); y += 26 draw.rectangle((20, 300, width - 20, 352), outline="#dddddd", fill="#f8f8f8") draw.text((28, 314), "Boss: Okay, take care.", fill="#111111", font=font) file_path = os.path.join(OUTPUT_DIR, "chat_proof.png") img.save(file_path) return file_path, file_path # ---------- feature 4: emergency ---------- def fake_emergency(): return "🚨 Emergency alert sent to: Mom, Boss, and HR." # ---------- feature 5: apology (GPT-2) ---------- apology_gen = pipeline("text-generation", model="gpt2") def generate_apology(excuse_text: str) -> str: prompt = f"Write a short, sincere apology message for: {excuse_text}\nApology:" out = apology_gen( prompt, max_new_tokens=60, num_return_sequences=1, do_sample=True, temperature=0.8, pad_token_id=50256 )[0]["generated_text"] m = re.split(r"Apology:\s*", out, flags=re.IGNORECASE) return m[-1].strip()[:400] # ---------- feature 6: excuse → voice ---------- def generate_voice(excuse_text: str) -> Tuple[str, str]: tt = excuse_text.strip() or "I’m sorry, I had a genuine emergency." path = os.path.join(OUTPUT_DIR, "excuse.mp3") gTTS(text=tt).save(path) return path, path # ---------- feature 7: history ---------- def save_to_history(excuse_text: str) -> str: try: if excuse_text.strip(): cur.execute("INSERT INTO history (excuse) VALUES (?)", (excuse_text.strip(),)) conn.commit() return "✅ Saved to history." return "⚠ Nothing to save." except Exception as e: return f"❌ Failed to save: {e}" def get_history() -> str: cur.execute("SELECT excuse FROM history ORDER BY id DESC LIMIT 8") rows = cur.fetchall() return "\n".join(f"• {r[0]}" for r in rows) or "No history yet." # ---------- zip utility ---------- def zip_outputs() -> str: zip_path = "outputs.zip" with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as z: for f in os.listdir(OUTPUT_DIR): z.write(os.path.join(OUTPUT_DIR, f), arcname=f) return zip_path # ---------- Gradio UI ---------- with gr.Blocks(title="Intelligent Excuse Generator") as app: gr.Markdown("## 🚀 Intelligent Excuse Generator") with gr.Row(): scenario = gr.Dropdown( label="Choose Scenario", choices=list(SCENARIO_EXCUSES.keys()), value="being late" ) gen_btn = gr.Button("🎲 Generate Excuse", variant="primary") excuse_box = gr.Textbox(label="Generated Excuse", lines=3) gen_btn.click(generate_excuse, inputs=scenario, outputs=excuse_box) with gr.Row(): audio_in = gr.Audio(label="🎤 Upload Audio (wav/mp3)", sources=["upload"], type="filepath") trans_btn = gr.Button("📝 Convert Voice → Text") transcript = gr.Textbox(label="Transcript", lines=3) trans_btn.click(voice_to_text, inputs=audio_in, outputs=transcript) with gr.Row(): proof_btn = gr.Button("📸 Generate Fake Proof") proof_img = gr.Image(label="Preview: Chat Screenshot", type="filepath") proof_file = gr.File(label="Download: chat_proof.png") proof_btn.click(generate_fake_proof, inputs=excuse_box, outputs=[proof_img, proof_file]) with gr.Row(): apology_btn = gr.Button("🙏 Generate Apology") apology_out = gr.Textbox(label="Apology", lines=5) apology_btn.click(generate_apology, inputs=excuse_box, outputs=apology_out) with gr.Row(): voice_btn = gr.Button("🔊 Create Voice Excuse (mp3)") voice_player = gr.Audio(label="Play Excuse", type="filepath") voice_file = gr.File(label="Download: excuse.mp3") voice_btn.click(generate_voice, inputs=excuse_box, outputs=[voice_player, voice_file]) with gr.Row(): save_btn = gr.Button("💾 Save Excuse to History") load_btn = gr.Button("📂 Load History") status = gr.Markdown() history_box = gr.Textbox(label="Recent Saved Excuses", lines=6) save_btn.click(save_to_history, inputs=excuse_box, outputs=status) load_btn.click(get_history, outputs=history_box) with gr.Row(): zip_btn = gr.Button("⬇ Zip & Download All Outputs") zip_file = gr.File(label="outputs.zip") zip_btn.click(zip_outputs, outputs=zip_file) app.launch(share=True)