Studytool / app.py
mikaelJ46's picture
Update app.py
376cac5 verified
import gradio as gr
import json
import random
import string
from datetime import datetime, timedelta
from pathlib import Path
# Admin password
ADMIN_PASSWORD = "@mikaelJ46"
# Storage file for school codes
STORAGE_FILE = Path("school_codes.json")
# Platform links - UPDATE THESE WITH YOUR ACTUAL HUGGINGFACE SPACE URLS
PLATFORMS = [
{
"name": "Chemistry & Biology",
"description": "Deep understanding focus with AI-powered learning",
"subjects": ["Chemistry", "Biology"],
"url": "https://mikaelj46-chembio.hf.space/",
"emoji": ""
},
{
"name": "Geography, History & Business",
"description": "Comprehensive humanities and business studies",
"subjects": ["Geography", "History", "Business"],
"url": "https://mikaelj46-goehistbusn.hf.space/",
"emoji": ""
},
{
"name": "French & EFL",
"description": "Language learning with AI translation and dictionary",
"subjects": ["French", "EFL"],
"url": "https://mikaelj46-language-app.hf.space/",
"emoji": ""
},
{
"name": "Mathematics & Physics",
"description": "Step-by-step problem solving and practice",
"subjects": ["Mathematics", "Physics"],
"url": "https://mikaelj46-mathphysicstool.hf.space/",
"emoji": ""
},
{
"name": "Physical education $ ICT",
"description": "Step-by-step problem solving and practice",
"subjects": ["PE", "ICT"],
"url": "https://mikaelj46-peict.hf.space/",
"emoji": ""
}
]
# Storage functions
def load_codes():
"""Load school codes from storage file"""
if STORAGE_FILE.exists():
with open(STORAGE_FILE, 'r') as f:
return json.load(f)
return {}
def save_codes(codes):
"""Save school codes to storage file"""
with open(STORAGE_FILE, 'w') as f:
json.dump(codes, f, indent=2)
def generate_code():
"""Generate random 8-character school code"""
chars = string.ascii_uppercase + string.digits
return ''.join(random.choice(chars) for _ in range(8))
# Authentication functions
def verify_student(school_code):
"""Verify student school code"""
codes = load_codes()
code = school_code.upper().strip()
if code in codes:
if codes[code]['active']:
# Check expiry
try:
expiry = datetime.fromisoformat(codes[code].get('expiry_date', datetime.now().isoformat()))
if datetime.now() < expiry:
return True, f" Welcome! Access granted with code: {code}", codes[code].get('name', 'Unknown School')
else:
return False, " This school code has expired", None
except:
return True, f" Welcome! Access granted with code: {code}", codes[code].get('name', 'Unknown School')
else:
return False, " This school code has been deactivated", None
return False, " Invalid school code", None
def verify_admin(password):
"""Verify admin password"""
if password == ADMIN_PASSWORD:
return True, " Admin access granted"
return False, " Incorrect admin password"
def create_school_code(school_name, admin_password, expiry_days=365):
"""Admin function to create new school code"""
if admin_password != ADMIN_PASSWORD:
return " Invalid admin password", ""
if not school_name.strip():
return " Please enter a school name", ""
codes = load_codes()
new_code = generate_code()
expiry_date = (datetime.now() + timedelta(days=expiry_days)).isoformat()
codes[new_code] = {
"name": school_name,
"code": new_code,
"active": True,
"created_at": datetime.now().isoformat(),
"expiry_date": expiry_date
}
save_codes(codes)
return f" Code generated successfully!\n\n**School Code:** `{new_code}`\n**School Name:** {school_name}\n**Expires:** {expiry_date[:10]}", new_code
def get_all_codes(admin_password):
"""Get list of all school codes for admin"""
if admin_password != ADMIN_PASSWORD:
return " Invalid admin password"
codes = load_codes()
if not codes:
return " No school codes created yet"
output = f"# All School Codes ({len(codes)})\n\n"
for code, data in codes.items():
status = "🟢 Active" if data['active'] else "🔴 Inactive"
created = datetime.fromisoformat(data['created_at']).strftime("%Y-%m-%d %H:%M")
# Check expiry
try:
expiry = datetime.fromisoformat(data.get('expiry_date', datetime.now().isoformat()))
expiry_str = expiry.strftime("%Y-%m-%d")
if datetime.now() >= expiry:
status = " Expired"
except:
expiry_str = "N/A"
output += f"### {status} `{code}`\n"
output += f"- **School:** {data['name']}\n"
output += f"- **Created:** {created}\n"
output += f"- **Expires:** {expiry_str}\n\n"
return output
def toggle_code_status(school_code, admin_password):
"""Toggle active status of a school code"""
if admin_password != ADMIN_PASSWORD:
return " Invalid admin password"
codes = load_codes()
code = school_code.upper().strip()
if code not in codes:
return " Code not found"
codes[code]['active'] = not codes[code]['active']
save_codes(codes)
status = "activated" if codes[code]['active'] else "deactivated"
return f" Code {code} has been {status}"
def create_platform_links():
"""Create HTML for platform links"""
html = "<div style='display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin-top: 20px;'>"
for platform in PLATFORMS:
subjects = ", ".join(platform['subjects'])
html += f"""
<div style='border: 2px solid #e5e7eb; border-radius: 12px; padding: 20px; background: white; box-shadow: 0 4px 6px rgba(0,0,0,0.1); transition: transform 0.3s;'>
<h3 style='margin: 0 0 10px 0; color: #1976d2;'>{platform['emoji']} {platform['name']}</h3>
<p style='color: #6b7280; font-size: 14px; margin: 10px 0;'>{platform['description']}</p>
<p style='font-size: 12px; color: #9ca3af; margin: 10px 0;'><strong>Subjects:</strong> {subjects}</p>
<a href='{platform['url']}' target='_blank' style='display: inline-block; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 10px 20px; border-radius: 8px; text-decoration: none; margin-top: 10px; font-weight: bold;'>Open Platform →</a>
</div>
"""
html += "</div>"
return html
# Create the Gradio interface
with gr.Blocks(title="IGCSE/GCSE Master Platform", theme=gr.themes.Soft(), css="""
.gradio-container {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.platform-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 12px rgba(0,0,0,0.15);
}
""") as app:
# Header
gr.Markdown("""
<div style="text-align: center; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 40px; border-radius: 15px; margin-bottom: 20px;">
<h1 style="color: white; margin: 0; font-size: 2.5rem;"> IGCSE/GCSE Master Platform</h1>
<p style="color: white; margin: 10px 0 0 0; font-size: 1.2rem;">AI-Powered Learning Platform for All Subjects</p>
</div>
<div style="text-align: center; margin-bottom: 30px;">
<span style="background: #e3f2fd; color: #1976d2; padding: 8px 16px; border-radius: 20px; margin: 0 5px; font-weight: bold;">🤖 AI Tutors</span>
<span style="background: #e8f5e9; color: #2e7d32; padding: 8px 16px; border-radius: 20px; margin: 0 5px; font-weight: bold;">📝 Past Papers</span>
<span style="background: #fff3e0; color: #e65100; padding: 8px 16px; border-radius: 20px; margin: 0 5px; font-weight: bold;">🎯 Practice Questions</span>
<span style="background: #fce4ec; color: #c2185b; padding: 8px 16px; border-radius: 20px; margin: 0 5px; font-weight: bold;">💯 Detailed Feedback</span>
</div>
""")
with gr.Tabs() as tabs:
# HOME TAB - REMOVED PLATFORM LINKS
with gr.Tab(" Home"):
gr.Markdown("""
## Welcome to IGCSE/GCSE Master!
Our comprehensive learning platform covers all major subjects with AI tutors, practice questions,
past papers, and deep understanding focus.
### Access Required
To view and access our learning platforms, please log in using the **Student Login** tab with your school code.
---
### ✨ Platform Features:
<div style='display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin-top: 20px;'>
<div style='background: #e3f2fd; padding: 20px; border-radius: 10px; border-left: 4px solid #1976d2;'>
<h4 style='color: #1976d2; margin-top: 0;'>Justice AI Tutors</h4>
<p style='color: #555; margin-bottom: 0;'>Get personalized help with deep understanding focus</p>
</div>
<div style='background: #e8f5e9; padding: 20px; border-radius: 10px; border-left: 4px solid #2e7d32;'>
<h4 style='color: #2e7d32; margin-top: 0;'> Past Papers</h4>
<p style='color: #555; margin-bottom: 0;'>Access real exam questions indexed by topic</p>
</div>
<div style='background: #fff3e0; padding: 20px; border-radius: 10px; border-left: 4px solid #e65100;'>
<h4 style='color: #e65100; margin-top: 0;'> Practice Questions</h4>
<p style='color: #555; margin-bottom: 0;'>Generate unlimited practice with detailed feedback</p>
</div>
<div style='background: #f3e5f5; padding: 20px; border-radius: 10px; border-left: 4px solid #7b1fa2;'>
<h4 style='color: #7b1fa2; margin-top: 0;'> Detailed Marking</h4>
<p style='color: #555; margin-bottom: 0;'>Comprehensive feedback on all answers</p>
</div>
</div>
---
### Getting Started:
**Students**: Enter your school code in the **Student Login** tab to access all platforms
**Teachers & Admins**: Use your respective tabs to manage content and school codes
""")
# STUDENT LOGIN TAB
with gr.Tab(" Student Login"):
gr.Markdown("""
<div style="text-align: center; padding: 20px;">
<h2 style="color: #1976d2;"> Student Access</h2>
<p style="color: #666;">Enter your school code to access all learning platforms</p>
</div>
""")
student_school_state = gr.State(None)
with gr.Row():
with gr.Column(scale=1):
pass
with gr.Column(scale=2):
with gr.Group() as student_login_section:
student_code_input = gr.Textbox(
label="Enter Your School Code",
placeholder="8-character code (e.g., ABC12345)",
max_lines=1
)
student_login_btn = gr.Button(" Verify Access", variant="primary", size="lg")
student_status = gr.Markdown("")
with gr.Column(scale=1):
pass
with gr.Group(visible=False) as student_platforms_section:
gr.Markdown("""
<div style="text-align: center; padding: 20px; background: linear-gradient(135deg, #e8f5e9 0%, #c8e6c9 100%); border-radius: 10px; margin-bottom: 20px;">
<h2 style="color: #2e7d32; margin: 0;"> Access Granted!</h2>
</div>
""")
student_info_display = gr.Markdown("")
gr.Markdown("### Choose Your Learning Platform:")
student_platforms_html = gr.HTML()
student_logout_btn = gr.Button("🚪 Logout", variant="secondary")
def student_login(code):
success, message, school_name = verify_student(code)
if success:
return {
student_login_section: gr.update(visible=False),
student_platforms_section: gr.update(visible=True),
student_status: gr.update(value=""),
student_info_display: gr.update(value=f"**School:** {school_name}\n**Code:** {code.upper()}"),
student_platforms_html: gr.update(value=create_platform_links()),
student_school_state: school_name
}
return {
student_status: gr.update(value=message),
student_platforms_section: gr.update(visible=False)
}
def student_logout():
return {
student_login_section: gr.update(visible=True),
student_platforms_section: gr.update(visible=False),
student_code_input: gr.update(value=""),
student_status: gr.update(value=""),
student_school_state: None
}
student_login_btn.click(
student_login,
inputs=[student_code_input],
outputs=[student_login_section, student_platforms_section, student_status,
student_info_display, student_platforms_html, student_school_state]
)
student_logout_btn.click(
student_logout,
outputs=[student_login_section, student_platforms_section, student_code_input,
student_status, student_school_state]
)
# ADMIN TAB
with gr.Tab(" Admin Panel"):
gr.Markdown("""
<div style="text-align: center; padding: 20px;">
<h2 style="color: #c62828;"> Administrator Panel</h2>
<p style="color: #666;">Manage school codes and platform access</p>
</div>
""")
admin_password_global = gr.Textbox(
label="Admin Password",
type="password",
placeholder="Enter admin password"
)
admin_verify_btn = gr.Button(" Login", variant="primary")
admin_login_status = gr.Markdown("")
with gr.Group(visible=False) as admin_tools:
gr.Markdown("### Admin Access Granted")
admin_logout_btn = gr.Button(" Logout", variant="secondary")
with gr.Tabs():
with gr.Tab(" Create Code"):
gr.Markdown("### Generate New School Code")
with gr.Row():
school_name_input = gr.Textbox(
label="School/Institution Name",
placeholder="Enter school or group name"
)
expiry_days_slider = gr.Slider(
minimum=30,
maximum=730,
value=365,
step=30,
label="Validity (days)"
)
create_code_btn = gr.Button(" Generate Code", variant="primary")
create_status = gr.Markdown("")
with gr.Tab("📋 Manage Codes"):
gr.Markdown("### All School Codes")
view_codes_btn = gr.Button(" View All Codes", variant="secondary")
codes_display = gr.Markdown("")
gr.Markdown("---")
gr.Markdown("### Activate/Deactivate Code")
with gr.Row():
toggle_code_input = gr.Textbox(
label="School Code",
placeholder="Enter code to toggle"
)
toggle_btn = gr.Button(" Toggle Status", variant="secondary")
toggle_status = gr.Markdown("")
def admin_login(password):
success, message = verify_admin(password)
if success:
return {
admin_tools: gr.update(visible=True),
admin_login_status: gr.update(value=message),
admin_password_global: gr.update(visible=False),
admin_verify_btn: gr.update(visible=False)
}
return {
admin_login_status: gr.update(value=message),
admin_tools: gr.update(visible=False)
}
def admin_logout_fn():
return {
admin_tools: gr.update(visible=False),
admin_password_global: gr.update(visible=True, value=""),
admin_verify_btn: gr.update(visible=True),
admin_login_status: gr.update(value="")
}
admin_verify_btn.click(
admin_login,
inputs=[admin_password_global],
outputs=[admin_tools, admin_login_status, admin_password_global, admin_verify_btn]
)
admin_logout_btn.click(
admin_logout_fn,
outputs=[admin_tools, admin_password_global, admin_verify_btn, admin_login_status]
)
create_code_btn.click(
lambda name, days, pwd: create_school_code(name, pwd, days),
inputs=[school_name_input, expiry_days_slider, admin_password_global],
outputs=[create_status]
)
view_codes_btn.click(
get_all_codes,
inputs=[admin_password_global],
outputs=[codes_display]
)
toggle_btn.click(
toggle_code_status,
inputs=[toggle_code_input, admin_password_global],
outputs=[toggle_status]
)
# Footer
gr.Markdown("""
---
<div style='text-align: center; color: #6b7280; font-size: 14px; padding: 20px;'>
<p style='margin: 5px 0;'><strong>© @mikael Jutice IGCSE/GCSE Master Platform</strong></p>
<p style='margin: 5px 0;'>Powered by Justice AI</p>
<p style='margin: 5px 0;'> system ensures 24/7 availability</p>
</div>
""")
# Launch the app
if __name__ == "__main__":
app.launch()