SanskrutiChopade
Initial commit
443b256
<!DOCTYPE html>
<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 !important;
}
/* Ensure all content is visible */
.accordion-collapse {
display: block !important;
}
/* Better page breaks */
.card,
.table-responsive,
.accordion-item {
page-break-inside: avoid;
}
/* Adjust colors for better printing */
body {
background: white !important;
color: black !important;
}
/* Ensure text contrast */
h1, h2, h3, h4 {
color: black !important;
-webkit-text-fill-color: black !important;
}
/* Adjust table styling for print */
.table {
border: 1px solid #ddd !important;
}
.table th,
.table td {
border: 1px solid #ddd !important;
}
/* Ensure graphs are properly sized */
.plotly-graph-div {
width: 100% !important;
height: auto !important;
}
/* 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>