kawaa99's picture
Update app.py
76b7e39 verified
Raw History Blame Contribute Delete
11.6 kB
import streamlit as st
import uuid
from utils import (
load_idioms, generate_audio, init_db, add_favorite, get_favorite,
detect_idioms, lemmatize_word, translate_literal, normalize_idiom, build_examples_map, remove_favorite,
generate_adaptive_quiz, update_analytics, get_learning_stats, detect_idioms_ai
)
st.set_page_config(page_title="Idioms Learning App", layout="wide")
st.title("English–Spanish Idioms Learning App")
# Load resources
idiom_map = load_idioms("idiom2.json")
idioms = sorted(idiom_map.keys())
conn = init_db()
examples_map = build_examples_map()
##13/5
topics = sorted(list(set(
v.get("topic", "General")
for v in idiom_map.values()
)))
# Sidebar
mode = st.sidebar.selectbox(
"Choose a mode",
["Explore Idioms", "Idioms in sentences", "Quiz time!", "Favorites", "Learning Analytics"]
)
# EXPLORE
if mode == "Explore Idioms":
search = st.text_input("Search idiom:")
topics = sorted(list(set(
v.get("topic", "General")
for v in idiom_map.values()
)))
selected_topic = st.selectbox("Choose Topic", ["All"] + topics)
#filtered = [i for i in idioms if search.lower() in i.lower()]
filtered = []
for idiom in idioms:
matches_search = search.lower() in idiom.lower()
topic = idiom_map[idiom].get("topic", "General")
matches_topic = (
selected_topic == "All"
or topic == selected_topic
)
if matches_search and matches_topic:
filtered.append(idiom)
selected = st.selectbox("Choose idiom:", filtered)
if selected:
st.subheader("Natural Spanish Meaning")
st.write(idiom_map[selected]["meaning"])
st.subheader("English Meaning")
st.write(idiom_map[selected].get("english_meaning", "Not available"))
st.subheader("Literal Translation")
st.write(translate_literal(selected))
st.subheader("Examples:")
examples = examples_map.get(normalize_idiom(selected), []) #changed
if examples:
for ex in examples[:3]:
st.write("**English:**", ex["en"])
st.write("**Spanish:**", ex["es"])
st.write("---")
else:
st.write("No examples found.")
st.subheader("Audio")
st.write("English Idiom")
audio_en = generate_audio(selected, lang="en")
st.audio(audio_en)
st.write("Spanish Equivalent")
audio_es = generate_audio(idiom_map[selected]["meaning"], lang="es")
st.audio(audio_es)
#audio_file = generate_audio(selected)
#st.audio(audio_file)
if st.button("⭐ Add to Favorites"):
add_favorite(conn, selected)
st.success("Added to favorites!")
# DETECT
elif mode == "Idioms in sentences":
text = st.text_area("Write your text:")
if st.button("Detect"):
found, spans = detect_idioms(text, idioms) #add spans
# use AI if no matching idioms
if not found:
found = detect_idioms_ai(text, idiom_map)
spans = {idiom: idiom for idiom in found}
if not found:
st.info("No idioms detected.")
else:
# Highlight detected idioms in the text
highlighted_text = text
for idiom in found:
matched_text = spans.get(idiom, idiom) #instead idiom
highlighted_text = highlighted_text.replace(
matched_text,
f"<span style='background-color: #FFAB91; font-weight:bold'>{idiom}</span>"
)
st.markdown("### Your Text with Detected Idioms")
st.markdown(highlighted_text, unsafe_allow_html=True)
st.markdown("---")
# Show idiom details
for idiom in found:
with st.expander(f"🔹 {idiom}"):
st.write("**Meaning:**", idiom_map[idiom]["meaning"])
st.write("**English Meaning:**", idiom_map[idiom].get("english_meaning", "Not available"))
st.caption(f"Topic: {idiom_map[idiom].get('topic', 'General')}")
st.write("**Literal Translation:**", translate_literal(idiom))
# Examples
examples = examples_map.get(normalize_idiom(idiom), []) #changed
if examples:
st.subheader("Examples:")
for ex in examples[:2]:
st.write("•", ex["en"])
else:
st.write("No examples available.")
# Audio
#audio_file = generate_audio(idiom)
#st.audio(audio_file)
st.write("English Idiom")
audio_en = generate_audio(idiom, lang="en")
st.audio(audio_en)
st.write("Spanish Equivalent")
audio_es = generate_audio(idiom_map[idiom]["meaning"], lang="es")
st.audio(audio_es)
# Practice button
if st.button(f"Practice '{idiom}'"):
st.session_state.quiz = generate_adaptive_quiz(
conn,
{idiom: idiom_map[idiom]},
examples_map,
st.session_state.used_questions,
st.session_state.used_structures)
st.rerun()
# QUIZ
elif mode == "Quiz time!":
st.header("🎮 Quiz")
# Initialize state FIRST, before anything else
if "xp" not in st.session_state:
st.session_state.xp = 0
if "used_structures" not in st.session_state:
st.session_state.used_structures = set()
if "used_questions" not in st.session_state:
st.session_state.used_questions = set()
st.metric("XP", st.session_state.xp)
if "quiz" not in st.session_state or st.session_state.quiz is None:
with st.spinner("Generating question..."):
st.session_state.quiz = generate_adaptive_quiz(
conn,
idiom_map,
examples_map,
st.session_state.used_questions,
st.session_state.used_structures
)
if st.session_state.quiz is None:
st.error("Could not generate a quiz question. The AI model may have failed. Try clicking New Question.")
if st.button("New Question"):
st.session_state.pop("quiz", None)
st.rerun()
st.stop()
quiz = st.session_state.quiz
st.write("Fill in the blank")
st.write(quiz["question"])
user_answer = st.radio(
"Choose your answer:",
quiz["options"]
)
# ---------- SUBMIT ----------
if st.button("Submit"):
correct = (user_answer == quiz["answer"])
update_analytics(conn, quiz["answer"], correct)
if correct:
st.success("Correct! +5 XP")
st.session_state.xp += 5
else:
st.error(f"Wrong! Correct answer: {quiz['answer']}")
# ---------- NEW QUESTION ----------
if st.button("New Question"):
with st.spinner("Generating question..."):
new_quiz = generate_adaptive_quiz(
conn,
idiom_map,
examples_map,
st.session_state.used_questions,
st.session_state.used_structures
)
#the spinner
if new_quiz is None:
st.error("Could not generate a new question. Try again.")
else:
# store used items properly
st.session_state.used_questions.add(new_quiz["answer"])
st.session_state.quiz = new_quiz
st.rerun()
# ANALYTICS
elif mode == "Learning Analytics":
st.header("Learning Dashboard")
stats = get_learning_stats(conn)
if not stats:
st.info("No quiz data yet. Try the quiz first!")
else:
import numpy as np
import pandas as pd
total_idioms = len(idioms)
mastered = len([i for i,a,c,acc in stats if acc >= 0.8 and a >= 2])
practiced = len([i for i,a,c,acc in stats if a > 0])
weak = len([i for i,a,c,acc in stats if acc < 0.6 and a > 0])
avg_acc = np.mean([acc for _,a,_,acc in stats if a > 0]) if stats else 0
# XP system
xp = st.session_state.get("xp",0)
next_level = 100
xp_progress = xp / next_level
st.subheader("⭐ XP Progress")
st.metric("Total XP", xp)
st.progress(xp_progress)
st.markdown("---")
# Global Stats
st.subheader("🏆 Your Progress")
col1,col2,col3,col4 = st.columns(4)
with col1:
st.metric(
label="🎯 Mastered",
value=f"{mastered}/{total_idioms}",
)
with st.expander("❓ What is Mastered?"):
st.caption("Idioms you have answered correctly at least 80% of the time.")
st.progress(mastered/total_idioms)
with col2:
st.metric(
label="📚 Practiced",
value=f"{practiced}/{total_idioms}",
)
with st.expander("❓ What is Practiced?"):
st.caption("Idioms you have attempted at least once.")
st.progress(practiced/total_idioms)
with col3:
st.metric(
label="⚠️ Weak",
value=weak,
)
with st.expander("❓ What is Weak?"):
st.caption("Idioms with accuracy below 60%.")
st.progress(weak/total_idioms)
with col4:
st.metric(
label="🎯 Accuracy",
value=f"{avg_acc*100:.1f}%",
)
with st.expander("❓ What is Accuracy?"):
st.caption("Your average correct rate across all attempted idioms.")
st.progress(avg_acc)
st.markdown("---")
# Performance Chart
st.subheader("📊 Performance")
df = pd.DataFrame(stats, columns=["Idiom","Attempts","Correct","Accuracy"])
df_sorted = df.sort_values("Accuracy")
st.bar_chart(
df_sorted.set_index("Idiom")["Accuracy"]
)
st.markdown("---")
# Weak Idioms
st.subheader("🔥 Idioms You Should Practice")
weak_list = df[df["Accuracy"] < 0.6]["Idiom"].tolist()
if weak_list:
for w in weak_list:
st.warning(f"Practice: **{w}**")
else:
st.success("Great job! No weak idioms 🎉")
st.markdown("---")
# Full Table
st.subheader("Detailed Stats")
st.dataframe(df)
# FAVORITES
elif mode == "Favorites":
st.header("Your Favorites")
favs = get_favorite(conn)
if favs:
for idiom in favs:
col1, col2 = st.columns([4, 1])
with col1:
st.write("⭐", idiom)
st.write("Meaning:",idiom_map.get(idiom, {}).get("meaning", "Unknown"))
with col2:
if st.button("Remove", key=f"remove_{idiom}"):
remove_favorite(conn, idiom)
st.rerun()
st.write("---")
else:
st.write("No favorites yet.")