Download app.py from krish-ai-dev/StudyAI-Smart-Dashboard: direct link, hf CLI and curl.
- Browser
- Download file 11.1 kB
-
https://huggingface.co/spaces/krish-ai-dev/StudyAI-Smart-Dashboard/resolve/a73dfcc41819d6b796894de105fbebf7204a2171/app.py
- Command line
-
hf download hf://spaces/krish-ai-dev/StudyAI-Smart-Dashboard@a73dfcc41819d6b796894de105fbebf7204a2171/app.py
-
curl -L -o app.py https://huggingface.co/spaces/krish-ai-dev/StudyAI-Smart-Dashboard/resolve/a73dfcc41819d6b796894de105fbebf7204a2171/app.py
11.1 kB
| 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 = [] | |
| for turn in history: | |
| formatted_contents.append(types.Content(role="user", parts=[types.Part.from_text(turn[0])])) | |
| formatted_contents.append(types.Content(role="model", parts=[types.Part.from_text(turn[1])])) | |
| current_parts = [types.Part.from_text(message)] | |
| if file_input is not None: | |
| try: | |
| with open(file_input.name, "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): | |
| subj = next((s["label"] for s in SUBJECTS if s["id"] == subject_id), "General Studies") | |
| if not client: return "API key missing." | |
| prompt = f"Generate a 3-question multiple choice quiz about {subj} with answers at the bottom. Format beautifully with markdown." | |
| response = client.models.generate_content(model='gemini-2.5-flash', contents=prompt) | |
| return response.text | |
| def generate_notes(history, subject_id): | |
| subj = next((s["label"] for s in SUBJECTS if s["id"] == subject_id), "General Studies") | |
| if not client: return "API key missing." | |
| prompt = f"Based on this study history for {subj}: {str(history)}. Create highly structured, clean summary revision notes with key bullet points." | |
| response = client.models.generate_content(model='gemini-2.5-flash', contents=prompt) | |
| return response.text | |
| def generate_flashcards(history, subject_id): | |
| subj = next((s["label"] for s in SUBJECTS if s["id"] == subject_id), "General Studies") | |
| if not client: return "API key missing." | |
| prompt = f"Based on this study history for {subj}: {str(history)}. Generate 4 interactive flashcards formatted as 'Question: [Text] | Answer: [Text]'." | |
| response = client.models.generate_content(model='gemini-2.5-flash', contents=prompt) | |
| return response.text | |
| # ── Gradio UI Construction ── | |
| with gr.Blocks(theme=gr.themes.Soft(primary_hue="indigo", secondary_hue="slate")) 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("<div style='font-size:24px; font-weight:bold; text-align:center;'>25:00</div>") | |
| with gr.Row(): | |
| gr.Button("▶️ Start", size="sm") | |
| gr.Button("⏹️ Reset", size="sm") | |
| gr.Markdown("---") | |
| gr.Markdown("📝 **Todo Checklist**") | |
| todo_list = gr.CheckboxGroup( | |
| choices=["Read textbook chapters", "Complete AI Quiz assignment", "Review Generated Notes"], | |
| label="Tasks for Session" | |
| ) | |
| new_todo = gr.Textbox(placeholder="+ Add custom task & press Enter", show_label=False) | |
| def add_todo(task, current_todos): | |
| if task.strip(): current_todos.append(task) | |
| return gr.update(choices=current_todos, value=current_todos), "" | |
| new_todo.submit(add_todo, [new_todo, todo_list], [todo_list, new_todo]) | |
| # MAIN WORKSPACE | |
| with gr.Column(scale=4): | |
| with gr.Tabs() as main_tabs: | |
| # TAB 1: Chat | |
| with gr.Tab("💬 AI Chat Workspace", id="chat_tab"): | |
| subject_info_banner = gr.Markdown("### 📐 Mathematics \n*Algebra, Calculus, Geometry & more*") | |
| suggestion_box = gr.Radio( | |
| choices=SUGGESTIONS["math"], | |
| label="💡 Instant Suggestions (Click to choose, then type or send)", | |
| interactive=True | |
| ) | |
| file_upload = gr.File(label="📂 Upload Study Material (PDF up to 50MB)", file_types=[".pdf"]) | |
| chatbot = gr.Chatbot(height=400, show_copy_button=True) | |
| with gr.Row(): | |
| msg_input = gr.Textbox(placeholder="Ask anything...", scale=4, show_label=False) | |
| audio_input = gr.Audio(sources=["microphone"], type="filepath", label="🎙️ Voice", scale=1) | |
| submit_btn = gr.Button("Send 🚀", variant="primary", scale=1) | |
| def update_subject_view(sub_id): | |
| subj_obj = next((s for s in SUBJECTS if s["id"] == sub_id), SUBJECTS[0]) | |
| banner_text = f"### {subj_obj['emoji']} {subj_obj['label']} \n*{subj_obj['description']}*" | |
| return banner_text, gr.update(choices=SUGGESTIONS.get(sub_id, [])), sub_id, [] | |
| subject_dropdown.change( | |
| update_subject_view, | |
| inputs=[subject_dropdown], | |
| outputs=[subject_info_banner, suggestion_box, current_subject_id, chatbot] | |
| ) | |
| suggestion_box.change(lambda x: x, inputs=[suggestion_box], outputs=[msg_input]) | |
| def handle_audio(audio_path): | |
| if audio_path: return f"[Voice Note Uploaded: Analyzing audio content]" | |
| return "" | |
| audio_input.change(handle_audio, inputs=[audio_input], outputs=[msg_input]) | |
| def respond(message, chat_history, sub_id, pdf_file): | |
| if not message.strip(): return "", chat_history | |
| chat_history.append((message, "")) | |
| for chunk in predict(message, chat_history[:-1], sub_id, pdf_file): | |
| chat_history[-1] = (message, chunk) | |
| yield "", chat_history | |
| submit_btn.click(respond, [msg_input, chatbot, current_subject_id, file_upload], [msg_input, chatbot]) | |
| msg_input.submit(respond, [msg_input, chatbot, current_subject_id, file_upload], [msg_input, chatbot]) | |
| # TAB 2: Quiz | |
| with gr.Tab("🎯 AI Quiz Mode", id="quiz_tab"): | |
| quiz_generate_btn = gr.Button("✨ Generate New Custom Quiz via Gemini", variant="secondary") | |
| quiz_output = gr.Markdown("*Click the button above to dynamically render an AI quiz.*") | |
| quiz_generate_btn.click(generate_quiz, inputs=[current_subject_id], outputs=[quiz_output]) | |
| # TAB 3: Notes | |
| with gr.Tab("📝 Summary Study Notes", id="notes_tab"): | |
| notes_generate_btn = gr.Button("📖 Compile Revision Notes from Chat History", variant="secondary") | |
| notes_output = gr.Markdown("*Click above to transform chat threads into notes.*") | |
| notes_generate_btn.click(generate_notes, inputs=[chatbot, current_subject_id], outputs=[notes_output]) | |
| # TAB 4: Flashcards | |
| with gr.Tab("🃏 Active Flashcards", id="flashcards_tab"): | |
| flash_generate_btn = gr.Button("🔄 Formulate Flashcards from Chat History", variant="secondary") | |
| flash_output = gr.Markdown("*Click above to extract flashcards.*") | |
| flash_generate_btn.click(generate_flashcards, inputs=[chatbot, current_subject_id], outputs=[flash_output]) | |
| gr.Markdown("⚡ *Powered by Gemini 2.5 Flash API.*") | |
| if __name__ == "__main__": | |
| demo.queue() | |
| demo.launch() |