Spaces:
Running
Running
| from datetime import date | |
| import streamlit as st | |
| from sqlalchemy import func | |
| from cert_study_app.config import DEFAULT_USER | |
| from cert_study_app.db import SessionLocal | |
| from cert_study_app.models import Attempt, Question | |
| from cert_study_app.services.learning_lab_service import ( | |
| PRACTICE_TASKS, | |
| active_tracks, | |
| certification_for_track, | |
| certifications_for_track, | |
| lessons_for_track, | |
| normalize_track_id, | |
| quizzes_for_track, | |
| track_by_id, | |
| track_progress, | |
| ) | |
| from cert_study_app.services.learning_progress_service import ( | |
| completed_steps, | |
| mark_learning_step, | |
| next_day_recommendation, | |
| save_preferred_track, | |
| spaced_review_count, | |
| spaced_review_due_today, | |
| streak_days, | |
| study_units, | |
| weekly_summary, | |
| record_activity, | |
| ) | |
| from cert_study_app.services.question_concept_service import concept_label | |
| from cert_study_app.ui.common import go_to, selected_lab_track | |
| def focus_apply_step(track_id: str) -> tuple[str, str, str, str]: | |
| if track_id == "linux": | |
| return ( | |
| "์ค์ต ์ ์ฉ", | |
| "๋ฐฉ๊ธ ๋ณธ ๊ฐ๋ ์ ๋ช ๋ น์ด ์ค์ต์ผ๋ก ๋ฐ๋ก ์จ๋ด ๋๋ค.", | |
| "์ค์ตํ๊ธฐ", | |
| "์ค์ตํ๊ธฐ", | |
| ) | |
| if track_id == "azure": | |
| return ( | |
| "๋ฌธ์ ์ ์ฉ", | |
| "๊ฐ๋ ์ AZ-104 ๋ฌธ์ ์ ๋ฐ๋ก ์ ์ฉํด ๋ด ๋๋ค.", | |
| "๋ฌธ์ ํ๊ธฐ", | |
| "์๊ฒฉ์ฆ ๋ฌธ์ ", | |
| ) | |
| return ( | |
| "๋ฌธ์ ์ ์ฉ", | |
| "๊ณต์ ๋ฌธ์ ์นด๋์ ํด์ฆ๋ฅผ ์ด์ด ๋ณด๋ฉฐ ๋๊ตฌ ๊ฐ๋ ์ ๊ตณํ๋๋ค.", | |
| "์ด๋ก ์ด์ด๋ณด๊ธฐ", | |
| "์ด๋ก ํ์ต", | |
| ) | |
| def focus_step_flow(track_id: str) -> list[tuple[str, str, str, str, str]]: | |
| lessons = lessons_for_track(track_id) | |
| quizzes = quizzes_for_track(track_id) | |
| apply_title, apply_description, apply_label, apply_target = focus_apply_step(track_id) | |
| return [ | |
| ("lesson", "๊ฐ๋ ์ดํด", f"์นด๋ {min(1, len(lessons))}๊ฐ๋ถํฐ ์์ํ๊ณ , ์ํ๋ฉด ๊ณ์ ๋ค์ ์นด๋๋ก ๋์ด๊ฐ๋๋ค.", "๊ฐ๋ ๋ณด๊ธฐ", "์ด๋ก ํ์ต"), | |
| ("quiz", "๋ฐ๋ก ํ์ธ", f"{min(3, len(quizzes))}๊ฐ๋ก ์ดํด๋๋ฅผ ์ ๊ฒํ ๋ค ๊ณ์ ํ ์ ์์ต๋๋ค.", "ํ์ธ ํด์ฆ ํ๊ธฐ", "ํ์ธ ํด์ฆ"), | |
| ("apply", apply_title, apply_description, apply_label, apply_target), | |
| ("review", "์ค๋ต ์ ๋ฆฌ", "์ค๋ต 1๊ฐ๋ถํฐ ๋ณด๊ณ , ๋ ๋ณต์ตํ๋ฉด ๋์ ํ์ต๋์ผ๋ก ๊ธฐ๋ก๋ฉ๋๋ค.", "์ค๋ต ๋ณต์ต์ผ๋ก ์ด๋", "์ค๋ต๋ ธํธ"), | |
| ] | |
| def render_home(exams): | |
| tracks = active_tracks() | |
| track_ids = [t["id"] for t in tracks] | |
| track_labels = [t["name"] for t in tracks] | |
| from cert_study_app.services.learning_progress_service import preferred_track | |
| current_track_id = normalize_track_id(st.session_state.get("lab_track", preferred_track())) | |
| current_idx = track_ids.index(current_track_id) if current_track_id in track_ids else 0 | |
| selected_label = st.radio("", track_labels, index=current_idx, horizontal=True) | |
| track_id = track_ids[track_labels.index(selected_label)] | |
| if track_id != st.session_state.get("lab_track"): | |
| save_preferred_track(track_id) | |
| st.session_state.lab_track = track_id | |
| certification = certification_for_track(track_id) | |
| session_done = completed_steps(track_id) | |
| streak = streak_days() | |
| units = study_units() | |
| due_count = spaced_review_count() | |
| _, _, apply_action_label, apply_target = focus_apply_step(track_id) | |
| concept_done = {"lesson", "quiz"} <= session_done | |
| practice_done = "apply" in session_done | |
| review_done = "review" in session_done | |
| done_count = sum([concept_done, practice_done, review_done]) | |
| all_done = done_count == 3 | |
| if not concept_done: | |
| next_label = "๊ฐ๋ ๊ณต๋ถ ์์ํ๊ธฐ โ" if "lesson" not in session_done else "ํ์ธ ํด์ฆ ์ด์ด๊ฐ๊ธฐ โ" | |
| next_page = "๊ฐ๋ ๊ณต๋ถ" | |
| elif not practice_done: | |
| next_label = f"{apply_action_label} โ" | |
| next_page = "์ค์ต" if track_id != "azure" else "์ํ์ค๋น" | |
| elif not review_done: | |
| next_label = "์ค๋ต ๋ณต์ตํ๊ธฐ โ" | |
| next_page = "์ค๋ต๋ ธํธ" | |
| else: | |
| next_label = "์ํ ๋ฌธ์ ๋ ํ๊ธฐ โ" | |
| next_page = "์ํ์ค๋น" | |
| celebrate_key = f"_celebrated_{track_id}_{date.today().isoformat()}" | |
| if all_done and not st.session_state.get(celebrate_key): | |
| st.session_state[celebrate_key] = True | |
| st.balloons() | |
| streak_text = f"๐ฅ {streak}์ผ ์ฐ์ ํ์ต ์ค" if streak > 0 else "์ค๋ ์ฒซ ํ์ต์ ์์ํด๋ณด์ธ์" | |
| step_label = "์ค๋ ๋ชฉํ ๋ฌ์ฑ! ๐" if all_done else f"์ค๋ {done_count}/3 ๋จ๊ณ ์๋ฃ" | |
| bar_pct = done_count / 3 * 100 | |
| cert_name = certification.get("name", "") | |
| st.markdown( | |
| f""" | |
| <div class="cert-hero"> | |
| <div class="cert-hero-track">{cert_name} ๋๋น</div> | |
| <div class="cert-hero-streak">{streak_text}</div> | |
| <div class="cert-hero-bar-wrap"> | |
| <div class="cert-hero-bar-fill" style="width:{bar_pct:.0f}%"></div> | |
| </div> | |
| <div class="cert-hero-bar-label">{step_label}</div> | |
| </div> | |
| <script> | |
| (function() {{ | |
| function connect() {{ | |
| try {{ | |
| var doc = window.parent.document; | |
| var heroes = doc.querySelectorAll('.cert-hero'); | |
| heroes.forEach(function(hero) {{ | |
| hero.style.borderBottomLeftRadius = '0'; | |
| hero.style.borderBottomRightRadius = '0'; | |
| hero.style.marginBottom = '0'; | |
| var el = hero; | |
| while (el && el.getAttribute && el.getAttribute('data-testid') !== 'element-container') el = el.parentElement; | |
| if (!el) return; | |
| var sib = el.nextElementSibling; | |
| for (var i = 0; i < 4 && sib; i++) {{ | |
| var btn = sib.querySelector('button[data-testid="stBaseButton-primary"]'); | |
| if (btn) {{ | |
| btn.style.borderTopLeftRadius = '0'; | |
| btn.style.borderTopRightRadius = '0'; | |
| break; | |
| }} | |
| sib = sib.nextElementSibling; | |
| }} | |
| }}); | |
| }} catch(e) {{}} | |
| }} | |
| setTimeout(connect, 120); | |
| setTimeout(connect, 600); | |
| }})(); | |
| </script> | |
| """, | |
| unsafe_allow_html=True, | |
| ) | |
| if all_done: | |
| if st.button("๐ ์ค๋ ์๋ฃ! ์ถ๊ฐ ๋ฌธ์ ๋ ํ๊ธฐ", type="primary", use_container_width=True): | |
| go_to("์๊ฒฉ์ฆ ๋ฌธ์ ") | |
| else: | |
| if st.button(next_label, type="primary", use_container_width=True): | |
| if next_page == apply_target and track_id == "azure": | |
| st.session_state.exam_source = "AZ-104" | |
| go_to(next_page) | |
| due_class = "cert-stat-card alert" if due_count > 0 else "cert-stat-card" | |
| due_value = str(due_count) if due_count > 0 else "โ" | |
| st.markdown( | |
| f""" | |
| <div class="cert-stats-row"> | |
| <div class="{due_class}"> | |
| <div class="cert-stat-value">{due_value}</div> | |
| <div class="cert-stat-label">๊ฐ๊ฒฉ ๋ณต์ต ๋๊ธฐ</div> | |
| </div> | |
| <div class="cert-stat-card"> | |
| <div class="cert-stat-value">{units:.1f}</div> | |
| <div class="cert-stat-label">์ค๋ ํ๋ ๋จ์</div> | |
| </div> | |
| <div class="cert-stat-card"> | |
| <div class="cert-stat-value">{streak}</div> | |
| <div class="cert-stat-label">์ฐ์ ํ์ต์ผ</div> | |
| </div> | |
| </div> | |
| """, | |
| unsafe_allow_html=True, | |
| ) | |
| st.markdown('<div class="cert-section-title">๋ฐ๋ก ๊ฐ๊ธฐ</div>', unsafe_allow_html=True) | |
| col1, col2 = st.columns(2) | |
| if col1.button("๐ ๊ฐ๋ ๊ณต๋ถ", use_container_width=True): | |
| go_to("๊ฐ๋ ๊ณต๋ถ") | |
| if col2.button("๐ฅ ์ค์ต", use_container_width=True): | |
| go_to("์ค์ต") | |
| col3, col4 = st.columns(2) | |
| if col3.button("๐ ์ํ ์ค๋น", use_container_width=True): | |
| go_to("์ํ์ค๋น") | |
| if col4.button("ํ์ต ํํฉ", use_container_width=True): | |
| go_to("๋์๋ณด๋") | |
| render_spaced_review_panel() | |
| def render_spaced_review_panel(): | |
| due_count = spaced_review_count() | |
| if due_count == 0: | |
| return | |
| with st.container(border=True): | |
| st.markdown(f"#### ๊ฐ๊ฒฉ ๋ณต์ต ยท ์ค๋ {due_count}๋ฌธ์ ๋๊ธฐ") | |
| st.caption("ํ๋ฆฐ ๋ฌธ์ ๋ฅผ 1โ3โ7โ14โ30์ผ ๊ฐ๊ฒฉ์ผ๋ก ์ฌ์ถ์ ํฉ๋๋ค. 3ํ ์ฐ์ ์ ๋ต์ด๋ฉด ์์ ํ์ต์ผ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค.") | |
| due_ids = spaced_review_due_today(limit=5) | |
| for qid in due_ids: | |
| if st.button(f"๋ฌธ์ #{qid} ํ๊ธฐ", key=f"spaced_go_{qid}", use_container_width=True): | |
| st.session_state.question_id = qid | |
| st.session_state.exam_source = None | |
| st.session_state.selected = None | |
| st.session_state.last_result = None | |
| go_to("์๊ฒฉ์ฆ ๋ฌธ์ ") | |
| def render_dashboard(exams): | |
| st.subheader("๋์๋ณด๋") | |
| st.caption("์ง๋์ ์ถ์ฒ ๋ณต์ต์ ์ฌ๊ธฐ์์๋ง ํ์ธํฉ๋๋ค.") | |
| render_today_plan(exams) | |
| render_spaced_review_panel() | |
| render_weak_recommendations() | |
| def render_today_plan(exams): | |
| total_questions = sum(exam["count"] for exam in exams) | |
| track_id = selected_lab_track() | |
| track = track_by_id(track_id) | |
| certification = certification_for_track(track_id) | |
| lessons = lessons_for_track(track_id) | |
| quizzes = quizzes_for_track(track_id) | |
| practices = [task for task in PRACTICE_TASKS if task.track == track_id and task.status == "approved"] | |
| persisted_steps = completed_steps(track_id) | |
| progress = track_progress( | |
| track_id, | |
| set(st.session_state.lab_completed_lessons), | |
| set(st.session_state.lab_completed_quizzes), | |
| set(st.session_state.lab_completed_practices), | |
| ) | |
| week = weekly_summary() | |
| streak = streak_days() | |
| with st.container(border=True): | |
| st.markdown("### ์ด์ด์ ๊ณต๋ถ") | |
| st.caption(f"{track['name']} ์ค์ฌ ยท ๋ชฉํ ์๊ฒฉ์ฆ: {certification['name']}") | |
| col1, col2, col3 = st.columns(3) | |
| col1.metric("์ด๋ก ์นด๋", f"{min(3, len(lessons))}๊ฐ") | |
| col2.metric("ํ์ธ ํด์ฆ", f"{min(5, len(quizzes))}๋ฌธ์ ") | |
| if track_id == "tool_docs": | |
| third_label = "Docs ๋ณต์ต" | |
| third_value = "1๊ฐ" | |
| else: | |
| third_label = "์ค๋ต ๋ณต์ต" | |
| third_value = "1๊ฐ" | |
| col3.metric(third_label, third_value) | |
| wrong_count = len([item for item in st.session_state.lab_wrong_notes if item.get("track") == track_id]) | |
| st.caption(f"์ค๋ต ๋ณต์ต {wrong_count}๊ฐ ยท ๋ฑ๋ก๋ ์๊ฒฉ์ฆ ๋ฌธ์ {total_questions}๊ฐ") | |
| st.progress(progress["percent"] / 100 if progress["total"] else 0, text=f"{track['name']} ์งํ๋ฅ {progress['completed']}/{progress['total']}") | |
| focus_step_count = len(persisted_steps & {"lesson", "quiz", "apply", "review"}) | |
| st.progress(focus_step_count / 4, text=f"Focus ์ง๋ {focus_step_count}/4") | |
| metric1, metric2, metric3 = st.columns(3) | |
| metric1.metric("์ฐ์ ํ์ต", f"{streak}์ผ") | |
| metric2.metric("์ค๋ ํ๋", f"{study_units():.1f}๋จ์") | |
| metric3.metric("์ด๋ฒ ์ฃผ ๋์ ", f"{week['study_units']:.1f}๋จ์") | |
| st.caption(next_day_recommendation(track_id)) | |
| def render_weak_recommendations(): | |
| db = SessionLocal() | |
| try: | |
| rows = ( | |
| db.query(Question.category, Question.subcategory, func.count(Attempt.id)) | |
| .join(Question, Attempt.question_id == Question.id) | |
| .filter(Attempt.user_id == DEFAULT_USER, Attempt.note_type == "wrong") | |
| .group_by(Question.category, Question.subcategory) | |
| .order_by(func.count(Attempt.id).desc()) | |
| .limit(3) | |
| .all() | |
| ) | |
| if not rows: | |
| return | |
| with st.container(border=True): | |
| st.markdown("### ์ค๋ ์ถ์ฒ ๋ณต์ต") | |
| for category, subcategory, count in rows: | |
| st.caption(f"{concept_label(category, subcategory)} ยท ์ค๋ต {count}ํ") | |
| if st.button("์ค๋ต ์ถ์ฒ์ผ๋ก ๋ณต์ต", use_container_width=True): | |
| go_to("์ค๋ต๋ ธํธ") | |
| finally: | |
| db.close() | |
| def render_focus_progress_flow(track_id: str): | |
| track = track_by_id(track_id) | |
| certification = certification_for_track(track_id) | |
| session_done = completed_steps(track_id) | |
| session_steps = focus_step_flow(track_id) | |
| _, _, _, apply_target = focus_apply_step(track_id) | |
| st.caption(f"{track['name']} Track ยท {certification['name']} ยท ๊ฐ๋ ๋ถํฐ ์ค๋ต๊น์ง ์์๋๋ก ์ด์ด๊ฐ๋๋ค.") | |
| done_count = len(session_done & {step[0] for step in session_steps}) | |
| st.progress(done_count / len(session_steps), text=f"์ง๋ ํ๋ฆ {done_count}/{len(session_steps)} ยท ์ค๋ ํ๋ {study_units():.1f}๋จ์") | |
| if st.button("๊ณ์ ์ด์ด๊ฐ๊ธฐ", type="primary", use_container_width=True): | |
| if "lesson" not in session_done: | |
| go_to("์ด๋ก ํ์ต") | |
| if "quiz" not in session_done: | |
| go_to("ํ์ธ ํด์ฆ") | |
| if "apply" not in session_done: | |
| if track_id == "azure": | |
| st.session_state.exam_source = "AZ-104" | |
| go_to(apply_target) | |
| if "review" not in session_done: | |
| go_to("์ค๋ต๋ ธํธ") | |
| go_to("์ด๋ก ํ์ต") | |
| for index, (step_id, title, description, action_label, target_page) in enumerate(session_steps, 1): | |
| with st.container(border=True): | |
| done = step_id in session_done | |
| st.markdown(f"### {index}. {'์๋ฃ ยท ' if done else ''}{title}") | |
| st.write(description) | |
| col1, col2 = st.columns([1, 1]) | |
| if col1.button(action_label, type="primary" if not done else "secondary", use_container_width=True, key=f"today_go_{step_id}"): | |
| if step_id == "apply" and track_id == "azure": | |
| st.session_state.exam_source = "AZ-104" | |
| go_to(target_page) | |
| if col2.button("์๋ฃ ์ฒดํฌ", use_container_width=True, key=f"today_done_{step_id}", disabled=done): | |
| mark_learning_step(track_id, step_id) | |
| st.rerun() | |
| if done_count == len(session_steps): | |
| st.success("์ง๋ ํ๋ฆ์ ์ง๋์์ต๋๋ค. ๋ ๊ณต๋ถํ๋ฉด ์ค๋ ํ๋๋์ ๊ณ์ ๋ํด์ง๋๋ค.") | |
| def render_continue_study(): | |
| st.subheader("Focus") | |
| track_id = selected_lab_track() | |
| render_focus_progress_flow(track_id) | |
| def render_focus_mode(): | |
| st.subheader("Focus ๊ณต๋ถ") | |
| track_id = selected_lab_track() | |
| track = track_by_id(track_id) | |
| certification = certification_for_track(track_id) | |
| st.caption(f"{track['name']} Track ยท {certification['name']} ยท ์ง๋๋ฅผ ์ด์ด๊ฐ๊ฑฐ๋, ์ง๊ธ ํ์ํ ๊ฒ๋ง ๊ณจ๋ผ ๊ณต๋ถํฉ๋๋ค.") | |
| focus_mode = st.radio("๊ณต๋ถ ๋ฐฉ์", ["์ง๋ ์ด์ด๊ฐ๊ธฐ", "์ํ๋ ๊ฒ๋ง ํ๊ธฐ"], horizontal=True) | |
| if focus_mode == "์ง๋ ์ด์ด๊ฐ๊ธฐ": | |
| render_focus_progress_flow(track_id) | |
| return | |
| focus_options = ["๊ฐ๋ ", "ํ์ธ", "์ ์ฉ", "์ค๋ต", "๋ก๋๋งต"] | |
| selected_focus = st.radio("์ง๊ธ ํ ๊ฒ", focus_options, horizontal=True) | |
| apply_target = focus_apply_step(track_id)[3] | |
| focus_targets = { | |
| "๊ฐ๋ ": "์ด๋ก ํ์ต", | |
| "ํ์ธ": "ํ์ธ ํด์ฆ", | |
| "์ ์ฉ": apply_target, | |
| "์ค๋ต": "์ค๋ต๋ ธํธ", | |
| "๋ก๋๋งต": "๋ก๋๋งต", | |
| } | |
| focus_descriptions = { | |
| "๊ฐ๋ ": "์ ๊ฐ๋ ์ ๋จผ์ ์ ๋ฆฌํฉ๋๋ค. ํท๊ฐ๋ฆฌ๋ ์ฉ์ด์ ์์ฃผ ํ๋ฆฌ๋ ํฌ์ธํธ๋ฅผ ํ์ธํ๊ธฐ ์ข์ต๋๋ค.", | |
| "ํ์ธ": "์งง์ ํด์ฆ๋ก ๋ฐฉ๊ธ ์๋์ง ๋ฐ๋ก ์ ๊ฒํฉ๋๋ค.", | |
| "์ ์ฉ": "Linux๋ ์ค์ต, Azure๋ ๋ฌธ์ ์ ์ฉ, Tool Docs๋ ๋ฌธ์ ์นด๋ ๋ณต์ต์ผ๋ก ์ฐ๊ฒฐํฉ๋๋ค.", | |
| "์ค๋ต": "ํ๋ฆฐ ๋ฌธ์ ์ ์ฝํ ๊ฐ๋ ์ ๋ค์ ๋ด ๋๋ค.", | |
| "๋ก๋๋งต": "์ง๊ธ ๊ณต๋ถํ๋ Track์ ์ ์ฒด ์์๋ฅผ ํ์ธํฉ๋๋ค.", | |
| } | |
| st.info(focus_descriptions[selected_focus]) | |
| if st.button(f"{selected_focus} ์์", type="primary", use_container_width=True): | |
| go_to(focus_targets[selected_focus]) | |
| if track_id == "tool_docs": | |
| st.info("Tool Docs๋ ๊ณต์ ๋ฌธ์ ์์ฝ ์นด๋์ ํ์ธ ํด์ฆ๋ฅผ ๋ฐ๋ณตํ๋ ๋ฐฉ์์ผ๋ก ์ด์ํฉ๋๋ค.") | |
| elif track_id == "azure": | |
| st.info("AZ-104 ๋ฌธ์ ํ์ด์ ๋ชฐ์ ํ๋ ค๋ฉด `Exam`์ ์ฌ์ฉํ์ธ์.") | |
| def render_exam_study_mode(): | |
| st.subheader("Exam") | |
| st.caption("์๊ฒฉ์ฆ ์ง์ค ๋ชจ๋์ ๋๋ค. ๋จผ์ Track๊ณผ ์ํ์ ๊ณ ๋ฅธ ๋ค ํ์ฌ ์ค๋น ์ํ์ ๋ง๊ฒ ๊ณต๋ถํฉ๋๋ค.") | |
| exam_tracks = [track for track in active_tracks() if track["id"] in {"azure", "linux"}] | |
| track_labels = [track["name"] for track in exam_tracks] | |
| current_track = normalize_track_id(st.session_state.get("lab_track", "linux")) | |
| track_index = next((index for index, track in enumerate(exam_tracks) if track["id"] == current_track), 0) | |
| selected_track_label = st.selectbox("Track", track_labels, index=track_index, key="exam_track_selector") | |
| selected_track = exam_tracks[track_labels.index(selected_track_label)] | |
| st.session_state.lab_track = selected_track["id"] | |
| save_preferred_track(selected_track["id"]) | |
| certifications = certifications_for_track(selected_track["id"]) | |
| cert_labels = [f"{cert['name']} ยท {cert['study_mode']}" for cert in certifications] | |
| selected_cert_label = st.selectbox("์๊ฒฉ์ฆ", cert_labels, key="exam_certification_selector") | |
| certification = certifications[cert_labels.index(selected_cert_label)] | |
| if certification["id"] == "az-104": | |
| st.session_state.exam_source = "AZ-104" | |
| else: | |
| st.session_state.exam_source = None | |
| readiness_messages = { | |
| "ready_with_questions": "๋ฌธ์ ์ํ์ด ์ค๋น๋์ด ์์ด ๋ฌธ์ ํ์ด์ ์ธ๋ถ๊ฐ๋ ๋ฐ๋ณต์ ๋ฐ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.", | |
| "practice_based": "๋ฌธ์ ์ํ์ ์์ง ์์ง๋ง, ์ค์ต ๊ณผ์ ์ ๋ช ๋ น์ด ์ํ์ผ๋ก ์ํ ๋๋น๋ฅผ ์งํํฉ๋๋ค.", | |
| "concept_quiz_based": "๋ฌธ์ ์ํ์ ์์ง ์์ง๋ง, ๊ฐ๋ ์นด๋์ ํ์ธ ํด์ฆ๋ก ํ๊ธฐํ ๋๋น๋ฅผ ์์ํฉ๋๋ค.", | |
| } | |
| st.info(readiness_messages.get(certification.get("readiness"), "ํ์ต ์๋ฃ๋ฅผ ์ค๋น ์ค์ ๋๋ค.")) | |
| col1, col2 = st.columns(2) | |
| if col1.button("๋ฌธ์ ํ์ด", type="primary", use_container_width=True): | |
| if certification["id"] == "lfcs": | |
| st.toast("LFCS ๋ฌธ์ ์ํ์ ์์ง ์ค๋น ์ค์ ๋๋ค. ์ค์ตํ ํ์ต์ผ๋ก ์ฐ๊ฒฐํฉ๋๋ค.") | |
| go_to("์ค์ตํ๊ธฐ") | |
| if certification["id"] == "linux-master": | |
| st.toast("๋ฆฌ๋ ์ค๋ง์คํฐ ๋ฌธ์ ์ํ์ ์์ง ์ค๋น ์ค์ ๋๋ค. ํ์ธ ํด์ฆ๋ก ์ฐ๊ฒฐํฉ๋๋ค.") | |
| go_to("ํ์ธ ํด์ฆ") | |
| go_to("์๊ฒฉ์ฆ ๋ฌธ์ ") | |
| if col2.button("์ํ ๋ชจ๋ ์ค์ ", use_container_width=True): | |
| go_to("์ํ ๋ชจ๋") | |
| col3, col4 = st.columns(2) | |
| if col3.button("์ธ๋ถ๊ฐ๋ ๋ฐ๋ณต", use_container_width=True): | |
| if certification["id"] == "lfcs": | |
| go_to("๋ก๋๋งต") | |
| if certification["id"] == "linux-master": | |
| go_to("์ด๋ก ํ์ต") | |
| go_to("์๊ฒฉ์ฆ ๋ฌธ์ ") | |
| if col4.button("์ค๋ต ๋ณต์ต", use_container_width=True): | |
| go_to("์ค๋ต๋ ธํธ") | |