Update app.py
Browse files
app.py
CHANGED
|
@@ -1,31 +1,91 @@
|
|
| 1 |
import streamlit as st
|
| 2 |
from fpdf import FPDF
|
| 3 |
from datetime import datetime
|
| 4 |
-
import re
|
| 5 |
from gtts import gTTS
|
| 6 |
import os
|
|
|
|
| 7 |
|
| 8 |
-
# -------------------------------
|
| 9 |
# Page Setup
|
| 10 |
-
# -------------------------------
|
| 11 |
st.set_page_config(page_title="AI For Everyone", layout="wide")
|
| 12 |
-
|
| 13 |
-
# ---------------------------------
|
| 14 |
-
# Create folders if needed
|
| 15 |
-
# ---------------------------------
|
| 16 |
os.makedirs("audio", exist_ok=True)
|
| 17 |
|
| 18 |
-
# -------------------------------
|
| 19 |
# Analytics & Leaderboard
|
| 20 |
-
# -------------------------------
|
| 21 |
if "analytics" not in st.session_state:
|
| 22 |
st.session_state.analytics = {}
|
| 23 |
if "leaderboard" not in st.session_state:
|
| 24 |
st.session_state.leaderboard = {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
-
#
|
| 27 |
-
|
| 28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
modules = {
|
| 30 |
"What is AI?": {
|
| 31 |
"intro": [
|
|
@@ -243,125 +303,83 @@ modules = {
|
|
| 243 |
}
|
| 244 |
}
|
| 245 |
|
| 246 |
-
# Initialize analytics
|
| 247 |
for topic in modules:
|
| 248 |
st.session_state.analytics.setdefault(topic, 0)
|
| 249 |
st.session_state.leaderboard.setdefault(topic, [])
|
| 250 |
|
| 251 |
-
# -------------------------------
|
| 252 |
-
#
|
| 253 |
-
# -------------------------------
|
| 254 |
-
def clean_filename(text):
|
| 255 |
-
return re.sub(r"[^\w\s-]", "", text).replace(" ", "_")
|
| 256 |
-
|
| 257 |
-
def create_certificate(user, topic, score):
|
| 258 |
-
pdf = FPDF(orientation="L", unit="mm", format="A4")
|
| 259 |
-
pdf.add_page()
|
| 260 |
-
pdf.set_fill_color(0, 102, 204)
|
| 261 |
-
pdf.rect(0, 0, 297, 30, 'F')
|
| 262 |
-
pdf.set_font("Arial", "B", 28)
|
| 263 |
-
pdf.set_text_color(255, 255, 255)
|
| 264 |
-
pdf.cell(0, 15, "Certificate of Mastery", ln=True, align="C")
|
| 265 |
-
pdf.set_fill_color(50, 50, 50)
|
| 266 |
-
pdf.rect(0, 30, 297, 10, 'F')
|
| 267 |
-
pdf.set_font("Arial", "", 16)
|
| 268 |
-
pdf.set_text_color(255, 255, 255)
|
| 269 |
-
pdf.cell(0, 10, "Issued by Future Tech Leaders", ln=True, align="C")
|
| 270 |
-
pdf.ln(10)
|
| 271 |
-
pdf.set_text_color(0, 0, 0)
|
| 272 |
-
pdf.set_font("Arial", "", 14)
|
| 273 |
-
pdf.multi_cell(0, 8, f"Presented to {user} for completing:", align="C")
|
| 274 |
-
pdf.ln(5)
|
| 275 |
-
pdf.set_font("Arial", "B", 20)
|
| 276 |
-
pdf.cell(0, 10, topic, ln=True, align="C")
|
| 277 |
-
pdf.set_font("Arial", "", 14)
|
| 278 |
-
pdf.cell(0, 10, f"Score: {score}/5", ln=True, align="C")
|
| 279 |
-
pdf.ln(10)
|
| 280 |
-
pdf.set_font("Arial", "I", 12)
|
| 281 |
-
pdf.cell(0, 10, f"Date: {datetime.today().strftime('%Y-%m-%d')}", ln=True, align="C")
|
| 282 |
-
fn = f"{clean_filename(user)}_{clean_filename(topic)}.pdf"
|
| 283 |
-
pdf.output(fn)
|
| 284 |
-
return fn
|
| 285 |
-
|
| 286 |
-
def generate_audio_if_missing(topic):
|
| 287 |
-
fname = f"audio/{clean_filename(topic)}.mp3"
|
| 288 |
-
if not os.path.exists(fname):
|
| 289 |
-
text = "\n".join(modules[topic]["intro"])
|
| 290 |
-
tts = gTTS(text)
|
| 291 |
-
tts.save(fname)
|
| 292 |
-
return fname
|
| 293 |
-
|
| 294 |
-
# ---------------------------------
|
| 295 |
-
# Show topic, quiz, scoring, share, leaderboard
|
| 296 |
-
# ---------------------------------
|
| 297 |
def show_module(topic):
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
st.
|
| 303 |
-
st.info("Answer the quiz
|
| 304 |
|
| 305 |
answers = []
|
| 306 |
-
for
|
| 307 |
-
|
| 308 |
-
answers.append(
|
| 309 |
|
| 310 |
-
name = st.text_input("
|
| 311 |
|
| 312 |
if st.button("Submit Quiz", key=f"btn_{topic}"):
|
| 313 |
if "" in answers or not name.strip():
|
| 314 |
-
st.warning("
|
| 315 |
return
|
| 316 |
-
score = sum(1 for ans, qd in zip(answers, modules[topic]["quiz"]) if ans == qd["A"])
|
| 317 |
-
st.success(f"Your score: {score}/5")
|
| 318 |
-
st.session_state.analytics[topic] += 1
|
| 319 |
|
| 320 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 321 |
st.session_state.leaderboard[topic].append({"name": name, "score": score})
|
| 322 |
st.session_state.leaderboard[topic] = sorted(
|
| 323 |
st.session_state.leaderboard[topic], key=lambda x: -x["score"]
|
| 324 |
)[:5]
|
| 325 |
|
| 326 |
-
# Certificate & download
|
| 327 |
cert = create_certificate(name, topic, score)
|
| 328 |
-
st.download_button("Download Certificate", data=open(cert, "rb"), file_name=cert, mime="application/pdf")
|
| 329 |
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
st.markdown(f"[Share on WhatsApp](https://wa.me/?text={share_text}) | "
|
| 334 |
-
f"[Share on Twitter](https://twitter.com/intent/tweet?text={share_text})")
|
| 335 |
|
| 336 |
-
st.subheader("Answer Key")
|
| 337 |
for i, qd in enumerate(modules[topic]["quiz"]):
|
| 338 |
st.markdown(f"{i+1}. **{qd['q']}** β β
{qd['A']}")
|
| 339 |
|
| 340 |
-
# -------------------------------
|
| 341 |
-
# Start
|
| 342 |
-
# -------------------------------
|
| 343 |
-
if "started" not in st.session_state:
|
| 344 |
-
st.session_state.started = False
|
| 345 |
if not st.session_state.started:
|
| 346 |
-
st.title("AI For Everyone
|
| 347 |
-
st.
|
| 348 |
-
if st.button("
|
| 349 |
st.session_state.started = True
|
| 350 |
st.stop()
|
| 351 |
|
| 352 |
-
# -------------------------------
|
| 353 |
-
# Sidebar
|
| 354 |
-
# -------------------------------
|
| 355 |
-
st.sidebar.
|
| 356 |
-
|
| 357 |
-
|
|
|
|
|
|
|
|
|
|
| 358 |
|
| 359 |
-
st.sidebar.
|
| 360 |
-
for t,
|
| 361 |
-
if
|
| 362 |
-
st.sidebar.
|
| 363 |
-
for
|
| 364 |
-
st.sidebar.write(f"
|
| 365 |
|
| 366 |
-
|
|
|
|
|
|
|
| 367 |
show_module(topic)
|
|
|
|
| 1 |
import streamlit as st
|
| 2 |
from fpdf import FPDF
|
| 3 |
from datetime import datetime
|
|
|
|
| 4 |
from gtts import gTTS
|
| 5 |
import os
|
| 6 |
+
import re
|
| 7 |
|
| 8 |
+
# -------------------------------
|
| 9 |
# Page Setup
|
| 10 |
+
# -------------------------------
|
| 11 |
st.set_page_config(page_title="AI For Everyone", layout="wide")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
os.makedirs("audio", exist_ok=True)
|
| 13 |
|
| 14 |
+
# -------------------------------
|
| 15 |
# Analytics & Leaderboard
|
| 16 |
+
# -------------------------------
|
| 17 |
if "analytics" not in st.session_state:
|
| 18 |
st.session_state.analytics = {}
|
| 19 |
if "leaderboard" not in st.session_state:
|
| 20 |
st.session_state.leaderboard = {}
|
| 21 |
+
if "started" not in st.session_state:
|
| 22 |
+
st.session_state.started = False
|
| 23 |
+
|
| 24 |
+
# -------------------------------
|
| 25 |
+
# Clean Filename
|
| 26 |
+
# -------------------------------
|
| 27 |
+
def clean_filename(text):
|
| 28 |
+
return re.sub(r"[^\w\s-]", "", text).replace(" ", "_")
|
| 29 |
+
|
| 30 |
+
# -------------------------------
|
| 31 |
+
# Certificate Generator (DigiSkills style)
|
| 32 |
+
# -------------------------------
|
| 33 |
+
def create_certificate(user, topic, score):
|
| 34 |
+
pdf = FPDF(orientation="L", unit="mm", format="A4")
|
| 35 |
+
pdf.add_page()
|
| 36 |
+
|
| 37 |
+
# Header bar
|
| 38 |
+
pdf.set_fill_color(0, 102, 204)
|
| 39 |
+
pdf.rect(0, 0, 297, 20, 'F')
|
| 40 |
+
pdf.set_text_color(255, 255, 255)
|
| 41 |
+
pdf.set_font("Arial", "B", 22)
|
| 42 |
+
pdf.set_y(5)
|
| 43 |
+
pdf.cell(0, 10, "FUTURE TECH LEADERS", ln=True, align="C")
|
| 44 |
+
|
| 45 |
+
# Main content
|
| 46 |
+
pdf.set_y(35)
|
| 47 |
+
pdf.set_text_color(0, 0, 0)
|
| 48 |
+
pdf.set_font("Arial", "B", 28)
|
| 49 |
+
pdf.cell(0, 15, user.upper(), ln=True, align="C")
|
| 50 |
+
|
| 51 |
+
pdf.set_font("Arial", "", 16)
|
| 52 |
+
pdf.cell(0, 10, f"has completed the training in {topic.upper()} under", ln=True, align="C")
|
| 53 |
+
pdf.cell(0, 10, "AI For Everyone β Digital Literacy Hub", ln=True, align="C")
|
| 54 |
+
|
| 55 |
+
pdf.set_font("Arial", "I", 12)
|
| 56 |
+
pdf.cell(0, 10, "Batch-01 | Jul 2025 - Sep 2025", ln=True, align="C")
|
| 57 |
+
|
| 58 |
+
pdf.set_font("Arial", "", 14)
|
| 59 |
+
pdf.ln(4)
|
| 60 |
+
pdf.cell(0, 10, f"Score Achieved: {score}/5", ln=True, align="C")
|
| 61 |
|
| 62 |
+
# Footer
|
| 63 |
+
pdf.set_y(-35)
|
| 64 |
+
pdf.set_font("Arial", "I", 11)
|
| 65 |
+
pdf.cell(0, 10, f"Issue Date: {datetime.today().strftime('%d/%m/%Y')}", ln=True, align="C")
|
| 66 |
+
pdf.cell(0, 10, "Issued by Future Tech Leaders", ln=True, align="C")
|
| 67 |
+
cert_id = f"FTL-{datetime.now().strftime('%y%m%d%H%M%S')}"
|
| 68 |
+
pdf.cell(0, 10, f"Certificate ID: {cert_id}", ln=True, align="C")
|
| 69 |
+
|
| 70 |
+
filename = f"{clean_filename(user)}_{clean_filename(topic)}.pdf"
|
| 71 |
+
pdf.output(filename)
|
| 72 |
+
return filename
|
| 73 |
+
|
| 74 |
+
# -------------------------------
|
| 75 |
+
# Audio Generator
|
| 76 |
+
# -------------------------------
|
| 77 |
+
def generate_audio_if_missing(topic, text):
|
| 78 |
+
filename = f"audio/{clean_filename(topic)}.mp3"
|
| 79 |
+
if not os.path.exists(filename):
|
| 80 |
+
tts = gTTS(text)
|
| 81 |
+
tts.save(filename)
|
| 82 |
+
return filename
|
| 83 |
+
|
| 84 |
+
# -------------------------------
|
| 85 |
+
# Insert 10 full AI modules here
|
| 86 |
+
# Replace with your full topics from previous steps
|
| 87 |
+
# Each topic should have: "intro": [...], "quiz": [{q, O, A}, ...]
|
| 88 |
+
# -------------------------------
|
| 89 |
modules = {
|
| 90 |
"What is AI?": {
|
| 91 |
"intro": [
|
|
|
|
| 303 |
}
|
| 304 |
}
|
| 305 |
|
| 306 |
+
# Initialize analytics & leaderboard for all topics
|
| 307 |
for topic in modules:
|
| 308 |
st.session_state.analytics.setdefault(topic, 0)
|
| 309 |
st.session_state.leaderboard.setdefault(topic, [])
|
| 310 |
|
| 311 |
+
# -------------------------------
|
| 312 |
+
# Show Module + Quiz
|
| 313 |
+
# -------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 314 |
def show_module(topic):
|
| 315 |
+
explanation = "\n\n".join(modules[topic]["intro"])
|
| 316 |
+
audio_path = generate_audio_if_missing(topic, explanation)
|
| 317 |
+
|
| 318 |
+
st.audio(audio_path, format="audio/mp3")
|
| 319 |
+
st.markdown(explanation)
|
| 320 |
+
st.info("Answer the quiz:")
|
| 321 |
|
| 322 |
answers = []
|
| 323 |
+
for i, qd in enumerate(modules[topic]["quiz"]):
|
| 324 |
+
a = st.radio(f"Q{i+1}: {qd['q']}", qd['O'], index=None, key=f"{topic}_{i}")
|
| 325 |
+
answers.append(a)
|
| 326 |
|
| 327 |
+
name = st.text_input("Your full name (for certificate):", key=f"name_{topic}")
|
| 328 |
|
| 329 |
if st.button("Submit Quiz", key=f"btn_{topic}"):
|
| 330 |
if "" in answers or not name.strip():
|
| 331 |
+
st.warning("Please answer all questions and enter your name.")
|
| 332 |
return
|
|
|
|
|
|
|
|
|
|
| 333 |
|
| 334 |
+
score = sum(1 for ans, q in zip(answers, modules[topic]["quiz"]) if ans == q["A"])
|
| 335 |
+
st.success(f"You scored {score}/5")
|
| 336 |
+
st.balloons()
|
| 337 |
+
|
| 338 |
+
st.session_state.analytics[topic] += 1
|
| 339 |
st.session_state.leaderboard[topic].append({"name": name, "score": score})
|
| 340 |
st.session_state.leaderboard[topic] = sorted(
|
| 341 |
st.session_state.leaderboard[topic], key=lambda x: -x["score"]
|
| 342 |
)[:5]
|
| 343 |
|
|
|
|
| 344 |
cert = create_certificate(name, topic, score)
|
| 345 |
+
st.download_button("π Download Certificate", data=open(cert, "rb"), file_name=cert, mime="application/pdf")
|
| 346 |
|
| 347 |
+
share_text = f"I scored {score}/5 on '{topic}'! π #AIForEveryone"
|
| 348 |
+
st.markdown(f"[π Share on WhatsApp](https://wa.me/?text={share_text}) | "
|
| 349 |
+
f"[π¦ Share on Twitter](https://twitter.com/intent/tweet?text={share_text})")
|
|
|
|
|
|
|
| 350 |
|
| 351 |
+
st.subheader("β
Answer Key:")
|
| 352 |
for i, qd in enumerate(modules[topic]["quiz"]):
|
| 353 |
st.markdown(f"{i+1}. **{qd['q']}** β β
{qd['A']}")
|
| 354 |
|
| 355 |
+
# -------------------------------
|
| 356 |
+
# Start Screen
|
| 357 |
+
# -------------------------------
|
|
|
|
|
|
|
| 358 |
if not st.session_state.started:
|
| 359 |
+
st.title("π€ AI For Everyone β Future Tech Leaders")
|
| 360 |
+
st.markdown("### Empowering global learners with audio, quizzes, certificates, and AI education.")
|
| 361 |
+
if st.button("π Get Started Now"):
|
| 362 |
st.session_state.started = True
|
| 363 |
st.stop()
|
| 364 |
|
| 365 |
+
# -------------------------------
|
| 366 |
+
# Sidebar Info
|
| 367 |
+
# -------------------------------
|
| 368 |
+
st.sidebar.title("π Topics")
|
| 369 |
+
topic = st.selectbox("Choose your module:", list(modules.keys()))
|
| 370 |
+
|
| 371 |
+
st.sidebar.subheader("π Analytics")
|
| 372 |
+
for t, v in st.session_state.analytics.items():
|
| 373 |
+
st.sidebar.write(f"{t}: {v} completed")
|
| 374 |
|
| 375 |
+
st.sidebar.subheader("π Leaderboards")
|
| 376 |
+
for t, v in st.session_state.leaderboard.items():
|
| 377 |
+
if v:
|
| 378 |
+
st.sidebar.markdown(f"**{t}**")
|
| 379 |
+
for entry in v:
|
| 380 |
+
st.sidebar.write(f"{entry['name']}: {entry['score']}/5")
|
| 381 |
|
| 382 |
+
# -------------------------------
|
| 383 |
+
# Main Content
|
| 384 |
+
# -------------------------------
|
| 385 |
show_module(topic)
|