""" app.py - Smart Resource Finder Agent + Study Planner — Streamlit Interface """ import os import re import json from datetime import date, timedelta import streamlit as st from agent import ResourceFinderAgent # ─── Page Config ────────────────────────────────────────────────────────────── st.set_page_config( page_title="Smart Resource Finder", page_icon="🎓", layout="centered", initial_sidebar_state="collapsed", ) # ─── Session State Init ─────────────────────────────────────────────────────── if "plan" not in st.session_state: st.session_state.plan = [] if "plan_generated" not in st.session_state: st.session_state.plan_generated = False # ─── Custom CSS ─────────────────────────────────────────────────────────────── st.markdown(""" """, unsafe_allow_html=True) # ─── Hero ───────────────────────────────────────────────────────────────────── st.markdown("""
🎓

Smart Resource Finder

Agentic AI study assistant · Powered by Groq + LLaMA 3.3

""", unsafe_allow_html=True) st.markdown("
", unsafe_allow_html=True) # ─── Sidebar ────────────────────────────────────────────────────────────────── with st.sidebar: st.markdown("### ⚙️ Configuration") st.markdown("Get your **free** Groq API key at [console.groq.com](https://console.groq.com/keys)") sidebar_key = st.text_input("Groq API Key", type="password", placeholder="gsk_...", help="Never stored.") st.markdown("---") st.markdown("**Agent Loop**\n\n```\nObserve → Think → Act\n```\n\nLLaMA 3.3-70B with tool-use via Groq.") api_key = sidebar_key or os.getenv("GROQ_API_KEY", "") # $env:GROQ_API_KEY="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" if not api_key: st.markdown( '
⚠️ No API key found. ' 'Add your Groq key in the sidebar or set GROQ_API_KEY env variable.
', unsafe_allow_html=True, ) # ─── TABS ───────────────────────────────────────────────────────────────────── tab1, tab2 = st.tabs(["🔍 Resource Finder", "📅 Study Planner"]) # ══════════════════════════════════════════════════════════════════════════════ # TAB 1 — RESOURCE FINDER # ══════════════════════════════════════════════════════════════════════════════ with tab1: st.markdown('
', unsafe_allow_html=True) topic = st.text_input( "📖 Enter an academic topic", placeholder="e.g. Machine Learning, Fourier Transform, Operating Systems…", key="topic_input", ) find_clicked = st.button("🔍 Find Study Resources", disabled=not api_key, key="find_btn") st.markdown("
", unsafe_allow_html=True) st.markdown( "

" "Try:  Convolutional Neural Networks  ·  " "Digital Image Processing  ·  " "Data Structures  ·  Quantum Computing

", unsafe_allow_html=True, ) if find_clicked and topic.strip(): with st.spinner("Agent is thinking…"): try: agent = ResourceFinderAgent(api_key=api_key) output = agent.run(topic.strip()) st.markdown("#### 🤖 Agent Loop") for step in output["steps"]: html_step = re.sub(r'\*\*(.*?)\*\*', r'\1', step) st.markdown(f'
{html_step}
', unsafe_allow_html=True) st.markdown("
", unsafe_allow_html=True) st.markdown("#### 📚 Study Resources") st.markdown('
', unsafe_allow_html=True) st.markdown(output["result"]) st.markdown('
', unsafe_allow_html=True) except Exception as exc: st.error(f"❌ Error: {exc}") st.info("Check your Groq API key and internet connection.") elif find_clicked and not topic.strip(): st.warning("Please enter a topic before searching.") # ══════════════════════════════════════════════════════════════════════════════ # TAB 2 — STUDY PLANNER # ══════════════════════════════════════════════════════════════════════════════ with tab2: st.markdown("### 📅 AI Study Planner") st.markdown( "

" "Enter your exam date and topics — AI will auto-build a day-by-day " "study schedule counting backwards from your exam. " "Tick off sessions as you complete them!

", unsafe_allow_html=True, ) # ── Inputs ──────────────────────────────────────────────────────────────── st.markdown('
', unsafe_allow_html=True) col1, col2 = st.columns(2) with col1: exam_date = st.date_input( "🗓️ Exam Date", value=date.today() + timedelta(days=14), min_value=date.today() + timedelta(days=1), key="exam_date", ) with col2: hours_per_day = st.number_input( "⏰ Study Hours / Day", min_value=1, max_value=12, value=3, step=1, key="hours_day", ) topics_input = st.text_area( "📚 Topics to Study (one per line)", placeholder="Machine Learning\nDeep Learning\nConvolutional Neural Networks\nNLP", height=130, key="topics_area", ) generate_clicked = st.button( "🗺️ Generate My Study Plan", disabled=not api_key, key="gen_plan_btn", ) st.markdown("
", unsafe_allow_html=True) # ── Generate Plan ───────────────────────────────────────────────────────── if generate_clicked: topics_list = [t.strip() for t in topics_input.strip().splitlines() if t.strip()] if not topics_list: st.warning("Please enter at least one topic.") else: days_left = (exam_date - date.today()).days with st.spinner("AI is building your personalised study plan…"): try: from groq import Groq client = Groq(api_key=api_key) prompt = f"""You are an expert academic study planner. Student details: - Days until exam: {days_left} (exam on {exam_date}) - Study hours per day: {hours_per_day} - Topics to cover: {json.dumps(topics_list)} Create a day-by-day study plan starting from TODAY ({date.today()}) up to the day BEFORE the exam. The final day must be: topic="Exam Preparation", task="Full Revision + Mock Test + Rest" Rules: 1. Distribute topics evenly. Big topics can span multiple days. 2. Tasks must be specific (e.g. "Study Backpropagation & Gradient Descent" not "Study ML"). 3. Return ONLY a valid JSON array. No explanation, no markdown, no backticks. Each object must have exactly these keys: - "day": integer starting at 1 - "date": "YYYY-MM-DD" string - "topic": topic name - "task": specific actionable task - "hours": integer (equal to {hours_per_day})""" response = client.chat.completions.create( model="llama-3.3-70b-versatile", messages=[{"role": "user", "content": prompt}], max_tokens=2048, temperature=0.3, ) raw = response.choices[0].message.content.strip() raw = re.sub(r"```json|```", "", raw).strip() plan_data = json.loads(raw) st.session_state.plan = [{**item, "done": False} for item in plan_data] st.session_state.plan_generated = True st.rerun() except json.JSONDecodeError: st.error("❌ AI returned invalid format. Please try again.") except Exception as e: st.error(f"❌ Error: {e}") # ── Show Plan ───────────────────────────────────────────────────────────── if st.session_state.plan_generated and st.session_state.plan: plan = st.session_state.plan total = len(plan) done_count = sum(1 for p in plan if p["done"]) progress_pct = done_count / total if total > 0 else 0 # Exam badge + progress st.markdown( f'
🎯 Exam on {exam_date.strftime("%d %B %Y")}' f'  ·  {(exam_date - date.today()).days} days left
', unsafe_allow_html=True, ) st.markdown( f'
📊 Progress — {done_count}/{total} sessions done ' f'({int(progress_pct*100)}%)
', unsafe_allow_html=True, ) st.progress(progress_pct) st.markdown("
", unsafe_allow_html=True) # Clear button if st.button("🗑️ Clear Plan & Start Over", key="clear_btn"): st.session_state.plan = [] st.session_state.plan_generated = False st.rerun() st.markdown("---") st.markdown( "#### 📋 Your Study Schedule  " "" "— tick ✅ each session when done", unsafe_allow_html=True, ) # Day cards for i, item in enumerate(plan): is_done = item["done"] card_class = "day-card done" if is_done else "day-card" done_icon = "✅" if is_done else "⬜" is_revision = any(k in item["task"].lower() for k in ["revision", "mock", "rest", "exam prep"]) topic_color = "#f59e0b" if is_revision else "#818cf8" col_check, col_content = st.columns([0.07, 0.93]) with col_check: checked = st.checkbox( "", value=is_done, key=f"task_{i}", label_visibility="collapsed", ) if checked != is_done: st.session_state.plan[i]["done"] = checked st.rerun() with col_content: st.markdown( f"""
Day {item['day']}  ·  {item['date']}  ·  ⏱ {item.get('hours','—')}h
{done_icon} {item['task']}
📌 {item['topic']}
""", unsafe_allow_html=True, ) # All done 🎉 if done_count == total: st.markdown( "
" "
🎉
" "
All sessions completed! Go ace that exam!
" "
", unsafe_allow_html=True, ) # ─── Footer ─────────────────────────────────────────────────────────────────── st.markdown("

", unsafe_allow_html=True) st.markdown( "

" "Smart Resource Finder Agent  ·  Built with Groq API + LLaMA 3.3-70B + Streamlit" "

", unsafe_allow_html=True, )