import os import time import json import base64 from datetime import datetime import gradio as gr from google import genai from google.genai import types # ── Gemini Client Setup ── api_key = os.environ.get("GEMINI_API_KEY", "") client = genai.Client(api_key=api_key) if api_key else None # ── Mock Data & Configuration ── SUBJECTS = [ {"id": "math", "label": "Mathematics", "emoji": "📐", "description": "Algebra, Calculus, Geometry & more"}, {"id": "science", "label": "Science", "emoji": "🔬", "description": "Physics, Chemistry, Biology & more"}, {"id": "history", "label": "History", "emoji": "🏛️", "description": "World events, civilizations & culture"}, {"id": "literature", "label": "Literature", "emoji": "📖", "description": "Essays, poetry, novels & analysis"}, {"id": "geography", "label": "Geography", "emoji": "🌍", "description": "Maps, climate, human geography"}, {"id": "cs", "label": "Computer Science", "emoji": "💻", "description": "Algorithms, data structures & coding"}, ] SUGGESTIONS = { "math": ["Explain the quadratic formula", "What is a derivative?", "How do matrices work?"], "science": ["Explain Newton's third law", "What is DNA replication?", "How does nuclear fusion work?"], "history": ["What caused WWI?", "Explain the French Revolution", "Who was Genghis Khan?"], "literature": ["Analyse Hamlet's soliloquy", "What is a metaphor?", "Explain stream of consciousness"], "geography": ["What causes earthquakes?", "Explain plate tectonics", "What is the water cycle?"], "cs": ["Explain Big O notation", "What is recursion?", "How does a hash table work?"], } def get_greeting(): h = datetime.now().hour if h < 12: return "Good morning 👋" elif h < 17: return "Good afternoon 👋" else: return "Good evening 👋" # ── Gemini Stream & Logic Functions ── def predict(message, history, subject_id, file_input): if not client: yield "⚠️ Please configure GEMINI_API_KEY in your Hugging Face Space secrets." return subj = next((s["label"] for s in SUBJECTS if s["id"] == subject_id), "General Studies") system_instruction = f"You are an expert AI Tutor specializing in {subj}. Help the student understand concepts clearly." formatted_contents = [] if history: for turn in history: if isinstance(turn, dict): formatted_contents.append(types.Content(role=turn.get("role", "user"), parts=[types.Part.from_text(str(turn.get("content", "")))])) elif isinstance(turn, (list, tuple)) and len(turn) >= 2: if turn[0]: formatted_contents.append(types.Content(role="user", parts=[types.Part.from_text(str(turn[0]))])) if turn[1]: formatted_contents.append(types.Content(role="model", parts=[types.Part.from_text(str(turn[1]))])) current_parts = [types.Part.from_text(message)] if file_input is not None: try: filepath = file_input if isinstance(file_input, str) else getattr(file_input, "name", str(file_input)) with open(filepath, "rb") as f: pdf_bytes = f.read() current_parts.append( types.Part.from_bytes( data=pdf_bytes, mime_type="application/pdf" ) ) except Exception as e: yield f"Error reading PDF file: {str(e)}" return formatted_contents.append(types.Content(role="user", parts=current_parts)) try: response_stream = client.models.generate_content_stream( model='gemini-2.5-flash', contents=formatted_contents, config=types.GenerateContentConfig( system_instruction=system_instruction, temperature=0.7, ) ) partial_message = "" for chunk in response_stream: if chunk.text: partial_message += chunk.text yield partial_message except Exception as e: yield f"An error occurred: {str(e)}" # ── Dynamic Features Generators ── def generate_quiz(subject_id): if not client: return "API key missing." subj = next((s["label"] for s in SUBJECTS if s["id"] == subject_id), "General Studies") prompt = f"Generate a 3-question multiple choice quiz about {subj} with answers at the bottom. Format beautifully with markdown." try: response = client.models.generate_content(model='gemini-2.5-flash', contents=prompt) return response.text except Exception as e: return f"Error generating quiz: {str(e)}" def generate_notes(history, subject_id): if not client: return "API key missing." subj = next((s["label"] for s in SUBJECTS if s["id"] == subject_id), "General Studies") prompt = f"Based on this study history for {subj}: {str(history)}. Create highly structured, clean summary revision notes with key bullet points." try: response = client.models.generate_content(model='gemini-2.5-flash', contents=prompt) return response.text except Exception as e: return f"Error generating notes: {str(e)}" def generate_flashcards(history, subject_id): if not client: return "API key missing." subj = next((s["label"] for s in SUBJECTS if s["id"] == subject_id), "General Studies") prompt = f"Based on this study history for {subj}: {str(history)}. Generate 4 interactive flashcards formatted as 'Question: [Text] | Answer: [Text]'." try: response = client.models.generate_content(model='gemini-2.5-flash', contents=prompt) return response.text except Exception as e: return f"Error generating flashcards: {str(e)}" # ── Gradio UI Construction ── with gr.Blocks() as demo: current_subject_id = gr.State(value="math") with gr.Row(): # SIDEBAR with gr.Column(scale=1, min_width=280): gr.Markdown("## ⚡ StudyAI Dashboard") greeting_md = gr.Markdown(f"*{get_greeting()}*") subject_dropdown = gr.Dropdown( choices=[(s["label"] + " " + s["emoji"], s["id"]) for s in SUBJECTS], value="math", label="📚 Select Active Subject", interactive=True ) gr.Markdown("---") gr.Markdown("⏱️ **Focus Pomodoro Timer**") gr.HTML("