Spaces:
Sleeping
Sleeping
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Faculty Data Analysis</title> | |
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"> | |
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> | |
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
<style> | |
/* Modern and Enhanced Styles */ | |
body { | |
font-family: 'Inter', sans-serif; | |
background: linear-gradient(135deg, #18579693 0%, #0c5db9 100%); /* Light professional gradient */ | |
color: #415880; | |
line-height: 1.6; | |
} | |
/* Add this for a subtle pattern overlay */ | |
body::before { | |
content: ''; | |
position: fixed; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background-image: | |
linear-gradient(45deg, rgba(255, 255, 255, 0.1) 25%, transparent 25%), | |
linear-gradient(-45deg, rgba(255, 255, 255, 0.1) 25%, transparent 25%), | |
linear-gradient(45deg, transparent 75%, rgba(255, 255, 255, 0.1) 75%), | |
linear-gradient(-45deg, transparent 75%, rgba(255, 255, 255, 0.1) 75%); | |
background-size: 20px 20px; | |
z-index: -1; | |
} | |
/* Update card and form backgrounds for better contrast */ | |
.card, form { | |
background: rgba(255, 255, 255, 0.95); | |
backdrop-filter: blur(10px); | |
} | |
/* Update header colors for better visibility */ | |
h1 { | |
background: linear-gradient(120deg, #2c5282, #2b6cb0); | |
-webkit-background-clip: text; | |
-webkit-text-fill-color: transparent; | |
} | |
h2 { | |
color: #2d3748; | |
} | |
/* Update accordion headers */ | |
.accordion-button:not(.collapsed) { | |
background: linear-gradient(135deg, #2c5282 0%, #2b6cb0 100%); | |
color: white; | |
} | |
/* Update card headers */ | |
.card-header { | |
background: linear-gradient(135deg, #2c5282 0%, #2b6cb0 100%); | |
color: white; | |
} | |
.container { | |
max-width: 1400px; | |
margin: 40px auto; | |
padding: 0 30px; | |
} | |
h1 { | |
font-size: 3rem; | |
font-weight: 700; | |
background: #1e3c6d; | |
-webkit-background-clip: text; | |
-webkit-text-fill-color: transparent; | |
text-align: center; | |
margin-bottom: 2rem; | |
animation: fadeIn 1s ease-in; | |
} | |
h2 { | |
font-size: 2.2rem; | |
color: #1a365d; | |
font-weight: 600; | |
margin: 2rem 0; | |
text-align: center; | |
} | |
/* Enhanced Form Styles */ | |
form { | |
background: rgba(255, 255, 255, 0.9); | |
backdrop-filter: blur(10px); | |
padding: 2.5rem; | |
border-radius: 20px; | |
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1); | |
margin-bottom: 3rem; | |
transition: all 0.3s ease; | |
} | |
form:hover { | |
transform: translateY(-5px); | |
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.15); | |
border-radius: 25px solid #1e3c6d; | |
} | |
.form-label { | |
font-weight: 600; | |
color: #4a5568; | |
margin-bottom: 0.75rem; | |
font-size: 1.1rem; | |
} | |
.form-control { | |
border: 2px solid #e2e8f0; | |
border-radius: 12px; | |
padding: 1rem; | |
transition: all 0.3s ease; | |
} | |
.form-control:focus { | |
border-color: #3182ce; | |
box-shadow: 0 0 0 3px rgba(49, 130, 206, 0.2); | |
} | |
/* Modern Button Styles */ | |
.btn { | |
padding: 1rem 2rem; | |
border-radius: 12px; | |
font-weight: 600; | |
letter-spacing: 0.5px; | |
transition: all 0.3s ease; | |
} | |
.btn-primary { | |
background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%); | |
border: none; | |
box-shadow: 0 4px 15px rgba(37, 99, 235, 0.2); | |
} | |
.btn-primary:hover { | |
transform: translateY(-2px); | |
box-shadow: 0 6px 20px rgba(37, 99, 235, 0.3); | |
background: linear-gradient(135deg, #1d4ed8 0%, #2563eb 100%); | |
} | |
/* Enhanced Table Styles */ | |
.table-container { | |
background: white; | |
border-radius: 20px; | |
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1); | |
overflow: hidden; | |
margin-bottom: 2rem; | |
} | |
.table { | |
margin-bottom: 0; | |
} | |
.table thead th { | |
background: linear-gradient(135deg, #063292 0%, #3b82f6 100%); | |
color: white; | |
font-weight: 600; | |
text-transform: uppercase; | |
font-size: 0.9rem; | |
letter-spacing: 1px; | |
padding: 1.2rem solid #063292; | |
border: none; | |
} | |
.table tbody tr { | |
transition: all 0.2s ease; | |
} | |
.table tbody tr:hover { | |
background-color: #f8fafc; | |
transform: scale(1.01); | |
} | |
/* Card Styles for Insights */ | |
.card { | |
border: none; | |
border-radius: 20px; | |
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08); | |
transition: all 0.3s ease; | |
overflow: hidden; | |
} | |
.card:hover { | |
transform: translateY(-5px); | |
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.12); | |
} | |
.card-header { | |
background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%); | |
color: white; | |
font-weight: 600; | |
padding: 1.2rem; | |
border: none; | |
} | |
.card-body { | |
padding: 1.5rem; | |
} | |
/* Accordion Styles */ | |
.accordion-item { | |
border: none; | |
margin-bottom: 1rem; | |
border-radius: 15px; | |
overflow: hidden; | |
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05); | |
} | |
.accordion-button { | |
padding: 1.2rem; | |
font-weight: 600; | |
background: white; | |
} | |
.accordion-button:not(.collapsed) { | |
background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%); | |
color: white; | |
} | |
/* Animation Classes */ | |
.fade-in { | |
animation: fadeIn 1s ease-in; | |
} | |
.slide-up { | |
animation: slideInUp 0.5s ease-out; | |
} | |
/* Responsive Design */ | |
@media (max-width: 768px) { | |
.container { | |
padding: 0 15px; | |
} | |
h1 { | |
font-size: 2.2rem; | |
} | |
h2 { | |
font-size: 1.8rem; | |
} | |
form { | |
padding: 1.5rem; | |
} | |
.btn { | |
padding: 0.8rem 1.5rem; | |
} | |
} | |
/* Custom Scrollbar */ | |
::-webkit-scrollbar { | |
width: 10px; | |
} | |
::-webkit-scrollbar-track { | |
background: #f1f1f1; | |
} | |
::-webkit-scrollbar-thumb { | |
background: #3b82f6; | |
border-radius: 5px; | |
} | |
::-webkit-scrollbar-thumb:hover { | |
background: #2563eb; | |
} | |
/* Modern Variables */ | |
:root { | |
--primary-color: #2563eb; | |
--secondary-color: #3b82f6; | |
--accent-color: #7c3aed; | |
--success-color: #10b981; | |
--warning-color: #f59e0b; | |
--danger-color: #ef4444; | |
--background-color: #f8fafc; | |
--card-bg: #ffffff; | |
--text-primary: #1e293b; | |
--text-secondary: #64748b; | |
--border-radius: 12px; | |
--transition: all 0.3s ease; | |
} | |
/* Enhanced Base Styles */ | |
body { | |
font-family: 'Inter', sans-serif; | |
background: linear-gradient(135deg, var(--background-color) 0%, #e2e8f0 100%); | |
color: var(--text-primary); | |
line-height: 1.6; | |
} | |
.container { | |
max-width: 1400px; | |
margin: 40px auto; | |
padding: 0 30px; | |
} | |
/* Enhanced Form Elements */ | |
.form-control, .form-select { | |
border: 2px solid #e2e8f0; | |
border-radius: var(--border-radius); | |
padding: 0.75rem 1rem; | |
transition: var(--transition); | |
background-color: rgba(255, 255, 255, 0.9); | |
} | |
.form-control:focus, .form-select:focus { | |
border-color: var(--primary-color); | |
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1); | |
transform: translateY(-1px); | |
} | |
/* Custom Range Slider */ | |
.custom-range { | |
-webkit-appearance: none; | |
width: 100%; | |
height: 8px; | |
border-radius: 5px; | |
background: #e2e8f0; | |
outline: none; | |
margin: 15px 0; | |
} | |
.custom-range::-webkit-slider-thumb { | |
-webkit-appearance: none; | |
width: 24px; | |
height: 24px; | |
border-radius: 50%; | |
background: var(--primary-color); | |
cursor: pointer; | |
transition: var(--transition); | |
border: 2px solid white; | |
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | |
} | |
.custom-range::-webkit-slider-thumb:hover { | |
transform: scale(1.1); | |
} | |
/* Range Value Display */ | |
.range-value { | |
text-align: center; | |
font-weight: 600; | |
color: var(--primary-color); | |
margin-top: 8px; | |
} | |
/* Checkbox Group */ | |
.checkbox-group { | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
gap: 1rem; | |
margin-top: 0.5rem; | |
} | |
.form-check { | |
padding: 0.5rem; | |
border-radius: var(--border-radius); | |
transition: var(--transition); | |
} | |
.form-check:hover { | |
background: rgba(37, 99, 235, 0.05); | |
} | |
.form-check-input { | |
width: 1.2em; | |
height: 1.2em; | |
margin-top: 0.2em; | |
cursor: pointer; | |
} | |
.form-check-input:checked { | |
background-color: var(--primary-color); | |
border-color: var(--primary-color); | |
} | |
/* Card Enhancements */ | |
.card { | |
border: none; | |
border-radius: var(--border-radius); | |
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08); | |
transition: var(--transition); | |
overflow: hidden; | |
background: rgba(255, 255, 255, 0.95); | |
backdrop-filter: blur(10px); | |
} | |
.card:hover { | |
transform: translateY(-5px); | |
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.12); | |
} | |
/* Section Headers */ | |
h4 { | |
color: var(--text-primary); | |
font-weight: 600; | |
margin-bottom: 1.5rem; | |
padding-bottom: 0.5rem; | |
border-bottom: 2px solid var(--primary-color); | |
display: inline-block; | |
} | |
/* Textarea Enhancement */ | |
textarea.form-control { | |
resize: vertical; | |
min-height: 100px; | |
} | |
/* Animation Classes */ | |
.fade-in { | |
animation: fadeIn 0.5s ease-in; | |
} | |
@keyframes fadeIn { | |
from { opacity: 0; transform: translateY(10px); } | |
to { opacity: 1; transform: translateY(0); } | |
} | |
/* Responsive Design */ | |
@media (max-width: 768px) { | |
.checkbox-group { | |
grid-template-columns: 1fr; | |
} | |
.container { | |
padding: 0 15px; | |
} | |
.card { | |
margin: 1rem 0; | |
} | |
} | |
/* Loading State */ | |
.loading { | |
position: relative; | |
opacity: 0.8; | |
pointer-events: none; | |
} | |
.loading::after { | |
content: ""; | |
position: absolute; | |
top: 50%; | |
left: 50%; | |
width: 2rem; | |
height: 2rem; | |
border: 3px solid #f3f3f3; | |
border-top: 3px solid var(--primary-color); | |
border-radius: 50%; | |
animation: spin 1s linear infinite; | |
transform: translate(-50%, -50%); | |
} | |
@keyframes spin { | |
0% { transform: translate(-50%, -50%) rotate(0deg); } | |
100% { transform: translate(-50%, -50%) rotate(360deg); } | |
} | |
/* Print Button Styling */ | |
.print-btn { | |
position: fixed; | |
bottom: 30px; | |
right: 30px; | |
z-index: 1000; | |
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%); | |
color: white; | |
border: none; | |
padding: 12px 24px; | |
border-radius: 50px; | |
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); | |
transition: all 0.3s ease; | |
} | |
.print-btn:hover { | |
transform: translateY(-2px); | |
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3); | |
background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%); | |
color: white; | |
} | |
/* Print Media Styles */ | |
@media print { | |
.print-btn { | |
display: none; | |
} | |
/* Hide elements not needed in print */ | |
.btn-primary, | |
.form-control, | |
input[type="file"], | |
.accordion-button { | |
display: none ; | |
} | |
/* Ensure all content is visible */ | |
.accordion-collapse { | |
display: block ; | |
} | |
/* Better page breaks */ | |
.card, | |
.table-responsive, | |
.accordion-item { | |
page-break-inside: avoid; | |
} | |
/* Adjust colors for better printing */ | |
body { | |
background: white ; | |
color: black ; | |
} | |
/* Ensure text contrast */ | |
h1, h2, h3, h4 { | |
color: black ; | |
-webkit-text-fill-color: black ; | |
} | |
/* Adjust table styling for print */ | |
.table { | |
border: 1px solid #ddd ; | |
} | |
.table th, | |
.table td { | |
border: 1px solid #ddd ; | |
} | |
/* Ensure graphs are properly sized */ | |
.plotly-graph-div { | |
width: 100% ; | |
height: auto ; | |
} | |
/* Add page numbers */ | |
@page { | |
margin: 2cm; | |
} | |
body::after { | |
content: counter(page); | |
counter-increment: page; | |
position: fixed; | |
bottom: 0; | |
right: 0; | |
font-size: 12px; | |
} | |
} | |
/* Add this to your existing styles */ | |
.fa-sync-alt { | |
transition: transform 0.3s ease; | |
} | |
.fa-sync-alt:hover { | |
transform: rotate(180deg); | |
} | |
.fa-chart-bar, .fa-chart-line, .fa-chart-pie { | |
transition: transform 0.3s ease; | |
} | |
.fa-chart-bar:hover, .fa-chart-line:hover, .fa-chart-pie:hover { | |
transform: scale(1.2); | |
} | |
.fa-download { | |
animation: bounce 1s infinite; | |
} | |
@keyframes bounce { | |
0%, 100% { transform: translateY(0); } | |
50% { transform: translateY(-3px); } | |
} | |
/* Enhanced button hover effects with icons */ | |
.btn:hover i { | |
transform: scale(1.1); | |
} | |
/* Icon spacing */ | |
.me-2 { | |
margin-right: 0.5rem; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container mt-5"> | |
<h1 class="text-center text-primary mb-4"> | |
<i class="fas fa-university me-2"></i> Faculty Data Analysis | |
</h1> | |
<!-- File Upload Form --> | |
<form method="POST" enctype="multipart/form-data" class="mb-5"> | |
<div class="mb-3"> | |
<label for="faculty_file" class="form-label"> | |
<i class="fas fa-file-upload me-2"></i>Upload Faculty Data CSV | |
</label> | |
<input type="file" id="faculty_file" name="faculty_file" class="form-control" accept=".csv" required> | |
</div> | |
<!-- Input Fields for Student Counts --> | |
{% if departments %} | |
<h3 class="mt-4"> | |
<i class="fas fa-users me-2"></i>Enter Student Counts by Department | |
</h3> | |
{% for department in departments %} | |
<div class="mb-3"> | |
<label for="students_{{ department }}" class="form-label">{{ department }}</label> | |
<input type="number" id="students_{{ department }}" name="students_{{ department }}" class="form-control" min="0" required> | |
</div> | |
{% endfor %} | |
{% endif %} | |
<button type="submit" class="btn btn-primary w-100"> | |
<i class="fas fa-chart-bar me-2"></i>Analyze | |
</button> | |
</form> | |
<!-- Error Message --> | |
{% if error %} | |
<div class="alert alert-danger text-center"> | |
{{ error }} | |
</div> | |
{% endif %} | |
<!-- Download Graded CSV --> | |
{% if graded_csv %} | |
<div class="text-end mb-4"> | |
<a href="data:text/csv;base64,{{ graded_csv }}" download="graded_faculty_data.csv" class="btn btn-success"> | |
<i class="fas fa-download me-2"></i>Download Graded CSV | |
</a> | |
</div> | |
{% endif %} | |
{% if plots %} | |
<h2 class="text-center text-secondary"> | |
<i class="fas fa-chart-line me-2"></i>Visualizations with Insights | |
</h2> | |
<div class="accordion" id="plotsAccordion"> | |
{% for plot_title, plot_html in plots.items() %} | |
<div class="accordion-item"> | |
<h2 class="accordion-header" id="heading-{{ loop.index }}"> | |
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" | |
data-bs-target="#collapse-{{ loop.index }}" aria-expanded="false" aria-controls="collapse-{{ loop.index }}"> | |
{{ plot_title }} | |
</button> | |
</h2> | |
<div id="collapse-{{ loop.index }}" class="accordion-collapse collapse" | |
aria-labelledby="heading-{{ loop.index }}" data-bs-parent="#plotsAccordion"> | |
<div class="accordion-body"> | |
<div class="row"> | |
<!-- Graph Section --> | |
<div class="col-md-7"> | |
<div>{{ plot_html | safe }}</div> | |
</div> | |
<!-- Gemini Insight Section --> | |
<div class="col-md-5"> | |
<div class="card h-100"> | |
<div class="card-header bg-info text-white"> | |
<strong>Insights for {{ plot_title }}</strong> | |
</div> | |
<div class="card-body"> | |
<p>{{ gemini_insights[plot_title] }}</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
{% endfor %} | |
</div> | |
{% endif %} | |
<!-- Department Tables Section --> | |
{% if department_tables %} | |
<h2 class="text-center text-warning mt-5">Faculty Data by Department</h2> | |
{% for department, table in department_tables.items() %} | |
<div class="mb-4"> | |
<h3 class="text-center text-secondary">{{ department }}</h3> | |
<div class="table-responsive"> | |
<table class="table table-striped table-bordered"> | |
<thead> | |
<tr> | |
{% for col in table.columns %} | |
<th>{{ col }}</th> | |
{% endfor %} | |
</tr> | |
</thead> | |
<tbody> | |
{% for row in table.rows %} | |
<tr> | |
{% for cell in row %} | |
<td>{{ cell }}</td> | |
{% endfor %} | |
</tr> | |
{% endfor %} | |
</tbody> | |
</table> | |
</div> | |
</div> | |
{% endfor %} | |
{% endif %} | |
<!-- Deficiency Table Section --> | |
{% if deficiency_table %} | |
<h2 class="text-center text-danger mt-5">Deficiency Comparison: Faculty vs Students</h2> | |
<div class="table-responsive"> | |
{{ deficiency_table | safe }} | |
</div> | |
{% endif %} | |
<!-- SWOT Analysis Results --> | |
{% if swot_results %} | |
<div class="card mt-5"> | |
<div class="card-header bg-info text-white"> | |
<h3 class="mb-0"><i class="fas fa-chart-pie me-2"></i>SWOT Analysis Results</h3> | |
</div> | |
<div class="card-body"> | |
<div class="row"> | |
<div class="col-md-6"> | |
<h4 class="text-success"><i class="fas fa-star me-2"></i>Strengths</h4> | |
<ul> | |
{% for strength in swot_results.strengths %} | |
<li>{{ strength }}</li> | |
{% endfor %} | |
</ul> | |
</div> | |
<div class="col-md-6"> | |
<h4 class="text-danger"><i class="fas fa-exclamation-triangle me-2"></i>Weaknesses</h4> | |
<ul> | |
{% for weakness in swot_results.weaknesses %} | |
<li>{{ weakness }}</li> | |
{% endfor %} | |
</ul> | |
</div> | |
</div> | |
<div class="row"> | |
<div class="col-md-6"> | |
<h4 class="text-primary"><i class="fas fa-lightbulb me-2"></i>Opportunities</h4> | |
<ul> | |
{% for opportunity in swot_results.opportunities %} | |
<li>{{ opportunity }}</li> | |
{% endfor %} | |
</ul> | |
</div> | |
<div class="col-md-6"> | |
<h4 class="text-warning"><i class="fas fa-shield-alt me-2"></i>Threats</h4> | |
<ul> | |
{% for threat in swot_results.threats %} | |
<li>{{ threat }}</li> | |
{% endfor %} | |
</ul> | |
</div> | |
</div> | |
</div> | |
</div> | |
{% endif %} | |
<button class="btn btn-secondary print-btn" onclick="window.print()"> | |
<i class="fas fa-print"></i> Get Report | |
</button> | |
<!-- Scripts --> | |
<script> | |
// Initialize Bootstrap Popovers | |
document.addEventListener('DOMContentLoaded', function () { | |
var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')); | |
var popoverList = popoverTriggerList.map(function (popoverTriggerEl) { | |
return new bootstrap.Popover(popoverTriggerEl, { | |
html: true, | |
container: 'body' | |
}); | |
}); | |
}); | |
// Range slider value display | |
document.querySelectorAll('.custom-range').forEach(range => { | |
const valueDisplay = document.getElementById(range.id.replace('range', 'value')); | |
range.addEventListener('input', (e) => { | |
valueDisplay.textContent = e.target.value; | |
}); | |
}); | |
// Form submission loading state | |
document.querySelector('form').addEventListener('submit', function(e) { | |
this.classList.add('loading'); | |
}); | |
// Enhanced print functionality | |
function printReport() { | |
// Expand all accordion items before printing | |
const accordionItems = document.querySelectorAll('.accordion-collapse'); | |
accordionItems.forEach(item => { | |
item.classList.add('show'); | |
}); | |
// Wait for any graphs to finish rendering | |
setTimeout(() => { | |
window.print(); | |
// Restore accordion state after printing | |
accordionItems.forEach(item => { | |
item.classList.remove('show'); | |
}); | |
}, 500); | |
} | |
// Add click handler to print button | |
document.querySelector('.print-btn').addEventListener('click', printReport); | |
// Add keyboard shortcut (Ctrl/Cmd + P) | |
document.addEventListener('keydown', function(e) { | |
if ((e.ctrlKey || e.metaKey) && e.key === 'p') { | |
e.preventDefault(); | |
printReport(); | |
} | |
}); | |
</script> | |
</body> | |
</html> | |