NVIDIA / src /streamlit_app.py
shriramprabhu's picture
Update src/streamlit_app.py
c7e2640 verified
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()