|
|
import gradio as gr |
|
|
import json |
|
|
import random |
|
|
import string |
|
|
from datetime import datetime, timedelta |
|
|
from pathlib import Path |
|
|
|
|
|
|
|
|
ADMIN_PASSWORD = "@mikaelJ46" |
|
|
|
|
|
|
|
|
STORAGE_FILE = Path("school_codes.json") |
|
|
|
|
|
|
|
|
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": "" |
|
|
} |
|
|
] |
|
|
|
|
|
|
|
|
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)) |
|
|
|
|
|
|
|
|
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']: |
|
|
|
|
|
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") |
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
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: |
|
|
|
|
|
|
|
|
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: |
|
|
|
|
|
|
|
|
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 |
|
|
""") |
|
|
|
|
|
|
|
|
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] |
|
|
) |
|
|
|
|
|
|
|
|
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] |
|
|
) |
|
|
|
|
|
|
|
|
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> |
|
|
""") |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
app.launch() |