Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import pandas as pd | |
| import os | |
| # Configure the page | |
| st.set_page_config( | |
| page_title="NVIDIA GENL Mock Test", | |
| page_icon="π§ ", | |
| layout="wide", | |
| initial_sidebar_state="expanded" | |
| ) | |
| # Initialize session state | |
| if 'current_sheet' not in st.session_state: | |
| st.session_state.current_sheet = None | |
| if 'current_question' not in st.session_state: | |
| st.session_state.current_question = 0 | |
| if 'user_answers' not in st.session_state: | |
| st.session_state.user_answers = {} | |
| if 'show_answers' not in st.session_state: | |
| st.session_state.show_answers = {} | |
| if 'sheets_data' not in st.session_state: | |
| st.session_state.sheets_data = {} | |
| if 'show_results' not in st.session_state: | |
| st.session_state.show_results = False | |
| def load_excel_file(file_path): | |
| """Load the Excel file from the specified path""" | |
| try: | |
| excel_file = pd.read_excel(file_path, sheet_name=None) | |
| return excel_file | |
| except Exception as e: | |
| st.error(f"Error loading Excel file: {e}") | |
| return None | |
| def clean_data(value): | |
| """Clean and format data values""" | |
| if pd.isna(value) or value == '': | |
| return None | |
| return str(value).strip() | |
| def display_question(question_data, question_num, total_questions): | |
| """Display a single question and options with instant feedback""" | |
| # Create columns for better layout | |
| col1, col2 = st.columns([3, 1]) | |
| with col1: | |
| st.markdown(f"### Question {question_num + 1} of {total_questions}") | |
| with col2: | |
| progress = (question_num + 1) / total_questions | |
| st.progress(progress) | |
| st.caption(f"Progress: {question_num + 1}/{total_questions}") | |
| # Display the question | |
| st.markdown( | |
| f""" | |
| <div style=' | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| padding: 2rem; | |
| border-radius: 15px; | |
| margin-bottom: 2rem; | |
| box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
| '> | |
| <h3 style='margin:0; color: white; font-weight: 500;'>{question_data['Question']}</h3> | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| # Get available choices | |
| choices = [] | |
| for i in range(1, 7): | |
| choice_col = f'Choice{i}' | |
| if choice_col in question_data.index: | |
| choice_val = clean_data(question_data[choice_col]) | |
| if choice_val: | |
| choices.append(choice_val) | |
| question_key = f"q_{question_num}" | |
| # Get current answer (None if not answered yet) | |
| current_answer = st.session_state.user_answers.get(question_key, None) | |
| # Display options | |
| if choices: | |
| # Radio button with no default selection | |
| selected_option = st.radio( | |
| "**Select your answer:**", | |
| options=[""] + choices, # Add empty option at start | |
| format_func=lambda x: "-- Select an option --" if x == "" else x, | |
| key=f"radio_{question_key}", | |
| index=0 if current_answer is None else (choices.index(current_answer) + 1 if current_answer in choices else 0) | |
| ) | |
| # Only store if a real choice is selected | |
| if selected_option != "": | |
| st.session_state.user_answers[question_key] = selected_option | |
| # Get correct answer | |
| correct_answer = clean_data(question_data['Answer']) | |
| # Show instant feedback | |
| st.markdown("<br>", unsafe_allow_html=True) | |
| if selected_option == correct_answer: | |
| st.markdown( | |
| """ | |
| <div style=' | |
| background: #d4edda; | |
| border-left: 5px solid #28a745; | |
| padding: 1rem; | |
| border-radius: 8px; | |
| margin-top: 1rem; | |
| '> | |
| <span style='color: #155724; font-size: 1.1rem; font-weight: 600;'> | |
| β Correct! Well done. | |
| </span> | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| else: | |
| st.markdown( | |
| """ | |
| <div style=' | |
| background: #f8d7da; | |
| border-left: 5px solid #dc3545; | |
| padding: 1rem; | |
| border-radius: 8px; | |
| margin-top: 1rem; | |
| '> | |
| <span style='color: #721c24; font-size: 1.1rem; font-weight: 600;'> | |
| β Incorrect | |
| </span> | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| # Show correct answer button | |
| if st.session_state.show_answers.get(question_key, False): | |
| st.markdown( | |
| f""" | |
| <div style=' | |
| background: #d1ecf1; | |
| border-left: 5px solid #0c5460; | |
| padding: 1rem; | |
| border-radius: 8px; | |
| margin-top: 0.5rem; | |
| '> | |
| <span style='color: #0c5460; font-weight: 600;'> | |
| π‘ Correct answer: {correct_answer} | |
| </span> | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| else: | |
| if st.button("π Show Correct Answer", key=f"show_{question_num}"): | |
| st.session_state.show_answers[question_key] = True | |
| st.rerun() | |
| else: | |
| # Remove answer if user deselects | |
| if question_key in st.session_state.user_answers: | |
| del st.session_state.user_answers[question_key] | |
| else: | |
| st.warning("β οΈ No choices found for this question.") | |
| def calculate_score(sheet_data): | |
| """Calculate the score for the test""" | |
| total_score = 0 | |
| max_score = 0 | |
| results = [] | |
| for i in range(len(sheet_data)): | |
| question_data = sheet_data.iloc[i] | |
| question_key = f"q_{i}" | |
| user_answer = st.session_state.user_answers.get(question_key, "") | |
| correct_answer = clean_data(question_data['Answer']) | |
| is_correct = user_answer == correct_answer if correct_answer else False | |
| try: | |
| marks = float(question_data.get('Marks', 1.0)) | |
| except: | |
| marks = 1.0 | |
| if is_correct: | |
| total_score += marks | |
| max_score += marks | |
| results.append({ | |
| 'question': i + 1, | |
| 'question_text': question_data['Question'], | |
| 'user_answer': user_answer, | |
| 'correct_answer': correct_answer, | |
| 'is_correct': is_correct, | |
| 'marks': marks | |
| }) | |
| return total_score, max_score, results | |
| def main(): | |
| # Enhanced CSS | |
| st.markdown(""" | |
| <style> | |
| /* Import Google Fonts */ | |
| @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'); | |
| /* Global Styles */ | |
| * { | |
| font-family: 'Inter', sans-serif; | |
| } | |
| .main-header { | |
| font-size: 3rem; | |
| font-weight: 700; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| text-align: center; | |
| margin-bottom: 2rem; | |
| animation: fadeIn 1s ease-in; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(-20px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| /* Sidebar Styling */ | |
| [data-testid="stSidebar"] { | |
| background: linear-gradient(180deg, #f8f9fa 0%, #e9ecef 100%); | |
| } | |
| /* Metric Cards */ | |
| .metric-card { | |
| background: white; | |
| padding: 1.5rem; | |
| border-radius: 15px; | |
| box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); | |
| text-align: center; | |
| transition: transform 0.3s ease, box-shadow 0.3s ease; | |
| } | |
| .metric-card:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12); | |
| } | |
| /* Button Styling */ | |
| .stButton>button { | |
| border-radius: 10px; | |
| font-weight: 600; | |
| transition: all 0.3s ease; | |
| border: none; | |
| } | |
| .stButton>button:hover { | |
| transform: scale(1.02); | |
| box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); | |
| } | |
| /* Radio Button Styling */ | |
| .stRadio > div { | |
| background: white; | |
| padding: 1.5rem; | |
| border-radius: 12px; | |
| box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); | |
| } | |
| /* Progress Bar */ | |
| .stProgress > div > div > div { | |
| background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); | |
| } | |
| /* Expander Styling */ | |
| .streamlit-expanderHeader { | |
| background: white; | |
| border-radius: 10px; | |
| font-weight: 600; | |
| } | |
| /* Custom Scrollbar */ | |
| ::-webkit-scrollbar { | |
| width: 10px; | |
| } | |
| ::-webkit-scrollbar-track { | |
| background: #f1f1f1; | |
| } | |
| ::-webkit-scrollbar-thumb { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| border-radius: 5px; | |
| } | |
| ::-webkit-scrollbar-thumb:hover { | |
| background: #764ba2; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # Header | |
| st.markdown('<h1 class="main-header">π§ NVIDIA GENL Mock Test</h1>', unsafe_allow_html=True) | |
| # File path | |
| excel_file_path = "src/Nvidia GENL 1.xlsx" | |
| # Load data | |
| if not st.session_state.sheets_data: | |
| with st.spinner("π Loading test data..."): | |
| sheets_data = load_excel_file(excel_file_path) | |
| if sheets_data: | |
| st.session_state.sheets_data = sheets_data | |
| st.success("β Test data loaded successfully!") | |
| else: | |
| st.error(f"β Could not load Excel file from: {excel_file_path}") | |
| st.info("π‘ Please make sure the file exists at the specified path.") | |
| return | |
| sheets_data = st.session_state.sheets_data | |
| # Sidebar | |
| with st.sidebar: | |
| st.markdown("## π§ Navigation") | |
| available_sheets = list(sheets_data.keys()) | |
| selected_sheet = st.selectbox( | |
| "**Select Test Sheet:**", | |
| options=available_sheets, | |
| index=0 | |
| ) | |
| if selected_sheet != st.session_state.current_sheet: | |
| st.session_state.current_sheet = selected_sheet | |
| st.session_state.current_question = 0 | |
| st.session_state.user_answers = {} | |
| st.session_state.show_answers = {} | |
| st.session_state.show_results = False | |
| st.rerun() | |
| st.markdown("---") | |
| current_data = sheets_data[selected_sheet] | |
| if 'Type' in current_data.columns: | |
| objective_questions = current_data[current_data['Type'] == 'Objective'] | |
| else: | |
| objective_questions = current_data | |
| total_questions = len(objective_questions) | |
| # Info cards | |
| st.markdown(f"**π Sheet:** {selected_sheet}") | |
| st.markdown(f"**π Total Questions:** {total_questions}") | |
| answered_count = len([k for k in st.session_state.user_answers if st.session_state.user_answers[k]]) | |
| st.markdown(f"**β Answered:** {answered_count}/{total_questions}") | |
| st.markdown("---") | |
| st.markdown("### π― Quick Navigation") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| if st.button("β Prev", use_container_width=True, | |
| disabled=st.session_state.current_question == 0): | |
| st.session_state.current_question -= 1 | |
| st.rerun() | |
| with col2: | |
| if st.button("Next βΆ", use_container_width=True, | |
| disabled=st.session_state.current_question >= total_questions - 1): | |
| st.session_state.current_question += 1 | |
| st.rerun() | |
| selected_q = st.selectbox( | |
| "**Go to question:**", | |
| options=list(range(1, total_questions + 1)), | |
| index=st.session_state.current_question | |
| ) | |
| if selected_q - 1 != st.session_state.current_question: | |
| st.session_state.current_question = selected_q - 1 | |
| st.rerun() | |
| st.markdown("---") | |
| if st.button("π Reset Test", use_container_width=True, type="secondary"): | |
| st.session_state.user_answers = {} | |
| st.session_state.current_question = 0 | |
| st.session_state.show_answers = {} | |
| st.session_state.show_results = False | |
| st.rerun() | |
| if st.button("π View Results", use_container_width=True, type="primary"): | |
| if answered_count > 0: | |
| st.session_state.show_results = True | |
| st.rerun() | |
| else: | |
| st.warning("β οΈ Please answer some questions first!") | |
| # Main content | |
| if total_questions == 0: | |
| st.warning("β οΈ No questions found in this sheet.") | |
| return | |
| # Display question or results | |
| if st.session_state.show_results: | |
| st.markdown("---") | |
| st.markdown("## π Test Results") | |
| total_score, max_score, results = calculate_score(objective_questions) | |
| col1, col2, col3, col4 = st.columns(4) | |
| with col1: | |
| st.markdown('<div class="metric-card">', unsafe_allow_html=True) | |
| st.metric("Total Score", f"{total_score:.1f}/{max_score:.1f}") | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| with col2: | |
| st.markdown('<div class="metric-card">', unsafe_allow_html=True) | |
| percentage = (total_score / max_score) * 100 if max_score > 0 else 0 | |
| st.metric("Percentage", f"{percentage:.1f}%") | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| with col3: | |
| st.markdown('<div class="metric-card">', unsafe_allow_html=True) | |
| correct_count = sum(1 for r in results if r['is_correct']) | |
| st.metric("Correct", f"{correct_count}/{total_questions}") | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| with col4: | |
| st.markdown('<div class="metric-card">', unsafe_allow_html=True) | |
| incorrect_count = total_questions - correct_count | |
| st.metric("Incorrect", f"{incorrect_count}") | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| st.markdown("---") | |
| st.subheader("π Question-wise Results") | |
| for result in results: | |
| icon = "β " if result['is_correct'] else "β" | |
| with st.expander(f"{icon} Question {result['question']} ({result['marks']} mark{'s' if result['marks'] > 1 else ''})", expanded=False): | |
| st.write(f"**Question:** {result['question_text']}") | |
| col_a, col_b = st.columns(2) | |
| with col_a: | |
| st.write("**Your Answer:**") | |
| if result['user_answer']: | |
| if result['is_correct']: | |
| st.success(result['user_answer']) | |
| else: | |
| st.error(result['user_answer']) | |
| else: | |
| st.warning("Not answered") | |
| with col_b: | |
| st.write("**Correct Answer:**") | |
| st.success(result['correct_answer']) | |
| if st.button("β Back to Test", use_container_width=True, type="primary"): | |
| st.session_state.show_results = False | |
| st.rerun() | |
| else: | |
| current_q_data = objective_questions.iloc[st.session_state.current_question] | |
| display_question(current_q_data, st.session_state.current_question, total_questions) | |
| st.markdown("---") | |
| col1, col2, col3 = st.columns([1, 2, 1]) | |
| with col1: | |
| if st.button("β Previous Question", use_container_width=True, | |
| disabled=st.session_state.current_question == 0): | |
| st.session_state.current_question -= 1 | |
| st.rerun() | |
| with col3: | |
| if st.button("Next Question βΆ", use_container_width=True, | |
| disabled=st.session_state.current_question >= total_questions - 1): | |
| st.session_state.current_question += 1 | |
| st.rerun() | |
| if __name__ == "__main__": | |
| main() |