Spaces:
Sleeping
Sleeping
Upload 3 files
Browse files- app.py +123 -0
- encrypted_grades.csv +1 -0
- fernet_key.txt +1 -0
app.py
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import numpy as np
|
| 4 |
+
from cryptography.fernet import Fernet
|
| 5 |
+
import os
|
| 6 |
+
import io
|
| 7 |
+
from dotenv import load_dotenv
|
| 8 |
+
|
| 9 |
+
# Load environment variables from .env file
|
| 10 |
+
load_dotenv()
|
| 11 |
+
|
| 12 |
+
# Set page configuration
|
| 13 |
+
st.set_page_config(page_title="Student Grade Lookup", page_icon="📚", layout="centered")
|
| 14 |
+
|
| 15 |
+
# Custom CSS to improve the app's appearance
|
| 16 |
+
st.markdown("""
|
| 17 |
+
<style>
|
| 18 |
+
.reportview-container {
|
| 19 |
+
background: #f0f2f6
|
| 20 |
+
}
|
| 21 |
+
.big-font {
|
| 22 |
+
font-size:20px !important;
|
| 23 |
+
font-weight: bold;
|
| 24 |
+
}
|
| 25 |
+
.stAlert > div {
|
| 26 |
+
padding-top: 15px;
|
| 27 |
+
padding-bottom: 15px;
|
| 28 |
+
}
|
| 29 |
+
</style>
|
| 30 |
+
""", unsafe_allow_html=True)
|
| 31 |
+
|
| 32 |
+
# Load and decrypt the CSV file
|
| 33 |
+
@st.cache_data
|
| 34 |
+
def load_data():
|
| 35 |
+
encryption_key = os.getenv('ENCRYPTION_KEY')
|
| 36 |
+
if not encryption_key:
|
| 37 |
+
st.error("Encryption key not found in environment variables.")
|
| 38 |
+
return pd.DataFrame()
|
| 39 |
+
|
| 40 |
+
f = Fernet(encryption_key.encode())
|
| 41 |
+
try:
|
| 42 |
+
with open('encrypted_grades.csv', 'rb') as file:
|
| 43 |
+
encrypted_data = file.read()
|
| 44 |
+
decrypted_data = f.decrypt(encrypted_data)
|
| 45 |
+
return pd.read_csv(io.StringIO(decrypted_data.decode()))
|
| 46 |
+
except Exception as e:
|
| 47 |
+
st.error(f"Error decrypting file: {str(e)}")
|
| 48 |
+
return pd.DataFrame()
|
| 49 |
+
|
| 50 |
+
# Main function to run the Streamlit app
|
| 51 |
+
def main():
|
| 52 |
+
st.title('📚 Student Grade Lookup')
|
| 53 |
+
st.markdown("---")
|
| 54 |
+
|
| 55 |
+
# Load the data
|
| 56 |
+
df = load_data()
|
| 57 |
+
|
| 58 |
+
# Create two columns
|
| 59 |
+
col1, col2 = st.columns([2, 1])
|
| 60 |
+
|
| 61 |
+
with col1:
|
| 62 |
+
# Create an input field for the student ID
|
| 63 |
+
student_id = st.text_input('Enter Student ID:', placeholder="e.g., C21101100")
|
| 64 |
+
|
| 65 |
+
with col2:
|
| 66 |
+
st.write("")
|
| 67 |
+
st.write("")
|
| 68 |
+
search_button = st.button('Search', use_container_width=True)
|
| 69 |
+
|
| 70 |
+
if student_id and search_button:
|
| 71 |
+
# Search for the student in the dataframe
|
| 72 |
+
student = df[df['ID'].astype(str) == student_id]
|
| 73 |
+
|
| 74 |
+
if not student.empty:
|
| 75 |
+
st.markdown("---")
|
| 76 |
+
st.subheader('Student Information:')
|
| 77 |
+
|
| 78 |
+
# Display student information in a more structured way
|
| 79 |
+
col1, col2 = st.columns(2)
|
| 80 |
+
|
| 81 |
+
with col1:
|
| 82 |
+
st.markdown("<p class='big-font'>Name</p>", unsafe_allow_html=True)
|
| 83 |
+
st.write(f"{student['NAME'].values[0]}")
|
| 84 |
+
|
| 85 |
+
st.markdown("<p class='big-font'>ID</p>", unsafe_allow_html=True)
|
| 86 |
+
st.write(f"{student_id}")
|
| 87 |
+
|
| 88 |
+
with col2:
|
| 89 |
+
st.markdown("<p class='big-font'>Grade</p>", unsafe_allow_html=True)
|
| 90 |
+
# Check if grade is NA
|
| 91 |
+
grade = student['GRADE'].values[0]
|
| 92 |
+
if pd.isna(grade):
|
| 93 |
+
grade_display = "N/A"
|
| 94 |
+
else:
|
| 95 |
+
grade_display = f"{grade:.2f}"
|
| 96 |
+
st.write(grade_display)
|
| 97 |
+
|
| 98 |
+
st.markdown("<p class='big-font'>Remarks</p>", unsafe_allow_html=True)
|
| 99 |
+
remarks = student['REMARKS'].values[0]
|
| 100 |
+
if remarks == "Passed":
|
| 101 |
+
st.success(remarks)
|
| 102 |
+
elif remarks == "Conditional":
|
| 103 |
+
st.warning(remarks)
|
| 104 |
+
else:
|
| 105 |
+
st.write(remarks)
|
| 106 |
+
else:
|
| 107 |
+
st.error('Student ID not found. Please try again.')
|
| 108 |
+
|
| 109 |
+
# Display some statistics about the class
|
| 110 |
+
st.markdown("---")
|
| 111 |
+
st.subheader("Class Statistics")
|
| 112 |
+
col1, col2, col3 = st.columns(3)
|
| 113 |
+
with col1:
|
| 114 |
+
st.metric("Total Students", len(df))
|
| 115 |
+
with col2:
|
| 116 |
+
avg_grade = df['GRADE'].mean()
|
| 117 |
+
st.metric("Average Grade", f"{avg_grade:.2f}")
|
| 118 |
+
with col3:
|
| 119 |
+
passing_rate = (df['REMARKS'] == 'Passed').mean() * 100
|
| 120 |
+
st.metric("Passing Rate", f"{passing_rate:.1f}%")
|
| 121 |
+
|
| 122 |
+
if __name__ == '__main__':
|
| 123 |
+
main()
|
encrypted_grades.csv
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
gAAAAABnCqYeNNU_F-av2AD6lolJiVFxBvK7Q1udCgyrR3m_ioDyTDE2SebzLgdBdvFiJRWXFtszDaOtrZh25LfdD5ruHV57qRpNQKO3D7XtiVz3xMdnsTgE14Ex9ibNk8lfTR-vYsdhnwlRBAGuXgilrwErEwD-BrnfGGgh__sUoFsRN_V2dnU0TGjgUBKDTZV0EK6nV5D05YXz5FVNJtdsXVgzV0th3L2HE6qCtX9J6IIDSGpHpnZIh82zjeR2BlqPBFC9rHEmxn-O8dK1nHad9Q-sJF8bed5oi17j4w_4omhCjG44TbF-beM-aXJrQMeDFJmNoDA3JrkgdDVzcYpy2ImE4RSisqqRR19Wzl92mW4HAY-QPAopa3wHaEow3ujQey3LNujtN2nnpi5PbKqixs96nniDe3if3esXKqB9unKLsXDowaP98_6VPgbMP07XY8-rSdrZGhSCGCuxLhtQXww_YcC_ogXinXmscZpB18AZ6rYMKicBcaT1BT_TwqaXe-LSfwvE75RVOlVqDUEr_h7BufgwPK8M5zYIU1AitM_WQsvDY7gSzXKbaQUV_aLzvxc6WmwZtEfWdPipua2qqJJaWZrSbsd0GiLc_ZWurcvX4H9O2g1yz3xB03jhQvvX8cTUyNxAXIPDhaaBsYVcgYL3Q7-ZmUenRFAHj3fC01zuTctmHwDw9Y_hZtou0mbRmnHD4wrycUPrHwUEHe6jJ16ZDbO4aUBPIH0iMG8hBi-6rJcLoUtS5nfmpyuqJqznN-1J9IGgLU2UTROVZXnrzKNEMq-wl6ygAmbgwvcGvcx7yNGp0oBi3szUYbw2LoeTWaUDDhu43fUKsbBV3QXOGrE1G5Ooi4Jvat6gWyKSni03xzEo-COq4rKIAZNjN_E08zFNDTRiPbDPg_rugySHaBRksq5jC1lqbBlly2Cvdz7uJiJYeYsCfzv9FUj2HmdgX2BQipYUr6am9r0MbgJqEXmmNpLOY2nsG65bGsRsJt0cw4qvNcexAN2QyBhyD1QEVG_r1J2hlkovCPtfpmgEpZzz4jKPlDOVO53CIlmxPmvuRMJPMrW3WUYVOsrTTOQIlLZTmF7ZcwrLyQjAimjFPcCnsIqclyULZwfhMn3QgRHLXTyZImQhHWfuo-_d74_KGf1hOQ4Sor-yAckbI8-YB_Gy-en2hgrlBdr0MhnfvY86tZzFe-XtAZOKnXERaOCbV9crI2c95onYpuMH_yhyfo7ITj_suKiUD_nmmNcpNlxsTzz8vLSoMMbEXaO7_IoFt9gg4eN7940CfgDcniyAB8xhScypzuMXCS4EnUs3oRsWqON8zIsEwLR0wTPulxYIXNeDTfUrh7ClZSKSjV0PZ8m3AO4MuHIIc5oKLfwR_gaoLmqel_aCqegoECaUe2_xBS5TyYGK1zq7re6QP98wCOHSqvl9Xn2Ho_bSRoFbtX6HHmstWelxz5jaRJQZWTLOBqF7Oa9wO9feqVaFQL2O0Ew3yU9Y49Ho5iUpgi94Wb0TPRv5IgJ5MYaPEwPOxP1U5SGXS2RZoWfJ5qClYdMz6jZjAV_GIfwjcOdJPFk4NcR2NHJHcbr44dWkTHxARf9Nda4qPPe5f64fJtg7GTZ75j0NQO6XTEBgO7tQ4qJEhpASkhZ1l8irpm20XdsDPy8ErF1JcAEOMyJwyV3Z9eBRVQdPaRkPqf0qUJZYvJIbRTg_TZx7oCjMygS0d82dwRWirS5rw-NzJM6RNdLYFydDYfoQEsr-kQdOjuSHN-JLAmkvLNlvsA73jxKDDtZFhZFilvp6_FMPYyl-uSD7j02w_l9kuO7fKH5U1kMemarqylZ5fnexRgkARDYnUdtSdFddcrpknh75UFYkeMKbdmU0a0xzJNIqMC6Hhhf7rtFfH9w5aK2mQXw8teRq0hv5HSnH0j_HVyNdH8WgNkgqsIM36OkcjqwKa_SaXUA2IhInqH7FeZBNzUEAEmhTb8616bjQNsF2NByZgXauCk24os2LDXHseDmBW99-sNC_FDCSZhU6fSY98oEH-zylTGsRW50xw_Vr7FPhj3bW1tvy_mvZ7XnGGFeGiLUKX-AJgvgRA3Q87vf7SwnqdMtvsYbka0O2yOxSdxBXRAvyD15_m7r9iWl7-ufX1N0Lw191w1xVNUjgJEzYC7x5ZkbkrTaW-UToVcTyV3OglfXR24cTs9bi0bjZQVvFvNpz8lYMgrG4hfYVjxrLrUVM-MNVY-cd3G1tyDX10bmt0kl98ZPnAbKuil8mCH5ayJDektrm5ZX8pP9XoR3Hgh06ItRZo_jmfGg_HcMASibYdxcTUZ49fU-HGgDEXReQcMTNyJpRO0T4ehpfzYZHSzE8dz7b28-mtfg-bOYwlaK_n8w8s0In_61ssH9xn-CkhUty4nansJE3m7p4Ar2JiFSJut_k8938wV6gCni5ZyVCi48f29qg5CGcn6K3cKc8bkCc8kgBoMRVUSQQ9IXpwKl1hV49GbST3Xd9a9sUbo2DvDjrXwnGkTeBki3vlkkJ6EqzbY8gwBIhQtjTTZlFioofHGZ1mqy6J49VZCgmNpkBh6p4swXCk4-t9VMLY3HtTs7MChIhbLyho_W7WLUTUcWIdVF5JOiMJeHDFhQA5xJO
|
fernet_key.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
3vfbK_1k3_c2qxBdz244VphBiEx0db3cG_kg0If4Ois=
|