pranit144 commited on
Commit
1eabbf4
·
verified ·
1 Parent(s): 272ed75

Upload 12 files

Browse files
.env ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GEMINI_API_KEY = "AIzaSyAX6kFj6BqnY_5pBr54saD52svAJLg1Bjo"
2
+ # Supabase Credentials
3
+ SUPABASE_URL=https://dbbomivlqhbgpgqrmfwj.supabase.co
4
+ SUPABASE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImRiYm9taXZscWhiZ3BncXJtZndqIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc0NTMwNTY0OCwiZXhwIjoyMDYwODgxNjQ4fQ.faROkreac8Ojv_HWNnwHCT0hj19uTVgE8ekRONefvvA
5
+ # SUPABASE_KEY=qHgLNbTYUu86Z4YU
6
+
7
+ ADMIN_PORTAL_SECRET_KEY=a_different_very_strong_random_secret_key # Generate a unique key
8
+
9
+ # Add these to your .env file
10
+ SMTP_SERVER=smtp.gmail.com
11
+ SMTP_PORT=587
12
+ SMTP_USERNAME=pranitchilbule1@gmail.com
13
+ SMTP_PASSWORD=ljaqimdjyqitltnc
app.py ADDED
@@ -0,0 +1,1197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py (Company Portal)
2
+ import os
3
+ import pandas as pd
4
+ import smtplib
5
+ from email.mime.text import MIMEText
6
+ from email.mime.multipart import MIMEMultipart
7
+ import json
8
+ import io
9
+ import numpy as np
10
+ import hashlib
11
+ from datetime import datetime
12
+
13
+ year = datetime.now().year
14
+ import re
15
+ from flask import Flask, render_template, request, redirect, url_for, session, jsonify, send_file, flash, make_response
16
+ import google.generativeai as genai
17
+ from datetime import datetime
18
+ from supabase import create_client, Client
19
+ from dotenv import load_dotenv
20
+
21
+ load_dotenv()
22
+
23
+ app = Flask(__name__)
24
+ app.secret_key = os.getenv("COMPANY_PORTAL_SECRET_KEY", os.urandom(24))
25
+
26
+ # --- Supabase Client Initialization ---
27
+ supabase_url = os.getenv("SUPABASE_URL")
28
+ supabase_key = os.getenv("SUPABASE_KEY")
29
+
30
+ if not supabase_url or not supabase_key:
31
+ print("CRITICAL ERROR: SUPABASE_URL and SUPABASE_KEY environment variables are required.")
32
+ supabase: Client = None
33
+ else:
34
+ try:
35
+ supabase: Client = create_client(supabase_url, supabase_key)
36
+ print("Supabase client initialized successfully for Company Portal.")
37
+ except Exception as e:
38
+ print(f"CRITICAL ERROR: Error initializing Supabase client for Company Portal: {e}")
39
+ supabase = None
40
+
41
+ # --- Gemini API Configuration ---
42
+ GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
43
+ HAS_GEMINI = False
44
+ if GEMINI_API_KEY:
45
+ try:
46
+ genai.configure(api_key=GEMINI_API_KEY)
47
+ HAS_GEMINI = True
48
+ print("Gemini API Configured.")
49
+ except Exception as e:
50
+ print(f"Warning: Error configuring Gemini API: {e}. AI Insights & NL Query may fail.")
51
+ else:
52
+ print("Warning: GEMINI_API_KEY not found in .env file. AI Insights & NL Query will not work.")
53
+
54
+ # --- Helper Functions ---
55
+
56
+ def verify_password(stored_hash, password):
57
+ """Verifies a password against a stored SHA256 hash."""
58
+ input_hash = hashlib.sha256(password.encode()).hexdigest()
59
+ return input_hash == stored_hash
60
+
61
+ def load_student_data():
62
+ """Loads all student data from the Supabase 'students' table."""
63
+ if not supabase:
64
+ flash("Database connection error. Cannot load student data.", "danger")
65
+ return pd.DataFrame()
66
+
67
+ try:
68
+ response = supabase.table('students').select('*').execute()
69
+ if response.data:
70
+ df = pd.DataFrame(response.data)
71
+ numeric_cols = ['cgpa', 'backlogs', 'typing_speed']
72
+ for col in numeric_cols:
73
+ if col in df.columns:
74
+ # Coerce errors to NaN, then handle NaN later if needed
75
+ df[col] = pd.to_numeric(df[col], errors='coerce')
76
+ if 'backlogs' in df.columns:
77
+ # Fill NaN with 0 before converting to int
78
+ df['backlogs'] = df['backlogs'].fillna(0).astype(int)
79
+ # Example of how you might handle array columns if stored as strings (adjust based on DB schema)
80
+ # list_cols = ['programming_languages', 'tools_technologies', 'soft_skills', 'preferred_roles', 'certifications']
81
+ # for col in list_cols:
82
+ # if col in df.columns and df[col].dtype == 'object':
83
+ # # Attempt to parse comma-separated string or already list-like structure
84
+ # df[col] = df[col].apply(lambda x: [i.strip() for i in str(x).split(',')] if pd.notna(x) and isinstance(x, str) else x)
85
+
86
+ print(f"Loaded {len(df)} student records.") # Debug
87
+ return df
88
+ else:
89
+ print("No student data found in Supabase.") # Debug
90
+ return pd.DataFrame()
91
+ except Exception as e:
92
+ print(f"Error loading student data from Supabase: {e}")
93
+ flash(f"Error loading student data: {e}", "danger")
94
+ return pd.DataFrame()
95
+
96
+
97
+ def send_job_email(job_data):
98
+ """Sends job posting details via email."""
99
+ try:
100
+ # Email configuration from environment variables
101
+ smtp_server = os.getenv("SMTP_SERVER")
102
+ smtp_port = int(os.getenv("SMTP_PORT", 0))
103
+ smtp_username = os.getenv("SMTP_USERNAME")
104
+ smtp_password = os.getenv("SMTP_PASSWORD")
105
+ if not all([smtp_server, smtp_port, smtp_username, smtp_password]):
106
+ raise RuntimeError("SMTP credentials are missing or invalid in .env")
107
+ # Recipient email
108
+ recipient_email ="pranit.chilbule221@vit.edu"
109
+
110
+ # Create message
111
+ msg = MIMEMultipart()
112
+ msg['From'] = smtp_username
113
+ msg['To'] = recipient_email
114
+ msg['Subject'] = f"New Job Posting: {job_data['title']}"
115
+
116
+ # Email body
117
+ body = f"""
118
+ <html lang="en">
119
+ <head>
120
+ <meta charset="UTF-8">
121
+ <title>New Job Posting</title>
122
+ </head>
123
+ <body style="margin:0;padding:0;background-color:#f4f4f4;font-family:Arial,sans-serif;">
124
+ <!--[if mso]>
125
+ <style>
126
+ body, table, td {{
127
+ font-family: Arial, sans-serif !important;
128
+ }}
129
+ </style>
130
+ <![endif]-->
131
+
132
+ <table width="100%" cellpadding="0" cellspacing="0" role="presentation">
133
+ <tr>
134
+ <td align="center" style="padding:20px 0;">
135
+ <table width="600" cellpadding="0" cellspacing="0" role="presentation"
136
+ style="background-color:#ffffff;border-radius:8px;overflow:hidden;
137
+ box-shadow:0 2px 6px rgba(0,0,0,0.1);">
138
+
139
+ <!-- Header -->
140
+ <tr>
141
+ <td style="background-color:#004aad;padding:20px;text-align:center;color:#ffffff;">
142
+ <h1 style="margin:0;font-size:24px;line-height:28px;">New Job Posting</h1>
143
+ </td>
144
+ </tr>
145
+
146
+ <!-- Body content -->
147
+ <tr>
148
+ <td style="padding:30px;">
149
+ <p style="margin:0 0 16px;font-size:16px;line-height:22px;">
150
+ Hello Team,
151
+ </p>
152
+
153
+ <table width="100%" cellpadding="0" cellspacing="0" role="presentation"
154
+ style="margin-bottom:24px;">
155
+ <tr>
156
+ <td style="padding:8px 0;font-weight:bold;width:30%;">Title:</td>
157
+ <td style="padding:8px 0;">{job_data['title']}</td>
158
+ </tr>
159
+ <tr style="background-color:#f9f9f9;">
160
+ <td style="padding:8px 0;font-weight:bold;">Location:</td>
161
+ <td style="padding:8px 0;">{job_data['location']}</td>
162
+ </tr>
163
+ <tr>
164
+ <td style="padding:8px 0;font-weight:bold;">Required Skills:</td>
165
+ <td style="padding:8px 0;">{', '.join(job_data['required_skills'])}</td>
166
+ </tr>
167
+ <tr style="background-color:#f9f9f9;">
168
+ <td style="padding:8px 0;font-weight:bold;">Minimum CGPA:</td>
169
+ <td style="padding:8px 0;">
170
+ {job_data['min_cgpa'] if job_data['min_cgpa'] else 'Not specified'}
171
+ </td>
172
+ </tr>
173
+ <tr>
174
+ <td style="padding:8px 0;font-weight:bold;">Experience Level:</td>
175
+ <td style="padding:8px 0;">{job_data['experience_level']} year(s)</td>
176
+ </tr>
177
+ </table>
178
+
179
+ <p style="margin:0 0 8px;font-weight:bold;font-size:16px;">Description:</p>
180
+ <p style="margin:0 0 24px;font-size:15px;line-height:21px;">
181
+ {job_data['description']}
182
+ </p>
183
+ <a href="https://docs.google.com/forms/d/e/1FAIpQLSdcm0zkEqZjb1sDBaytj9ITLOX8L0LTD81HczJxRAS7LfvSKA/viewform?usp=header" target="_blank">
184
+ <button style="padding: 10px 20px; font-size: 16px; border-radius: 8px; background-color: #4CAF50; color: white; border: none; cursor: pointer;">
185
+ Fill Out the Form
186
+ </button>
187
+ </a>
188
+
189
+ <p style="margin:0;font-size:14px;color:#777777;line-height:20px;">
190
+ This is an automated message from the Company Portal.
191
+ </p>
192
+ </td>
193
+ </tr>
194
+
195
+ <!-- Footer -->
196
+ <tr>
197
+ <td style="background-color:#f4f4f4;padding:15px;
198
+ text-align:center;font-size:12px;color:#999999;">
199
+ &copy; {year} Your Company Name. All rights reserved.
200
+ </td>
201
+ </tr>
202
+
203
+ </table>
204
+ </td>
205
+ </tr>
206
+ </table>
207
+ </body>
208
+ </html>
209
+ """
210
+
211
+ msg.attach(MIMEText(body, 'html'))
212
+
213
+ # Connect to SMTP server and send
214
+ with smtplib.SMTP(smtp_server, smtp_port) as server:
215
+ server.ehlo() # Identify ourselves to SMTP
216
+ server.starttls() # Upgrade to secure TLS
217
+ server.ehlo() # Re-identify after STARTTLS
218
+ server.login(smtp_username, smtp_password)
219
+ server.send_message(msg)
220
+
221
+ print(f"Email sent successfully to {recipient_email}")
222
+ return True
223
+ except Exception as e:
224
+ print(f"Error sending email: {e}")
225
+ import traceback
226
+ traceback.print_exc()
227
+ return False
228
+
229
+
230
+ def get_unique_values(df, column):
231
+ """Gets unique, sorted, non-empty values from a DataFrame column, handling comma-separated strings and lists."""
232
+ values = set()
233
+ if column in df.columns and not df[column].isnull().all():
234
+ for item in df[column].dropna():
235
+ item_str = str(item).strip()
236
+ if item_str:
237
+ # Handle actual lists (from DB array type) or comma-separated strings
238
+ if isinstance(item, list):
239
+ # Ensure items in list are strings and clean them (remove proficiency)
240
+ values.update(str(x).split('(')[0].strip() for x in item if x and str(x).strip())
241
+ elif ',' in item_str:
242
+ # Strip proficiency like " (Beginner)"
243
+ values.update(x.split('(')[0].strip() for x in item_str.split(',') if x.strip())
244
+ else:
245
+ # Strip proficiency like " (Beginner)"
246
+ values.add(item_str.split('(')[0].strip())
247
+ return sorted(list(values))
248
+
249
+
250
+ def filter_students(df, filters):
251
+ """Filters the student DataFrame based on various criteria including job requirements."""
252
+ if df.empty:
253
+ print("Filter Students: Input DataFrame is empty.")
254
+ return df
255
+
256
+ filtered_df = df.copy()
257
+ print(f"Filter Students: Starting with {len(filtered_df)} students. Filters: {filters}")
258
+
259
+ try:
260
+ # CGPA filter
261
+ if filters.get('min_cgpa') is not None and filters['min_cgpa'] != '': # Check for not None explicitly
262
+ try:
263
+ min_cgpa_val = float(filters['min_cgpa'])
264
+ if 'cgpa' in filtered_df.columns:
265
+ original_count = len(filtered_df)
266
+ filtered_df = filtered_df[filtered_df['cgpa'].fillna(0) >= min_cgpa_val]
267
+ print(f" Applied CGPA >= {min_cgpa_val}: {original_count} -> {len(filtered_df)}")
268
+ except (ValueError, TypeError):
269
+ print(f" Warning: Invalid CGPA filter value '{filters['min_cgpa']}'")
270
+
271
+ # Backlogs filter
272
+ if filters.get('max_backlogs') is not None and filters['max_backlogs'] != '': # Check for not None explicitly
273
+ try:
274
+ max_backlogs_val = float(filters['max_backlogs'])
275
+ if 'backlogs' in filtered_df.columns:
276
+ original_count = len(filtered_df)
277
+ filtered_df = filtered_df[filtered_df['backlogs'] <= max_backlogs_val]
278
+ print(f" Applied Backlogs <= {max_backlogs_val}: {original_count} -> {len(filtered_df)}")
279
+ except (ValueError, TypeError):
280
+ print(f" Warning: Invalid Backlogs filter value '{filters['max_backlogs']}'")
281
+
282
+ # Department filter (added for NL Query possibility)
283
+ if filters.get('department') and 'department' in filtered_df.columns:
284
+ dept_filter = str(filters['department']).strip()
285
+ if dept_filter:
286
+ original_count = len(filtered_df)
287
+ # Case-insensitive comparison
288
+ filtered_df = filtered_df[filtered_df['department'].str.contains(dept_filter, case=False, na=False)]
289
+ print(f" Applied Department contains '{dept_filter}': {original_count} -> {len(filtered_df)}")
290
+
291
+
292
+ # Helper for text contains filtering (case-insensitive) for comma-separated strings or lists
293
+ def text_contains_any(series, patterns):
294
+ if not patterns or series.isnull().all():
295
+ return pd.Series([False] * len(series), index=series.index)
296
+
297
+ patterns_set = {str(p).lower().strip() for p in patterns if p and str(p).strip()}
298
+ if not patterns_set:
299
+ return pd.Series([False] * len(series), index=series.index)
300
+
301
+ def check_item(item):
302
+ if pd.isna(item): return False
303
+ item_elements = []
304
+ current_item_elements = []
305
+ if isinstance(item, list):
306
+ current_item_elements = [str(el).lower().split('(')[0].strip() for el in item if el]
307
+ elif isinstance(item, str):
308
+ current_item_elements = [el.lower().split('(')[0].strip() for el in item.split(',') if el.strip()]
309
+ else:
310
+ current_item_elements = [str(item).lower().split('(')[0].strip()]
311
+ # Extend the main list
312
+ item_elements.extend(el for el in current_item_elements if el) # Ensure no empty strings
313
+ return any(elem in patterns_set for elem in item_elements)
314
+
315
+ return series.apply(check_item)
316
+
317
+
318
+ # Skills filter (checks programming_languages OR tools_technologies)
319
+ if filters.get('skills'):
320
+ skill_patterns = filters['skills']
321
+ lang_col_exists = 'programming_languages' in filtered_df.columns
322
+ tools_col_exists = 'tools_technologies' in filtered_df.columns
323
+ lang_match = pd.Series([False] * len(filtered_df), index=filtered_df.index)
324
+ tools_match = pd.Series([False] * len(filtered_df), index=filtered_df.index)
325
+
326
+ if lang_col_exists: lang_match = text_contains_any(filtered_df['programming_languages'], skill_patterns)
327
+ if tools_col_exists: tools_match = text_contains_any(filtered_df['tools_technologies'], skill_patterns)
328
+
329
+ original_count = len(filtered_df)
330
+ filtered_df = filtered_df[lang_match | tools_match]
331
+ print(f" Applied Skills filter ({skill_patterns}): {original_count} -> {len(filtered_df)}")
332
+
333
+
334
+ # Preferred roles filter
335
+ if filters.get('roles'):
336
+ role_patterns = filters['roles']
337
+ if 'preferred_roles' in filtered_df.columns:
338
+ original_count = len(filtered_df)
339
+ filtered_df = filtered_df[text_contains_any(filtered_df['preferred_roles'], role_patterns)]
340
+ print(f" Applied Roles filter ({role_patterns}): {original_count} -> {len(filtered_df)}")
341
+
342
+ # Certifications filter (checks certifications OR detailed_certifications)
343
+ if filters.get('certifications'):
344
+ cert_patterns = filters['certifications']
345
+ cert_match = pd.Series([False] * len(filtered_df), index=filtered_df.index)
346
+ detail_cert_match = pd.Series([False] * len(filtered_df), index=filtered_df.index)
347
+
348
+ if 'certifications' in filtered_df.columns: cert_match = text_contains_any(filtered_df['certifications'], cert_patterns)
349
+ if 'detailed_certifications' in filtered_df.columns: detail_cert_match = text_contains_any(filtered_df['detailed_certifications'], cert_patterns)
350
+
351
+ original_count = len(filtered_df)
352
+ filtered_df = filtered_df[cert_match | detail_cert_match]
353
+ print(f" Applied Certifications filter ({cert_patterns}): {original_count} -> {len(filtered_df)}")
354
+
355
+
356
+ # Boolean flags (check if column exists and is not null/empty string/empty list)
357
+ def check_not_empty(series):
358
+ if series is None or series.empty: return pd.Series([False] * len(filtered_df), index=filtered_df.index)
359
+ # Handles NaN, None, empty strings, and potentially empty lists robustly
360
+ return series.apply(lambda x: pd.notna(x) and ( (isinstance(x, str) and x.strip()!='') or (isinstance(x, list) and len(x)>0) or (not isinstance(x,(str,list))) ) )
361
+
362
+ # Use the boolean value directly from filters dict (already processed in filter_students_route)
363
+ if filters.get('has_hackathons') is True:
364
+ if 'hackathons' in filtered_df.columns:
365
+ original_count = len(filtered_df)
366
+ filtered_df = filtered_df[check_not_empty(filtered_df['hackathons'])]
367
+ print(f" Applied Has Hackathons: {original_count} -> {len(filtered_df)}")
368
+ else: print(" Skipped Has Hackathons: Column not found")
369
+
370
+ if filters.get('has_experience') is True:
371
+ proj_exists = 'projects' in filtered_df.columns
372
+ intern_exists = 'internships' in filtered_df.columns
373
+ has_proj = check_not_empty(filtered_df.get('projects')) if proj_exists else pd.Series([False] * len(filtered_df), index=filtered_df.index)
374
+ has_intern = check_not_empty(filtered_df.get('internships')) if intern_exists else pd.Series([False] * len(filtered_df), index=filtered_df.index)
375
+ original_count = len(filtered_df)
376
+ filtered_df = filtered_df[has_proj | has_intern]
377
+ print(f" Applied Has Experience (Proj/Intern): {original_count} -> {len(filtered_df)}")
378
+
379
+
380
+ if filters.get('has_research') is True:
381
+ pub_exists = 'publications' in filtered_df.columns
382
+ patent_exists = 'patents' in filtered_df.columns
383
+ has_pub = check_not_empty(filtered_df.get('publications')) if pub_exists else pd.Series([False] * len(filtered_df), index=filtered_df.index)
384
+ has_patent = check_not_empty(filtered_df.get('patents')) if patent_exists else pd.Series([False] * len(filtered_df), index=filtered_df.index)
385
+ original_count = len(filtered_df)
386
+ filtered_df = filtered_df[has_pub | has_patent]
387
+ print(f" Applied Has Research (Pub/Patent): {original_count} -> {len(filtered_df)}")
388
+
389
+
390
+ # --- Job role-based filtering (Applied if job_id is present) ---
391
+ job_id_filter = filters.get('job_id')
392
+ if job_id_filter and job_id_filter != '' and supabase:
393
+ try:
394
+ job_id_val = int(job_id_filter)
395
+ print(f" Applying filters for Job ID: {job_id_val}")
396
+ response = supabase.table('jobs').select('min_cgpa, required_skills, experience_level').eq('id', job_id_val).maybe_single().execute()
397
+
398
+ if response.data:
399
+ job = response.data
400
+ print(f" Job Requirements: {job}")
401
+ # Filter by minimum CGPA requirement
402
+ if job.get('min_cgpa') is not None and 'cgpa' in filtered_df.columns:
403
+ original_count = len(filtered_df)
404
+ filtered_df = filtered_df[filtered_df['cgpa'].fillna(0) >= float(job['min_cgpa'])]
405
+ print(f" Applied Job CGPA >= {job['min_cgpa']}: {original_count} -> {len(filtered_df)}")
406
+
407
+ # Filter by required skills (ANY logic)
408
+ if job.get('required_skills'):
409
+ required_skills_list = job['required_skills']
410
+ lang_col_exists = 'programming_languages' in filtered_df.columns
411
+ tools_col_exists = 'tools_technologies' in filtered_df.columns
412
+ lang_match = pd.Series([False] * len(filtered_df), index=filtered_df.index)
413
+ tools_match = pd.Series([False] * len(filtered_df), index=filtered_df.index)
414
+
415
+ if lang_col_exists: lang_match = text_contains_any(filtered_df['programming_languages'], required_skills_list)
416
+ if tools_col_exists: tools_match = text_contains_any(filtered_df['tools_technologies'], required_skills_list)
417
+
418
+ original_count = len(filtered_df)
419
+ filtered_df = filtered_df[lang_match | tools_match]
420
+ print(f" Applied Job Skills filter ({required_skills_list}): {original_count} -> {len(filtered_df)}")
421
+
422
+ # Filter by experience level (Checks if internships or projects exist if experience > 0)
423
+ if job.get('experience_level') and job['experience_level'] > 0:
424
+ intern_exists = 'internships' in filtered_df.columns
425
+ proj_exists = 'projects' in filtered_df.columns
426
+ has_intern = check_not_empty(filtered_df.get('internships')) if intern_exists else pd.Series([False] * len(filtered_df), index=filtered_df.index)
427
+ has_proj = check_not_empty(filtered_df.get('projects')) if proj_exists else pd.Series([False] * len(filtered_df), index=filtered_df.index)
428
+
429
+ if intern_exists or proj_exists:
430
+ original_count = len(filtered_df)
431
+ filtered_df = filtered_df[has_proj | has_intern]
432
+ print(f" Applied Job Experience (>0 requires Internship/Project): {original_count} -> {len(filtered_df)}")
433
+ else: print(" Skipped Job Experience: Internships/Projects columns not found")
434
+ else:
435
+ print(f" Warning: Job ID {job_id_val} not found for filtering.")
436
+ flash(f"Warning: Job ID {job_id_val} not found, could not apply job-specific filters.", "warning")
437
+
438
+ except ValueError:
439
+ print(f" Invalid job_id format: {job_id_filter}")
440
+ except Exception as e:
441
+ print(f" Error fetching/applying job details for filtering: {e}")
442
+ flash(f"Warning: Could not apply filters for Job ID {job_id_filter}. Error: {e}", "warning")
443
+
444
+ except Exception as e:
445
+ print(f"Error during filtering process: {e}")
446
+ import traceback
447
+ traceback.print_exc()
448
+ flash(f"An critical error occurred during filtering: {e}", "danger")
449
+ return df # Return original df on major error
450
+
451
+ print(f"Filter Students: Finished with {len(filtered_df)} students.")
452
+ return filtered_df
453
+
454
+
455
+ def get_ai_insights(students_data, role):
456
+ """Generates AI insights using Gemini for selected students and a role."""
457
+ if not HAS_GEMINI:
458
+ return "AI Insights disabled: Gemini API key not configured."
459
+ if students_data.empty:
460
+ return "No student data provided for analysis."
461
+
462
+ print(f"Generating AI insights for {len(students_data)} students, role: {role}") # Debug
463
+
464
+ # Format the student data for Gemini prompt (Simplified)
465
+ students_prompt = f"Analyze the following {len(students_data)} students based *only* on the provided profile data for suitability regarding the **{role}** role:\n\n---\n"
466
+ columns_to_include = [
467
+ 'full_name', 'department', 'cgpa', 'backlogs',
468
+ 'programming_languages', 'tools_technologies', 'soft_skills',
469
+ 'projects', 'internships', 'certifications', 'preferred_roles',
470
+ 'strengths', 'weaknesses'
471
+ ]
472
+
473
+ for index, student in students_data.iterrows():
474
+ profile_str = f"**Student {index + 1}: {student.get('full_name', 'N/A')}**\n"
475
+ for col in columns_to_include:
476
+ if col != 'full_name':
477
+ value = student.get(col)
478
+ display_value = "N/A"
479
+ if pd.notna(value):
480
+ if isinstance(value, list):
481
+ display_value = ", ".join(map(str, value)) if value else "N/A"
482
+ elif isinstance(value, float):
483
+ display_value = f"{value:.2f}"
484
+ elif isinstance(value, (int, np.integer)):
485
+ display_value = str(value)
486
+ elif isinstance(value, str) and value.strip():
487
+ display_value = value.strip()
488
+
489
+ if display_value != "N/A":
490
+ profile_str += f"- {col.replace('_', ' ').title()}: {display_value}\n"
491
+ students_prompt += profile_str + "---\n"
492
+
493
+ students_prompt += f"""
494
+ **Analysis Request for {role}:**
495
+
496
+ 1. **Ranked List:** Provide a ranked list (Top 3-5 recommended) of these students for the role. Briefly justify each rank based *only* on the provided data points (e.g., relevant skills, experience, CGPA if applicable).
497
+ 2. **Strengths & Potential Gaps:** For *each* student listed above, concisely identify 1-2 key strengths and 1-2 potential gaps or areas needing clarification *specifically* for the '{role}' role, based *only* on their profile.
498
+ 3. **Overall Summary:** Briefly summarize which student(s) appear most promising overall for this *specific* role, considering the data provided. Mention any significant trade-offs.
499
+
500
+ **Important Constraints:**
501
+ * Base your entire analysis *strictly* on the profile data given above.
502
+ * Do not invent or assume information not present.
503
+ * Focus on relevance to the specified '{role}'.
504
+ * Format the output clearly using Markdown (bolding, lists).
505
+ """
506
+
507
+ try:
508
+ model = genai.GenerativeModel('gemini-1.5-flash') # Or gemini-pro
509
+ # Safety settings can be adjusted if needed
510
+ # safety_settings = [...]
511
+ # response = model.generate_content(students_prompt, safety_settings=safety_settings)
512
+ response = model.generate_content(students_prompt)
513
+
514
+ if not response.parts:
515
+ print("Warning: AI response might be blocked due to safety settings.")
516
+ feedback = response.prompt_feedback if hasattr(response, 'prompt_feedback') else "No feedback available."
517
+ print(f"Prompt Feedback: {feedback}")
518
+ return f"AI analysis could not be completed (content potentially blocked by safety filters). Feedback: {feedback}"
519
+
520
+ print("AI insights generated successfully.") # Debug
521
+ return response.text
522
+ except Exception as e:
523
+ print(f"Error generating AI insights: {e}")
524
+ import traceback
525
+ traceback.print_exc()
526
+ return f"Error generating AI insights: {str(e)}\n\nPlease check your Gemini API key and configuration."
527
+
528
+
529
+ # --- Chart Data Calculation Functions ---
530
+
531
+ def calculate_cgpa_distribution(df):
532
+ """Calculates data for CGPA distribution chart."""
533
+ result = {'labels': [], 'data': []}
534
+ if df.empty or 'cgpa' not in df.columns or df['cgpa'].isnull().all():
535
+ print("CGPA Calc: DataFrame empty or 'cgpa' column missing/all null.")
536
+ return result
537
+ try:
538
+ bins = [0, 6, 7, 7.5, 8, 8.5, 9, 9.5, 10.1]
539
+ labels = ['< 6.0', '6.0-6.9', '7.0-7.4', '7.5-7.9', '8.0-8.4', '8.5-8.9', '9.0-9.4', '9.5-10.0']
540
+ cgpa_binned = pd.cut(df['cgpa'].dropna(), bins=bins, labels=labels, right=False, include_lowest=True)
541
+ counts = cgpa_binned.value_counts().sort_index()
542
+ result = {'labels': counts.index.tolist(), 'data': counts.values.tolist()}
543
+ print(f"CGPA Calc Results: Labels={result['labels']}, Data={result['data']}") # DEBUG
544
+ return result
545
+ except Exception as e:
546
+ print(f"Error calculating CGPA dist data: {e}")
547
+ return result
548
+
549
+ def calculate_department_distribution(df):
550
+ """Calculates data for department distribution chart."""
551
+ result = {'labels': [], 'data': []}
552
+ if df.empty or 'department' not in df.columns or df['department'].isnull().all():
553
+ print("Dept Calc: DataFrame empty or 'department' column missing/all null.")
554
+ return result
555
+ try:
556
+ counts = df['department'].value_counts()
557
+ result = {'labels': counts.index.tolist(), 'data': counts.values.tolist()}
558
+ print(f"Dept Calc Results: Labels={result['labels']}, Data={result['data']}") # DEBUG
559
+ return result
560
+ except Exception as e:
561
+ print(f"Error calculating Dept dist data: {e}")
562
+ return result
563
+
564
+ def calculate_skills_distribution(df, top_n=10):
565
+ """Calculates data for top N programming skills distribution."""
566
+ result = {'labels': [], 'data': []}
567
+ if df.empty or 'programming_languages' not in df.columns:
568
+ print("Skills Calc: DataFrame empty or 'programming_languages' column missing.")
569
+ return result
570
+ try:
571
+ all_skills = []
572
+ for skills_item in df['programming_languages'].dropna():
573
+ skills = []
574
+ if isinstance(skills_item, str) and skills_item.strip():
575
+ skills = [s.split('(')[0].strip().lower() for s in skills_item.split(',') if s.strip()]
576
+ elif isinstance(skills_item, list):
577
+ skills = [str(s).split('(')[0].strip().lower() for s in skills_item if s and str(s).strip()]
578
+ all_skills.extend(skills)
579
+
580
+ if not all_skills: print("Skills Calc: No skills found after parsing."); return result
581
+ skill_counts = pd.Series(all_skills).value_counts().nlargest(top_n)
582
+ labels = [s.capitalize() for s in skill_counts.index.tolist()]
583
+ result = {'labels': labels, 'data': skill_counts.values.tolist()}
584
+ print(f"Skills Calc Results: Labels={result['labels']}, Data={result['data']}") # DEBUG
585
+ return result
586
+ except Exception as e:
587
+ print(f"Error calculating Skills dist data: {e}")
588
+ return result
589
+
590
+ def calculate_roles_distribution(df, top_n=10):
591
+ """Calculates data for top N preferred roles distribution."""
592
+ result = {'labels': [], 'data': []}
593
+ if df.empty or 'preferred_roles' not in df.columns:
594
+ print("Roles Calc: DataFrame empty or 'preferred_roles' column missing.")
595
+ return result
596
+ try:
597
+ all_roles = []
598
+ for roles_item in df['preferred_roles'].dropna():
599
+ roles = []
600
+ if isinstance(roles_item, str) and roles_item.strip():
601
+ roles = [r.strip().lower() for r in roles_item.split(',') if r.strip()]
602
+ elif isinstance(roles_item, list):
603
+ roles = [str(r).strip().lower() for r in roles_item if r and str(r).strip()]
604
+ all_roles.extend(roles)
605
+
606
+ if not all_roles: print("Roles Calc: No roles found after parsing."); return result
607
+ role_counts = pd.Series(all_roles).value_counts().nlargest(top_n)
608
+ labels = [r.title() for r in role_counts.index.tolist()]
609
+ result = {'labels': labels, 'data': role_counts.values.tolist()}
610
+ print(f"Roles Calc Results: Labels={result['labels']}, Data={result['data']}") # DEBUG
611
+ return result
612
+ except Exception as e:
613
+ print(f"Error calculating Roles dist data: {e}")
614
+ return result
615
+
616
+ # --- Routes ---
617
+
618
+ @app.route('/')
619
+ def home():
620
+ """Redirects to dashboard if logged in, otherwise to login page."""
621
+ if 'company_email' in session:
622
+ return redirect(url_for('dashboard'))
623
+ return redirect(url_for('login'))
624
+
625
+
626
+ @app.route('/login', methods=['GET', 'POST'])
627
+ def login():
628
+ if not supabase:
629
+ return make_response(render_template('company_login.html', error="Database service unavailable. Please try again later."), 503)
630
+
631
+ error = None
632
+ if request.method == 'POST':
633
+ email = request.form.get('email')
634
+ password = request.form.get('password')
635
+
636
+ if not email or not password:
637
+ error = 'Email and password are required.'
638
+ return render_template('company_login.html', error=error)
639
+
640
+ try:
641
+ print(f"--- Attempting login for: {email}")
642
+ response = supabase.table('companies').select('*').eq('email', email).maybe_single().execute()
643
+ print(f"--- Supabase response status: {response.data is not None}")
644
+
645
+ if response.data:
646
+ company_data = response.data
647
+ print(f"--- Company data found: {company_data.keys()}")
648
+ stored_hash = company_data.get('password')
649
+ print(f"--- Stored hash found: {stored_hash is not None}")
650
+
651
+ if stored_hash and verify_password(stored_hash, password):
652
+ print("--- Password verified")
653
+ required_keys = ['id', 'email', 'company_name']
654
+ if all(k in company_data for k in required_keys):
655
+ session['company_id'] = company_data['id']
656
+ session['company_email'] = company_data['email']
657
+ session['company_name'] = company_data['company_name']
658
+ session.permanent = True
659
+ print("--- Session set successfully")
660
+ flash(f"Welcome back, {session['company_name']}!", "success")
661
+ return redirect(url_for('dashboard'))
662
+ else:
663
+ print(f"--- Error: Missing required keys in company_data. Found: {company_data.keys()}")
664
+ error = "Login failed: Incomplete company profile data in database."
665
+ else:
666
+ print("--- Password verification failed")
667
+ error = 'Invalid credentials. Please try again.'
668
+ else:
669
+ print(f"--- Company email '{email}' not found in database.")
670
+ error = 'Company email not found.'
671
+ except Exception as e:
672
+ print(f"--- Login error exception: {e}")
673
+ import traceback
674
+ traceback.print_exc()
675
+ error = 'An error occurred during login. Please contact support.'
676
+
677
+ if 'company_email' in session:
678
+ return redirect(url_for('dashboard'))
679
+ return render_template('company_login.html', error=error)
680
+
681
+
682
+ @app.route('/logout')
683
+ def logout():
684
+ """Logs the company out."""
685
+ session.pop('company_id', None)
686
+ session.pop('company_email', None)
687
+ session.pop('company_name', None)
688
+ session.pop('filter_options_cache', None) # Clear cached options on logout
689
+ flash("You have been logged out.", "info")
690
+ return redirect(url_for('login'))
691
+
692
+
693
+ @app.route('/dashboard')
694
+ def dashboard():
695
+ """Displays the main company dashboard."""
696
+ if 'company_email' not in session:
697
+ flash("Please log in to access the dashboard.", "warning")
698
+ return redirect(url_for('login'))
699
+ if not supabase:
700
+ flash("Database service unavailable.", "danger")
701
+ return render_template('company_dashboard.html', company_name=session.get('company_name', 'Company'), students=[], filter_options={}, initial_chart_data='{}', jobs=[], error="Database connection failed")
702
+
703
+ # Load student data
704
+ df = load_student_data()
705
+
706
+ # Prepare data for filters
707
+ filter_options = {
708
+ 'departments': get_unique_values(df, 'department'),
709
+ 'programming_languages': get_unique_values(df, 'programming_languages'),
710
+ 'tools': get_unique_values(df, 'tools_technologies'),
711
+ 'roles': get_unique_values(df, 'preferred_roles'),
712
+ 'certifications': sorted(list(set(get_unique_values(df, 'certifications') + get_unique_values(df, 'detailed_certifications'))))
713
+ }
714
+ # --- Cache filter options in session ---
715
+ session['filter_options_cache'] = filter_options
716
+ # --- End Caching ---
717
+
718
+ # --- Calculate Initial Chart Data ---
719
+ initial_chart_data = {
720
+ 'cgpa': calculate_cgpa_distribution(df),
721
+ 'department': calculate_department_distribution(df),
722
+ 'skills': calculate_skills_distribution(df),
723
+ 'roles': calculate_roles_distribution(df)
724
+ }
725
+ print("\n--- Initial Chart Data (Backend - Dashboard Route) ---")
726
+ try:
727
+ print(json.dumps(initial_chart_data, indent=2))
728
+ except Exception as json_e: print(f"Error dumping initial chart data: {json_e}")
729
+ print("-----------------------------------------------------\n")
730
+
731
+ # Fetch jobs posted by this company
732
+ jobs_list = []
733
+ try:
734
+ response = supabase.table('jobs').select('id, title').eq('company_id', session['company_id']).order('posted_date', desc=True).execute()
735
+ jobs_list = response.data if response.data else []
736
+ except Exception as e:
737
+ print(f"Error fetching jobs for dashboard: {e}")
738
+ flash("Could not load job postings.", "warning")
739
+
740
+ # Convert DataFrame NaNs to None for JSON serialization
741
+ display_cols = ['full_name', 'email', 'department', 'cgpa', 'backlogs', 'programming_languages', 'preferred_roles', 'internships', 'projects', 'hackathons', 'publications']
742
+ # Only select columns that actually exist in the dataframe
743
+ existing_display_cols = [col for col in display_cols if col in df.columns]
744
+ students_list = df[existing_display_cols].replace({np.nan: None}).to_dict('records') if not df.empty else []
745
+
746
+ return render_template(
747
+ 'company_dashboard.html',
748
+ initial_chart_data=initial_chart_data, # Pass dict directly
749
+ company_name=session['company_name'],
750
+ students=students_list,
751
+ filter_options=filter_options, # Pass for initial rendering
752
+ jobs=jobs_list
753
+ )
754
+
755
+
756
+ @app.route('/filter_students', methods=['POST'])
757
+ def filter_students_route():
758
+ """Handles AJAX request to filter students and provides updated chart data."""
759
+ if 'company_email' not in session:
760
+ return jsonify({'error': 'Not authenticated'}), 401
761
+ if not supabase:
762
+ return jsonify({'error': 'Database service unavailable'}), 503
763
+
764
+ print("\n--- Filter Students Route Called ---") # Debug
765
+ df = load_student_data()
766
+ if df.empty:
767
+ print("Filter Students Route: No student data loaded.")
768
+ return jsonify({'students': [], 'chart_data': {}, 'count': 0})
769
+
770
+ filters = request.form.to_dict()
771
+
772
+ # Explicitly process boolean flags from form data ('on' means True)
773
+ filters['has_hackathons'] = filters.get('has_hackathons') == 'on'
774
+ filters['has_experience'] = filters.get('has_experience') == 'on'
775
+ filters['has_research'] = filters.get('has_research') == 'on'
776
+
777
+ # Get lists correctly
778
+ filters['skills'] = request.form.getlist('skills')
779
+ filters['roles'] = request.form.getlist('roles')
780
+ filters['certifications'] = request.form.getlist('certifications')
781
+
782
+ # Apply filters
783
+ filtered_df = filter_students(df, filters)
784
+
785
+ # --- Calculate Chart Data for Filtered Results ---
786
+ filtered_chart_data = {
787
+ 'cgpa': calculate_cgpa_distribution(filtered_df),
788
+ 'department': calculate_department_distribution(filtered_df),
789
+ 'skills': calculate_skills_distribution(filtered_df),
790
+ 'roles': calculate_roles_distribution(filtered_df)
791
+ }
792
+ print("\n--- Filtered Chart Data (Backend - Filter Route) ---")
793
+ try: print(json.dumps(filtered_chart_data, indent=2))
794
+ except Exception as json_e: print(f"Error dumping filtered chart data: {json_e}")
795
+ print("----------------------------------------------------\n")
796
+
797
+ # Prepare data for JSON response
798
+ display_cols = ['full_name', 'email', 'department', 'cgpa', 'backlogs', 'programming_languages', 'preferred_roles', 'internships', 'projects', 'hackathons', 'publications']
799
+ existing_display_cols = [col for col in display_cols if col in filtered_df.columns]
800
+ students_result = filtered_df[existing_display_cols].replace({np.nan: None}).to_dict('records') if not filtered_df.empty else []
801
+
802
+ print(f"Filter Students Route: Returning {len(students_result)} students.") # Debug
803
+ return jsonify({
804
+ 'students': students_result,
805
+ 'chart_data': filtered_chart_data,
806
+ 'count': len(filtered_df)
807
+ })
808
+
809
+
810
+ @app.route('/process_nl_query', methods=['POST'])
811
+ def process_nl_query():
812
+ """Handles AJAX request to convert natural language query to filters."""
813
+ if 'company_email' not in session:
814
+ return jsonify({'error': 'Not authenticated'}), 401
815
+ if not supabase:
816
+ return jsonify({'error': 'Database service unavailable'}), 503
817
+ if not HAS_GEMINI:
818
+ return jsonify({'error': 'AI Query service not configured or unavailable.'}), 503
819
+
820
+ nl_query = request.json.get('query')
821
+ if not nl_query:
822
+ return jsonify({'error': 'No query provided.'}), 400
823
+
824
+ print(f"Processing NL Query: '{nl_query}'")
825
+
826
+ # Retrieve cached filter options
827
+ cached_options = session.get('filter_options_cache')
828
+ if not cached_options:
829
+ # Fallback: Regenerate if not in session (should be rare)
830
+ print("Warning: Filter options cache miss in NL Query route, regenerating.")
831
+ df_temp = load_student_data()
832
+ cached_options = {
833
+ 'departments': get_unique_values(df_temp, 'department'),
834
+ 'programming_languages': get_unique_values(df_temp, 'programming_languages'),
835
+ 'tools': get_unique_values(df_temp, 'tools_technologies'),
836
+ 'roles': get_unique_values(df_temp, 'preferred_roles'),
837
+ 'certifications': sorted(list(set(get_unique_values(df_temp, 'certifications') + get_unique_values(df_temp, 'detailed_certifications'))))
838
+ }
839
+ session['filter_options_cache'] = cached_options # Cache it now
840
+
841
+ # Combine skills for context
842
+ all_skill_examples = list(set(cached_options.get('programming_languages', []) + cached_options.get('tools', [])))
843
+
844
+ # --- Construct Prompt for Gemini ---
845
+ prompt = f"""
846
+ Analyze the following natural language query from a recruiter and convert it into a JSON object containing filter parameters for a student database.
847
+
848
+ **Available Filter Fields and Keys (Use these keys in the JSON output):**
849
+ * `min_cgpa`: Minimum CGPA (float, 0.0 to 10.0).
850
+ * `max_backlogs`: Maximum number of backlogs allowed (integer, >= 0).
851
+ * `skills`: List of required skills (strings). Match these against programming languages OR tools.
852
+ * `roles`: List of preferred job roles (strings).
853
+ * `certifications`: List of certifications (strings).
854
+ * `department`: Specific department name (string). Extract if mentioned clearly.
855
+ * `has_hackathons`: Boolean (true if user mentions hackathons or competitions).
856
+ * `has_experience`: Boolean (true if user mentions projects or internships).
857
+ * `has_research`: Boolean (true if user mentions research, publications, or patents).
858
+
859
+ **Context - Available Values (Examples - Use for guidance, not exhaustive):**
860
+ * Departments: {json.dumps(cached_options.get('departments', [])[:10])}...
861
+ * Skills (Programming/Tools): {json.dumps(all_skill_examples[:15])}...
862
+ * Roles: {json.dumps(cached_options.get('roles', [])[:10])}...
863
+ * Certifications: {json.dumps(cached_options.get('certifications', [])[:10])}...
864
+
865
+ **Recruiter's Query:**
866
+ "{nl_query}"
867
+
868
+ **Instructions:**
869
+ 1. Parse the query to extract filtering criteria.
870
+ 2. Map criteria to the correct filter keys listed above.
871
+ 3. For list fields (`skills`, `roles`, `certifications`), output a JSON list of strings. Include the user's terms.
872
+ 4. For boolean fields (`has_...`), output `true` only if explicitly mentioned. Otherwise, omit the key or set to `false`.
873
+ 5. For `min_cgpa` and `max_backlogs`, extract the numeric value.
874
+ 6. For `department`, extract the specific department name mentioned.
875
+ 7. If a criterion isn't mentioned, omit its key from the JSON.
876
+ 8. Output *only* the JSON object, without any explanations or markdown formatting.
877
+
878
+ **Example Input Query:** "Find computer science students with CGPA over 7.5, no backlogs, and who know Python or Java. Experience with projects is a plus."
879
+ **Example JSON Output:**
880
+ {{
881
+ "department": "Computer Science",
882
+ "min_cgpa": 7.5,
883
+ "max_backlogs": 0,
884
+ "skills": ["Python", "Java"],
885
+ "has_experience": true
886
+ }}
887
+
888
+ **Now, process the recruiter's query above and generate the JSON output.**
889
+ """
890
+
891
+ try:
892
+ print("--- Sending NL prompt to Gemini ---")
893
+ model = genai.GenerativeModel('gemini-1.5-flash') # Or gemini-pro
894
+ response = model.generate_content(prompt)
895
+
896
+ # Clean the response (remove markdown backticks, etc.)
897
+ print(f"--- Gemini Raw Response Text ---\n{response.text}\n-----------------------------")
898
+ cleaned_response_text = response.text.strip()
899
+ if cleaned_response_text.startswith('```json'): cleaned_response_text = cleaned_response_text[7:]
900
+ if cleaned_response_text.startswith('```'): cleaned_response_text = cleaned_response_text[3:]
901
+ if cleaned_response_text.endswith('```'): cleaned_response_text = cleaned_response_text[:-3]
902
+ cleaned_response_text = cleaned_response_text.strip()
903
+
904
+ if not cleaned_response_text:
905
+ raise ValueError("Gemini returned an empty response after cleaning.")
906
+
907
+ filter_params = json.loads(cleaned_response_text)
908
+ print(f"--- Parsed Filter Params ---\n{json.dumps(filter_params, indent=2)}\n--------------------------")
909
+
910
+ if not isinstance(filter_params, dict):
911
+ raise ValueError("Gemini response was not a valid JSON object.")
912
+
913
+ # Optional: Further validation/type conversion can be added here if needed
914
+
915
+ return jsonify({'filters': filter_params})
916
+
917
+ except json.JSONDecodeError as e:
918
+ print(f"Error decoding Gemini JSON response: {e}")
919
+ print(f"Response text was: {cleaned_response_text}") # Log cleaned text
920
+ return jsonify({'error': f'AI could not generate valid filter parameters. Please rephrase your query. (JSON Error: {e}). Raw response: {response.text}'}), 400
921
+ except Exception as e:
922
+ print(f"Error processing NL query with Gemini: {e}")
923
+ import traceback
924
+ traceback.print_exc()
925
+ return jsonify({'error': f'An error occurred while processing the AI query: {e}'}), 500
926
+
927
+
928
+ @app.route('/ai_insights', methods=['POST'])
929
+ def ai_insights_route():
930
+ """Handles AJAX request for AI insights."""
931
+ if 'company_email' not in session:
932
+ return jsonify({'error': 'Not authenticated'}), 401
933
+ if not supabase:
934
+ return jsonify({'error': 'Database service unavailable'}), 503
935
+ if not HAS_GEMINI:
936
+ return jsonify({'error': 'AI Insights service not configured or unavailable.'}), 503
937
+
938
+ df = load_student_data()
939
+ selected_emails = request.form.getlist('selected_students')
940
+ role = request.form.get('role', 'General Role Analysis')
941
+
942
+ print(f"AI Insights requested for emails: {selected_emails} and role: {role}")
943
+
944
+ if not selected_emails:
945
+ print("No students selected for AI analysis.")
946
+ return jsonify({'error': 'No students selected for analysis.'}), 400
947
+
948
+ selected_students_df = df[df['email'].isin(selected_emails)].copy()
949
+
950
+ if selected_students_df.empty:
951
+ print(f"Selected student emails not found in loaded data: {selected_emails}")
952
+ return jsonify({'error': 'Selected student data could not be found.'}), 404
953
+
954
+ insights = get_ai_insights(selected_students_df, role)
955
+ return jsonify({'insights': insights})
956
+
957
+
958
+ @app.route('/export_filtered', methods=['POST'])
959
+ def export_filtered():
960
+ """Exports the currently filtered student list (sent from client) to CSV."""
961
+ if 'company_email' not in session:
962
+ return jsonify({"error": "Authentication required for export"}), 401
963
+
964
+ student_data_json = request.form.get('filtered_students')
965
+ if not student_data_json:
966
+ return jsonify({"error": "No student data provided"}), 400
967
+
968
+ try:
969
+ student_data = json.loads(student_data_json)
970
+ if not student_data:
971
+ return jsonify({"error": "No students to export"}), 400
972
+
973
+ df_to_export = pd.DataFrame(student_data)
974
+ export_columns = [
975
+ 'full_name', 'email', 'department', 'cgpa', 'backlogs',
976
+ 'programming_languages', 'tools_technologies', 'soft_skills',
977
+ 'projects', 'internships', 'certifications', 'detailed_certifications',
978
+ 'hackathons', 'publications', 'patents',
979
+ 'preferred_roles', 'preferred_location', 'strengths', 'weaknesses',
980
+ 'typing_speed', 'linkedin_profile', 'github_profile', 'portfolio_url'
981
+ ]
982
+ available_export_cols = [col for col in export_columns if col in df_to_export.columns]
983
+ df_to_export = df_to_export[available_export_cols]
984
+
985
+ except json.JSONDecodeError:
986
+ print("Error decoding JSON for export")
987
+ return jsonify({"error": "Invalid data format for export"}), 400
988
+ except Exception as e:
989
+ print(f"Error preparing export data: {e}")
990
+ return jsonify({"error": f"Server error during export preparation: {e}"}), 500
991
+
992
+ try:
993
+ mem_file = io.BytesIO()
994
+ mem_file.write(u'\ufeff'.encode('utf8')) # BOM for Excel
995
+ df_to_export.to_csv(mem_file, index=False, encoding='utf-8-sig')
996
+ mem_file.seek(0)
997
+
998
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
999
+ response = make_response(send_file(
1000
+ mem_file,
1001
+ mimetype='text/csv',
1002
+ download_name=f'filtered_students_{timestamp}.csv',
1003
+ as_attachment=True
1004
+ ))
1005
+ response.headers['Content-Disposition'] = f"attachment; filename=filtered_students_{timestamp}.csv"
1006
+ response.headers["Content-type"] = "text/csv; charset=utf-8"
1007
+ print(f"Exporting {len(df_to_export)} students to CSV.")
1008
+ return response
1009
+
1010
+ except Exception as e:
1011
+ print(f"Error sending export file: {e}")
1012
+ return jsonify({"error": f"Server error during file generation: {e}"}), 500
1013
+
1014
+
1015
+ @app.route('/jobs', methods=['GET', 'POST'])
1016
+ def jobs():
1017
+ """Displays job postings and handles new job creation."""
1018
+ if 'company_email' not in session:
1019
+ flash("Please log in to manage job postings.", "warning")
1020
+ return redirect(url_for('login'))
1021
+ if not supabase:
1022
+ flash("Database service unavailable.", "danger")
1023
+ return render_template('jobs.html', jobs=[], skills=[], company_name=session.get('company_name', 'Company'),
1024
+ error="Database connection failed")
1025
+
1026
+ company_id = session.get('company_id')
1027
+ if not company_id:
1028
+ flash("Company session error. Please log in again.", "danger")
1029
+ return redirect(url_for('logout'))
1030
+
1031
+ # Load student data once for skills list generation
1032
+ df_students = load_student_data()
1033
+ prog_langs = get_unique_values(df_students, 'programming_languages')
1034
+ tools_tech = get_unique_values(df_students, 'tools_technologies')
1035
+ available_skills = sorted(list(set(prog_langs + tools_tech)))
1036
+
1037
+ if request.method == 'POST':
1038
+ try:
1039
+ required_skills_list = request.form.getlist('required_skills')
1040
+ min_cgpa_str = request.form.get('min_cgpa')
1041
+ experience_str = request.form.get('experience_level', '0')
1042
+ title = request.form.get('title')
1043
+ description = request.form.get('description')
1044
+ location = request.form.get('location')
1045
+
1046
+ # Basic validation
1047
+ error_msg = None
1048
+ if not title:
1049
+ error_msg = "Job Title is required."
1050
+ elif not description:
1051
+ error_msg = "Job Description is required."
1052
+ elif not required_skills_list:
1053
+ error_msg = "At least one required skill must be selected."
1054
+ elif not location:
1055
+ error_msg = "Location is required."
1056
+
1057
+ if error_msg:
1058
+ flash(error_msg, "warning")
1059
+ response = supabase.table('jobs').select('*').eq('company_id', company_id).order('posted_date',
1060
+ desc=True).execute()
1061
+ jobs_list = response.data if response.data else []
1062
+ return render_template('jobs.html', jobs=jobs_list, skills=available_skills,
1063
+ company_name=session['company_name'])
1064
+
1065
+ new_job_data = {
1066
+ 'company_id': company_id,
1067
+ 'title': title,
1068
+ 'description': description,
1069
+ 'required_skills': required_skills_list, # Store as array
1070
+ 'min_cgpa': float(min_cgpa_str) if min_cgpa_str else None,
1071
+ 'experience_level': int(experience_str) if experience_str.isdigit() else 0,
1072
+ 'location': location
1073
+ }
1074
+ response = supabase.table('jobs').insert(new_job_data).execute()
1075
+
1076
+ if response.data:
1077
+ flash("New job posted successfully!", "success")
1078
+
1079
+ # Send email notification about the new job
1080
+ email_sent = send_job_email(new_job_data)
1081
+ if email_sent:
1082
+ flash("Job details sent by email successfully.", "info")
1083
+ else:
1084
+ flash("Job posted but email notification failed to send.", "warning")
1085
+ else:
1086
+ print(f"Job insert response structure: {response}")
1087
+ flash("Failed to post job. Please check details and try again.", "danger")
1088
+
1089
+ except Exception as e:
1090
+ print(f"Error posting job: {e}")
1091
+ import traceback;
1092
+ traceback.print_exc()
1093
+ flash(f"An error occurred while posting the job: {e}", "danger")
1094
+
1095
+ return redirect(url_for('jobs')) # Redirect after POST
1096
+
1097
+ # GET request handling
1098
+ jobs_list = []
1099
+ try:
1100
+ response_jobs = supabase.table('jobs').select('*').eq('company_id', company_id).order('posted_date',
1101
+ desc=True).execute()
1102
+ jobs_list = response_jobs.data if response_jobs.data else []
1103
+ except Exception as e:
1104
+ print(f"Error fetching data for jobs page: {e}")
1105
+ flash("Could not load job data.", "warning")
1106
+
1107
+ return render_template('jobs.html', jobs=jobs_list, skills=available_skills, company_name=session['company_name'])
1108
+
1109
+
1110
+ @app.route('/job/<int:job_id>')
1111
+ def job_details(job_id):
1112
+ """Displays details for a specific job and eligible candidates."""
1113
+ if 'company_email' not in session:
1114
+ flash("Please log in to view job details.", "warning")
1115
+ return redirect(url_for('login'))
1116
+ if not supabase:
1117
+ flash("Database service unavailable.", "danger")
1118
+ return render_template('job_details.html', job=None, candidates_full=[], candidates_table=[], company_name=session.get('company_name', 'Company'), error="Database connection failed")
1119
+
1120
+ job_data = None
1121
+ eligible_candidates_list = []
1122
+ candidates_full_list = []
1123
+ company_id = session.get('company_id')
1124
+
1125
+ try:
1126
+ # Fetch the specific job details
1127
+ response_job = supabase.table('jobs').select('*').eq('id', job_id).maybe_single().execute()
1128
+ job_data = response_job.data
1129
+
1130
+ if not job_data:
1131
+ flash("Job not found.", "danger")
1132
+ return redirect(url_for('jobs'))
1133
+
1134
+ if job_data.get('company_id') != company_id:
1135
+ flash("You are not authorized to view details for this job.", "danger")
1136
+ print(f"Unauthorized access attempt to job {job_id} by company {company_id}")
1137
+ return redirect(url_for('jobs'))
1138
+
1139
+ # Find eligible candidates
1140
+ df_students = load_student_data()
1141
+ if not df_students.empty:
1142
+ filters = {'job_id': job_id}
1143
+ eligible_df = filter_students(df_students.copy(), filters)
1144
+
1145
+ # Prepare list for the table view (limited columns)
1146
+ display_cols_table = ['full_name', 'email', 'department', 'cgpa', 'programming_languages', 'projects', 'internships']
1147
+ existing_display_cols_table = [col for col in display_cols_table if col in eligible_df.columns]
1148
+ eligible_candidates_list = eligible_df[existing_display_cols_table].replace({np.nan: None}).to_dict('records') if not eligible_df.empty else []
1149
+
1150
+ # Prepare list with full data for the modal
1151
+ candidates_full_list = eligible_df.replace({np.nan: None}).to_dict('records') if not eligible_df.empty else []
1152
+
1153
+ else:
1154
+ flash("Could not load student data to find eligible candidates.", "warning")
1155
+
1156
+ except Exception as e:
1157
+ print(f"Error fetching job details or candidates for job {job_id}: {e}")
1158
+ import traceback; traceback.print_exc()
1159
+ flash("An error occurred while loading job details or finding candidates.", "danger")
1160
+ if not job_data: return redirect(url_for('jobs'))
1161
+
1162
+ return render_template(
1163
+ 'job_details.html',
1164
+ job=job_data,
1165
+ candidates_full=json.dumps(candidates_full_list), # Pass full data as JSON string for JS
1166
+ candidates_table=eligible_candidates_list, # Data for the HTML table
1167
+ company_name=session.get('company_name', 'Company')
1168
+ )
1169
+
1170
+
1171
+ # --- Error Handlers (Use base.html now) ---
1172
+ @app.errorhandler(404)
1173
+ def page_not_found(e):
1174
+ return render_template('404.html'), 404
1175
+
1176
+ @app.errorhandler(500)
1177
+ def internal_server_error(e):
1178
+ print(f"Server Error: {e}")
1179
+ import traceback
1180
+ traceback.print_exc()
1181
+ return render_template('500.html', error=e), 500
1182
+
1183
+ # --- Context Processor for Year ---
1184
+ @app.context_processor
1185
+ def inject_now():
1186
+ return {'now': datetime.utcnow()}
1187
+
1188
+ # --- Run Application ---
1189
+ if __name__ == '__main__':
1190
+ if not supabase:
1191
+ print("\nWARNING: Supabase client failed to initialize.")
1192
+ print("Application will run but database operations will likely fail.")
1193
+ print("Check your .env file and Supabase project status.\n")
1194
+ port = int(os.environ.get("PORT", 5001))
1195
+ debug_mode = os.environ.get("FLASK_DEBUG", "true").lower() == "true"
1196
+ print(f"Starting Flask app on port {port} with debug mode: {debug_mode}")
1197
+ app.run(debug=debug_mode, port=port, host='0.0.0.0')
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ flask
2
+ pandas
3
+ numpy
4
+ google-generativeai
5
+ supabase-python
6
+ python-dotenv
7
+ plotly
8
+ numpy
static/css/style.css ADDED
@@ -0,0 +1,364 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* ======= Global Styles ======= */
2
+ :root {
3
+ --primary-color: #0d6efd; /* Bootstrap Blue */
4
+ --primary-dark: #0a58ca;
5
+ --secondary-color: #6c757d; /* Bootstrap Gray */
6
+ --success-color: #198754; /* Bootstrap Green */
7
+ --info-color: #0dcaf0; /* Bootstrap Cyan */
8
+ --warning-color: #ffc107; /* Bootstrap Yellow */
9
+ --danger-color: #dc3545; /* Bootstrap Red */
10
+ --light-color: #f8f9fa;
11
+ --dark-color: #212529;
12
+ --border-radius: 0.375rem;
13
+ --box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
14
+ --box-shadow-lg: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
15
+ }
16
+
17
+ body {
18
+ font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
19
+ background-color: #f0f2f5; /* Slightly different background */
20
+ color: #333;
21
+ font-size: 0.95rem; /* Slightly smaller base font */
22
+ }
23
+
24
+ /* ======= Typography ======= */
25
+ h1, h2, h3, h4, h5, h6 {
26
+ font-weight: 600;
27
+ margin-top: 0;
28
+ margin-bottom: 0.75rem;
29
+ color: var(--dark-color);
30
+ }
31
+
32
+ /* ======= Layout Components ======= */
33
+ .main-container {
34
+ padding-top: 1rem;
35
+ padding-bottom: 2rem;
36
+ }
37
+
38
+ .card {
39
+ border-radius: var(--border-radius);
40
+ box-shadow: var(--box-shadow);
41
+ margin-bottom: 1.5rem;
42
+ border: none; /* Remove default border */
43
+ }
44
+
45
+ .card-header {
46
+ background-color: #fff; /* White header */
47
+ border-bottom: 1px solid #e9ecef;
48
+ padding: 0.75rem 1.25rem;
49
+ font-weight: 600;
50
+ }
51
+
52
+ .card-header.bg-primary,
53
+ .card-header.bg-secondary { /* Keep colored headers */
54
+ color: white !important;
55
+ }
56
+ .card-header.bg-primary { background-color: var(--primary-color) !important; }
57
+ .card-header.bg-secondary { background-color: var(--secondary-color) !important; }
58
+
59
+
60
+ .card-body {
61
+ padding: 1.25rem;
62
+ }
63
+
64
+ .card-footer {
65
+ padding: 0.75rem 1.25rem;
66
+ background-color: var(--light-color);
67
+ border-top: 1px solid #e9ecef;
68
+ }
69
+
70
+ /* ======= Navigation ======= */
71
+ .navbar {
72
+ padding-top: 0.6rem;
73
+ padding-bottom: 0.6rem;
74
+ box-shadow: var(--box-shadow);
75
+ }
76
+
77
+ .navbar-brand {
78
+ font-weight: 600;
79
+ font-size: 1.15rem;
80
+ }
81
+
82
+ .nav-link {
83
+ padding: 0.4rem 0.8rem;
84
+ transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
85
+ border-radius: var(--border-radius);
86
+ }
87
+
88
+ .nav-link:hover {
89
+ background-color: rgba(255, 255, 255, 0.1);
90
+ }
91
+
92
+ .nav-link.active {
93
+ font-weight: 600;
94
+ background-color: rgba(255, 255, 255, 0.15);
95
+ }
96
+ .navbar-dark .navbar-nav .nav-link {
97
+ color: rgba(255, 255, 255, 0.85);
98
+ }
99
+ .navbar-dark .navbar-nav .nav-link:hover,
100
+ .navbar-dark .navbar-nav .nav-link:focus {
101
+ color: #fff;
102
+ }
103
+ .navbar-dark .navbar-nav .nav-link.active {
104
+ color: #fff;
105
+ }
106
+
107
+ /* ======= Forms ======= */
108
+ .form-control, .form-select {
109
+ border-radius: var(--border-radius);
110
+ padding: 0.4rem 0.8rem;
111
+ border: 1px solid #ced4da;
112
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
113
+ font-size: 0.9rem;
114
+ }
115
+ .form-control-sm, .form-select-sm {
116
+ padding: 0.3rem 0.6rem;
117
+ font-size: 0.8rem;
118
+ }
119
+
120
+ .form-control:focus, .form-select:focus {
121
+ border-color: var(--primary-dark);
122
+ box-shadow: 0 0 0 0.2rem rgba(var(--bs-primary-rgb), 0.25); /* Use BS variable */
123
+ }
124
+
125
+ .form-label {
126
+ margin-bottom: 0.4rem;
127
+ font-weight: 500;
128
+ font-size: 0.9rem;
129
+ }
130
+
131
+ .form-text {
132
+ color: var(--secondary-color);
133
+ margin-top: 0.25rem;
134
+ font-size: 0.8rem;
135
+ }
136
+ .form-check-label {
137
+ font-size: 0.9rem;
138
+ }
139
+
140
+ /* ======= Login Page ======= */
141
+ .login-container {
142
+ min-height: 100vh;
143
+ display: flex;
144
+ align-items: center;
145
+ justify-content: center;
146
+ background: linear-gradient(to bottom right, var(--primary-color), var(--primary-dark)); /* Gradient background */
147
+ }
148
+
149
+ .login-card {
150
+ width: 100%;
151
+ max-width: 420px; /* Slightly wider */
152
+ box-shadow: var(--box-shadow-lg);
153
+ border-radius: 0.5rem; /* More rounded */
154
+ }
155
+ .login-card .card-header {
156
+ background-color: rgba(255, 255, 255, 0.9); /* Semi-transparent */
157
+ border-bottom: none;
158
+ text-align: center;
159
+ }
160
+ .login-card .card-body {
161
+ padding: 2rem; /* More padding */
162
+ }
163
+
164
+ .demo-credentials {
165
+ background-color: var(--light-color);
166
+ padding: 0.75rem;
167
+ border-radius: var(--border-radius);
168
+ margin-top: 1rem;
169
+ font-size: 0.85rem;
170
+ border: 1px solid #e9ecef;
171
+ }
172
+
173
+ /* ======= Dashboard/Filter Section ======= */
174
+ .filter-section .card-body {
175
+ max-height: calc(100vh - 200px); /* Limit height */
176
+ overflow-y: auto;
177
+ }
178
+ .filter-heading {
179
+ font-weight: 600;
180
+ font-size: 0.85rem;
181
+ margin-bottom: 0.5rem;
182
+ color: var(--secondary-color);
183
+ text-transform: uppercase;
184
+ }
185
+ .filter-group {
186
+ margin-bottom: 1rem;
187
+ padding-bottom: 0.75rem;
188
+ border-bottom: 1px solid #eee;
189
+ }
190
+ .filter-group:last-child {
191
+ border-bottom: none;
192
+ margin-bottom: 0;
193
+ padding-bottom: 0;
194
+ }
195
+
196
+ .filter-section .filter-group {
197
+ padding-bottom: 1rem; /* Ensure consistent padding below groups */
198
+ margin-bottom: 1rem; /* Ensure consistent margin below groups */
199
+ border-bottom: 1px solid #eee; /* Keep visual separation */
200
+ }
201
+ .filter-section .row > div:last-child .filter-group:last-child, /* Target last group in last div of row */
202
+ .filter-section .row > .col-12:last-child .filter-group:last-of-type { /* More specific for last group in last col */
203
+ border-bottom: none; /* Remove border from very last group */
204
+ margin-bottom: 0;
205
+ padding-bottom: 0;
206
+ }
207
+
208
+ /* ======= Tables ======= */
209
+ .table {
210
+ margin-bottom: 0;
211
+ font-size: 0.9rem;
212
+ }
213
+ .table th, .table td {
214
+ vertical-align: middle;
215
+ padding: 0.6rem 0.75rem; /* Adjust padding */
216
+ }
217
+ .table th {
218
+ font-weight: 600;
219
+ border-top: none;
220
+ background-color: #f8f9fa; /* Light header */
221
+ }
222
+ .table-hover tbody tr:hover {
223
+ background-color: rgba(var(--bs-primary-rgb), 0.06);
224
+ }
225
+ .table-responsive {
226
+ border: 1px solid #dee2e6;
227
+ border-radius: var(--border-radius);
228
+ }
229
+
230
+ /* ======= Badges ======= */
231
+ .badge {
232
+ padding: 0.3em 0.55em;
233
+ font-weight: 500;
234
+ border-radius: 0.25rem;
235
+ margin: 0 0.1rem; /* Add slight margin */
236
+ font-size: 0.75em; /* Relative size */
237
+ }
238
+
239
+ /* ======= Visualization Section ======= */
240
+ .visualization-card {
241
+ height: 100%;
242
+ }
243
+ .chart-container {
244
+ position: relative;
245
+ height: 280px; /* Adjust height */
246
+ width: 100%;
247
+ }
248
+ canvas {
249
+ display: block;
250
+ }
251
+
252
+ /* ======= Job Listings ======= */
253
+ .job-card {
254
+ transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
255
+ height: 100%;
256
+ }
257
+ .job-card:hover {
258
+ transform: translateY(-3px);
259
+ box-shadow: var(--box-shadow-lg);
260
+ }
261
+ .job-title {
262
+ font-weight: 600;
263
+ margin-bottom: 0.5rem;
264
+ color: var(--primary-color);
265
+ }
266
+ .job-location {
267
+ color: var(--secondary-color);
268
+ font-size: 0.875rem;
269
+ }
270
+ .job-skills .badge {
271
+ margin-bottom: 0.25rem;
272
+ }
273
+
274
+ /* ======= AI Insights ======= */
275
+ #insights-content {
276
+ white-space: pre-wrap;
277
+ max-height: 450px;
278
+ overflow-y: auto;
279
+ padding: 1rem;
280
+ background-color: white;
281
+ border: 1px solid #dee2e6;
282
+ border-radius: var(--border-radius);
283
+ font-size: 0.9rem;
284
+ line-height: 1.6;
285
+ }
286
+ #insights-content h6 {
287
+ font-size: 1rem;
288
+ margin-top: 1rem;
289
+ margin-bottom: 0.5rem;
290
+ border-bottom: 1px solid #eee;
291
+ padding-bottom: 0.25rem;
292
+ }
293
+ #insights-content ul {
294
+ padding-left: 1.5rem;
295
+ margin-bottom: 1rem;
296
+ }
297
+ #insights-content strong {
298
+ color: var(--primary-dark);
299
+ }
300
+
301
+ /* ======= Button Styles ======= */
302
+ .btn {
303
+ padding: 0.4rem 0.8rem;
304
+ border-radius: var(--border-radius);
305
+ font-weight: 500;
306
+ transition: all 0.2s ease-in-out;
307
+ font-size: 0.9rem;
308
+ display: inline-flex; /* Align icons nicely */
309
+ align-items: center;
310
+ gap: 0.35rem; /* Space between icon and text */
311
+ }
312
+ .btn i {
313
+ margin-right: 0.1rem; /* Adjust if gap isn't used */
314
+ font-size: 1em; /* Make icon size relative to button text */
315
+ }
316
+
317
+ .btn-sm {
318
+ padding: 0.3rem 0.6rem;
319
+ font-size: 0.8rem;
320
+ }
321
+
322
+ /* ======= Modals ======= */
323
+ .modal-header {
324
+ padding: 1rem 1.5rem;
325
+ border-bottom: 1px solid #dee2e6;
326
+ }
327
+ .modal-body {
328
+ padding: 1.5rem;
329
+ }
330
+ .modal-footer {
331
+ padding: 1rem 1.5rem;
332
+ border-top: 1px solid #dee2e6;
333
+ }
334
+
335
+ /* ======= Alerts ======= */
336
+ .alert {
337
+ padding: 0.8rem 1rem;
338
+ margin-bottom: 1rem;
339
+ border-radius: var(--border-radius);
340
+ font-size: 0.9rem;
341
+ }
342
+
343
+ /* ======= Spinner ======= */
344
+ .spinner-border {
345
+ width: 2rem;
346
+ height: 2rem;
347
+ }
348
+
349
+ /* ======= Responsive Adjustments ======= */
350
+ @media (max-width: 992px) { /* Use lg breakpoint */
351
+ .filter-section .card-body {
352
+ max-height: none; /* Remove height limit on smaller screens */
353
+ overflow-y: visible;
354
+ }
355
+ }
356
+ @media (max-width: 768px) {
357
+ body { font-size: 0.9rem; }
358
+ .card-body { padding: 1rem; }
359
+ .navbar-brand { font-size: 1rem; }
360
+ .btn { font-size: 0.85rem; padding: 0.35rem 0.7rem; }
361
+ .table { font-size: 0.85rem; }
362
+ .table th, .table td { padding: 0.5rem 0.6rem; }
363
+ .chart-container { height: 250px; }
364
+ }
students.csv ADDED
@@ -0,0 +1,1316 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ email,password,full_name,department,cgpa,semester_records,backlogs,programming_languages,tools_technologies,certifications,soft_skills,typing_speed,projects,internships,portfolio_links,hackathons,coding_ratings,competitive_exams,detailed_certifications,competitions,publications,patents,preferred_roles,preferred_industry,preferred_location,higher_studies,aptitude_score,mock_interview,english_fluency,personality_type,strengths,weaknesses,faculty_feedback
2
+ pranit.chilbule@example.com,5eccb825edc768e8702618f3c7047f994df24e3f81d51186188f9a787a3cb4ac,Pranit Chilbule,Computer Science and Engineering,9.2,"Sem 1: 8.5
3
+
4
+ Sem 2: 9.0
5
+
6
+ Sem 3: 9.1
7
+
8
+ Sem 4: 9.3
9
+
10
+ Sem 5: 9.4
11
+
12
+ Sem 6: 9.2",0,"Python (Expert), Java (Intermediate), C++ (Intermediate), JavaScript (Beginner)","Docker, Git, AWS, React, Node.js, MongoDB, MySQL, TensorFlow","AWS Certified Developer
13
+
14
+ Google Cloud Associate Engineer
15
+
16
+ Microsoft AI Fundamentals","Communication, Leadership, Teamwork, Time Management",70,,,,,,,,,,,,,,,,,,,, ,
17
+ jillrhodes@miller.com,af738b28e0a93deae4483d186d93ab0ae1300f80dbd1bf73b8b367a58cb3cb4b,Allison Hill,Computer Science and Engineering,6.59,"Sem 1: 7.46
18
+
19
+ Sem 2: 7.28
20
+
21
+ Sem 3: 9.08
22
+
23
+ Sem 4: 8.87
24
+
25
+ Sem 5: 9.62
26
+
27
+ Sem 6: 6.8",1,"Python (Beginner), Ruby (Beginner), Go (Expert)","Git, AWS, React, Node.js, GCP","Google Cloud Associate
28
+
29
+ AWS Certified Developer","Problem-Solving, Leadership",47 WPM,Ago current practice nation determine operation speak according.,Wolfe LLC,https://www.bernard.com/,0.0,LeetCode: 753,None,Here grow gas enough.,2.0,1.0,0.0,Data Scientist,Finance,Bangalore,Yes,74.0,Yes,Medium,ISFJ,"Persistence, Analytical Thinking",Shyness,Role movie win.
30
+ janetwilliams@gmail.com,cdfeaee88ad132f0b2488c09e4ad862ad1b21c30c6fe78eecc1b06dd6ec80315,Juan Calderon,Computer Science and Engineering,9.91,"Sem 1: 7.82
31
+
32
+ Sem 2: 8.43
33
+
34
+ Sem 3: 9.4
35
+
36
+ Sem 4: 8.66
37
+
38
+ Sem 5: 9.52
39
+
40
+ Sem 6: 8.52",2,"Python (Intermediate), Ruby (Beginner), Java (Beginner)","Docker, Node.js, Kubernetes, AWS, MySQL","AWS Certified Developer
41
+
42
+ Google Cloud Associate","Leadership, Communication",47 WPM,Talk term herself law.,Martin-Kelly,https://www.reid.info/,0.0,LeetCode: 2595,GRE,Establish understand read detail food shoulder.,4.0,2.0,0.0,Data Scientist,Research,Chennai,No,90.0,Yes,Low,ISFJ,"Analytical Thinking, Empathy",Perfectionism,Director allow firm environment.
43
+ dianafoster@hotmail.com,abb346954e29a8141c8cb94eddfb8190b61b3051dfa0b4ec95d5e29d93e182d8,Tommy Walter,Electronics and Communication Engineering,7.9,"Sem 1: 6.73
44
+
45
+ Sem 2: 9.7
46
+
47
+ Sem 3: 8.49
48
+
49
+ Sem 4: 9.01
50
+
51
+ Sem 5: 7.24
52
+
53
+ Sem 6: 8.25",2,"JavaScript (Beginner), Java (Beginner), C++ (Expert)","MongoDB, GCP, React, MySQL, AWS","Oracle Java Certification
54
+
55
+ Google Cloud Associate","Leadership, Communication",38 WPM,Cause seat much section investment.,"Ross, Robinson and Bright",https://www.callahan.com/,3.0,LeetCode: 472,GATE,Others his other life edge network.,0.0,0.0,0.0,AI Researcher,IT,Chennai,No,88.0,No,Low,ISFJ,"Analytical Thinking, Persistence",Perfectionism,Quite boy those.
56
+ amoore@hotmail.com,3ba35621a8b4afa459ab7703717f87ac6aeb485d2bf446f0edf6ff01a8189425,Patricia Peterson,Electronics and Communication Engineering,9.19,"Sem 1: 7.69
57
+
58
+ Sem 2: 7.53
59
+
60
+ Sem 3: 7.05
61
+
62
+ Sem 4: 6.51
63
+
64
+ Sem 5: 9.03
65
+
66
+ Sem 6: 9.02",2,"Ruby (Beginner), Java (Expert), C# (Intermediate)","MongoDB, AWS, Docker, Kubernetes, Node.js","Oracle Java Certification
67
+
68
+ AWS Certified Developer","Leadership, Teamwork",31 WPM,Will seven medical blood personal.,"Romero, Gonzalez and Brooks",http://www.nguyen.com/,0.0,LeetCode: 1586,TOEFL,Around there water beat magazine.,1.0,0.0,0.0,Software Developer,IT,Chennai,Yes,98.0,Yes,High,ESFP,"Creativity, Empathy",Shyness,Within mouth call process.
69
+ sarahcampos@hotmail.com,e3198d6aa62a6f5cdfa33a496c69e0eb63025e5dfa19f687b567eca45e45c535,Carmen Rose,Information Technology,9.75,"Sem 1: 9.14
70
+
71
+ Sem 2: 8.91
72
+
73
+ Sem 3: 9.0
74
+
75
+ Sem 4: 7.9
76
+
77
+ Sem 5: 8.85
78
+
79
+ Sem 6: 7.81",2,"JavaScript (Beginner), Python (Beginner), Java (Intermediate)","Git, AWS, GCP, Docker, MongoDB","AWS Certified Developer
80
+
81
+ Oracle Java Certification","Teamwork, Communication",32 WPM,Human public health tonight later.,Walker LLC,http://www.robinson.com/,2.0,LeetCode: 390,GRE,Town teacher audience draw.,2.0,2.0,1.0,Data Scientist,Education,Chennai,Yes,100.0,No,Medium,ENTP,"Analytical Thinking, Empathy",Shyness,Democrat car very number line six space.
82
+ uowens@gmail.com,e8afd9f6742d8cbd469f04cb79a1fdf3f3e96b4039d40c22657a37d745b4da5a,Brent Jordan,Electronics and Communication Engineering,7.98,"Sem 1: 8.13
83
+
84
+ Sem 2: 9.05
85
+
86
+ Sem 3: 8.86
87
+
88
+ Sem 4: 9.94
89
+
90
+ Sem 5: 6.84
91
+
92
+ Sem 6: 7.91",1,"Ruby (Beginner), Python (Beginner), Java (Expert)","MySQL, Kubernetes, AWS, Docker, MongoDB","Google Cloud Associate
93
+
94
+ AWS Certified Developer","Communication, Teamwork",65 WPM,Art rock song body.,Lee Group,http://ramirez.com/,0.0,LeetCode: 307,GATE,Space task better present music address.,0.0,0.0,0.0,AI Researcher,Research,Chennai,Yes,75.0,Yes,High,ESFP,"Analytical Thinking, Creativity",Procrastination,Unit support coach magazine.
95
+ gallowayjoseph@yahoo.com,7b308ffa1ed446a0ed87fe1a06770e0a1c8231fca309d82603740e5e551c63a1,James Brown,Mechanical Engineering,7.5,"Sem 1: 8.94
96
+
97
+ Sem 2: 9.06
98
+
99
+ Sem 3: 9.24
100
+
101
+ Sem 4: 8.82
102
+
103
+ Sem 5: 8.2
104
+
105
+ Sem 6: 7.16",0,"Python (Beginner), C# (Expert), Go (Intermediate)","Git, MongoDB, GCP, AWS, Node.js","Oracle Java Certification
106
+
107
+ AWS Certified Developer","Communication, Leadership",35 WPM,Product main couple design around save article.,Brown-Silva,http://www.miller.com/,1.0,LeetCode: 380,GATE,Build three east organization people information.,5.0,0.0,1.0,Software Developer,Education,Bangalore,Yes,76.0,No,Medium,ENTP,"Persistence, Analytical Thinking",Procrastination,North first end prove fire enter capital population.
108
+ khowell@jones.net,8b124a42d3eeb70314712b3e1cd4bb408059dce0dc3e35c34b552b69d04e9512,Timothy Walls,Mechanical Engineering,6.96,"Sem 1: 8.76
109
+
110
+ Sem 2: 8.1
111
+
112
+ Sem 3: 9.75
113
+
114
+ Sem 4: 9.78
115
+
116
+ Sem 5: 6.53
117
+
118
+ Sem 6: 8.67",2,"Python (Beginner), Ruby (Expert), C# (Intermediate)","Kubernetes, React, Git, Docker, MongoDB","Google Cloud Associate
119
+
120
+ AWS Certified Developer","Problem-Solving, Leadership",49 WPM,Thing these hard citizen street region.,"Riggs, Roman and Rice",https://www.baker.net/,0.0,LeetCode: 2835,TOEFL,Evening painting response data.,5.0,0.0,0.0,System Engineer,IT,Bangalore,Yes,67.0,No,Low,ENTP,"Persistence, Analytical Thinking",Procrastination,Measure economy traditional anything plant.
121
+ evan78@patterson.com,1d2befd06e8cdfcab58bad1e92ab198690b719f637ad0fa3bb3ceb974d7f308c,Amanda Cook,Mechanical Engineering,7.38,"Sem 1: 9.68
122
+
123
+ Sem 2: 6.68
124
+
125
+ Sem 3: 8.72
126
+
127
+ Sem 4: 9.4
128
+
129
+ Sem 5: 6.65
130
+
131
+ Sem 6: 7.67",0,"Go (Expert), C++ (Intermediate), Java (Expert)","Node.js, Git, MySQL, MongoDB, Docker","Oracle Java Certification
132
+
133
+ AWS Certified Developer","Leadership, Problem-Solving",65 WPM,Old challenge camera final together someone.,Nolan and Sons,http://www.deleon-henson.biz/,1.0,LeetCode: 1860,GRE,See understand door class son computer include conference.,0.0,1.0,1.0,Software Developer,Finance,Hyderabad,Yes,92.0,Yes,Medium,ESFP,"Creativity, Analytical Thinking",Impatience,Site in prove same easy city.
134
+ jamessellers@yahoo.com,7f60cf721e511eef5351c189352e0ee5be7f6a533bb83a2ab79ab6e609167674,Janet Williams,Information Technology,9.58,"Sem 1: 6.59
135
+
136
+ Sem 2: 9.08
137
+
138
+ Sem 3: 7.66
139
+
140
+ Sem 4: 9.76
141
+
142
+ Sem 5: 9.31
143
+
144
+ Sem 6: 9.52",0,"C++ (Intermediate), Java (Beginner), Python (Intermediate)","AWS, MongoDB, Node.js, MySQL, Kubernetes","Google Cloud Associate
145
+
146
+ AWS Certified Developer","Teamwork, Communication",42 WPM,Development process huge everything attorney.,Bell-Hicks,https://www.wiley.com/,3.0,LeetCode: 1444,TOEFL,While enter board its rock finish paper memory.,0.0,1.0,1.0,AI Researcher,Finance,Bangalore,Yes,66.0,Yes,Low,ISFJ,"Analytical Thinking, Empathy",Shyness,Tonight couple and job mind southern.
147
+ ryan59@alvarado-martinez.com,cbe87f8efe32c9cbf55a062d264727891280c501822e38ad9494585c7c7cb228,Teresa Mclaughlin,Electronics and Communication Engineering,9.05,"Sem 1: 7.6
148
+
149
+ Sem 2: 8.62
150
+
151
+ Sem 3: 8.29
152
+
153
+ Sem 4: 7.85
154
+
155
+ Sem 5: 8.52
156
+
157
+ Sem 6: 7.39",2,"JavaScript (Expert), Python (Expert), C# (Expert)","AWS, React, MongoDB, Git, Kubernetes","Oracle Java Certification
158
+
159
+ Google Cloud Associate","Communication, Leadership",49 WPM,For recent never court professor here.,"Orr, Gilbert and Turner",http://clark-floyd.org/,2.0,LeetCode: 2831,None,Let kind degree list top somebody.,2.0,1.0,1.0,Data Scientist,Education,Chennai,No,93.0,Yes,Low,ISFJ,"Empathy, Persistence",Perfectionism,Probably exist professional people.
160
+ lindsayhernandez@gmail.com,0764349837af5adb7f6fa800b376f8e2ca7728e21d8834d1453d5c6d7cb1c1a6,Trevor Young,Electronics and Communication Engineering,7.5,"Sem 1: 8.0
161
+
162
+ Sem 2: 8.53
163
+
164
+ Sem 3: 8.79
165
+
166
+ Sem 4: 8.13
167
+
168
+ Sem 5: 8.05
169
+
170
+ Sem 6: 7.25",1,"Ruby (Expert), Go (Beginner), Java (Intermediate)","MongoDB, React, Git, Docker, Kubernetes","AWS Certified Developer
171
+
172
+ Oracle Java Certification","Teamwork, Communication",32 WPM,Particularly shoulder lay though offer responsibility himself.,Sanchez-Douglas,http://www.robinson-brock.net/,1.0,LeetCode: 2046,GATE,Anyone eat summer lead soon property write.,3.0,1.0,0.0,AI Researcher,Research,Chennai,Yes,59.0,Yes,High,ESFP,"Creativity, Analytical Thinking",Shyness,Fish sense kind spring throughout interview trade knowledge.
173
+ katie87@allen.com,e7c152f3f5b21b0cf642ded735cf7ce8a99da8e54f2a8a495641c850c2c63610,Scott Cole,Computer Science and Engineering,8.45,"Sem 1: 9.71
174
+
175
+ Sem 2: 6.92
176
+
177
+ Sem 3: 6.97
178
+
179
+ Sem 4: 8.13
180
+
181
+ Sem 5: 8.36
182
+
183
+ Sem 6: 8.46",1,"Ruby (Expert), JavaScript (Expert), C# (Intermediate)","MongoDB, MySQL, Docker, React, AWS","Google Cloud Associate
184
+
185
+ Oracle Java Certification","Teamwork, Leadership",47 WPM,Throw ball character him check degree.,Russell-Daniels,https://www.wall.org/,3.0,LeetCode: 2667,GRE,Task she herself.,2.0,1.0,0.0,System Engineer,Education,Pune,No,70.0,Yes,High,ENTP,"Creativity, Empathy",Impatience,Wall fear hope.
186
+ brobinson@johnson-rogers.biz,eb09451244f742eb9e9105ed978643bbc39ed50a7e95bdb0c69a1245e95748ba,Sara Medina,Information Technology,6.72,"Sem 1: 7.93
187
+
188
+ Sem 2: 8.4
189
+
190
+ Sem 3: 7.96
191
+
192
+ Sem 4: 7.22
193
+
194
+ Sem 5: 7.97
195
+
196
+ Sem 6: 9.67",2,"Go (Intermediate), Python (Intermediate), C# (Beginner)","React, GCP, Node.js, AWS, MongoDB","Oracle Java Certification
197
+
198
+ AWS Certified Developer","Problem-Solving, Communication",47 WPM,Try wonder move trade option production base.,Taylor-Murray,http://murphy-gibson.com/,3.0,LeetCode: 2089,GATE,Everything week instead strong like see.,3.0,1.0,1.0,Data Scientist,Research,Hyderabad,Yes,75.0,Yes,High,ESFP,"Creativity, Empathy",Impatience,Yourself glass practice.
199
+ maryhowell@martinez.com,c1750f794cfd4331404689b4e3bfbf535a28bd6727abf160ef0500b0e2ccee53,Marissa Webster,Computer Science and Engineering,7.41,"Sem 1: 7.65
200
+
201
+ Sem 2: 8.09
202
+
203
+ Sem 3: 7.68
204
+
205
+ Sem 4: 9.58
206
+
207
+ Sem 5: 7.47
208
+
209
+ Sem 6: 9.83",1,"C++ (Beginner), Python (Expert), JavaScript (Expert)","Git, React, Docker, MySQL, MongoDB","Oracle Java Certification
210
+
211
+ AWS Certified Developer","Communication, Problem-Solving",42 WPM,Let eight hard paper white.,"Wilson, Weiss and Oconnell",http://www.johnston-odonnell.biz/,0.0,LeetCode: 2644,GRE,Walk cup option store drug recent.,1.0,0.0,1.0,Software Developer,Education,Chennai,No,99.0,No,High,INTJ,"Creativity, Empathy",Perfectionism,Sure outside building worker site.
212
+ atkinsonlynn@gmail.com,6004a866b561f50b4e7bb207f0d5bbd71727dbff8d9716ef7df8c46ba88c9469,Jeffrey Wood,Computer Science and Engineering,9.75,"Sem 1: 8.52
213
+
214
+ Sem 2: 9.68
215
+
216
+ Sem 3: 7.81
217
+
218
+ Sem 4: 9.8
219
+
220
+ Sem 5: 7.19
221
+
222
+ Sem 6: 8.57",2,"Java (Expert), Python (Expert), C++ (Beginner)","Git, React, GCP, AWS, Kubernetes","AWS Certified Developer
223
+
224
+ Google Cloud Associate","Communication, Teamwork",61 WPM,Player stock religious itself safe whole.,Gilbert-Gillespie,https://petersen-vargas.com/,0.0,LeetCode: 1875,TOEFL,Store beautiful think during let.,5.0,1.0,0.0,AI Researcher,Education,Pune,No,79.0,No,Low,ISFJ,"Persistence, Analytical Thinking",Perfectionism,Property from management foot maintain great election evidence.
225
+ allenrichard@chang.info,036a80ebc72d5fe8a411d0c8b47e6927b900115a2ac56d2ef22f7ec5757b245a,Sheryl Peters,Electronics and Communication Engineering,9.59,"Sem 1: 7.35
226
+
227
+ Sem 2: 8.13
228
+
229
+ Sem 3: 8.64
230
+
231
+ Sem 4: 7.83
232
+
233
+ Sem 5: 6.6
234
+
235
+ Sem 6: 9.48",0,"JavaScript (Intermediate), Java (Intermediate), C++ (Intermediate)","GCP, Git, MongoDB, Docker, MySQL","AWS Certified Developer
236
+
237
+ Google Cloud Associate","Problem-Solving, Leadership",45 WPM,Behavior develop reality.,Beck-Wood,https://pierce.com/,3.0,LeetCode: 2745,None,Discover return firm sea week.,3.0,0.0,0.0,System Engineer,Education,Chennai,Yes,69.0,No,Medium,ISFJ,"Empathy, Persistence",Procrastination,Course school everybody operation.
238
+ jeremy24@erickson.com,7b3643054ba803a56c0b0f5ca25db9192d884965688e4ff5de04960eede9f144,Linda Hooper,Electronics and Communication Engineering,8.96,"Sem 1: 7.45
239
+
240
+ Sem 2: 7.38
241
+
242
+ Sem 3: 6.92
243
+
244
+ Sem 4: 7.17
245
+
246
+ Sem 5: 6.92
247
+
248
+ Sem 6: 8.38",2,"Java (Expert), Ruby (Intermediate), Go (Intermediate)","MongoDB, GCP, Git, Docker, Kubernetes","AWS Certified Developer
249
+
250
+ Google Cloud Associate","Teamwork, Problem-Solving",30 WPM,Network recently call.,Garcia-Smith,https://alexander-lopez.com/,1.0,LeetCode: 1223,GATE,Wait local state husband available.,0.0,2.0,1.0,Data Scientist,Research,Bangalore,Yes,86.0,No,Medium,ESFP,"Empathy, Creativity",Impatience,Rather charge specific we be easy newspaper indicate.
251
+ tkerr@hotmail.com,89d53b7c08a9e4647d314edf073f68f7bd257329609a71759cd9a5994fb48986,Lisa Rowe,Computer Science and Engineering,7.38,"Sem 1: 9.52
252
+
253
+ Sem 2: 6.9
254
+
255
+ Sem 3: 6.73
256
+
257
+ Sem 4: 8.22
258
+
259
+ Sem 5: 8.52
260
+
261
+ Sem 6: 8.9",0,"Java (Beginner), C# (Beginner), C++ (Beginner)","MongoDB, Node.js, GCP, MySQL, React","AWS Certified Developer
262
+
263
+ Google Cloud Associate","Problem-Solving, Teamwork",49 WPM,Notice art whether between several.,"Clark, Guerrero and Moore",http://www.smith.org/,3.0,LeetCode: 1350,GATE,Fact discuss religious reflect law reach under.,4.0,2.0,0.0,Data Scientist,Education,Pune,Yes,60.0,Yes,High,INTJ,"Creativity, Analytical Thinking",Shyness,Operation sound cup boy different chance enter central.
264
+ smartinez@yahoo.com,20ec3ecd328fc168a19f4f23112e037945b50254dccd306ad08ec88950fc686b,Ricky Larson,Mechanical Engineering,8.91,"Sem 1: 8.14
265
+
266
+ Sem 2: 6.61
267
+
268
+ Sem 3: 7.51
269
+
270
+ Sem 4: 7.49
271
+
272
+ Sem 5: 9.51
273
+
274
+ Sem 6: 6.75",0,"C++ (Expert), Go (Beginner), C# (Intermediate)","Docker, AWS, React, MongoDB, Kubernetes","AWS Certified Developer
275
+
276
+ Oracle Java Certification","Communication, Problem-Solving",49 WPM,Matter management ball always it.,Munoz-Johnson,http://www.underwood.com/,2.0,LeetCode: 1898,GATE,Million kind everything young job sport why.,3.0,2.0,1.0,AI Researcher,Finance,Chennai,No,55.0,Yes,Medium,ISFJ,"Persistence, Analytical Thinking",Perfectionism,Girl four prove tax form really explain.
277
+ edwardsmarcus@yahoo.com,3eff41ce850c8072eda343c62273462a658bcc33af0dd8b7800e10bb70906072,Robin Pierce,Information Technology,9.87,"Sem 1: 9.43
278
+
279
+ Sem 2: 8.51
280
+
281
+ Sem 3: 9.83
282
+
283
+ Sem 4: 10.0
284
+
285
+ Sem 5: 8.85
286
+
287
+ Sem 6: 7.44",0,"Ruby (Expert), Java (Expert), JavaScript (Intermediate)","GCP, Kubernetes, MongoDB, AWS, React","AWS Certified Developer
288
+
289
+ Google Cloud Associate","Leadership, Teamwork",51 WPM,Price my including.,Stone PLC,https://harris.com/,2.0,LeetCode: 2844,GATE,Just recognize building win participant.,1.0,1.0,1.0,AI Researcher,Finance,Chennai,Yes,79.0,Yes,Medium,ISFJ,"Persistence, Analytical Thinking",Shyness,Report financial add impact different.
290
+ scantu@thornton.info,2fed9bbb717ad2b2fcdd17a4841291513fcc7f4cc724d2b7122f8b3206e6f0be,Ashley Valentine,Computer Science and Engineering,8.8,"Sem 1: 8.4
291
+
292
+ Sem 2: 7.95
293
+
294
+ Sem 3: 7.16
295
+
296
+ Sem 4: 7.77
297
+
298
+ Sem 5: 9.15
299
+
300
+ Sem 6: 8.69",0,"Java (Beginner), C++ (Intermediate), C# (Intermediate)","MySQL, Docker, Git, React, GCP","AWS Certified Developer
301
+
302
+ Oracle Java Certification","Leadership, Problem-Solving",30 WPM,Certain course out second carry attorney significant.,Morgan-French,https://www.barber-monroe.org/,3.0,LeetCode: 481,GRE,Tend land machine forward several help usually.,0.0,1.0,0.0,Data Scientist,Research,Pune,No,76.0,No,Medium,ENTP,"Empathy, Persistence",Impatience,Wonder draw him task improve.
303
+ ymcneil@hotmail.com,a58290097f5067812a6168ba609dd1d3273ad0afd99a165b04e9d2eccb3efdc9,John Mcintyre,Mechanical Engineering,7.17,"Sem 1: 8.6
304
+
305
+ Sem 2: 9.11
306
+
307
+ Sem 3: 6.98
308
+
309
+ Sem 4: 6.74
310
+
311
+ Sem 5: 9.2
312
+
313
+ Sem 6: 9.49",1,"Ruby (Beginner), C# (Intermediate), C++ (Expert)","GCP, MySQL, Node.js, Docker, AWS","Oracle Java Certification
314
+
315
+ Google Cloud Associate","Leadership, Teamwork",65 WPM,Who call whole forward beyond suddenly between.,Smith-Thomas,http://www.harrington-baker.org/,3.0,LeetCode: 1965,TOEFL,Power system system teacher here first.,1.0,2.0,0.0,AI Researcher,Education,Chennai,Yes,70.0,No,Low,ESFP,"Empathy, Persistence",Impatience,Their along attention piece TV young section.
316
+ tjackson@williams.com,8def98a6abbdab0199fa812c7bf02ffc8a4c052178b1ffcada8c924115990337,Brett Schultz,Mechanical Engineering,9.88,"Sem 1: 6.94
317
+
318
+ Sem 2: 9.88
319
+
320
+ Sem 3: 7.66
321
+
322
+ Sem 4: 6.85
323
+
324
+ Sem 5: 9.46
325
+
326
+ Sem 6: 6.85",1,"Python (Intermediate), Go (Expert), Java (Beginner)","Docker, MySQL, Node.js, Kubernetes, React","Oracle Java Certification
327
+
328
+ Google Cloud Associate","Communication, Teamwork",64 WPM,Certainly most not society color bad.,Harvey-Allen,http://www.little-stevens.com/,3.0,LeetCode: 1397,None,Top quality citizen kid generation onto police.,4.0,0.0,0.0,Data Scientist,Finance,Hyderabad,Yes,77.0,Yes,Low,INTJ,"Empathy, Analytical Thinking",Procrastination,Real lead few yourself table blood.
329
+ spencedominique@yahoo.com,e9efb46293d2710e363c4552d8a85551f4146852adb291103a9f1d37ef7980f5,Ian Phillips,Computer Science and Engineering,6.66,"Sem 1: 9.29
330
+
331
+ Sem 2: 7.53
332
+
333
+ Sem 3: 7.81
334
+
335
+ Sem 4: 7.01
336
+
337
+ Sem 5: 8.36
338
+
339
+ Sem 6: 8.48",0,"Java (Expert), Ruby (Intermediate), Python (Expert)","AWS, MySQL, GCP, Docker, React","Google Cloud Associate
340
+
341
+ Oracle Java Certification","Problem-Solving, Teamwork",30 WPM,Treat seat strategy.,Parsons-Hall,https://www.lee.com/,3.0,LeetCode: 1278,GRE,Best physical always small almost half capital travel.,0.0,1.0,1.0,System Engineer,Research,Pune,No,69.0,Yes,Medium,ESFP,"Analytical Thinking, Empathy",Shyness,Section compare car much will most.
342
+ julie51@yahoo.com,b2f8deb6bb969668fbdfc8f3364852aa0924c93e1b3698d0e8f67345d690f5cf,Sandra Scott,Electronics and Communication Engineering,8.51,"Sem 1: 9.97
343
+
344
+ Sem 2: 7.53
345
+
346
+ Sem 3: 9.92
347
+
348
+ Sem 4: 8.8
349
+
350
+ Sem 5: 7.46
351
+
352
+ Sem 6: 8.48",2,"Ruby (Expert), Go (Expert), Python (Intermediate)","GCP, AWS, MongoDB, Kubernetes, Docker","Oracle Java Certification
353
+
354
+ AWS Certified Developer","Leadership, Problem-Solving",38 WPM,Senior difficult put purpose.,Coffey-Ballard,https://www.smith-herrera.info/,0.0,LeetCode: 2670,GATE,Pull public once state wait board.,2.0,1.0,0.0,System Engineer,Education,Bangalore,No,70.0,No,High,ENTP,"Creativity, Persistence",Procrastination,Likely people wall foreign particular.
355
+ cwilson@gmail.com,47e707b039ca66c11f453b03ab7669a83292e4326b9208d4d0cbfedd3f5b8125,Madison Marshall,Electronics and Communication Engineering,9.41,"Sem 1: 7.4
356
+
357
+ Sem 2: 9.39
358
+
359
+ Sem 3: 8.19
360
+
361
+ Sem 4: 9.32
362
+
363
+ Sem 5: 9.11
364
+
365
+ Sem 6: 7.69",0,"JavaScript (Beginner), Python (Expert), Java (Expert)","Node.js, React, Git, AWS, MongoDB","Google Cloud Associate
366
+
367
+ AWS Certified Developer","Problem-Solving, Teamwork",46 WPM,Break doctor Mr home he we recent.,"Barnes, Newton and Moore",https://www.gilbert-crosby.com/,3.0,LeetCode: 2715,TOEFL,Real describe know.,0.0,2.0,0.0,AI Researcher,IT,Pune,Yes,91.0,Yes,Low,ESFP,"Persistence, Empathy",Shyness,Talk between rate name within.
368
+ ndavis@fowler.com,4ecbc040643a6a382ec7098e4300a5011509b65c71916da02fcb47d9f0810d2d,James Lopez,Computer Science and Engineering,6.99,"Sem 1: 9.81
369
+
370
+ Sem 2: 7.57
371
+
372
+ Sem 3: 8.22
373
+
374
+ Sem 4: 6.84
375
+
376
+ Sem 5: 9.61
377
+
378
+ Sem 6: 6.97",1,"C++ (Intermediate), Go (Expert), C# (Expert)","Kubernetes, Node.js, React, Git, AWS","Oracle Java Certification
379
+
380
+ Google Cloud Associate","Leadership, Communication",53 WPM,Skin day stop never.,"Robinson, Kane and Murphy",http://www.garrison-thomas.com/,1.0,LeetCode: 1916,None,Economy company produce ago address so draw.,1.0,1.0,0.0,System Engineer,Finance,Bangalore,No,67.0,Yes,High,ESFP,"Analytical Thinking, Persistence",Impatience,Administration enter camera inside box as.
381
+ soniawilliams@hotmail.com,56bac80050c404a1944f07c6217a1e7352a7ac9c217a1a621675636ce0218836,Ivan Wheeler,Computer Science and Engineering,6.68,"Sem 1: 7.67
382
+
383
+ Sem 2: 9.96
384
+
385
+ Sem 3: 9.25
386
+
387
+ Sem 4: 7.22
388
+
389
+ Sem 5: 9.4
390
+
391
+ Sem 6: 8.44",2,"Java (Beginner), Ruby (Expert), C++ (Beginner)","GCP, Kubernetes, Docker, MongoDB, MySQL","AWS Certified Developer
392
+
393
+ Oracle Java Certification","Communication, Problem-Solving",30 WPM,Poor all your suggest international blue Republican.,Jones-Miller,http://www.hill.org/,2.0,LeetCode: 1074,TOEFL,Republican herself our far measure involve soldier.,0.0,0.0,1.0,Software Developer,Education,Chennai,Yes,97.0,Yes,Medium,ESFP,"Persistence, Empathy",Perfectionism,Table prepare shoulder result.
394
+ uross@gmail.com,38194021fce0308395c68a3b1c38fff5b94e40b33f74c5d2c775bf790b6821bf,Jesse Perez,Mechanical Engineering,8.26,"Sem 1: 9.81
395
+
396
+ Sem 2: 6.65
397
+
398
+ Sem 3: 9.24
399
+
400
+ Sem 4: 9.53
401
+
402
+ Sem 5: 8.33
403
+
404
+ Sem 6: 8.1",0,"Python (Intermediate), JavaScript (Expert), Go (Beginner)","MySQL, MongoDB, Git, Node.js, Kubernetes","Oracle Java Certification
405
+
406
+ AWS Certified Developer","Communication, Problem-Solving",47 WPM,Professor hear check type attack story.,Reynolds Ltd,https://www.brown.com/,2.0,LeetCode: 1660,TOEFL,Government program seek test return why.,3.0,2.0,1.0,Software Developer,IT,Hyderabad,No,78.0,Yes,Medium,ISFJ,"Empathy, Creativity",Shyness,Fine billion medical choice lot suggest glass news.
407
+ lynchdiane@hotmail.com,aef4cf6b6228c34a0e24f45d02b3d9d9b320e64b6a27019787aa25c9b0fb55b0,Donald Perez,Computer Science and Engineering,7.59,"Sem 1: 7.59
408
+
409
+ Sem 2: 7.39
410
+
411
+ Sem 3: 9.84
412
+
413
+ Sem 4: 8.9
414
+
415
+ Sem 5: 8.16
416
+
417
+ Sem 6: 6.82",0,"Python (Expert), JavaScript (Expert), Ruby (Intermediate)","Kubernetes, Git, GCP, Node.js, React","Google Cloud Associate
418
+
419
+ AWS Certified Developer","Problem-Solving, Teamwork",57 WPM,Event several TV go.,Kane PLC,https://www.figueroa.com/,0.0,LeetCode: 1278,TOEFL,Democrat information game have return since nothing.,2.0,0.0,0.0,Data Scientist,Research,Hyderabad,Yes,72.0,No,High,ISFJ,"Creativity, Empathy",Perfectionism,Third choose senior anyone.
420
+ wnelson@hotmail.com,70544bee5e638d035f39d0d0eb7bf96367b57f5e24261b8092c8bc4517999118,Jeremy Coleman,Electronics and Communication Engineering,6.6,"Sem 1: 7.46
421
+
422
+ Sem 2: 9.17
423
+
424
+ Sem 3: 9.73
425
+
426
+ Sem 4: 7.73
427
+
428
+ Sem 5: 7.13
429
+
430
+ Sem 6: 7.0",2,"JavaScript (Expert), Python (Expert), Java (Beginner)","Docker, AWS, MySQL, Node.js, React","Google Cloud Associate
431
+
432
+ AWS Certified Developer","Leadership, Teamwork",50 WPM,Book question or money final determine.,"Brown, Harris and Dougherty",http://murphy-smith.biz/,0.0,LeetCode: 315,GRE,Can mouth discover next.,1.0,2.0,0.0,Software Developer,Finance,Chennai,No,81.0,No,Medium,ISFJ,"Creativity, Persistence",Perfectionism,Author technology amount affect TV television.
433
+ darius05@gmail.com,d3bf3444caea8d869fcfdf779d2d4ce0aff0e73d7a25b58bf3909d52f822852e,Laura Mckinney,Electronics and Communication Engineering,8.0,"Sem 1: 7.49
434
+
435
+ Sem 2: 8.87
436
+
437
+ Sem 3: 8.2
438
+
439
+ Sem 4: 8.83
440
+
441
+ Sem 5: 6.66
442
+
443
+ Sem 6: 7.88",2,"Python (Intermediate), Ruby (Beginner), Java (Beginner)","GCP, MongoDB, Kubernetes, Git, React","Google Cloud Associate
444
+
445
+ Oracle Java Certification","Teamwork, Communication",54 WPM,Least ready gun join black job hundred bad.,Reese-Walker,http://www.schultz.com/,1.0,LeetCode: 2149,TOEFL,Road standard spring door chair culture.,0.0,1.0,0.0,AI Researcher,IT,Chennai,Yes,70.0,No,Low,ESFP,"Empathy, Creativity",Perfectionism,Check service away week physical less nor often.
446
+ edward17@yahoo.com,f7db3801e31dc141e04bd6d3b7b79ab5e3b653a1b653b6e4178b4cf3aa1679b4,Sonia Day,Mechanical Engineering,6.57,"Sem 1: 7.64
447
+
448
+ Sem 2: 9.3
449
+
450
+ Sem 3: 8.66
451
+
452
+ Sem 4: 9.41
453
+
454
+ Sem 5: 9.72
455
+
456
+ Sem 6: 6.81",0,"Java (Intermediate), JavaScript (Expert), C# (Beginner)","Node.js, GCP, React, Kubernetes, Docker","Google Cloud Associate
457
+
458
+ AWS Certified Developer","Communication, Leadership",70 WPM,Option goal avoid left also.,Decker-Jones,http://carpenter-best.com/,0.0,LeetCode: 2273,GRE,Training occur could painting may whatever late.,2.0,1.0,0.0,Data Scientist,IT,Hyderabad,No,62.0,Yes,Low,ENTP,"Analytical Thinking, Empathy",Shyness,Word base position always remain yard.
459
+ vortiz@hotmail.com,aa7c17f25d23948083b96211859e6dd044f884139df13c23dfe28fbedc92828e,Lisa Cox,Mechanical Engineering,9.14,"Sem 1: 9.16
460
+
461
+ Sem 2: 8.07
462
+
463
+ Sem 3: 9.73
464
+
465
+ Sem 4: 8.48
466
+
467
+ Sem 5: 8.72
468
+
469
+ Sem 6: 8.69",2,"C++ (Beginner), Java (Intermediate), JavaScript (Intermediate)","GCP, MongoDB, MySQL, Git, Kubernetes","Oracle Java Certification
470
+
471
+ AWS Certified Developer","Leadership, Teamwork",58 WPM,Positive at behind question exist rich prevent trade.,Cook PLC,http://ponce-hale.biz/,0.0,LeetCode: 333,TOEFL,Organization visit finally heavy.,2.0,0.0,0.0,AI Researcher,Research,Bangalore,No,86.0,Yes,Medium,ESFP,"Creativity, Analytical Thinking",Shyness,Spend prove stock school rate money.
472
+ henry35@yahoo.com,56e72a8119a84d8ee703f3e014af3e2d5cab70a46dd1059332176b3fb6d15c59,Jessica Cox,Computer Science and Engineering,9.34,"Sem 1: 9.43
473
+
474
+ Sem 2: 9.94
475
+
476
+ Sem 3: 6.8
477
+
478
+ Sem 4: 8.76
479
+
480
+ Sem 5: 6.64
481
+
482
+ Sem 6: 8.98",1,"C# (Beginner), Ruby (Intermediate), Go (Intermediate)","GCP, Node.js, AWS, Kubernetes, MongoDB","AWS Certified Developer
483
+
484
+ Google Cloud Associate","Communication, Teamwork",36 WPM,Choice fast small medical.,"Conley, Stephenson and Johnson",https://www.bennett.org/,3.0,LeetCode: 1263,TOEFL,Return analysis hair rest.,5.0,2.0,0.0,System Engineer,IT,Hyderabad,No,69.0,No,High,INTJ,"Persistence, Empathy",Shyness,Particular sell six doctor dream whole.
485
+ xhammond@yahoo.com,221356491746203cb305d390ea47dccaab3b304f1a76b9d860655b3ba1a94def,Stephanie Lee,Electronics and Communication Engineering,9.35,"Sem 1: 8.85
486
+
487
+ Sem 2: 9.4
488
+
489
+ Sem 3: 9.09
490
+
491
+ Sem 4: 8.9
492
+
493
+ Sem 5: 8.34
494
+
495
+ Sem 6: 8.76",1,"C# (Intermediate), C++ (Intermediate), Python (Beginner)","AWS, React, Node.js, MongoDB, Docker","AWS Certified Developer
496
+
497
+ Oracle Java Certification","Teamwork, Communication",48 WPM,Whom stage soon catch economic political.,Spencer-Garcia,http://hines.info/,0.0,LeetCode: 2179,GATE,Challenge join watch develop later glass ago.,5.0,1.0,0.0,AI Researcher,Education,Hyderabad,Yes,94.0,Yes,Low,ESFP,"Analytical Thinking, Creativity",Procrastination,How hear history.
498
+ lacey20@lowery-kennedy.com,bf1be9868e36ca698f76c50aaebfddb51e5148d7efcd3b75a71c568ebae1d54e,Danny Flores,Information Technology,9.89,"Sem 1: 8.64
499
+
500
+ Sem 2: 9.13
501
+
502
+ Sem 3: 9.24
503
+
504
+ Sem 4: 7.32
505
+
506
+ Sem 5: 7.34
507
+
508
+ Sem 6: 9.88",1,"Ruby (Expert), Java (Expert), C++ (Intermediate)","MySQL, GCP, Node.js, AWS, MongoDB","Oracle Java Certification
509
+
510
+ Google Cloud Associate","Teamwork, Communication",68 WPM,Large accept bad eight strong nature road.,"Henderson, Parsons and Young",http://www.barnes.info/,1.0,LeetCode: 1124,GATE,Book toward others administration.,5.0,1.0,1.0,Software Developer,IT,Pune,Yes,98.0,Yes,Medium,ESFP,"Creativity, Empathy",Perfectionism,Offer responsibility fact ability good number cost.
511
+ cmarks@hughes.com,69e02d5b6ffd5af1e251574d723596bf1921b95e6e0f5ab247d473a8f8f3af19,Kelly Ward,Information Technology,9.36,"Sem 1: 9.6
512
+
513
+ Sem 2: 9.76
514
+
515
+ Sem 3: 7.95
516
+
517
+ Sem 4: 7.89
518
+
519
+ Sem 5: 7.81
520
+
521
+ Sem 6: 7.85",0,"C++ (Intermediate), Java (Beginner), Python (Expert)","React, Kubernetes, Docker, Git, MySQL","Google Cloud Associate
522
+
523
+ AWS Certified Developer","Problem-Solving, Teamwork",69 WPM,Drop price billion old series card.,Payne-Li,http://mendoza.info/,0.0,LeetCode: 424,GATE,Fall analysis current.,2.0,0.0,0.0,AI Researcher,IT,Pune,Yes,69.0,Yes,High,ENTP,"Empathy, Persistence",Shyness,Firm financial huge.
524
+ michael05@martinez-richardson.biz,372711d6646e3cedd5706b39c52780c499a37abb65e9e322f6158e54fd3efea4,Kara Johnson,Computer Science and Engineering,6.89,"Sem 1: 9.67
525
+
526
+ Sem 2: 8.59
527
+
528
+ Sem 3: 6.56
529
+
530
+ Sem 4: 8.3
531
+
532
+ Sem 5: 7.35
533
+
534
+ Sem 6: 7.0",1,"Python (Beginner), C# (Expert), C++ (Intermediate)","Kubernetes, Docker, GCP, MongoDB, Git","Oracle Java Certification
535
+
536
+ AWS Certified Developer","Problem-Solving, Teamwork",32 WPM,Fund cost reality happen something entire.,Acosta Inc,https://www.carter.com/,3.0,LeetCode: 1629,TOEFL,Knowledge response coach know language.,5.0,0.0,1.0,Software Developer,Finance,Hyderabad,Yes,99.0,No,High,INTJ,"Persistence, Empathy",Procrastination,Past itself police social arm provide.
537
+ thomascathy@johnson-jones.com,18091453e151613cb3736a7aa601b5e805479a48b1bd910b92bd7c2501963db1,Jose Brady,Information Technology,9.41,"Sem 1: 8.9
538
+
539
+ Sem 2: 9.93
540
+
541
+ Sem 3: 8.17
542
+
543
+ Sem 4: 7.14
544
+
545
+ Sem 5: 6.97
546
+
547
+ Sem 6: 9.01",1,"Python (Beginner), C++ (Beginner), Java (Beginner)","React, GCP, MySQL, AWS, Node.js","Google Cloud Associate
548
+
549
+ Oracle Java Certification","Communication, Leadership",42 WPM,Allow check last he know baby case.,Sanders-Banks,http://www.fitzgerald.net/,2.0,LeetCode: 1562,GATE,Trial brother simple region Democrat partner.,5.0,1.0,1.0,Software Developer,Finance,Chennai,No,97.0,No,Medium,ISFJ,"Creativity, Empathy",Shyness,Customer career available common require young specific.
550
+ patricia22@hicks-martinez.com,002d519f44238c5132b4012b02b65cb0c00b4beb5fa4b2b6632a96b4626521e4,Victoria Contreras,Electronics and Communication Engineering,9.74,"Sem 1: 8.32
551
+
552
+ Sem 2: 9.3
553
+
554
+ Sem 3: 9.04
555
+
556
+ Sem 4: 6.78
557
+
558
+ Sem 5: 8.61
559
+
560
+ Sem 6: 9.38",2,"C++ (Beginner), Ruby (Intermediate), Python (Expert)","GCP, MongoDB, AWS, MySQL, Node.js","AWS Certified Developer
561
+
562
+ Google Cloud Associate","Leadership, Teamwork",32 WPM,So ago network hard sound.,"Anderson, Henson and Jones",https://jenkins.com/,2.0,LeetCode: 2618,None,Politics last quite general there sister.,2.0,2.0,0.0,Software Developer,Research,Pune,Yes,51.0,Yes,Low,ESFP,"Analytical Thinking, Empathy",Perfectionism,Consider whom item treat area buy check clearly.
563
+ kingcynthia@hotmail.com,cbc76f1468ed01edd05bdc3e6453ffd28acb1c481e23c660602f85c490cab343,Michael Reed,Information Technology,9.22,"Sem 1: 7.78
564
+
565
+ Sem 2: 7.84
566
+
567
+ Sem 3: 8.49
568
+
569
+ Sem 4: 8.62
570
+
571
+ Sem 5: 8.88
572
+
573
+ Sem 6: 9.82",1,"JavaScript (Beginner), Python (Expert), C# (Intermediate)","Node.js, React, MySQL, Kubernetes, Docker","AWS Certified Developer
574
+
575
+ Oracle Java Certification","Teamwork, Problem-Solving",63 WPM,Field move maybe collection walk child probably result.,"Morgan, Bradshaw and Williams",http://www.fry.com/,3.0,LeetCode: 2400,GATE,Short indicate police marriage phone.,2.0,1.0,1.0,Data Scientist,Finance,Chennai,Yes,57.0,Yes,High,ESFP,"Creativity, Persistence",Shyness,Politics few each southern image.
576
+ vmarshall@hotmail.com,ae637135d5c320d9b916c10b7252f9eba017b3c7c4d2ce15b667a30a906fabae,Michael Moore,Computer Science and Engineering,9.34,"Sem 1: 9.89
577
+
578
+ Sem 2: 9.95
579
+
580
+ Sem 3: 8.84
581
+
582
+ Sem 4: 8.98
583
+
584
+ Sem 5: 8.42
585
+
586
+ Sem 6: 7.52",1,"Ruby (Intermediate), Java (Expert), Go (Beginner)","Docker, AWS, Node.js, MongoDB, React","Google Cloud Associate
587
+
588
+ AWS Certified Developer","Leadership, Problem-Solving",66 WPM,Safe team wish candidate have no.,Allen-Martinez,https://www.davis.biz/,2.0,LeetCode: 2014,GRE,Industry while total spend value return couple city.,4.0,0.0,0.0,System Engineer,Research,Chennai,No,99.0,No,Low,INTJ,"Creativity, Empathy",Perfectionism,Level these market bed hotel lead drive.
589
+ amanda16@gmail.com,9b23be4dcfb3a5a1b7a4c4ba8ff4f17c30c047b627cb3e84a6aa504202588316,Amber Campbell,Mechanical Engineering,8.13,"Sem 1: 8.31
590
+
591
+ Sem 2: 6.95
592
+
593
+ Sem 3: 9.4
594
+
595
+ Sem 4: 8.43
596
+
597
+ Sem 5: 8.56
598
+
599
+ Sem 6: 9.19",0,"JavaScript (Beginner), C# (Expert), Python (Beginner)","GCP, Kubernetes, Docker, MySQL, Node.js","Google Cloud Associate
600
+
601
+ Oracle Java Certification","Communication, Teamwork",42 WPM,Shake hand hundred now crime network.,Hughes Group,https://www.hester.com/,2.0,LeetCode: 612,TOEFL,Newspaper hand certain own husband American.,4.0,2.0,0.0,Data Scientist,Education,Hyderabad,No,86.0,Yes,High,INTJ,"Analytical Thinking, Persistence",Procrastination,Case four listen.
602
+ francisco94@hotmail.com,b79acdf5afca82a5ac6c77181214ab05681c5255aa9e566b02aac0b44adb995b,Larry Robertson,Information Technology,9.18,"Sem 1: 7.96
603
+
604
+ Sem 2: 8.74
605
+
606
+ Sem 3: 8.24
607
+
608
+ Sem 4: 8.7
609
+
610
+ Sem 5: 7.51
611
+
612
+ Sem 6: 9.85",1,"Java (Intermediate), Go (Intermediate), JavaScript (Beginner)","Git, Kubernetes, AWS, Node.js, React","Google Cloud Associate
613
+
614
+ AWS Certified Developer","Leadership, Problem-Solving",39 WPM,Mother remember feel staff happy purpose woman.,"Parker, Roach and Wiggins",http://coffey-patton.org/,2.0,LeetCode: 1407,TOEFL,Dinner anything lose modern return simple herself.,3.0,0.0,1.0,Software Developer,Finance,Hyderabad,No,57.0,No,Medium,ENTP,"Creativity, Analytical Thinking",Perfectionism,All way body affect finish.
615
+ thorntonapril@hotmail.com,965ba874764988a2d924436c4bb5230eee9995bbb17b0abb6a61a92812472843,Michael Jenkins,Electronics and Communication Engineering,9.81,"Sem 1: 9.52
616
+
617
+ Sem 2: 7.96
618
+
619
+ Sem 3: 9.87
620
+
621
+ Sem 4: 9.66
622
+
623
+ Sem 5: 9.35
624
+
625
+ Sem 6: 9.77",2,"C++ (Intermediate), Java (Expert), Go (Intermediate)","MySQL, GCP, AWS, Git, React","Google Cloud Associate
626
+
627
+ Oracle Java Certification","Teamwork, Communication",67 WPM,Moment finish community treatment garden great sign.,"Becker, Lara and Baker",https://www.ramirez.com/,2.0,LeetCode: 299,GATE,Side relate real major look.,2.0,1.0,1.0,System Engineer,IT,Bangalore,No,58.0,No,Low,ISFJ,"Empathy, Creativity",Perfectionism,Value somebody event business quality here woman.
628
+ robertsjennifer@yahoo.com,88610e29d42c5e88dd640075251cd071d675b12ecf4d06539937d8c5bc6e9413,Tina Ballard,Mechanical Engineering,6.68,"Sem 1: 8.47
629
+
630
+ Sem 2: 7.77
631
+
632
+ Sem 3: 7.51
633
+
634
+ Sem 4: 7.85
635
+
636
+ Sem 5: 8.08
637
+
638
+ Sem 6: 8.42",2,"Go (Beginner), C# (Beginner), Python (Intermediate)","React, MongoDB, GCP, Kubernetes, Docker","AWS Certified Developer
639
+
640
+ Google Cloud Associate","Communication, Problem-Solving",32 WPM,Section degree still even no.,Taylor-Gilbert,http://www.santiago.com/,1.0,LeetCode: 1464,None,Appear including response beyond side.,4.0,1.0,0.0,Data Scientist,Finance,Pune,Yes,75.0,No,Low,ISFJ,"Empathy, Persistence",Procrastination,Who within citizen.
641
+ manuel01@andrews.com,28db82072eb8f01aadde28cd56b3ea4559588547eab5ea4adb3125da332ad540,Shirley Alvarez,Mechanical Engineering,9.36,"Sem 1: 7.79
642
+
643
+ Sem 2: 8.86
644
+
645
+ Sem 3: 9.93
646
+
647
+ Sem 4: 8.54
648
+
649
+ Sem 5: 9.29
650
+
651
+ Sem 6: 9.04",2,"Go (Intermediate), Python (Intermediate), C# (Expert)","AWS, Git, GCP, MongoDB, Docker","Oracle Java Certification
652
+
653
+ Google Cloud Associate","Teamwork, Leadership",45 WPM,Individual study value already.,French-Lopez,https://www.evans.com/,0.0,LeetCode: 2445,GATE,Expect writer myself management voice surface.,1.0,0.0,1.0,System Engineer,Research,Hyderabad,No,94.0,Yes,Medium,ESFP,"Analytical Thinking, Persistence",Impatience,Evening speak former room possible responsibility add.
654
+ cherylfowler@wilcox-robertson.com,d881043311ef3b6db037d6656cd033f7e89d49a69a9c5663744e49e02970fdb8,Edward Craig,Information Technology,8.46,"Sem 1: 9.99
655
+
656
+ Sem 2: 8.17
657
+
658
+ Sem 3: 7.82
659
+
660
+ Sem 4: 9.85
661
+
662
+ Sem 5: 8.11
663
+
664
+ Sem 6: 8.37",2,"C++ (Expert), Go (Intermediate), Ruby (Beginner)","AWS, GCP, MySQL, Kubernetes, Docker","Google Cloud Associate
665
+
666
+ Oracle Java Certification","Teamwork, Leadership",61 WPM,Continue cell food easy.,Reyes-Griffin,https://aguilar-berry.com/,2.0,LeetCode: 2065,TOEFL,Realize artist brother fill if maybe.,4.0,2.0,1.0,System Engineer,IT,Chennai,No,72.0,Yes,Medium,INTJ,"Persistence, Empathy",Perfectionism,Real police wait happen determine.
667
+ emiles@hotmail.com,f7a6b6df3b8c2e3cb4e77cea718b44a48b04b586023019c57744f537b3177d03,Karen Gibson,Electronics and Communication Engineering,9.73,"Sem 1: 8.8
668
+
669
+ Sem 2: 9.12
670
+
671
+ Sem 3: 7.25
672
+
673
+ Sem 4: 9.4
674
+
675
+ Sem 5: 7.45
676
+
677
+ Sem 6: 8.47",1,"Java (Expert), Python (Expert), C# (Beginner)","AWS, Git, React, GCP, Docker","Oracle Java Certification
678
+
679
+ AWS Certified Developer","Communication, Problem-Solving",56 WPM,Seven quite other skin moment.,"Padilla, Miller and Elliott",http://www.herrera.info/,2.0,LeetCode: 2034,GATE,Quite response major together.,5.0,0.0,0.0,Data Scientist,Research,Chennai,No,91.0,Yes,Medium,ISFJ,"Persistence, Empathy",Perfectionism,Speak law message lead around left southern.
680
+ williamsmelvin@weaver.com,ec3152388fdb28c35d993726866f7724654551d2323f6ca0872ccbdb125a1318,Jennifer Velasquez,Computer Science and Engineering,8.78,"Sem 1: 7.31
681
+
682
+ Sem 2: 9.09
683
+
684
+ Sem 3: 9.48
685
+
686
+ Sem 4: 6.63
687
+
688
+ Sem 5: 9.73
689
+
690
+ Sem 6: 7.96",0,"Python (Beginner), JavaScript (Expert), Go (Intermediate)","Git, MongoDB, Kubernetes, GCP, React","AWS Certified Developer
691
+
692
+ Google Cloud Associate","Leadership, Teamwork",64 WPM,All important shoulder she within position inside.,West-Stark,https://vega.net/,3.0,LeetCode: 649,None,President girl condition Mr.,2.0,0.0,0.0,System Engineer,Education,Chennai,No,95.0,Yes,High,ISFJ,"Persistence, Empathy",Impatience,Camera without strong series without leg rest.
693
+ eric31@gmail.com,1b6c70ffcdff997148095b8d12d36741df350b7ed8276a18116df126cc30e888,James Hall,Information Technology,8.64,"Sem 1: 8.74
694
+
695
+ Sem 2: 7.92
696
+
697
+ Sem 3: 8.0
698
+
699
+ Sem 4: 7.65
700
+
701
+ Sem 5: 7.9
702
+
703
+ Sem 6: 6.83",0,"JavaScript (Beginner), C++ (Intermediate), Java (Intermediate)","AWS, MySQL, Node.js, Kubernetes, React","Google Cloud Associate
704
+
705
+ AWS Certified Developer","Leadership, Problem-Solving",53 WPM,Past view threat drive attack order.,Harper-Warner,http://www.williams.com/,1.0,LeetCode: 354,GATE,Mean eye staff rule.,3.0,1.0,0.0,AI Researcher,Finance,Bangalore,No,73.0,Yes,High,ENTP,"Empathy, Analytical Thinking",Shyness,Officer significant stand down then worry.
706
+ dpeters@david-powers.net,0d2f8a1ea0b456331f211200548edfdb61e7f89ecc1ed0c30ece12e4e5cecf52,Jennifer Hill,Electronics and Communication Engineering,7.96,"Sem 1: 8.42
707
+
708
+ Sem 2: 8.15
709
+
710
+ Sem 3: 8.38
711
+
712
+ Sem 4: 8.82
713
+
714
+ Sem 5: 7.26
715
+
716
+ Sem 6: 7.37",2,"Ruby (Intermediate), Python (Expert), C# (Expert)","React, Docker, GCP, Git, MongoDB","Oracle Java Certification
717
+
718
+ AWS Certified Developer","Teamwork, Communication",50 WPM,Impact feel contain Mrs drive different.,"Thomas, Ford and Brown",https://moreno.com/,3.0,LeetCode: 576,GRE,Two suggest begin right.,5.0,2.0,1.0,Software Developer,Research,Bangalore,No,58.0,No,Medium,INTJ,"Empathy, Persistence",Procrastination,Appear help painting always authority.
719
+ vclark@krueger-smith.com,00c8c6b46635800246724d11c19c7c44fd29582bb8adb24ec65e402efc6bbc8c,Laurie Powers,Computer Science and Engineering,7.89,"Sem 1: 9.36
720
+
721
+ Sem 2: 9.11
722
+
723
+ Sem 3: 8.52
724
+
725
+ Sem 4: 6.66
726
+
727
+ Sem 5: 7.71
728
+
729
+ Sem 6: 6.72",0,"Python (Intermediate), JavaScript (Intermediate), Ruby (Beginner)","Kubernetes, Node.js, MongoDB, AWS, React","Google Cloud Associate
730
+
731
+ Oracle Java Certification","Communication, Leadership",64 WPM,Section senior trial receive.,"Harris, Herman and Arnold",https://ferguson-howard.com/,1.0,LeetCode: 2776,TOEFL,Mention market better wonder light style.,0.0,0.0,1.0,Data Scientist,Education,Bangalore,Yes,69.0,No,Low,ESFP,"Empathy, Analytical Thinking",Impatience,Have including none determine certainly.
732
+ elijah53@yahoo.com,4c961514a4537b09daf6057cc17b2c3fd9ae30f95d777ae4f9e965d2364c47a8,Timothy Riley,Mechanical Engineering,7.71,"Sem 1: 7.46
733
+
734
+ Sem 2: 9.78
735
+
736
+ Sem 3: 9.04
737
+
738
+ Sem 4: 6.89
739
+
740
+ Sem 5: 9.33
741
+
742
+ Sem 6: 7.97",0,"Java (Beginner), Ruby (Expert), Python (Beginner)","MySQL, Git, Docker, React, MongoDB","Google Cloud Associate
743
+
744
+ Oracle Java Certification","Teamwork, Leadership",43 WPM,Material pressure range either start.,"May, Henry and Jackson",https://www.cortez.com/,0.0,LeetCode: 673,TOEFL,Wrong whatever model stuff avoid stand any.,1.0,2.0,1.0,System Engineer,Education,Pune,Yes,92.0,Yes,Medium,ISFJ,"Persistence, Analytical Thinking",Impatience,Include successful discuss.
745
+ williamsonelizabeth@hotmail.com,52260b17e66fb24a1d9453a9c0ba52d9de0f9fb38faeee3f972ad45b687788cb,Alexa Wagner,Mechanical Engineering,8.45,"Sem 1: 6.66
746
+
747
+ Sem 2: 7.71
748
+
749
+ Sem 3: 8.75
750
+
751
+ Sem 4: 7.83
752
+
753
+ Sem 5: 8.34
754
+
755
+ Sem 6: 8.94",1,"Java (Beginner), C++ (Expert), JavaScript (Intermediate)","AWS, MongoDB, Kubernetes, React, Docker","Google Cloud Associate
756
+
757
+ AWS Certified Developer","Problem-Solving, Teamwork",65 WPM,Administration mother in admit reveal movie expert.,"Li, Craig and Drake",http://www.warren.com/,1.0,LeetCode: 1690,GRE,Money spring environment however health image north wrong.,2.0,0.0,1.0,Software Developer,Research,Pune,Yes,84.0,Yes,High,ISFJ,"Empathy, Persistence",Perfectionism,Feel stock ball yard practice.
758
+ walshjacqueline@gmail.com,4dc29081a8ff8675c0dca05b29cbe37fa6464455891f18b5c723689967a58011,Jared Bennett,Computer Science and Engineering,7.16,"Sem 1: 9.17
759
+
760
+ Sem 2: 9.04
761
+
762
+ Sem 3: 8.46
763
+
764
+ Sem 4: 8.18
765
+
766
+ Sem 5: 9.54
767
+
768
+ Sem 6: 7.67",0,"Java (Expert), Ruby (Intermediate), Python (Beginner)","AWS, Node.js, Docker, GCP, Kubernetes","Google Cloud Associate
769
+
770
+ Oracle Java Certification","Problem-Solving, Leadership",52 WPM,Population former with wind thus try.,Lewis Ltd,https://glass.com/,2.0,LeetCode: 1171,TOEFL,Nor allow up fire which onto sell.,4.0,1.0,1.0,Software Developer,Research,Pune,Yes,73.0,No,Medium,INTJ,"Creativity, Persistence",Impatience,Up federal nor note support quality.
771
+ brian63@peterson.org,1aa4774c7cec3624b5bfac5f15a9cc73ea335186fb77f35fe1c9744eb81ad523,Janet Singh,Computer Science and Engineering,7.41,"Sem 1: 9.77
772
+
773
+ Sem 2: 8.53
774
+
775
+ Sem 3: 7.96
776
+
777
+ Sem 4: 7.03
778
+
779
+ Sem 5: 7.65
780
+
781
+ Sem 6: 7.83",0,"JavaScript (Intermediate), C# (Intermediate), C++ (Expert)","MySQL, MongoDB, Docker, React, Kubernetes","AWS Certified Developer
782
+
783
+ Oracle Java Certification","Problem-Solving, Communication",64 WPM,Ahead event yeah make green wait.,Lopez-Willis,https://www.phillips.com/,0.0,LeetCode: 2246,GATE,Here six child hope.,0.0,2.0,0.0,Software Developer,Research,Hyderabad,Yes,54.0,Yes,High,ENTP,"Empathy, Creativity",Perfectionism,Blood accept final growth especially car.
784
+ johnsonmichael@gmail.com,71f86bd9964867fae2402e9de0e041461b0cd177e674bd11e2f8764098788839,Jerry Peters,Mechanical Engineering,8.81,"Sem 1: 6.56
785
+
786
+ Sem 2: 8.36
787
+
788
+ Sem 3: 7.94
789
+
790
+ Sem 4: 6.56
791
+
792
+ Sem 5: 9.03
793
+
794
+ Sem 6: 8.38",1,"Python (Beginner), C# (Beginner), JavaScript (Beginner)","MongoDB, Kubernetes, Docker, Node.js, GCP","Oracle Java Certification
795
+
796
+ Google Cloud Associate","Leadership, Teamwork",55 WPM,Tell activity including single right nice.,Armstrong and Sons,https://www.adams.info/,0.0,LeetCode: 1628,None,As itself inside machine.,3.0,2.0,0.0,Data Scientist,Finance,Bangalore,Yes,55.0,No,Medium,ESFP,"Empathy, Analytical Thinking",Perfectionism,Guess want result many.
797
+ ncook@brock-rivera.com,e8fb86e82425719a03be05dacbd54e031c9beeee4af7e75780ded5c99dc5376c,Judith Taylor,Information Technology,6.79,"Sem 1: 9.46
798
+
799
+ Sem 2: 8.76
800
+
801
+ Sem 3: 7.66
802
+
803
+ Sem 4: 9.92
804
+
805
+ Sem 5: 9.91
806
+
807
+ Sem 6: 9.63",0,"Java (Intermediate), Ruby (Intermediate), C# (Beginner)","Docker, GCP, MySQL, Node.js, Git","AWS Certified Developer
808
+
809
+ Google Cloud Associate","Communication, Problem-Solving",67 WPM,Carry fly water cut fire who why fact.,"Chen, Faulkner and Casey",https://velasquez-long.com/,1.0,LeetCode: 1731,GATE,Customer young conference should agree road wall.,2.0,0.0,0.0,AI Researcher,Finance,Chennai,Yes,100.0,Yes,Low,ISFJ,"Analytical Thinking, Empathy",Shyness,Just fact realize standard somebody.
810
+ donna66@cole.info,e3922a22ab2eb77a4f77feffde7cee4ac4f73a8dc39d522794bbda148630cfc1,Jonathan Schultz,Information Technology,9.44,"Sem 1: 7.69
811
+
812
+ Sem 2: 9.19
813
+
814
+ Sem 3: 9.84
815
+
816
+ Sem 4: 7.89
817
+
818
+ Sem 5: 9.21
819
+
820
+ Sem 6: 6.6",1,"Ruby (Beginner), JavaScript (Intermediate), Go (Expert)","Node.js, MongoDB, Docker, React, GCP","Oracle Java Certification
821
+
822
+ Google Cloud Associate","Communication, Leadership",48 WPM,Media turn reality myself so growth time.,"Wheeler, Rocha and Rodriguez",http://holland.org/,1.0,LeetCode: 401,GATE,Whom former someone black better develop.,2.0,0.0,1.0,Data Scientist,Research,Pune,No,56.0,Yes,High,ISFJ,"Empathy, Creativity",Procrastination,Newspaper reach determine hear leg quickly real.
823
+ fknapp@gmail.com,4f9c13c9b0e39defddd0f1ab86f4aee8c6145c6be2fe006bad830eab93dcfb73,Zachary Webb,Computer Science and Engineering,6.96,"Sem 1: 7.16
824
+
825
+ Sem 2: 8.07
826
+
827
+ Sem 3: 8.44
828
+
829
+ Sem 4: 7.93
830
+
831
+ Sem 5: 6.59
832
+
833
+ Sem 6: 7.74",0,"C# (Intermediate), Ruby (Beginner), C++ (Intermediate)","Node.js, MongoDB, MySQL, Git, GCP","AWS Certified Developer
834
+
835
+ Oracle Java Certification","Problem-Solving, Communication",38 WPM,Give gas six miss.,Alvarez-Kim,https://evans.com/,2.0,LeetCode: 1333,TOEFL,Support possible quality.,3.0,0.0,0.0,Data Scientist,Research,Pune,No,69.0,No,High,ISFJ,"Persistence, Analytical Thinking",Shyness,Upon scientist might necessary.
836
+ jacobsandoval@yahoo.com,605bd6c2f9b01bc5bdbc83ffdfb7bd9ef8d523c5c3f006b659155e2d250c8f0b,Jeffery Murray,Information Technology,8.1,"Sem 1: 6.97
837
+
838
+ Sem 2: 6.52
839
+
840
+ Sem 3: 7.88
841
+
842
+ Sem 4: 9.45
843
+
844
+ Sem 5: 7.83
845
+
846
+ Sem 6: 9.52",1,"C++ (Beginner), JavaScript (Intermediate), C# (Intermediate)","AWS, MySQL, Kubernetes, Docker, MongoDB","Google Cloud Associate
847
+
848
+ Oracle Java Certification","Problem-Solving, Leadership",45 WPM,Third last involve above Democrat everything region somebody.,"Garcia, Wiggins and Lopez",https://www.wilson-lambert.info/,2.0,LeetCode: 1640,TOEFL,Whole finish home hotel box goal leader.,3.0,1.0,0.0,Data Scientist,Education,Bangalore,No,95.0,Yes,Medium,ISFJ,"Analytical Thinking, Creativity",Shyness,Sport relationship father pass.
849
+ whiteheather@hotmail.com,2930a09094a8d42998fdd105f021898c09b8dcb2ee65dffb76299e5f29144def,Cesar Wilson,Information Technology,8.72,"Sem 1: 7.35
850
+
851
+ Sem 2: 8.81
852
+
853
+ Sem 3: 9.0
854
+
855
+ Sem 4: 9.26
856
+
857
+ Sem 5: 6.76
858
+
859
+ Sem 6: 9.97",1,"C# (Expert), JavaScript (Expert), Ruby (Intermediate)","MongoDB, Git, Node.js, Kubernetes, GCP","Oracle Java Certification
860
+
861
+ AWS Certified Developer","Communication, Problem-Solving",52 WPM,Case himself control player really population yourself never.,Roberts-Lopez,https://www.crane-washington.com/,1.0,LeetCode: 2750,GATE,White measure manager range indeed style.,4.0,2.0,1.0,System Engineer,Research,Bangalore,Yes,56.0,No,High,ENTP,"Empathy, Creativity",Shyness,Cold not somebody determine allow different eye.
862
+ armstrongjoseph@hotmail.com,e49ce57cabf898d62d9a320ade7516a5027af4506df7b5c609fbbcc3b10e3cb2,Krystal Barton,Mechanical Engineering,9.2,"Sem 1: 8.56
863
+
864
+ Sem 2: 8.25
865
+
866
+ Sem 3: 7.71
867
+
868
+ Sem 4: 6.59
869
+
870
+ Sem 5: 6.87
871
+
872
+ Sem 6: 7.96",0,"Python (Intermediate), Go (Intermediate), Java (Intermediate)","MySQL, AWS, GCP, MongoDB, Kubernetes","Google Cloud Associate
873
+
874
+ AWS Certified Developer","Problem-Solving, Leadership",58 WPM,My series service kid despite interesting.,"Greer, Potter and Evans",http://bailey-montoya.info/,2.0,LeetCode: 375,TOEFL,Simply down specific onto.,0.0,2.0,0.0,Software Developer,Finance,Bangalore,Yes,97.0,Yes,Low,ENTP,"Creativity, Empathy",Shyness,Technology particular into pattern size spend.
875
+ tiffany44@adams.com,902527015e941225dba2d5a2a0d41f8b1dc2188493b585967cf153ebc754d320,Laura Patel,Mechanical Engineering,7.31,"Sem 1: 7.92
876
+
877
+ Sem 2: 7.15
878
+
879
+ Sem 3: 8.74
880
+
881
+ Sem 4: 8.01
882
+
883
+ Sem 5: 6.6
884
+
885
+ Sem 6: 8.65",0,"JavaScript (Intermediate), C# (Beginner), Ruby (Expert)","AWS, MongoDB, Kubernetes, React, Git","Oracle Java Certification
886
+
887
+ AWS Certified Developer","Teamwork, Problem-Solving",50 WPM,Try yeah term camera tend economic.,"Morris, Wright and Bridges",https://ray.biz/,1.0,LeetCode: 1974,GATE,Later plant they behavior middle everything.,2.0,2.0,1.0,System Engineer,Research,Chennai,Yes,72.0,No,Medium,ENTP,"Persistence, Empathy",Perfectionism,Lawyer maintain old than suggest behavior.
888
+ brobinson@simpson.com,83593749421757f1edcbc9d70d631978874f8d1955bf5e9435f281d654714909,Madison Terry,Information Technology,7.6,"Sem 1: 7.34
889
+
890
+ Sem 2: 6.91
891
+
892
+ Sem 3: 7.81
893
+
894
+ Sem 4: 6.99
895
+
896
+ Sem 5: 7.86
897
+
898
+ Sem 6: 8.59",2,"JavaScript (Intermediate), Ruby (Expert), Java (Expert)","Kubernetes, MongoDB, AWS, MySQL, Docker","AWS Certified Developer
899
+
900
+ Google Cloud Associate","Problem-Solving, Leadership",33 WPM,Candidate system small thus several animal phone.,Smith-Noble,http://smith-rubio.com/,2.0,LeetCode: 139,None,Think few themselves theory.,1.0,0.0,1.0,AI Researcher,Research,Chennai,No,95.0,No,Medium,ENTP,"Analytical Thinking, Persistence",Perfectionism,Pressure economy head tough.
901
+ trios@smith.com,000c88700161f93a05d033e9f6e09eb0b3e8b1504a3fa4b1024fc9aa58aee2fc,James Torres,Information Technology,7.52,"Sem 1: 7.46
902
+
903
+ Sem 2: 8.38
904
+
905
+ Sem 3: 7.09
906
+
907
+ Sem 4: 8.1
908
+
909
+ Sem 5: 9.1
910
+
911
+ Sem 6: 9.18",2,"C# (Beginner), Python (Intermediate), Ruby (Expert)","React, Git, Node.js, MongoDB, AWS","Oracle Java Certification
912
+
913
+ AWS Certified Developer","Problem-Solving, Communication",45 WPM,Mind knowledge account gas building.,Benson-Woods,http://cross.com/,2.0,LeetCode: 232,None,Happen federal him spend themselves political.,2.0,1.0,0.0,AI Researcher,IT,Hyderabad,Yes,97.0,No,Low,ESFP,"Creativity, Persistence",Impatience,Attention none particular clearly.
914
+ fheath@gmail.com,1c8a5a6effdff58b2b24536346821df5aade1ed4e7303edd88bbdb2971c6e618,Daniel Goodman,Information Technology,9.35,"Sem 1: 9.32
915
+
916
+ Sem 2: 8.5
917
+
918
+ Sem 3: 8.36
919
+
920
+ Sem 4: 8.59
921
+
922
+ Sem 5: 7.09
923
+
924
+ Sem 6: 9.93",1,"C++ (Expert), C# (Expert), Ruby (Beginner)","Kubernetes, Node.js, Git, MongoDB, Docker","Oracle Java Certification
925
+
926
+ AWS Certified Developer","Teamwork, Communication",50 WPM,Operation himself white fire.,Wright Ltd,http://www.burke.com/,1.0,LeetCode: 2869,None,Day parent country hot position.,3.0,0.0,1.0,AI Researcher,Research,Chennai,Yes,90.0,Yes,Medium,ISFJ,"Persistence, Creativity",Shyness,Manager both matter order month.
927
+ kvalencia@diaz-vega.info,ebd26a86db2ec2b6e74de5e8878acd4b8b1ddfa2e8178dd93618f1f48d536be4,Victoria Peck,Electronics and Communication Engineering,8.54,"Sem 1: 9.54
928
+
929
+ Sem 2: 9.47
930
+
931
+ Sem 3: 6.83
932
+
933
+ Sem 4: 9.9
934
+
935
+ Sem 5: 8.72
936
+
937
+ Sem 6: 8.94",0,"Ruby (Beginner), C# (Intermediate), JavaScript (Beginner)","MySQL, GCP, Kubernetes, Node.js, React","Oracle Java Certification
938
+
939
+ AWS Certified Developer","Problem-Solving, Teamwork",33 WPM,Admit attack energy always.,Fry Group,https://miles-miller.net/,0.0,LeetCode: 507,None,Pattern everyone finally memory data space movie.,0.0,0.0,0.0,AI Researcher,Research,Bangalore,No,62.0,Yes,Low,ISFJ,"Creativity, Empathy",Perfectionism,Only shake power poor financial join.
940
+ chavezchelsea@yahoo.com,39d5e5988d8aef599d3d3d5053adbfe3505af0862915a8c8137b44a5691c98df,Cynthia Sanchez,Electronics and Communication Engineering,7.38,"Sem 1: 7.8
941
+
942
+ Sem 2: 9.66
943
+
944
+ Sem 3: 7.08
945
+
946
+ Sem 4: 7.89
947
+
948
+ Sem 5: 7.57
949
+
950
+ Sem 6: 8.95",0,"JavaScript (Expert), Go (Beginner), Python (Beginner)","AWS, MySQL, Git, Docker, GCP","AWS Certified Developer
951
+
952
+ Google Cloud Associate","Communication, Problem-Solving",51 WPM,Budget remain reduce clearly.,Mills-Logan,https://www.martinez-norman.com/,0.0,LeetCode: 1829,GRE,Sign ahead southern evening.,3.0,0.0,0.0,AI Researcher,IT,Bangalore,Yes,70.0,No,Medium,ENTP,"Empathy, Analytical Thinking",Impatience,Enjoy window physical many.
953
+ eric19@sharp.com,c79140f46dd31ef71f0b3fbf2c29fe0357597ac2a632e3c080a3b93d1464e58e,Amy Villarreal,Computer Science and Engineering,8.36,"Sem 1: 6.53
954
+
955
+ Sem 2: 8.78
956
+
957
+ Sem 3: 8.04
958
+
959
+ Sem 4: 9.03
960
+
961
+ Sem 5: 8.7
962
+
963
+ Sem 6: 7.03",1,"C# (Beginner), Go (Beginner), JavaScript (Beginner)","Kubernetes, Docker, GCP, React, AWS","Google Cloud Associate
964
+
965
+ Oracle Java Certification","Leadership, Communication",45 WPM,Each line him.,White Inc,https://www.wright-moon.com/,2.0,LeetCode: 2740,GATE,Step number budget pull apply.,1.0,2.0,1.0,Software Developer,Finance,Hyderabad,Yes,97.0,No,Medium,INTJ,"Creativity, Empathy",Shyness,Source wonder west attention let.
966
+ woodkelly@yahoo.com,5cadfebe02ef8ac4870eb822786c818d2a0cef52166231bd62027405f8edf96b,Ryan Murphy,Computer Science and Engineering,7.34,"Sem 1: 8.73
967
+
968
+ Sem 2: 6.75
969
+
970
+ Sem 3: 9.61
971
+
972
+ Sem 4: 6.54
973
+
974
+ Sem 5: 7.76
975
+
976
+ Sem 6: 7.61",1,"Ruby (Intermediate), C# (Expert), JavaScript (Expert)","Kubernetes, MySQL, Node.js, Git, React","Oracle Java Certification
977
+
978
+ AWS Certified Developer","Communication, Teamwork",43 WPM,Less option management significant crime.,"Hodges, Sanchez and Smith",https://www.weaver.com/,0.0,LeetCode: 347,None,Ability price support road billion morning.,4.0,1.0,1.0,AI Researcher,Research,Bangalore,Yes,67.0,Yes,Medium,INTJ,"Creativity, Analytical Thinking",Procrastination,Information which win central evidence.
979
+ stephen19@gmail.com,dc5d81ee36d5ba800430055df19c1f1a3c57763040afdf0fd3011a221ffc09eb,David Bruce,Mechanical Engineering,8.55,"Sem 1: 9.17
980
+
981
+ Sem 2: 8.77
982
+
983
+ Sem 3: 8.75
984
+
985
+ Sem 4: 7.59
986
+
987
+ Sem 5: 8.03
988
+
989
+ Sem 6: 9.84",0,"Python (Intermediate), Java (Beginner), Ruby (Intermediate)","Git, GCP, React, Node.js, Docker","AWS Certified Developer
990
+
991
+ Oracle Java Certification","Teamwork, Leadership",30 WPM,Avoid nothing itself who door end.,Howe-Long,https://nelson-jones.com/,1.0,LeetCode: 2133,TOEFL,Sister once choice clearly.,4.0,2.0,1.0,Data Scientist,Finance,Hyderabad,No,96.0,Yes,High,ISFJ,"Empathy, Creativity",Perfectionism,Finish building group show later leg system.
992
+ marymurphy@dawson.biz,60acc8de30cbbcbad2ef448782735cd8da0ad3b396d3dc397125615eb48f3823,Robert Torres,Electronics and Communication Engineering,8.99,"Sem 1: 8.52
993
+
994
+ Sem 2: 6.77
995
+
996
+ Sem 3: 8.09
997
+
998
+ Sem 4: 7.76
999
+
1000
+ Sem 5: 8.25
1001
+
1002
+ Sem 6: 8.48",1,"Java (Expert), C++ (Expert), Python (Expert)","Docker, AWS, React, GCP, Git","AWS Certified Developer
1003
+
1004
+ Oracle Java Certification","Teamwork, Communication",60 WPM,Employee wrong all identify laugh.,"Pierce, Davis and Garcia",http://www.brown.com/,2.0,LeetCode: 1668,GRE,Statement head piece popular old.,1.0,0.0,1.0,Data Scientist,Finance,Hyderabad,No,96.0,No,Medium,INTJ,"Persistence, Analytical Thinking",Perfectionism,True avoid young cup position.
1005
+ williamssteven@gmail.com,ab278fb4a0a0853d2e14efe9c6e23ab895f2ca23b90b7000fbfb716ebb3e1fca,Anna Boone,Information Technology,7.28,"Sem 1: 8.31
1006
+
1007
+ Sem 2: 6.66
1008
+
1009
+ Sem 3: 7.9
1010
+
1011
+ Sem 4: 9.57
1012
+
1013
+ Sem 5: 9.53
1014
+
1015
+ Sem 6: 9.21",1,"C++ (Intermediate), Python (Beginner), C# (Intermediate)","AWS, GCP, MySQL, Kubernetes, Node.js","AWS Certified Developer
1016
+
1017
+ Google Cloud Associate","Leadership, Problem-Solving",61 WPM,Start house ahead raise common Democrat.,Hill Group,http://www.harvey.biz/,1.0,LeetCode: 2338,GRE,Look because him information poor something eat.,1.0,0.0,1.0,Software Developer,Education,Pune,Yes,71.0,Yes,Low,ESFP,"Persistence, Analytical Thinking",Impatience,Some writer site grow name machine tree.
1018
+ anthonycochran@yahoo.com,64a02493d7c80999620a4f3b1a27892b1c1ad1d17b1586135c47b9132ca0dde5,Jasmine White,Information Technology,7.97,"Sem 1: 9.86
1019
+
1020
+ Sem 2: 9.9
1021
+
1022
+ Sem 3: 7.0
1023
+
1024
+ Sem 4: 7.48
1025
+
1026
+ Sem 5: 6.65
1027
+
1028
+ Sem 6: 7.31",2,"JavaScript (Intermediate), Go (Expert), C++ (Beginner)","Docker, Kubernetes, React, AWS, Git","Oracle Java Certification
1029
+
1030
+ AWS Certified Developer","Problem-Solving, Leadership",38 WPM,Morning short yourself wind beyond prevent entire.,"Brown, Davies and Robinson",https://thompson.com/,1.0,LeetCode: 1294,TOEFL,Trial agreement red way nor none.,2.0,1.0,1.0,System Engineer,Research,Pune,Yes,54.0,Yes,High,INTJ,"Creativity, Analytical Thinking",Impatience,Student special wife my compare.
1031
+ nsmith@drake.com,4059d2dac86be43ca3a9bc71f84b1fb6577f9541be1d0fd18323ff1dc47156a5,Anthony Guzman,Mechanical Engineering,8.13,"Sem 1: 7.92
1032
+
1033
+ Sem 2: 8.38
1034
+
1035
+ Sem 3: 9.88
1036
+
1037
+ Sem 4: 7.23
1038
+
1039
+ Sem 5: 7.58
1040
+
1041
+ Sem 6: 7.43",0,"Python (Expert), Java (Expert), C++ (Expert)","Git, AWS, Node.js, Kubernetes, Docker","AWS Certified Developer
1042
+
1043
+ Oracle Java Certification","Leadership, Teamwork",62 WPM,Arrive challenge relate center book money.,Yu-Brooks,https://www.turner-taylor.com/,0.0,LeetCode: 2873,TOEFL,Social whether power company why really.,2.0,0.0,0.0,AI Researcher,Research,Hyderabad,Yes,79.0,Yes,High,INTJ,"Analytical Thinking, Empathy",Impatience,Skin development open compare fill read camera rock.
1044
+ carriemccall@walker.com,53a6b5dce6247ac7e8dc091e485dfcdd135d9db46e182ee610e87dc59526612c,Tiffany Myers,Information Technology,7.19,"Sem 1: 7.9
1045
+
1046
+ Sem 2: 8.9
1047
+
1048
+ Sem 3: 9.78
1049
+
1050
+ Sem 4: 6.79
1051
+
1052
+ Sem 5: 8.55
1053
+
1054
+ Sem 6: 9.71",0,"Python (Expert), Ruby (Intermediate), Java (Beginner)","Docker, React, Git, Node.js, AWS","AWS Certified Developer
1055
+
1056
+ Oracle Java Certification","Problem-Solving, Leadership",55 WPM,Draw word collection those.,Underwood Ltd,https://baker.com/,3.0,LeetCode: 220,None,Either blue ability history run why.,5.0,1.0,0.0,System Engineer,Education,Hyderabad,No,67.0,No,High,INTJ,"Creativity, Persistence",Procrastination,Manage her national big look tell.
1057
+ phillipslucas@jones.biz,d9a8fab9822778e7e9128cd29f57a542058c3ad03eb4b6171df31a9e47b240d1,Melissa Martin,Mechanical Engineering,7.94,"Sem 1: 8.43
1058
+
1059
+ Sem 2: 6.71
1060
+
1061
+ Sem 3: 7.48
1062
+
1063
+ Sem 4: 6.98
1064
+
1065
+ Sem 5: 7.2
1066
+
1067
+ Sem 6: 9.6",2,"Java (Beginner), Go (Intermediate), C# (Expert)","React, MySQL, GCP, AWS, Kubernetes","Oracle Java Certification
1068
+
1069
+ Google Cloud Associate","Problem-Solving, Teamwork",41 WPM,Natural together behavior order.,"Barry, Bush and Reynolds",http://brown.com/,0.0,LeetCode: 1406,GRE,Important never understand music produce.,0.0,1.0,0.0,AI Researcher,Finance,Hyderabad,Yes,56.0,Yes,Low,ENTP,"Persistence, Empathy",Perfectionism,Down anyone occur style child.
1070
+ collinclark@hotmail.com,c7cc40bf3a068ea35e444d7b3551933adecbf5574cb96eb8f50616c3b3e223a4,Jeffrey Phillips,Information Technology,8.51,"Sem 1: 9.94
1071
+
1072
+ Sem 2: 7.86
1073
+
1074
+ Sem 3: 9.77
1075
+
1076
+ Sem 4: 9.97
1077
+
1078
+ Sem 5: 7.11
1079
+
1080
+ Sem 6: 7.33",1,"Ruby (Expert), Go (Beginner), C++ (Expert)","React, Kubernetes, GCP, Docker, AWS","Oracle Java Certification
1081
+
1082
+ Google Cloud Associate","Teamwork, Problem-Solving",32 WPM,List break size likely.,"Baker, May and Hughes",https://lopez-williams.info/,0.0,LeetCode: 330,GRE,Enjoy student nor character recent benefit property.,4.0,0.0,0.0,AI Researcher,IT,Pune,Yes,58.0,No,Low,ENTP,"Persistence, Analytical Thinking",Perfectionism,Including series dinner article hit mission whole.
1083
+ zevans@johnson.org,23b71cc7fffeb885380cd88d745c32a0a47ba694eba5589323b1134aa1ef3b57,Taylor Armstrong,Information Technology,8.55,"Sem 1: 9.71
1084
+
1085
+ Sem 2: 9.21
1086
+
1087
+ Sem 3: 9.46
1088
+
1089
+ Sem 4: 9.51
1090
+
1091
+ Sem 5: 9.86
1092
+
1093
+ Sem 6: 7.81",2,"JavaScript (Intermediate), C# (Intermediate), Python (Intermediate)","Kubernetes, MongoDB, React, AWS, Node.js","Oracle Java Certification
1094
+
1095
+ Google Cloud Associate","Teamwork, Leadership",65 WPM,Challenge we last we cold deep cover amount.,Mcneil Group,http://www.scott.com/,2.0,LeetCode: 1014,GRE,Hold however for everybody.,3.0,1.0,1.0,Data Scientist,Education,Bangalore,No,99.0,Yes,High,ISFJ,"Creativity, Persistence",Perfectionism,True actually red onto site both change.
1096
+ hartcraig@dillon-beard.biz,79fe922a61ae5676677183d18b75af542ee1728513cf590add84bc9a6a1281a7,Lauren Hanna,Mechanical Engineering,6.99,"Sem 1: 9.11
1097
+
1098
+ Sem 2: 7.33
1099
+
1100
+ Sem 3: 9.94
1101
+
1102
+ Sem 4: 7.09
1103
+
1104
+ Sem 5: 9.6
1105
+
1106
+ Sem 6: 6.81",2,"Go (Intermediate), Ruby (Beginner), C++ (Intermediate)","AWS, MongoDB, React, Git, Kubernetes","Google Cloud Associate
1107
+
1108
+ AWS Certified Developer","Communication, Problem-Solving",54 WPM,Occur list common idea peace race I.,Preston-Rivera,http://www.alvarez.com/,3.0,LeetCode: 1818,GRE,Financial successful teach range win.,3.0,1.0,1.0,System Engineer,Research,Bangalore,No,100.0,Yes,High,ESFP,"Analytical Thinking, Empathy",Procrastination,Care wind kitchen stay especially.
1109
+ wfigueroa@camacho.com,d7ae3dd31bfab08eb337576504fae74a6876c617a90ef9a3b517428b17a35e2c,Matthew Lopez,Computer Science and Engineering,7.62,"Sem 1: 9.83
1110
+
1111
+ Sem 2: 6.76
1112
+
1113
+ Sem 3: 7.1
1114
+
1115
+ Sem 4: 7.81
1116
+
1117
+ Sem 5: 9.06
1118
+
1119
+ Sem 6: 8.41",0,"C++ (Intermediate), C# (Expert), Go (Beginner)","Node.js, Kubernetes, GCP, AWS, Docker","AWS Certified Developer
1120
+
1121
+ Oracle Java Certification","Leadership, Communication",42 WPM,Idea sister modern notice community themselves customer.,Wright Group,http://gonzalez.biz/,3.0,LeetCode: 2955,TOEFL,Race drop major land.,5.0,1.0,1.0,Data Scientist,IT,Bangalore,No,86.0,No,High,INTJ,"Persistence, Analytical Thinking",Shyness,Only glass clear thus see read expect.
1122
+ deborahbyrd@pearson-palmer.com,d2f654b695aab3ab9ec3cf3ba8acc88b060650d7bc1bf0ef82cff99422c6d0d3,Christopher Armstrong,Computer Science and Engineering,7.53,"Sem 1: 8.82
1123
+
1124
+ Sem 2: 8.6
1125
+
1126
+ Sem 3: 7.2
1127
+
1128
+ Sem 4: 6.59
1129
+
1130
+ Sem 5: 7.1
1131
+
1132
+ Sem 6: 7.52",0,"JavaScript (Intermediate), Python (Intermediate), C++ (Intermediate)","GCP, Docker, React, MongoDB, AWS","AWS Certified Developer
1133
+
1134
+ Google Cloud Associate","Problem-Solving, Teamwork",41 WPM,Positive over across education.,Marquez-Fletcher,https://york-stevens.com/,3.0,LeetCode: 282,TOEFL,Few minute perhaps once account yourself whom.,3.0,1.0,1.0,Data Scientist,Finance,Bangalore,Yes,98.0,Yes,High,ISFJ,"Empathy, Persistence",Impatience,No order executive range loss from.
1135
+ edwardcannon@gmail.com,88ea674d7d303515fb1f89d5ff713abb801c9f43a4fbee2cc8fc1d216e0ecf09,Frederick Hill,Computer Science and Engineering,9.44,"Sem 1: 9.36
1136
+
1137
+ Sem 2: 7.97
1138
+
1139
+ Sem 3: 8.37
1140
+
1141
+ Sem 4: 9.53
1142
+
1143
+ Sem 5: 8.16
1144
+
1145
+ Sem 6: 9.59",1,"C++ (Expert), Python (Beginner), JavaScript (Expert)","MongoDB, Kubernetes, Git, AWS, Docker","AWS Certified Developer
1146
+
1147
+ Oracle Java Certification","Teamwork, Communication",32 WPM,Identify floor cause agent market fast trade identify.,"Johnson, Erickson and Armstrong",http://reeves.info/,3.0,LeetCode: 420,None,Medical suddenly subject theory Congress best.,1.0,2.0,0.0,System Engineer,Finance,Bangalore,Yes,74.0,No,Low,ISFJ,"Persistence, Empathy",Shyness,Scientist rise next tree.
1148
+ jeffrey46@watson-richards.info,c3630d11312e4e55782f86a8e74613da1235c1b729c63cf9a1f727e52cde4864,Stephanie Pena,Computer Science and Engineering,9.25,"Sem 1: 8.68
1149
+
1150
+ Sem 2: 8.33
1151
+
1152
+ Sem 3: 7.97
1153
+
1154
+ Sem 4: 7.95
1155
+
1156
+ Sem 5: 7.02
1157
+
1158
+ Sem 6: 8.56",0,"Python (Intermediate), C# (Expert), Ruby (Intermediate)","Node.js, GCP, AWS, React, MongoDB","Oracle Java Certification
1159
+
1160
+ Google Cloud Associate","Communication, Problem-Solving",47 WPM,Approach plant oil per line create build.,"James, Evans and Brown",http://www.cooper.info/,3.0,LeetCode: 689,None,First resource single maintain.,0.0,1.0,1.0,Data Scientist,IT,Chennai,No,73.0,Yes,Medium,ISFJ,"Persistence, Creativity",Shyness,Would finish around later decide similar office citizen.
1161
+ epowell@yahoo.com,8bb7848e064edaf597e41472685eaa33519405c98ed035c83a32774e389e7b1b,Penny Anderson,Computer Science and Engineering,9.9,"Sem 1: 7.3
1162
+
1163
+ Sem 2: 7.55
1164
+
1165
+ Sem 3: 9.1
1166
+
1167
+ Sem 4: 9.21
1168
+
1169
+ Sem 5: 7.62
1170
+
1171
+ Sem 6: 9.05",2,"Go (Intermediate), Python (Beginner), Java (Intermediate)","MySQL, React, Node.js, Git, GCP","AWS Certified Developer
1172
+
1173
+ Oracle Java Certification","Leadership, Problem-Solving",62 WPM,Current health add focus street course quality.,"Gross, Perez and Wiley",https://www.reyes.com/,3.0,LeetCode: 655,GATE,Assume animal way lay.,1.0,0.0,0.0,Software Developer,Education,Bangalore,No,53.0,No,Low,ENTP,"Persistence, Creativity",Shyness,Others full thousand yet garden top grow.
1174
+ perezjessica@gmail.com,aa82c819efd169455fb83f79e28ac2b4d90543a87fec8c92af8a4cf104ee0255,Travis Hull,Mechanical Engineering,8.72,"Sem 1: 6.93
1175
+
1176
+ Sem 2: 6.61
1177
+
1178
+ Sem 3: 7.8
1179
+
1180
+ Sem 4: 8.58
1181
+
1182
+ Sem 5: 7.12
1183
+
1184
+ Sem 6: 9.55",2,"C# (Beginner), C++ (Intermediate), Go (Expert)","Docker, GCP, Git, AWS, Node.js","AWS Certified Developer
1185
+
1186
+ Oracle Java Certification","Teamwork, Leadership",44 WPM,Operation college hand.,"Conner, Brooks and Bowman",http://www.rodriguez.com/,1.0,LeetCode: 1202,None,Know buy education reduce day rate.,4.0,0.0,0.0,AI Researcher,Education,Hyderabad,Yes,64.0,No,Low,ISFJ,"Persistence, Creativity",Shyness,Feeling product production.
1187
+ campbellkristen@gonzalez-gonzalez.com,3214164a5565be0f0cfc20a18f772e4f07aa0870a47bc569a6719b2f30a29cdd,Larry Taylor,Electronics and Communication Engineering,8.11,"Sem 1: 7.26
1188
+
1189
+ Sem 2: 7.56
1190
+
1191
+ Sem 3: 8.32
1192
+
1193
+ Sem 4: 8.68
1194
+
1195
+ Sem 5: 8.55
1196
+
1197
+ Sem 6: 6.53",2,"Ruby (Expert), C++ (Expert), C# (Expert)","GCP, MongoDB, React, Git, AWS","AWS Certified Developer
1198
+
1199
+ Google Cloud Associate","Leadership, Problem-Solving",50 WPM,Group important civil nature travel.,"Fitzpatrick, Rivera and Smith",http://www.caldwell.net/,2.0,LeetCode: 1169,TOEFL,Rich big eight discuss.,1.0,0.0,0.0,Software Developer,Research,Pune,Yes,96.0,Yes,Low,ESFP,"Persistence, Creativity",Shyness,Enough anyone spend them system.
1200
+ yorkpamela@christian.com,679d861c03118ebcd369bde72c391780474b4014cbcbd56e61ea936e19ff65b5,Michael Simmons,Mechanical Engineering,7.86,"Sem 1: 6.62
1201
+
1202
+ Sem 2: 8.98
1203
+
1204
+ Sem 3: 8.5
1205
+
1206
+ Sem 4: 7.16
1207
+
1208
+ Sem 5: 9.04
1209
+
1210
+ Sem 6: 7.28",2,"Go (Expert), JavaScript (Intermediate), C++ (Beginner)","MongoDB, Kubernetes, MySQL, Git, AWS","AWS Certified Developer
1211
+
1212
+ Google Cloud Associate","Teamwork, Leadership",51 WPM,Western environmental run head garden box.,Rivers-Nelson,https://banks-robles.com/,0.0,LeetCode: 1010,TOEFL,Receive around wall city.,1.0,2.0,1.0,AI Researcher,Finance,Pune,No,87.0,No,Medium,INTJ,"Empathy, Analytical Thinking",Perfectionism,Treat lot notice just particularly single.
1213
+ hknapp@alexander-brown.com,4018e725c3f0d9aaace06e5adc293f3c4f9dbed236de31acd0b26646463deabb,Shari Hobbs,Mechanical Engineering,9.61,"Sem 1: 8.25
1214
+
1215
+ Sem 2: 9.54
1216
+
1217
+ Sem 3: 7.84
1218
+
1219
+ Sem 4: 7.54
1220
+
1221
+ Sem 5: 6.69
1222
+
1223
+ Sem 6: 9.49",0,"Java (Expert), C++ (Intermediate), JavaScript (Beginner)","React, Kubernetes, Node.js, Git, AWS","Google Cloud Associate
1224
+
1225
+ AWS Certified Developer","Leadership, Problem-Solving",33 WPM,Should office north within prove full mission.,"Montgomery, Reynolds and Barber",https://rhodes.net/,0.0,LeetCode: 1951,TOEFL,Approach poor church support system thank avoid man.,1.0,0.0,0.0,AI Researcher,IT,Hyderabad,No,90.0,No,Medium,ESFP,"Empathy, Creativity",Perfectionism,Former everything medical nearly her.
1226
+ gatessergio@gmail.com,8328ae6c441bdbe8d0edd6a7d1b5008db4310232326abac9b3d84d1a0b165d7f,Angela Wallace,Computer Science and Engineering,8.37,"Sem 1: 9.06
1227
+
1228
+ Sem 2: 9.83
1229
+
1230
+ Sem 3: 9.62
1231
+
1232
+ Sem 4: 9.15
1233
+
1234
+ Sem 5: 8.36
1235
+
1236
+ Sem 6: 6.56",0,"Go (Beginner), Ruby (Expert), Java (Intermediate)","GCP, Kubernetes, Git, AWS, MongoDB","Oracle Java Certification
1237
+
1238
+ Google Cloud Associate","Teamwork, Communication",32 WPM,Bill include news.,Petersen PLC,https://www.powers.com/,2.0,LeetCode: 1291,None,Such forward should outside respond.,5.0,2.0,1.0,AI Researcher,Education,Pune,No,72.0,Yes,High,ESFP,"Analytical Thinking, Empathy",Impatience,Respond box service develop game stop.
1239
+ princetravis@newton.com,a5746e580089498d437ddd5440ecf7d0bb60c20d26f37c6c8d1559624d73c834,Dorothy Boyd,Information Technology,7.24,"Sem 1: 6.58
1240
+
1241
+ Sem 2: 8.27
1242
+
1243
+ Sem 3: 6.93
1244
+
1245
+ Sem 4: 8.99
1246
+
1247
+ Sem 5: 9.27
1248
+
1249
+ Sem 6: 7.81",2,"C++ (Beginner), C# (Expert), Go (Beginner)","Docker, Git, MySQL, React, Node.js","Google Cloud Associate
1250
+
1251
+ Oracle Java Certification","Problem-Solving, Communication",65 WPM,Democratic station course full serious another.,"Monroe, Chapman and Barton",https://lawrence.com/,2.0,LeetCode: 2043,GRE,Save network item one under sit travel.,1.0,2.0,0.0,System Engineer,Research,Bangalore,No,89.0,Yes,Medium,INTJ,"Analytical Thinking, Creativity",Perfectionism,Community spring billion price paper focus thing industry.
1252
+ tara72@gmail.com,de945b3a4aaefc980d57b8e56357298a876a5459761a9863828c302b83b8bcec,Melissa Wright,Computer Science and Engineering,8.24,"Sem 1: 8.63
1253
+
1254
+ Sem 2: 9.22
1255
+
1256
+ Sem 3: 9.41
1257
+
1258
+ Sem 4: 9.91
1259
+
1260
+ Sem 5: 7.75
1261
+
1262
+ Sem 6: 7.93",0,"Python (Beginner), C# (Expert), JavaScript (Intermediate)","React, AWS, Git, Node.js, MongoDB","AWS Certified Developer
1263
+
1264
+ Google Cloud Associate","Teamwork, Communication",62 WPM,Federal reduce team Republican very plan cut.,"Klein, Parks and Morse",http://www.daniels.com/,0.0,LeetCode: 514,TOEFL,Lose number project individual security subject experience.,5.0,0.0,1.0,System Engineer,Finance,Chennai,Yes,56.0,Yes,High,ISFJ,"Persistence, Empathy",Procrastination,Space mission agent certainly prove customer.
1265
+ maryvaughn@yahoo.com,5ff723c079d46f152c53166182c66780d9cdd4d596e7e2dad50494b27f40dc7f,Candace Mitchell,Mechanical Engineering,9.08,"Sem 1: 6.83
1266
+
1267
+ Sem 2: 9.15
1268
+
1269
+ Sem 3: 6.66
1270
+
1271
+ Sem 4: 9.48
1272
+
1273
+ Sem 5: 8.82
1274
+
1275
+ Sem 6: 7.1",1,"JavaScript (Expert), C# (Beginner), C++ (Intermediate)","React, Kubernetes, Git, AWS, MongoDB","Google Cloud Associate
1276
+
1277
+ Oracle Java Certification","Problem-Solving, Leadership",60 WPM,Allow sport bill test science ten score.,"Price, Dixon and Robles",https://www.hughes-frye.com/,3.0,LeetCode: 2757,GRE,Approach season data than team kitchen difficult.,0.0,0.0,0.0,Data Scientist,IT,Chennai,No,86.0,No,High,ESFP,"Persistence, Empathy",Perfectionism,Sense national owner simply who family.
1278
+ bennettroy@baker.com,f9a7350c76a8890ab21f06bf272f809c1b1260cd0fc2ee252b2209928e881636,Michael Lopez,Information Technology,8.19,"Sem 1: 8.21
1279
+
1280
+ Sem 2: 9.61
1281
+
1282
+ Sem 3: 8.04
1283
+
1284
+ Sem 4: 6.72
1285
+
1286
+ Sem 5: 8.79
1287
+
1288
+ Sem 6: 6.54",2,"C# (Expert), Go (Expert), Ruby (Beginner)","React, Docker, AWS, MongoDB, MySQL","Google Cloud Associate
1289
+
1290
+ Oracle Java Certification","Problem-Solving, Communication",65 WPM,Always up others similar.,"Gilbert, Stanley and Henry",https://www.stewart.com/,0.0,LeetCode: 147,GRE,City myself idea glass third professional former.,4.0,1.0,1.0,Data Scientist,IT,Chennai,No,65.0,No,Medium,INTJ,"Creativity, Persistence",Shyness,Despite sell most you statement.
1291
+ flemingmanuel@cruz.com,0c09ad671a072cd77977e3209e13793af17e61007c4d5883c6df914c4a7c7697,Mrs. Maureen Griffin,Mechanical Engineering,9.36,"Sem 1: 6.78
1292
+
1293
+ Sem 2: 8.05
1294
+
1295
+ Sem 3: 8.51
1296
+
1297
+ Sem 4: 6.81
1298
+
1299
+ Sem 5: 8.24
1300
+
1301
+ Sem 6: 7.61",1,"Go (Beginner), Ruby (Intermediate), Python (Intermediate)","Git, MongoDB, Node.js, MySQL, GCP","Oracle Java Certification
1302
+
1303
+ Google Cloud Associate","Teamwork, Leadership",59 WPM,State heart sort knowledge analysis together court.,"Miller, Davis and Bonilla",http://www.santiago.biz/,2.0,LeetCode: 1588,GATE,Day stock these scientist.,1.0,1.0,1.0,AI Researcher,Finance,Chennai,Yes,56.0,Yes,High,ISFJ,"Persistence, Empathy",Procrastination,Position vote section child learn forward.
1304
+ rhondarussell@mccoy-hamilton.com,e8530cb052dc75c5eec77e96deb16c5b0648cf2a6556ba13c80b367cbeb26aa0,Anthony Bauer,Electronics and Communication Engineering,8.96,"Sem 1: 6.66
1305
+
1306
+ Sem 2: 7.07
1307
+
1308
+ Sem 3: 6.99
1309
+
1310
+ Sem 4: 9.01
1311
+
1312
+ Sem 5: 9.03
1313
+
1314
+ Sem 6: 6.87",2,"Java (Intermediate), Ruby (Beginner), Python (Intermediate)","AWS, React, Git, MongoDB, Node.js","Oracle Java Certification
1315
+
1316
+ AWS Certified Developer","Problem-Solving, Teamwork",67 WPM,Movement political peace series.,"Williams, Charles and Howard",http://turner.info/,1.0,LeetCode: 2143,GATE,House produce listen mouth carry hospital.,4.0,2.0,0.0,AI Researcher,Research,Hyderabad,Yes,96.0,Yes,High,ESFP,"Persistence, Empathy",Shyness,Far plant fear thought whole term possible.
templates/404.html ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'base.html' %}
2
+ {% block title %}Page Not Found{% endblock %}
3
+ {% block content %}
4
+ <div class="text-center py-5">
5
+ <h1 class="display-1">404</h1>
6
+ <h2>Oops! Page Not Found</h2>
7
+ <p class="lead">The page you are looking for does not exist or has been moved.</p>
8
+ <a href="{{ url_for('home') }}" class="btn btn-primary mt-3">Go to Homepage</a>
9
+ </div>
10
+ {% endblock %}
templates/500.html ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'base.html' %}
2
+ {% block title %}Server Error{% endblock %}
3
+ {% block content %}
4
+ <div class="text-center py-5">
5
+ <h1 class="display-1">500</h1>
6
+ <h2>Oops! Internal Server Error</h2>
7
+ <p class="lead">Something went wrong on our end. We are working to fix it.</p>
8
+ <p>Please try again later or contact support if the problem persists.</p>
9
+ <a href="{{ url_for('home') }}" class="btn btn-primary mt-3">Go to Homepage</a>
10
+ </div>
11
+ {% endblock %}
templates/base.html ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <!-- Block for title -->
7
+ <title>{% block title %}Campus Recruitment Portal{% endblock %}</title>
8
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
9
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
10
+ <!-- Link to your static CSS file -->
11
+ <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
12
+ <!-- Block for additional head elements -->
13
+ {% block head %}{% endblock %}
14
+ </head>
15
+ <body>
16
+ <!-- Optional: Add a common navbar or header here if needed for error pages -->
17
+ <!--
18
+ <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
19
+ <div class="container-fluid">
20
+ <a class="navbar-brand" href="/">Recruitment Portal</a>
21
+ </div>
22
+ </nav>
23
+ -->
24
+
25
+ <div class="container mt-4">
26
+ <!-- Display Flash Messages -->
27
+ {% with messages = get_flashed_messages(with_categories=true) %}
28
+ {% if messages %}
29
+ {% for category, message in messages %}
30
+ <div class="alert alert-{{ category if category in ['danger', 'warning', 'info', 'success'] else 'secondary' }} alert-dismissible fade show" role="alert">
31
+ {{ message }}
32
+ <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
33
+ </div>
34
+ {% endfor %}
35
+ {% endif %}
36
+ {% endwith %}
37
+
38
+ <!-- Block for main content -->
39
+ {% block content %}{% endblock %}
40
+ </div>
41
+
42
+ <!-- Optional: Add a common footer here -->
43
+ <!--
44
+ <footer class="text-center mt-5 py-3 bg-light">
45
+ <small>© {{ now.year }} Campus Recruitment Portal</small>
46
+ </footer>
47
+ -->
48
+
49
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
50
+ <!-- Block for additional scripts -->
51
+ {% block scripts %}{% endblock %}
52
+ </body>
53
+ </html>
templates/company_dashboard.html ADDED
@@ -0,0 +1,890 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Company Dashboard | Campus Recruitment Portal</title>
7
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
8
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
9
+ <!-- Link to your EXTERNAL static CSS file -->
10
+ <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
11
+ <style>
12
+ /* Minimal page-specific overrides */
13
+ .chart-container {
14
+ position: relative;
15
+ height: 280px; /* Default height */
16
+ width: 100%;
17
+ min-height: 200px; /* Ensure minimum height */
18
+ }
19
+ canvas {
20
+ display: block; /* Prevents extra space below canvas */
21
+ max-width: 100%; /* Ensure canvas doesn't overflow container */
22
+ }
23
+ /* Make table header sticky */
24
+ .table-responsive thead {
25
+ position: sticky;
26
+ top: 0;
27
+ z-index: 1;
28
+ /* Background applied by .table-light in the thead tag */
29
+ }
30
+ .filter-section .card-body {
31
+ max-height: calc(100vh - 150px); /* Adjust based on nav height etc. */
32
+ overflow-y: auto;
33
+ }
34
+ @media (max-width: 992px) {
35
+ .filter-section .card-body {
36
+ max-height: none;
37
+ overflow-y: visible;
38
+ }
39
+ }
40
+ /* Style for AI Query section */
41
+ #nl-query-error {
42
+ font-size: 0.85rem;
43
+ }
44
+ </style>
45
+ </head>
46
+ <body>
47
+ <!-- Navigation -->
48
+ <nav class="navbar navbar-expand-lg navbar-dark bg-primary sticky-top shadow-sm">
49
+ <div class="container-fluid">
50
+ <a class="navbar-brand" href="{{ url_for('dashboard') }}">
51
+ <i class="bi bi-building"></i> {{ company_name }} - Portal
52
+ </a>
53
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
54
+ <span class="navbar-toggler-icon"></span>
55
+ </button>
56
+ <div class="collapse navbar-collapse" id="navbarNav">
57
+ <ul class="navbar-nav me-auto mb-2 mb-lg-0">
58
+ <li class="nav-item">
59
+ <a class="nav-link active" aria-current="page" href="{{ url_for('dashboard') }}"><i class="bi bi-speedometer2"></i> Dashboard</a>
60
+ </li>
61
+ <li class="nav-item">
62
+ <a class="nav-link" href="{{ url_for('jobs') }}"><i class="bi bi-briefcase-fill"></i> Job Postings</a>
63
+ </li>
64
+ </ul>
65
+ <ul class="navbar-nav">
66
+ <!-- Display Flash Messages Dropdown -->
67
+ {% with messages = get_flashed_messages(with_categories=true) %}
68
+ {% if messages %}
69
+ <li class="nav-item dropdown">
70
+ <a class="nav-link dropdown-toggle text-warning position-relative" href="#" id="messagesDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
71
+ <i class="bi bi-bell-fill"></i>
72
+ <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger" style="font-size: 0.6em;">
73
+ {{ messages|length }}
74
+ <span class="visually-hidden">notifications</span>
75
+ </span>
76
+ </a>
77
+ <ul class="dropdown-menu dropdown-menu-end shadow border-0 mt-2" aria-labelledby="messagesDropdown" style="min-width: 250px;">
78
+ <li><h6 class="dropdown-header small text-muted">Notifications</h6></li>
79
+ {% for category, message in messages %}
80
+ <li>
81
+ <div class="dropdown-item small py-2">
82
+ <span class="badge bg-{{ category if category in ['danger', 'warning', 'info', 'success'] else 'secondary' }} me-1"> </span>
83
+ {{ message }}
84
+ </div>
85
+ </li>
86
+ {% endfor %}
87
+ <li><hr class="dropdown-divider my-1"></li>
88
+ <li><a class="dropdown-item small text-muted text-center" href="#">View All (Not implemented)</a></li>
89
+ </ul>
90
+ </li>
91
+ {% endif %}
92
+ {% endwith %}
93
+ <li class="nav-item">
94
+ <a class="nav-link" href="{{ url_for('logout') }}" title="Logout">
95
+ <i class="bi bi-box-arrow-right"></i> Logout
96
+ </a>
97
+ </li>
98
+ </ul>
99
+ </div>
100
+ </div>
101
+ </nav>
102
+
103
+ <!-- Main Content -->
104
+ <div class="container-fluid mt-3 main-container">
105
+ <!-- Display top-level error if passed -->
106
+ {% if error %}
107
+ <div class="alert alert-danger alert-dismissible fade show" role="alert">
108
+ {{ error }}
109
+ <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
110
+ </div>
111
+ {% endif %}
112
+
113
+ <div class="row">
114
+ <!-- Filters Column -->
115
+ <div class="col-lg-3">
116
+ <!-- Filters Card -->
117
+ <div class="card mb-3 filter-section shadow-sm">
118
+ <div class="card-header bg-secondary text-white">
119
+ <h5 class="card-title mb-0"><i class="bi bi-filter"></i> Filter Candidates</h5>
120
+ </div>
121
+ <div class="card-body">
122
+ <form id="filter-form">
123
+ <!-- Row for Job Filter (Spans full width initially for emphasis) -->
124
+ <div class="row mb-3">
125
+ <div class="col-12 filter-group border-bottom pb-3">
126
+ <label for="job_id_filter" class="form-label filter-heading">Filter by Job</label>
127
+ <select class="form-select form-select-sm" name="job_id" id="job_id_filter">
128
+ <option value="">(All Candidates / Use Manual Filters)</option>
129
+ {% for job in jobs %}
130
+ <option value="{{ job.id }}">{{ job.title }}</option>
131
+ {% endfor %}
132
+ </select>
133
+ <small class="form-text text-muted">Applies job's requirements & overrides manual filters below if selected.</small>
134
+ </div>
135
+ </div>
136
+
137
+ <!-- Row for the rest of the filters (2 columns on large screens) -->
138
+ <div class="row">
139
+ <!-- Column 1: Basic Criteria & Experience -->
140
+ <div class="col-12 col-lg-6">
141
+ <div class="mb-3 filter-group">
142
+ <label for="min_cgpa_filter" class="form-label filter-heading">Min CGPA</label>
143
+ <input type="number" class="form-control form-control-sm" name="min_cgpa" id="min_cgpa_filter" min="0" max="10" step="0.1" placeholder="e.g., 7.5">
144
+ </div>
145
+
146
+ <div class="mb-3 filter-group">
147
+ <label for="max_backlogs_filter" class="form-label filter-heading">Max Backlogs</label>
148
+ <input type="number" class="form-control form-control-sm" name="max_backlogs" id="max_backlogs_filter" min="0" step="1" placeholder="e.g., 0">
149
+ </div>
150
+
151
+ <div class="mb-3 filter-group">
152
+ <label class="form-label filter-heading">Experience Flags</label>
153
+ <div class="form-check form-switch">
154
+ <input class="form-check-input" type="checkbox" role="switch" name="has_hackathons" id="hasHackathons">
155
+ <label class="form-check-label" for="hasHackathons">Has Hackathon</label>
156
+ </div>
157
+ <div class="form-check form-switch">
158
+ <input class="form-check-input" type="checkbox" role="switch" name="has_experience" id="hasExperience">
159
+ <label class="form-check-label" for="hasExperience">Has Project/Internship</label>
160
+ </div>
161
+ <div class="form-check form-switch">
162
+ <input class="form-check-input" type="checkbox" role="switch" name="has_research" id="hasResearch">
163
+ <label class="form-check-label" for="hasResearch">Has Research/Pubs</label>
164
+ </div>
165
+ </div>
166
+ </div><!-- End Column 1 -->
167
+
168
+ <!-- Column 2: Skills, Roles, Certifications -->
169
+ <div class="col-12 col-lg-6">
170
+ <div class="mb-3 filter-group">
171
+ <label for="skills_filter" class="form-label filter-heading">Skills (any)</label>
172
+ <select class="form-select form-select-sm" name="skills" id="skills_filter" multiple size="5" aria-label="Select skills">
173
+ <!-- Combine programming languages and tools -->
174
+ {% set all_skills = filter_options.programming_languages + filter_options.tools %}
175
+ {% for skill in all_skills | unique | sort %}
176
+ <option value="{{ skill }}">{{ skill }}</option>
177
+ {% endfor %}
178
+ </select>
179
+ <small class="form-text text-muted">Hold Ctrl/Cmd to select multiple</small>
180
+ </div>
181
+
182
+ <div class="mb-3 filter-group">
183
+ <label for="roles_filter" class="form-label filter-heading">Preferred Roles (any)</label>
184
+ <select class="form-select form-select-sm" name="roles" id="roles_filter" multiple size="5" aria-label="Select preferred roles">
185
+ {% for role in filter_options.roles %}
186
+ <option value="{{ role }}">{{ role }}</option>
187
+ {% endfor %}
188
+ </select>
189
+ <small class="form-text text-muted">Hold Ctrl/Cmd to select multiple</small>
190
+ </div>
191
+
192
+ <div class="mb-3 filter-group">
193
+ <label for="certifications_filter" class="form-label filter-heading">Certifications (any)</label>
194
+ <select class="form-select form-select-sm" name="certifications" id="certifications_filter" multiple size="5" aria-label="Select certifications">
195
+ {% for cert in filter_options.certifications %}
196
+ <option value="{{ cert }}">{{ cert }}</option>
197
+ {% endfor %}
198
+ </select>
199
+ <small class="form-text text-muted">Hold Ctrl/Cmd to select multiple</small>
200
+ </div>
201
+ </div><!-- End Column 2 -->
202
+ </div><!-- End Row for columns -->
203
+
204
+ <!-- Buttons (Placed after the columns row) -->
205
+ <div class="d-grid gap-2 mt-3">
206
+ <button type="submit" class="btn btn-primary"><i class="bi bi-funnel-fill"></i> Apply Filters</button>
207
+ <button type="reset" class="btn btn-outline-secondary" id="reset-filters"><i class="bi bi-arrow-clockwise"></i> Reset Filters</button>
208
+ </div>
209
+ </form>
210
+ </div><!-- End card-body -->
211
+ </div><!-- End Filters Card -->
212
+
213
+ <!-- Export Options Card -->
214
+ <div class="card mb-3 shadow-sm">
215
+ <div class="card-header bg-secondary text-white">
216
+ <h5 class="card-title mb-0"><i class="bi bi-download"></i> Export Options</h5>
217
+ </div>
218
+ <div class="card-body">
219
+ <div class="d-grid">
220
+ <button type="button" class="btn btn-success" id="export-csv-btn" disabled>
221
+ <i class="bi bi-file-earmark-spreadsheet"></i> Export Filtered to CSV
222
+ </button>
223
+ </div>
224
+ <small class="form-text text-muted d-block mt-2">Exports the students currently shown in the table.</small>
225
+ <form id="export-form" class="d-none" action="{{ url_for('export_filtered') }}" method="post" target="_blank">
226
+ <input type="hidden" name="filtered_students" id="filtered-students-data-hidden">
227
+ </form>
228
+ </div>
229
+ </div>
230
+ </div> <!-- End Filters Column -->
231
+
232
+ <!-- Main Content Area -->
233
+ <div class="col-lg-9">
234
+
235
+ <!-- Natural Language Query Section -->
236
+ <div class="card mb-3 shadow-sm">
237
+ <div class="card-header bg-light text-dark">
238
+ <h5 class="card-title mb-0"><i class="bi bi-robot"></i> Query Candidates with AI</h5>
239
+ </div>
240
+ <div class="card-body">
241
+ <div id="nl-query-error" class="alert alert-danger d-none p-2" role="alert"></div>
242
+ <div class="mb-2">
243
+ <label for="nl-query-input" class="form-label small">Enter your query (e.g., "Show Computer Science students with CGPA over 8 and Python skill, must have internships")</label>
244
+ <textarea class="form-control form-control-sm" id="nl-query-input" rows="2" placeholder="Describe the candidates you're looking for..."></textarea>
245
+ </div>
246
+ <button type="button" class="btn btn-info btn-sm" id="nl-query-submit">
247
+ <i class="bi bi-magic"></i> Generate & Apply Filters
248
+ </button>
249
+ <span id="nl-query-spinner" class="spinner-border spinner-border-sm text-info ms-2 d-none" role="status" aria-hidden="true"></span>
250
+ <small class="text-muted d-block mt-1">AI will attempt to translate your query into the filters on the left.</small>
251
+ </div>
252
+ </div>
253
+ <!-- End Natural Language Query Section -->
254
+
255
+
256
+ <!-- Visualization Section -->
257
+ <div class="card mb-3 shadow-sm">
258
+ <div class="card-header bg-light text-dark d-flex justify-content-between align-items-center">
259
+ <h5 class="card-title mb-0"><i class="bi bi-bar-chart-line-fill"></i> Data Visualizations <small class="text-muted">(Updates with filters)</small></h5>
260
+ <button class="btn btn-sm btn-outline-secondary" type="button" data-bs-toggle="collapse" data-bs-target="#visualizationsCollapse" aria-expanded="true" aria-controls="visualizationsCollapse" id="collapseVizButton">
261
+ <i class="bi bi-chevron-up"></i> <span>Collapse</span>
262
+ </button>
263
+ </div>
264
+ <div class="collapse show" id="visualizationsCollapse">
265
+ <div class="card-body">
266
+ <div class="row">
267
+ <div class="col-xl-6 col-lg-12 mb-3">
268
+ <div class="card visualization-card h-100 border">
269
+ <div class="card-header small">CGPA Distribution</div>
270
+ <div class="card-body chart-container">
271
+ <canvas id="cgpaChart"></canvas>
272
+ </div>
273
+ </div>
274
+ </div>
275
+ <div class="col-xl-6 col-lg-12 mb-3">
276
+ <div class="card visualization-card h-100 border">
277
+ <div class="card-header small">Department Distribution</div>
278
+ <div class="card-body chart-container">
279
+ <canvas id="deptChart"></canvas>
280
+ </div>
281
+ </div>
282
+ </div>
283
+ <div class="col-xl-6 col-lg-12 mb-3">
284
+ <div class="card visualization-card h-100 border">
285
+ <div class="card-header small">Top Programming Skills</div>
286
+ <div class="card-body chart-container">
287
+ <canvas id="skillsChart"></canvas>
288
+ </div>
289
+ </div>
290
+ </div>
291
+ <div class="col-xl-6 col-lg-12 mb-3">
292
+ <div class="card visualization-card h-100 border">
293
+ <div class="card-header small">Top Preferred Roles</div>
294
+ <div class="card-body chart-container">
295
+ <canvas id="rolesChart"></canvas>
296
+ </div>
297
+ </div>
298
+ </div>
299
+ </div>
300
+ </div>
301
+ </div>
302
+ </div>
303
+
304
+ <!-- Students Table Card -->
305
+ <div class="card mb-3 shadow-sm">
306
+ <div class="card-header bg-light text-dark d-flex justify-content-between align-items-center">
307
+ <h5 class="card-title mb-0">
308
+ <i class="bi bi-people-fill"></i> Students List <span id="student-count" class="badge bg-primary rounded-pill">{{ students|length }}</span>
309
+ </h5>
310
+ <div class="btn-group btn-group-sm">
311
+ <button class="btn btn-outline-primary" id="select-all" title="Select all visible students"><i class="bi bi-check-square"></i> Select All</button>
312
+ <button class="btn btn-outline-primary" id="deselect-all" title="Deselect all visible students"><i class="bi bi-square"></i> Deselect All</button>
313
+ </div>
314
+ </div>
315
+ <div class="card-body p-0">
316
+ <div class="table-responsive" style="max-height: 60vh; overflow-y: auto;">
317
+ <table class="table table-striped table-hover table-sm mb-0">
318
+ <thead class="table-light">
319
+ <tr>
320
+ <th class="text-center" style="width: 3%;"><input type="checkbox" id="select-all-checkbox" class="form-check-input"></th>
321
+ <th style="width: 20%;">Name</th>
322
+ <th style="width: 15%;">Department</th>
323
+ <th style="width: 7%;">CGPA</th>
324
+ <th style="width: 7%;">Backlogs</th>
325
+ <th style="width: 28%;">Top Skills</th>
326
+ <th style="width: 10%;">Experience</th>
327
+ </tr>
328
+ </thead>
329
+ <tbody id="students-tbody">
330
+ <!-- Student rows populated by initial Flask render AND JS updates -->
331
+ {% for student in students %}
332
+ <tr data-email="{{ student.email }}">
333
+ <td class="text-center"><input type="checkbox" class="form-check-input student-checkbox" value="{{ student.email }}"></td>
334
+ <td>{{ student.full_name | default('N/A', true) }}</td>
335
+ <td>{{ student.department | default('N/A', true) }}</td>
336
+ <td>{{ "%.2f"|format(student.cgpa) if student.cgpa is not none else 'N/A' }}</td>
337
+ <td>{{ student.backlogs | default(0, true) }}</td>
338
+ <td>
339
+ {# --- CORRECTED SKILL PROCESSING --- #}
340
+ {% set raw_skills = [] %}
341
+ {% if student.programming_languages %}
342
+ {% if student.programming_languages is string %}
343
+ {% set raw_skills = student.programming_languages.split(',') %}
344
+ {% elif student.programming_languages is iterable and student.programming_languages is not string %} {# Check if it's list-like but not a string #}
345
+ {% set raw_skills = student.programming_languages %}
346
+ {% endif %}
347
+ {% endif %}
348
+
349
+ {# Use namespace to collect unique, cleaned skills #}
350
+ {% set ns = namespace(unique_cleaned_skills=[]) %}
351
+ {% for skill in raw_skills %}
352
+ {% set trimmed_skill = skill | trim %}
353
+ {% if trimmed_skill %}
354
+ {# Basic removal of "(...)" suffix #}
355
+ {% set base_skill = trimmed_skill.split('(')[0] | trim %}
356
+ {% if base_skill and base_skill not in ns.unique_cleaned_skills %}
357
+ {# Append to the list within the namespace #}
358
+ {% set ns.unique_cleaned_skills = ns.unique_cleaned_skills + [base_skill] %}
359
+ {% endif %}
360
+ {% endif %}
361
+ {% endfor %}
362
+
363
+ <small>
364
+ {# Display top 3 unique, cleaned skills #}
365
+ {{ ns.unique_cleaned_skills[:3] | join(', ') }}
366
+ {% if ns.unique_cleaned_skills | length > 3 %}...{% endif %}
367
+ {% if not ns.unique_cleaned_skills %}N/A{% endif %} {# Show N/A if no skills found #}
368
+ </small>
369
+ {# --- END OF CORRECTION --- #}
370
+ </td>
371
+ <td>
372
+ {% if student.internships %}<span class="badge bg-success" title="Internship">I</span>{% endif %}
373
+ {% if student.projects %}<span class="badge bg-primary" title="Projects">P</span>{% endif %}
374
+ {% if student.hackathons %}<span class="badge bg-warning text-dark" title="Hackathon">H</span>{% endif %}
375
+ {% if student.publications %}<span class="badge bg-info text-dark" title="Publication/Research">R</span>{% endif %}
376
+ {% if not student.internships and not student.projects and not student.hackathons and not student.publications %}
377
+ <span class="text-muted small">None</span>
378
+ {% endif %}
379
+ </td>
380
+ </tr>
381
+ {% endfor %}
382
+ </tbody>
383
+ </table>
384
+ </div>
385
+ <div id="no-students-message" class="alert alert-info m-3 {% if students %}d-none{% endif %}">
386
+ No students match the current filters. Try resetting or modifying filters.
387
+ </div>
388
+ </div>
389
+ </div>
390
+
391
+ <!-- AI Insights Section -->
392
+ <div class="card mb-3 shadow-sm">
393
+ <div class="card-header bg-light text-dark">
394
+ <h5 class="card-title mb-0"><i class="bi bi-robot"></i> Gemini-Powered Candidate Insights</h5>
395
+ </div>
396
+ <div class="card-body">
397
+ <form id="ai-insights-form" class="mb-3">
398
+ <div class="row g-2 align-items-end">
399
+ <div class="col-md-6">
400
+ <label for="ai-role-input" class="form-label small mb-1">Job Role for Analysis</label>
401
+ <input type="text" class="form-control form-control-sm" id="ai-role-input" name="role" placeholder="e.g., Software Engineer Intern" required>
402
+ </div>
403
+ <div class="col-md-6">
404
+ <div class="d-grid">
405
+ <button type="submit" class="btn btn-primary btn-sm" id="generate-insights-btn" disabled>
406
+ <i class="bi bi-magic"></i> Generate Insights for Selected (<span id="selected-count">0</span>)
407
+ </button>
408
+ </div>
409
+ </div>
410
+ </div>
411
+ <small class="text-muted d-block mt-1">Select students from the table above first.</small>
412
+ </form>
413
+ <div id="insights-result" class="p-3 border rounded bg-light d-none">
414
+ <h6 class="mb-2">AI Analysis Results <span id="analysis-role" class="text-muted small"></span></h6>
415
+ <div id="insights-spinner" class="text-center d-none my-3">
416
+ <div class="spinner-border text-primary spinner-border-sm" role="status">
417
+ <span class="visually-hidden">Loading...</span>
418
+ </div>
419
+ <p class="mt-1 mb-0 small text-muted">Generating insights...</p>
420
+ </div>
421
+ <div id="insights-content" class="overflow-auto" style="max-height: 450px; white-space: pre-wrap; font-size: 0.9rem; line-height: 1.6;">
422
+ <!-- Insights will be loaded here -->
423
+ </div>
424
+ <div id="insights-error" class="alert alert-danger small p-2 d-none"></div>
425
+ </div>
426
+ </div>
427
+ </div>
428
+ </div> <!-- End Main Content Area Col -->
429
+ </div> <!-- End Row -->
430
+ </div> <!-- End Main Container -->
431
+
432
+ <!-- JavaScript -->
433
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
434
+ <script src="https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js"></script>
435
+
436
+ <!-- Store initial data passed from Flask -->
437
+ <script>
438
+ const initialChartData = {{ initial_chart_data|tojson }};
439
+ // Store the initial full student data (list of dicts) directly if needed, otherwise it's rendered in the table
440
+ let allStudentsInitially = {{ students|tojson|safe }};
441
+ </script>
442
+
443
+ <!-- Custom JS -->
444
+ <script>
445
+ document.addEventListener('DOMContentLoaded', function() {
446
+ console.log("Dashboard DOM Loaded.");
447
+
448
+ // --- DOM Elements ---
449
+ const filterForm = document.getElementById('filter-form');
450
+ const resetButton = document.getElementById('reset-filters');
451
+ const studentsTableBody = document.getElementById('students-tbody');
452
+ const studentCountBadge = document.getElementById('student-count');
453
+ const noStudentsMessage = document.getElementById('no-students-message');
454
+ const exportCsvBtn = document.getElementById('export-csv-btn');
455
+ const aiInsightsForm = document.getElementById('ai-insights-form');
456
+ const aiRoleInput = document.getElementById('ai-role-input');
457
+ const insightsResultDiv = document.getElementById('insights-result');
458
+ const insightsContentDiv = document.getElementById('insights-content');
459
+ const insightsErrorDiv = document.getElementById('insights-error'); // Added error div
460
+ const insightsSpinner = document.getElementById('insights-spinner');
461
+ const generateInsightsBtn = document.getElementById('generate-insights-btn');
462
+ const selectedCountSpan = document.getElementById('selected-count');
463
+ const analysisRoleSpan = document.getElementById('analysis-role');
464
+ const selectAllBtn = document.getElementById('select-all');
465
+ const deselectAllBtn = document.getElementById('deselect-all');
466
+ const selectAllCheckbox = document.getElementById('select-all-checkbox');
467
+ const collapseVizButton = document.getElementById('collapseVizButton');
468
+ const collapseVizIcon = collapseVizButton.querySelector('i');
469
+ const collapseVizText = collapseVizButton.querySelector('span');
470
+ const visualizationsCollapse = document.getElementById('visualizationsCollapse');
471
+ // NL Query Elements
472
+ const nlQueryInput = document.getElementById('nl-query-input');
473
+ const nlQuerySubmitBtn = document.getElementById('nl-query-submit');
474
+ const nlQuerySpinner = document.getElementById('nl-query-spinner');
475
+ const nlQueryErrorDiv = document.getElementById('nl-query-error');
476
+
477
+ // --- Chart Variables ---
478
+ const chartInstances = {}; // Store instances by ID
479
+
480
+ // --- Chart Options ---
481
+ const commonChartOptions = { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { backgroundColor: 'rgba(0, 0, 0, 0.7)', titleFont: { size: 14 }, bodyFont: { size: 12 }, padding: 10 } }, layout: { padding: { top: 5, bottom: 5 } } };
482
+ const verticalBarOptions = { ...commonChartOptions, scales: { y: { beginAtZero: true, ticks: { precision: 0 } } } };
483
+ const horizontalBarOptions = { ...commonChartOptions, indexAxis: 'y', scales: { x: { beginAtZero: true, ticks: { precision: 0 } } } };
484
+ const pieChartOptions = { ...commonChartOptions, plugins: { legend: { position: 'right', labels: { font: { size: 10 }, boxWidth: 10 } }, tooltip: commonChartOptions.plugins.tooltip } };
485
+ const chartColors = ['rgba(0, 123, 255, 0.7)', 'rgba(255, 193, 7, 0.7)', 'rgba(40, 167, 69, 0.7)', 'rgba(220, 53, 69, 0.7)', 'rgba(23, 162, 184, 0.7)', 'rgba(108, 117, 125, 0.7)', 'rgba(52, 58, 64, 0.7)', 'rgba(111, 66, 193, 0.7)', 'rgba(253, 126, 20, 0.7)', 'rgba(32, 201, 151, 0.7)'];
486
+ const chartBorderColors = chartColors.map(color => color.replace('0.7', '1'));
487
+
488
+
489
+ // --- State ---
490
+ let currentFilteredStudentsData = []; // Stores full data for visible students
491
+
492
+ // --- Utility Functions ---
493
+ const getSafe = (fn, defaultVal) => { try { const result = fn(); return (result === undefined || result === null) ? defaultVal : result; } catch (e) { return defaultVal; } };
494
+
495
+ function showCanvasMessage(canvasId, message) {
496
+ const ctx = document.getElementById(canvasId)?.getContext('2d');
497
+ if (ctx) {
498
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
499
+ ctx.save(); ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillStyle = '#aaa'; ctx.font = '14px Arial';
500
+ ctx.fillText(message, ctx.canvas.width / 2, ctx.canvas.height / 2); ctx.restore();
501
+ }
502
+ }
503
+
504
+ function createOrUpdateChart(canvasId, type, chartDataObj, options) {
505
+ const ctx = document.getElementById(canvasId)?.getContext('2d');
506
+ if (!ctx) { console.error(`Canvas element "${canvasId}" not found.`); return; }
507
+ if (chartInstances[canvasId]) { chartInstances[canvasId].destroy(); }
508
+
509
+ const labels = getSafe(() => chartDataObj.labels, []);
510
+ const dataValues = getSafe(() => chartDataObj.data, []);
511
+ const numericData = dataValues.map(Number);
512
+
513
+ if (labels.length === 0 || numericData.length === 0 || numericData.every(v => v === 0 && !isNaN(v))) {
514
+ showCanvasMessage(canvasId, 'No data available'); chartInstances[canvasId] = null; return;
515
+ }
516
+ try {
517
+ chartInstances[canvasId] = new Chart(ctx, { type: type, data: { labels: labels, datasets: [{ label: canvasId.replace('Chart', ''), data: numericData, backgroundColor: chartColors, borderColor: chartBorderColors, borderWidth: 1 }] }, options: options });
518
+ console.log(`Chart updated: ${canvasId}`);
519
+ } catch (error) {
520
+ console.error(`Error creating chart ${canvasId}:`, error); showCanvasMessage(canvasId, 'Error loading chart'); chartInstances[canvasId] = null;
521
+ }
522
+ }
523
+
524
+ function updateAllCharts(chartData) {
525
+ console.log("Updating All Charts (Frontend) with:", chartData);
526
+ if (!chartData) { console.error("updateAllCharts called with null/undefined data."); return; }
527
+ const defaultData = { labels: [], data: [] };
528
+ createOrUpdateChart('cgpaChart', 'bar', chartData.cgpa || defaultData, verticalBarOptions);
529
+ createOrUpdateChart('deptChart', 'pie', chartData.department || defaultData, pieChartOptions);
530
+ createOrUpdateChart('skillsChart', 'bar', chartData.skills || defaultData, horizontalBarOptions);
531
+ createOrUpdateChart('rolesChart', 'bar', chartData.roles || defaultData, horizontalBarOptions);
532
+ }
533
+
534
+ function updateStudentsTable(students) {
535
+ console.log(`Updating table with ${students ? students.length : 0} students.`);
536
+ studentsTableBody.innerHTML = '';
537
+ currentFilteredStudentsData = students || []; // Store full data for export/AI
538
+
539
+ if (!currentFilteredStudentsData || currentFilteredStudentsData.length === 0) {
540
+ noStudentsMessage.classList.remove('d-none');
541
+ exportCsvBtn.disabled = true;
542
+ } else {
543
+ noStudentsMessage.classList.add('d-none');
544
+ exportCsvBtn.disabled = false;
545
+ currentFilteredStudentsData.forEach(student => {
546
+ const row = document.createElement('tr');
547
+ row.dataset.email = student.email;
548
+
549
+ const fullName = getSafe(() => student.full_name, 'N/A');
550
+ const department = getSafe(() => student.department, 'N/A');
551
+ const cgpa = getSafe(() => student.cgpa, null);
552
+ const cgpaFormatted = cgpa !== null ? cgpa.toFixed(2) : 'N/A';
553
+ const backlogs = getSafe(() => student.backlogs, 0);
554
+
555
+ // Simplified Skill Display Logic (handles list or string)
556
+ let skillsRaw = getSafe(() => student.programming_languages, []);
557
+ let skillsArray = [];
558
+ if (typeof skillsRaw === 'string') {
559
+ skillsArray = skillsRaw.split(',').map(s => s.trim()).filter(Boolean);
560
+ } else if (Array.isArray(skillsRaw)) {
561
+ skillsArray = skillsRaw.map(s => String(s).trim()).filter(Boolean);
562
+ }
563
+ // Remove proficiency in brackets for display
564
+ const skillsCleaned = skillsArray.map(s => s.replace(/\s*\(.*\)$/, ''));
565
+ const topSkills = skillsCleaned.slice(0, 3).join(', ') + (skillsCleaned.length > 3 ? '...' : '');
566
+
567
+
568
+ let experienceHtml = '';
569
+ if (getSafe(() => student.internships, null)) experienceHtml += '<span class="badge bg-success" title="Internship">I</span> ';
570
+ if (getSafe(() => student.projects, null)) experienceHtml += '<span class="badge bg-primary" title="Projects">P</span> ';
571
+ if (getSafe(() => student.hackathons, null)) experienceHtml += '<span class="badge bg-warning text-dark" title="Hackathon">H</span> ';
572
+ if (getSafe(() => student.publications, null)) experienceHtml += '<span class="badge bg-info text-dark" title="Publication/Research">R</span> ';
573
+ if (!experienceHtml) experienceHtml = '<span class="text-muted small">None</span>';
574
+
575
+ row.innerHTML = `
576
+ <td class="text-center"><input type="checkbox" class="form-check-input student-checkbox" value="${student.email}"></td>
577
+ <td>${fullName}</td>
578
+ <td>${department}</td>
579
+ <td>${cgpaFormatted}</td>
580
+ <td>${backlogs}</td>
581
+ <td><small>${topSkills || 'N/A'}</small></td>
582
+ <td>${experienceHtml.trim()}</td>
583
+ `;
584
+ studentsTableBody.appendChild(row);
585
+ });
586
+ }
587
+ studentCountBadge.textContent = currentFilteredStudentsData.length;
588
+ selectAllCheckbox.checked = false;
589
+ updateAiButtonState();
590
+ }
591
+
592
+ function updateAiButtonState() {
593
+ const selectedCheckboxes = studentsTableBody.querySelectorAll('.student-checkbox:checked');
594
+ const count = selectedCheckboxes.length;
595
+ selectedCountSpan.textContent = count;
596
+ generateInsightsBtn.disabled = count === 0;
597
+ }
598
+
599
+ function exportToCsv(filename, rows) {
600
+ console.log(`Exporting ${rows.length} rows to ${filename}`);
601
+ if (rows.length === 0) { alert("No data to export."); return; }
602
+ // Use the actual headers from the first row object keys for flexibility
603
+ const headers = Object.keys(rows[0]);
604
+ const processRow = (row) => headers.map(header => {
605
+ let value = row[header]; if (value === null || value === undefined) return ''; if (Array.isArray(value)) value = value.join('; '); let stringValue = String(value); if (stringValue.includes('"') || stringValue.includes(',') || stringValue.includes('\n')) stringValue = `"${stringValue.replace(/"/g, '""')}"`; return stringValue;
606
+ }).join(',');
607
+ const csvContent = [headers.join(','), ...rows.map(processRow)].join('\n');
608
+ const blob = new Blob([`\uFEFF${csvContent}`], { type: 'text/csv;charset=utf-8;' }); // Add BOM
609
+ const link = document.createElement("a");
610
+ if (link.download !== undefined) { const url = URL.createObjectURL(blob); link.setAttribute("href", url); link.setAttribute("download", filename); link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); } else { alert("CSV export is not supported."); }
611
+ }
612
+
613
+ // --- Function to update filter form from AI results ---
614
+ function updateFilterForm(filters) {
615
+ console.log("Updating filter form with:", filters);
616
+ // Resetting form ensures clean slate
617
+ filterForm.reset();
618
+ // Reset multi-selects explicitly
619
+ filterForm.querySelectorAll('select[multiple]').forEach(select => {
620
+ Array.from(select.options).forEach(option => option.selected = false);
621
+ });
622
+
623
+ // Clear Job ID filter if applying manual/AI filters
624
+ document.getElementById('job_id_filter').value = '';
625
+
626
+ // Apply filters from AI
627
+ if (filters.min_cgpa !== undefined && filters.min_cgpa !== null) {
628
+ document.getElementById('min_cgpa_filter').value = filters.min_cgpa;
629
+ } else {
630
+ document.getElementById('min_cgpa_filter').value = ''; // Explicitly clear if null/undefined
631
+ }
632
+ if (filters.max_backlogs !== undefined && filters.max_backlogs !== null) {
633
+ document.getElementById('max_backlogs_filter').value = filters.max_backlogs;
634
+ } else {
635
+ document.getElementById('max_backlogs_filter').value = ''; // Explicitly clear
636
+ }
637
+
638
+ // Boolean flags
639
+ document.getElementById('hasHackathons').checked = filters.has_hackathons === true;
640
+ document.getElementById('hasExperience').checked = filters.has_experience === true;
641
+ document.getElementById('hasResearch').checked = filters.has_research === true;
642
+
643
+ // Handle multi-selects (Skills, Roles, Certifications)
644
+ function applyMultiSelect(selectId, values) {
645
+ if (values && Array.isArray(values) && values.length > 0) {
646
+ const selectElement = document.getElementById(selectId);
647
+ if (selectElement) {
648
+ Array.from(selectElement.options).forEach(option => {
649
+ option.selected = values.some(val =>
650
+ option.value.toLowerCase() === String(val).toLowerCase().trim() ||
651
+ option.text.toLowerCase() === String(val).toLowerCase().trim()
652
+ );
653
+ });
654
+ } else {
655
+ console.warn(`Select element #${selectId} not found.`);
656
+ }
657
+ }
658
+ }
659
+
660
+ applyMultiSelect('skills_filter', filters.skills);
661
+ applyMultiSelect('roles_filter', filters.roles);
662
+ applyMultiSelect('certifications_filter', filters.certifications);
663
+
664
+ // Handle department (if mentioned by AI and a filter field exists)
665
+ // Note: 'department' is not currently a standard filter field in the form
666
+ if (filters.department) {
667
+ console.log(`AI suggested department filter: ${filters.department} (No dedicated form field yet)`);
668
+ // If you add a department filter input/select later, update it here:
669
+ // const deptSelect = document.getElementById('department_filter');
670
+ // if (deptSelect) deptSelect.value = filters.department;
671
+ }
672
+
673
+ console.log("Filter form updated by AI result.");
674
+ }
675
+
676
+
677
+ // --- Event Listeners ---
678
+ filterForm.addEventListener('submit', function(e) {
679
+ e.preventDefault(); const formData = new FormData(filterForm);
680
+ console.log("Applying Filters (Manual or AI Triggered)...");
681
+ filterForm.querySelector('button[type="submit"]').disabled = true;
682
+ filterForm.querySelector('button[type="submit"]').innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Filtering...';
683
+ noStudentsMessage.classList.add('d-none'); // Hide message initially
684
+
685
+ // Clear Job ID if manual filters are being changed (except job ID itself)
686
+ const jobIdFilter = document.getElementById('job_id_filter');
687
+ if (e.submitter !== jobIdFilter && jobIdFilter.value !== '') {
688
+ // Check if the submit was triggered by something other than changing the job filter itself
689
+ // AND if a job ID was previously selected. This logic might need refinement depending on desired interaction.
690
+ // A simpler approach might be to always clear job ID if any manual filter is touched.
691
+ // console.log("Manual filter change detected, clearing Job ID filter.");
692
+ // jobIdFilter.value = '';
693
+ // formData.set('job_id', ''); // Update formData as well
694
+ }
695
+
696
+
697
+ fetch('{{ url_for("filter_students_route") }}', { method: 'POST', body: formData })
698
+ .then(response => { if (!response.ok) { return response.json().then(errData => { throw new Error(getSafe(() => errData.error, `HTTP ${response.status}`)); }).catch(() => { throw new Error(`HTTP ${response.status}`); }); } return response.json(); })
699
+ .then(data => {
700
+ console.log("Filter Response:", data);
701
+ if (data.error) { throw new Error(data.error); }
702
+ updateStudentsTable(data.students); // Update table with full data
703
+ if (data.chart_data) {
704
+ updateAllCharts(data.chart_data);
705
+ } else { console.error("Chart data missing in filter response!"); }
706
+ exportCsvBtn.disabled = data.students.length === 0;
707
+ })
708
+ .catch(error => {
709
+ console.error('Filter Error:', error);
710
+ noStudentsMessage.textContent = `Error applying filters: ${error.message}`;
711
+ noStudentsMessage.classList.remove('d-none', 'alert-info');
712
+ noStudentsMessage.classList.add('alert-danger');
713
+ studentsTableBody.innerHTML = ''; // Clear table on error
714
+ studentCountBadge.textContent = 0;
715
+ updateAllCharts({ cgpa: {}, department: {}, skills: {}, roles: {} }); // Clear charts
716
+ exportCsvBtn.disabled = true;
717
+ })
718
+ .finally(() => {
719
+ filterForm.querySelector('button[type="submit"]').disabled = false;
720
+ filterForm.querySelector('button[type="submit"]').innerHTML = '<i class="bi bi-funnel-fill"></i> Apply Filters';
721
+ });
722
+ });
723
+
724
+ resetButton.addEventListener('click', function() {
725
+ console.log("Resetting filters...");
726
+ filterForm.reset();
727
+ // Explicitly reset multi-selects
728
+ filterForm.querySelectorAll('select[multiple]').forEach(select => {
729
+ Array.from(select.options).forEach(option => option.selected = false);
730
+ });
731
+ // Reset Job ID filter
732
+ document.getElementById('job_id_filter').value = '';
733
+ // Automatically trigger a filter update after reset
734
+ setTimeout(() => filterForm.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true })), 50);
735
+ });
736
+
737
+ exportCsvBtn.addEventListener('click', () => {
738
+ const timestamp = new Date().toISOString().slice(0, 19).replace(/[-T:]/g, "");
739
+ const filename = `filtered_students_${timestamp}.csv`;
740
+ // Export the stored full data of currently filtered students
741
+ exportToCsv(filename, currentFilteredStudentsData);
742
+ });
743
+
744
+ selectAllBtn.addEventListener('click', () => { studentsTableBody.querySelectorAll('.student-checkbox:not(:disabled)').forEach(cb => cb.checked = true); selectAllCheckbox.checked = true; updateAiButtonState(); });
745
+ deselectAllBtn.addEventListener('click', () => { studentsTableBody.querySelectorAll('.student-checkbox:not(:disabled)').forEach(cb => cb.checked = false); selectAllCheckbox.checked = false; updateAiButtonState(); });
746
+ selectAllCheckbox.addEventListener('change', function() { studentsTableBody.querySelectorAll('.student-checkbox:not(:disabled)').forEach(cb => cb.checked = this.checked); updateAiButtonState(); });
747
+ studentsTableBody.addEventListener('change', function(event) {
748
+ if (event.target.classList.contains('student-checkbox')) {
749
+ updateAiButtonState();
750
+ const allVisible = studentsTableBody.querySelectorAll('.student-checkbox:not(:disabled)');
751
+ const checkedVisible = studentsTableBody.querySelectorAll('.student-checkbox:checked:not(:disabled)');
752
+ selectAllCheckbox.checked = allVisible.length > 0 && allVisible.length === checkedVisible.length;
753
+ }
754
+ });
755
+
756
+ aiInsightsForm.addEventListener('submit', function(e) {
757
+ e.preventDefault();
758
+ const selectedStudents = Array.from(studentsTableBody.querySelectorAll('.student-checkbox:checked')).map(cb => cb.value);
759
+ const role = aiRoleInput.value.trim();
760
+
761
+ if (selectedStudents.length === 0) { alert('Please select one or more students from the table first.'); return; }
762
+ if (!role) { alert('Please enter the Job Role for analysis.'); aiRoleInput.focus(); return; }
763
+
764
+ const formData = new FormData();
765
+ selectedStudents.forEach(email => formData.append('selected_students', email));
766
+ formData.append('role', role);
767
+
768
+ insightsResultDiv.classList.remove('d-none');
769
+ insightsContentDiv.innerHTML = '';
770
+ insightsErrorDiv.classList.add('d-none'); // Hide previous errors
771
+ insightsSpinner.classList.remove('d-none');
772
+ generateInsightsBtn.disabled = true;
773
+ generateInsightsBtn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Generating...';
774
+ analysisRoleSpan.textContent = `(for ${role})`;
775
+
776
+ fetch('{{ url_for("ai_insights_route") }}', { method: 'POST', body: formData })
777
+ .then(response => { if (!response.ok) { return response.json().then(errData => { throw new Error(getSafe(() => errData.error, `HTTP ${response.status}`)); }).catch(() => { throw new Error(`HTTP ${response.status}`); }); } return response.json(); })
778
+ .then(data => {
779
+ console.log("AI Insights Response:", data);
780
+ if (data.error) {
781
+ throw new Error(data.error); // Throw error to be caught below
782
+ } else {
783
+ let formatted = data.insights || "No insights generated.";
784
+ // Basic Markdown-like formatting
785
+ formatted = formatted
786
+ .replace(/</g, "<").replace(/>/g, ">") // Basic HTML escaping first
787
+ .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>') // Bold
788
+ .replace(/\*(.*?)\*/g, '<em>$1</em>') // Italics
789
+ .replace(/^### (.*$)/gim, '<h6 class="mt-2 mb-1">$1</h6>') // Headings
790
+ .replace(/^## (.*$)/gim, '<h5 class="mt-2 mb-1">$1</h5>')
791
+ .replace(/^# (.*$)/gim, '<h4 class="mt-2 mb-1">$1</h4>')
792
+ .replace(/^\s*[-*+] (.*$)/gim, '<li>$1</li>'); // List items
793
+
794
+ // Wrap consecutive list items in <ul>
795
+ formatted = formatted.replace(/(<li>.*<\/li>\s*)+/g, (match) => `<ul class="list-unstyled mb-2 ms-3">${match.replace(/<\/li>\s*<li>/g, '</li><li>')}</ul>`);
796
+
797
+ // Replace newlines with <br>, but not inside lists or after headings
798
+ formatted = formatted.replace(/(\<\/(?:ul|h[4-6])\>)\n+/g, '$1'); // Remove newlines after block elements
799
+ formatted = formatted.replace(/\n/g, '<br>'); // Convert remaining newlines
800
+
801
+ insightsContentDiv.innerHTML = formatted;
802
+ insightsErrorDiv.classList.add('d-none');
803
+ }
804
+ })
805
+ .catch(error => {
806
+ console.error('AI Insights Error:', error);
807
+ insightsErrorDiv.textContent = `Error: ${error.message}`;
808
+ insightsErrorDiv.classList.remove('d-none');
809
+ insightsContentDiv.innerHTML = ''; // Clear content on error
810
+ })
811
+ .finally(() => {
812
+ insightsSpinner.classList.add('d-none');
813
+ // Re-enable button using the count from the function
814
+ updateAiButtonState();
815
+ const currentCount = studentsTableBody.querySelectorAll('.student-checkbox:checked').length;
816
+ generateInsightsBtn.innerHTML = `<i class="bi bi-magic"></i> Generate Insights for Selected (${currentCount})`;
817
+ });
818
+ });
819
+
820
+ // Event Listener for Natural Language Query
821
+ nlQuerySubmitBtn.addEventListener('click', function() {
822
+ const query = nlQueryInput.value.trim();
823
+ if (!query) {
824
+ nlQueryErrorDiv.textContent = 'Please enter a query.';
825
+ nlQueryErrorDiv.classList.remove('d-none');
826
+ return;
827
+ }
828
+
829
+ nlQuerySubmitBtn.disabled = true;
830
+ nlQuerySpinner.classList.remove('d-none');
831
+ nlQueryErrorDiv.classList.add('d-none');
832
+ nlQueryErrorDiv.textContent = '';
833
+
834
+ fetch('{{ url_for("process_nl_query") }}', {
835
+ method: 'POST',
836
+ headers: { 'Content-Type': 'application/json' },
837
+ body: JSON.stringify({ query: query })
838
+ })
839
+ .then(response => {
840
+ if (!response.ok) {
841
+ return response.json().then(errData => { throw new Error(errData.error || `HTTP error! Status: ${response.status}`); })
842
+ .catch(() => { throw new Error(`HTTP error! Status: ${response.status}`); });
843
+ }
844
+ return response.json();
845
+ })
846
+ .then(data => {
847
+ if (data.error) { throw new Error(data.error); }
848
+ console.log("Received filter parameters from AI:", data.filters);
849
+ updateFilterForm(data.filters);
850
+ console.log("Triggering filter form submission...");
851
+ // Use setTimeout to allow the browser to update the form values before submitting
852
+ setTimeout(() => {
853
+ filterForm.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
854
+ }, 50); // Small delay
855
+ })
856
+ .catch(error => {
857
+ console.error('Error processing NL query:', error);
858
+ nlQueryErrorDiv.textContent = `Error translating query: ${error.message}`;
859
+ nlQueryErrorDiv.classList.remove('d-none');
860
+ })
861
+ .finally(() => {
862
+ nlQuerySubmitBtn.disabled = false;
863
+ nlQuerySpinner.classList.add('d-none');
864
+ });
865
+ });
866
+
867
+ visualizationsCollapse.addEventListener('show.bs.collapse', () => { collapseVizIcon.classList.replace('bi-chevron-down', 'bi-chevron-up'); collapseVizText.textContent = 'Collapse'; });
868
+ visualizationsCollapse.addEventListener('hide.bs.collapse', () => { collapseVizIcon.classList.replace('bi-chevron-up', 'bi-chevron-down'); collapseVizText.textContent = 'Expand'; });
869
+
870
+
871
+ // --- Initial Load ---
872
+ console.log("--- Initializing Dashboard ---");
873
+ // Data is rendered server-side initially. JS updates state.
874
+ currentFilteredStudentsData = allStudentsInitially; // Initialize JS state
875
+ updateAiButtonState(); // Set initial AI button state
876
+ exportCsvBtn.disabled = currentFilteredStudentsData.length === 0; // Set initial export button state
877
+
878
+ if (initialChartData) {
879
+ console.log("Initializing Charts with Initial Data (Frontend):", initialChartData);
880
+ updateAllCharts(initialChartData);
881
+ } else {
882
+ console.error("Initial chart data is missing!");
883
+ updateAllCharts({ cgpa: {}, department: {}, skills: {}, roles: {} }); // Init empty charts
884
+ }
885
+ console.log("--- Dashboard Initialized ---");
886
+ }); // End DOMContentLoaded
887
+ </script>
888
+
889
+ </body>
890
+ </html>
templates/company_login.html ADDED
@@ -0,0 +1,458 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Company Login | Campus Recruitment Portal</title>
7
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
8
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
9
+ <style>
10
+ /* Campus Recruitment Portal - Main Stylesheet
11
+ This file contains styles for all pages in the application */
12
+ :root {
13
+ --primary-color: #0d6efd;
14
+ --primary-dark: #0b5ed7;
15
+ --secondary-color: #6c757d;
16
+ --success-color: #198754;
17
+ --info-color: #0dcaf0;
18
+ --warning-color: #ffc107;
19
+ --danger-color: #dc3545;
20
+ --light-color: #f8f9fa;
21
+ --dark-color: #212529;
22
+ --border-radius: 0.375rem;
23
+ --box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
24
+ }
25
+
26
+ body {
27
+ font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
28
+ background-color: #f5f5f5;
29
+ color: #333;
30
+ }
31
+
32
+ /* ======= Typography ======= */
33
+ h1, h2, h3, h4, h5, h6 {
34
+ font-weight: 600;
35
+ margin-bottom: 1rem;
36
+ }
37
+
38
+ .text-primary {
39
+ color: var(--primary-color) !important;
40
+ }
41
+
42
+ /* ======= Layout Components ======= */
43
+ .main-container {
44
+ padding-top: 1.5rem;
45
+ padding-bottom: 2rem;
46
+ }
47
+
48
+ .card {
49
+ border-radius: var(--border-radius);
50
+ box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
51
+ margin-bottom: 1.5rem;
52
+ border: none;
53
+ }
54
+
55
+ .card-header {
56
+ background-color: rgba(0, 0, 0, 0.03);
57
+ border-bottom: 1px solid rgba(0, 0, 0, 0.125);
58
+ padding: 0.75rem 1.25rem;
59
+ }
60
+
61
+ .card-header.bg-primary {
62
+ background-color: var(--primary-color) !important;
63
+ color: white;
64
+ }
65
+
66
+ .card-header.bg-secondary {
67
+ background-color: var(--secondary-color) !important;
68
+ color: white;
69
+ }
70
+
71
+ .card-body {
72
+ padding: 1.25rem;
73
+ }
74
+
75
+ .card-footer {
76
+ padding: 0.75rem 1.25rem;
77
+ background-color: rgba(0, 0, 0, 0.03);
78
+ border-top: 1px solid rgba(0, 0, 0, 0.125);
79
+ }
80
+
81
+ /* ======= Navigation ======= */
82
+ .navbar {
83
+ padding: 0.5rem 1rem;
84
+ box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
85
+ }
86
+
87
+ .navbar-brand {
88
+ font-weight: 600;
89
+ font-size: 1.25rem;
90
+ }
91
+
92
+ .nav-link {
93
+ padding: 0.5rem 1rem;
94
+ transition: all 0.2s ease-in-out;
95
+ }
96
+
97
+ .nav-link:hover {
98
+ opacity: 0.85;
99
+ }
100
+
101
+ .nav-link.active {
102
+ font-weight: 600;
103
+ background-color: rgba(255, 255, 255, 0.1);
104
+ }
105
+
106
+ /* ======= Forms ======= */
107
+ .form-control, .form-select {
108
+ border-radius: var(--border-radius);
109
+ padding: 0.375rem 0.75rem;
110
+ border: 1px solid #ced4da;
111
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
112
+ }
113
+
114
+ .form-control:focus, .form-select:focus {
115
+ border-color: rgba(13, 110, 253, 0.5);
116
+ box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
117
+ }
118
+
119
+ .form-label {
120
+ margin-bottom: 0.5rem;
121
+ font-weight: 500;
122
+ }
123
+
124
+ .form-text {
125
+ color: #6c757d;
126
+ margin-top: 0.25rem;
127
+ }
128
+
129
+ /* ======= Login Page ======= */
130
+ .login-container {
131
+ min-height: 100vh;
132
+ display: flex;
133
+ align-items: center;
134
+ justify-content: center;
135
+ }
136
+
137
+ .login-card {
138
+ width: 100%;
139
+ max-width: 450px;
140
+ box-shadow: var(--box-shadow);
141
+ }
142
+
143
+ .demo-credentials {
144
+ background-color: #f8f9fa;
145
+ padding: 0.75rem;
146
+ border-radius: var(--border-radius);
147
+ margin-top: 1rem;
148
+ }
149
+
150
+ /* ======= Dashboard ======= */
151
+ .dashboard-stats {
152
+ padding: 1.5rem;
153
+ background-color: white;
154
+ box-shadow: var(--box-shadow);
155
+ border-radius: var(--border-radius);
156
+ margin-bottom: 1.5rem;
157
+ }
158
+
159
+ .stats-card {
160
+ text-align: center;
161
+ padding: 1.25rem;
162
+ border: 1px solid rgba(0, 0, 0, 0.125);
163
+ border-radius: var(--border-radius);
164
+ background-color: white;
165
+ }
166
+
167
+ .stats-icon {
168
+ font-size: 2rem;
169
+ margin-bottom: 0.75rem;
170
+ }
171
+
172
+ .stats-value {
173
+ font-size: 2rem;
174
+ font-weight: 600;
175
+ margin-bottom: 0.25rem;
176
+ }
177
+
178
+ .stats-label {
179
+ color: #6c757d;
180
+ font-size: 0.875rem;
181
+ }
182
+
183
+ /* ======= Filter Section ======= */
184
+ .filter-section {
185
+ background-color: white;
186
+ border-radius: var(--border-radius);
187
+ margin-bottom: 1.5rem;
188
+ }
189
+
190
+ .filter-heading {
191
+ font-weight: 600;
192
+ margin-bottom: 1rem;
193
+ }
194
+
195
+ .filter-group {
196
+ margin-bottom: 1.25rem;
197
+ }
198
+
199
+ /* ======= Tables ======= */
200
+ .table {
201
+ margin-bottom: 0;
202
+ }
203
+
204
+ .table-striped tbody tr:nth-of-type(odd) {
205
+ background-color: rgba(0, 0, 0, 0.02);
206
+ }
207
+
208
+ .table th {
209
+ font-weight: 600;
210
+ border-top: none;
211
+ }
212
+
213
+ .table-hover tbody tr:hover {
214
+ background-color: rgba(13, 110, 253, 0.05);
215
+ }
216
+
217
+ /* ======= Badges ======= */
218
+ .badge {
219
+ padding: 0.35em 0.65em;
220
+ font-weight: 500;
221
+ border-radius: 0.25rem;
222
+ margin-right: 0.25rem;
223
+ }
224
+
225
+ .skills-container {
226
+ display: flex;
227
+ flex-wrap: wrap;
228
+ gap: 0.25rem;
229
+ }
230
+
231
+ /* ======= Visualization Section ======= */
232
+ .visualization-card {
233
+ height: 100%;
234
+ }
235
+
236
+ .visualization-chart {
237
+ width: 100%;
238
+ height: auto;
239
+ }
240
+
241
+ /* ======= Job Listings ======= */
242
+ .job-card {
243
+ transition: transform 0.2s ease-in-out;
244
+ height: 100%;
245
+ }
246
+
247
+ .job-card:hover {
248
+ transform: translateY(-5px);
249
+ box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
250
+ }
251
+
252
+ .job-title {
253
+ font-weight: 600;
254
+ margin-bottom: 0.5rem;
255
+ }
256
+
257
+ .job-location {
258
+ color: #6c757d;
259
+ font-size: 0.875rem;
260
+ }
261
+
262
+ .job-skills {
263
+ margin-top: 0.5rem;
264
+ margin-bottom: 1rem;
265
+ }
266
+
267
+ /* ======= Student Details ======= */
268
+ .student-profile {
269
+ padding: 1.5rem;
270
+ }
271
+
272
+ .student-name {
273
+ font-size: 1.5rem;
274
+ font-weight: 600;
275
+ margin-bottom: 0.5rem;
276
+ }
277
+
278
+ .student-info {
279
+ margin-bottom: 0.5rem;
280
+ }
281
+
282
+ .section-heading {
283
+ font-weight: 600;
284
+ margin-bottom: 0.75rem;
285
+ border-bottom: 1px solid #e9ecef;
286
+ padding-bottom: 0.5rem;
287
+ }
288
+
289
+ /* ======= AI Insights ======= */
290
+ .insights-section {
291
+ background-color: #f8f9fa;
292
+ padding: 1.5rem;
293
+ border-radius: var(--border-radius);
294
+ margin-bottom: 1.5rem;
295
+ }
296
+
297
+ .insights-text {
298
+ white-space: pre-wrap;
299
+ max-height: 500px;
300
+ overflow-y: auto;
301
+ padding: 1rem;
302
+ background-color: white;
303
+ border: 1px solid #dee2e6;
304
+ border-radius: var(--border-radius);
305
+ }
306
+
307
+ /* ======= Button Styles ======= */
308
+ .btn {
309
+ padding: 0.375rem 0.75rem;
310
+ border-radius: var(--border-radius);
311
+ font-weight: 500;
312
+ transition: all 0.2s ease-in-out;
313
+ }
314
+
315
+ .btn-primary {
316
+ background-color: var(--primary-color);
317
+ border-color: var(--primary-color);
318
+ }
319
+
320
+ .btn-primary:hover {
321
+ background-color: var(--primary-dark);
322
+ border-color: var(--primary-dark);
323
+ }
324
+
325
+ .btn-outline-primary {
326
+ color: var(--primary-color);
327
+ border-color: var(--primary-color);
328
+ }
329
+
330
+ .btn-outline-primary:hover {
331
+ background-color: var(--primary-color);
332
+ color: white;
333
+ border-color: var(--primary-color);
334
+ }
335
+
336
+ .btn-sm {
337
+ padding: 0.25rem 0.5rem;
338
+ font-size: 0.875rem;
339
+ }
340
+
341
+ /* ======= Modals ======= */
342
+ .modal-header {
343
+ padding: 1rem;
344
+ border-bottom: 1px solid #dee2e6;
345
+ }
346
+
347
+ .modal-body {
348
+ padding: 1.5rem;
349
+ }
350
+
351
+ .modal-footer {
352
+ padding: 1rem;
353
+ border-top: 1px solid #dee2e6;
354
+ }
355
+
356
+ /* ======= Alerts ======= */
357
+ .alert {
358
+ padding: 1rem;
359
+ margin-bottom: 1rem;
360
+ border-radius: var(--border-radius);
361
+ }
362
+
363
+ /* ======= Spinner ======= */
364
+ .spinner-container {
365
+ display: flex;
366
+ justify-content: center;
367
+ align-items: center;
368
+ padding: 2rem;
369
+ }
370
+
371
+ .spinner-border {
372
+ width: 3rem;
373
+ height: 3rem;
374
+ }
375
+
376
+ /* ======= Responsive Adjustments ======= */
377
+ @media (max-width: 768px) {
378
+ .card-body {
379
+ padding: 1rem;
380
+ }
381
+
382
+ .navbar-brand {
383
+ font-size: 1rem;
384
+ }
385
+
386
+ .stats-value {
387
+ font-size: 1.5rem;
388
+ }
389
+
390
+ .stats-icon {
391
+ font-size: 1.5rem;
392
+ }
393
+
394
+ .table-responsive {
395
+ border: 0;
396
+ }
397
+ }
398
+
399
+ /* ======= Print Styles ======= */
400
+ @media print {
401
+ .navbar, .card-header, .btn, .filter-section {
402
+ display: none !important;
403
+ }
404
+
405
+ .card {
406
+ box-shadow: none !important;
407
+ border: 1px solid #dee2e6 !important;
408
+ }
409
+
410
+ .container-fluid {
411
+ width: 100% !important;
412
+ max-width: none !important;
413
+ }
414
+ }
415
+ </style>
416
+ </head>
417
+ <body class="bg-light">
418
+ <div class="container">
419
+ <div class="row justify-content-center mt-5">
420
+ <div class="col-md-6">
421
+ <div class="card shadow-lg">
422
+ <div class="card-header bg-primary text-white text-center">
423
+ <h3>Campus Recruitment Portal</h3>
424
+ <h4>Company Login</h4>
425
+ </div>
426
+ <div class="card-body p-4">
427
+ {% if error %}
428
+ <div class="alert alert-danger" role="alert">
429
+ {{ error }}
430
+ </div>
431
+ {% endif %}
432
+ <form method="POST" action="{{ url_for('login') }}">
433
+ <div class="mb-3">
434
+ <label for="email" class="form-label">Email address</label>
435
+ <input type="email" class="form-control" id="email" name="email" required>
436
+ </div>
437
+ <div class="mb-3">
438
+ <label for="password" class="form-label">Password</label>
439
+ <input type="password" class="form-control" id="password" name="password" required>
440
+ </div>
441
+ <div class="d-grid gap-2">
442
+ <button type="submit" class="btn btn-primary">Log In</button>
443
+ </div>
444
+ </form>
445
+ </div>
446
+ <div class="card-footer text-center">
447
+ <small class="text-muted">Demo Credentials:<br>
448
+ Email: google@example.com | Password: google123<br>
449
+ Email: microsoft@example.com | Password: microsoft123<br>
450
+ Email: amazon@example.com | Password: amazon123
451
+ </small>
452
+ </div>
453
+ </div>
454
+ </div>
455
+ </div>
456
+ </div>
457
+ </body>
458
+ </html>
templates/job_details.html ADDED
@@ -0,0 +1,820 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>{{ job.title }} | Job Details</title>
7
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
8
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
9
+ <style>
10
+ /* Campus Recruitment Portal - Main Stylesheet
11
+ This file contains styles for all pages in the application */
12
+
13
+ /* ======= Global Styles ======= */
14
+ :root {
15
+ --primary-color: #0d6efd;
16
+ --primary-dark: #0b5ed7;
17
+ --secondary-color: #6c757d;
18
+ --success-color: #198754;
19
+ --info-color: #0dcaf0;
20
+ --warning-color: #ffc107;
21
+ --danger-color: #dc3545;
22
+ --light-color: #f8f9fa;
23
+ --dark-color: #212529;
24
+ --border-radius: 0.375rem;
25
+ --box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
26
+ }
27
+
28
+ body {
29
+ font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
30
+ background-color: #f5f5f5;
31
+ color: #333;
32
+ }
33
+
34
+ /* ======= Typography ======= */
35
+ h1, h2, h3, h4, h5, h6 {
36
+ font-weight: 600;
37
+ margin-bottom: 1rem;
38
+ }
39
+
40
+ .text-primary {
41
+ color: var(--primary-color) !important;
42
+ }
43
+
44
+ /* ======= Layout Components ======= */
45
+ .main-container {
46
+ padding-top: 1.5rem;
47
+ padding-bottom: 2rem;
48
+ }
49
+
50
+ .card {
51
+ border-radius: var(--border-radius);
52
+ box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
53
+ margin-bottom: 1.5rem;
54
+ border: none;
55
+ }
56
+
57
+ .card-header {
58
+ background-color: rgba(0, 0, 0, 0.03);
59
+ border-bottom: 1px solid rgba(0, 0, 0, 0.125);
60
+ padding: 0.75rem 1.25rem;
61
+ }
62
+
63
+ .card-header.bg-primary {
64
+ background-color: var(--primary-color) !important;
65
+ color: white;
66
+ }
67
+
68
+ .card-header.bg-secondary {
69
+ background-color: var(--secondary-color) !important;
70
+ color: white;
71
+ }
72
+
73
+ .card-body {
74
+ padding: 1.25rem;
75
+ }
76
+
77
+ .card-footer {
78
+ padding: 0.75rem 1.25rem;
79
+ background-color: rgba(0, 0, 0, 0.03);
80
+ border-top: 1px solid rgba(0, 0, 0, 0.125);
81
+ }
82
+
83
+ /* ======= Navigation ======= */
84
+ .navbar {
85
+ padding: 0.5rem 1rem;
86
+ box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
87
+ }
88
+
89
+ .navbar-brand {
90
+ font-weight: 600;
91
+ font-size: 1.25rem;
92
+ }
93
+
94
+ .nav-link {
95
+ padding: 0.5rem 1rem;
96
+ transition: all 0.2s ease-in-out;
97
+ }
98
+
99
+ .nav-link:hover {
100
+ opacity: 0.85;
101
+ }
102
+
103
+ .nav-link.active {
104
+ font-weight: 600;
105
+ background-color: rgba(255, 255, 255, 0.1);
106
+ }
107
+
108
+ /* ======= Forms ======= */
109
+ .form-control, .form-select {
110
+ border-radius: var(--border-radius);
111
+ padding: 0.375rem 0.75rem;
112
+ border: 1px solid #ced4da;
113
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
114
+ }
115
+
116
+ .form-control:focus, .form-select:focus {
117
+ border-color: rgba(13, 110, 253, 0.5);
118
+ box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
119
+ }
120
+
121
+ .form-label {
122
+ margin-bottom: 0.5rem;
123
+ font-weight: 500;
124
+ }
125
+
126
+ .form-text {
127
+ color: #6c757d;
128
+ margin-top: 0.25rem;
129
+ }
130
+
131
+ /* ======= Login Page ======= */
132
+ .login-container {
133
+ min-height: 100vh;
134
+ display: flex;
135
+ align-items: center;
136
+ justify-content: center;
137
+ }
138
+
139
+ .login-card {
140
+ width: 100%;
141
+ max-width: 450px;
142
+ box-shadow: var(--box-shadow);
143
+ }
144
+
145
+ .demo-credentials {
146
+ background-color: #f8f9fa;
147
+ padding: 0.75rem;
148
+ border-radius: var(--border-radius);
149
+ margin-top: 1rem;
150
+ }
151
+
152
+ /* ======= Dashboard ======= */
153
+ .dashboard-stats {
154
+ padding: 1.5rem;
155
+ background-color: white;
156
+ box-shadow: var(--box-shadow);
157
+ border-radius: var(--border-radius);
158
+ margin-bottom: 1.5rem;
159
+ }
160
+
161
+ .stats-card {
162
+ text-align: center;
163
+ padding: 1.25rem;
164
+ border: 1px solid rgba(0, 0, 0, 0.125);
165
+ border-radius: var(--border-radius);
166
+ background-color: white;
167
+ }
168
+
169
+ .stats-icon {
170
+ font-size: 2rem;
171
+ margin-bottom: 0.75rem;
172
+ }
173
+
174
+ .stats-value {
175
+ font-size: 2rem;
176
+ font-weight: 600;
177
+ margin-bottom: 0.25rem;
178
+ }
179
+
180
+ .stats-label {
181
+ color: #6c757d;
182
+ font-size: 0.875rem;
183
+ }
184
+
185
+ /* ======= Filter Section ======= */
186
+ .filter-section {
187
+ background-color: white;
188
+ border-radius: var(--border-radius);
189
+ margin-bottom: 1.5rem;
190
+ }
191
+
192
+ .filter-heading {
193
+ font-weight: 600;
194
+ margin-bottom: 1rem;
195
+ }
196
+
197
+ .filter-group {
198
+ margin-bottom: 1.25rem;
199
+ }
200
+
201
+ /* ======= Tables ======= */
202
+ .table {
203
+ margin-bottom: 0;
204
+ }
205
+
206
+ .table-striped tbody tr:nth-of-type(odd) {
207
+ background-color: rgba(0, 0, 0, 0.02);
208
+ }
209
+
210
+ .table th {
211
+ font-weight: 600;
212
+ border-top: none;
213
+ }
214
+
215
+ .table-hover tbody tr:hover {
216
+ background-color: rgba(13, 110, 253, 0.05);
217
+ }
218
+
219
+ /* ======= Badges ======= */
220
+ .badge {
221
+ padding: 0.35em 0.65em;
222
+ font-weight: 500;
223
+ border-radius: 0.25rem;
224
+ margin-right: 0.25rem;
225
+ }
226
+
227
+ .skills-container {
228
+ display: flex;
229
+ flex-wrap: wrap;
230
+ gap: 0.25rem;
231
+ }
232
+
233
+ /* ======= Visualization Section ======= */
234
+ .visualization-card {
235
+ height: 100%;
236
+ }
237
+
238
+ .visualization-chart {
239
+ width: 100%;
240
+ height: auto;
241
+ }
242
+
243
+ /* ======= Job Listings ======= */
244
+ .job-card {
245
+ transition: transform 0.2s ease-in-out;
246
+ height: 100%;
247
+ }
248
+
249
+ .job-card:hover {
250
+ transform: translateY(-5px);
251
+ box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
252
+ }
253
+
254
+ .job-title {
255
+ font-weight: 600;
256
+ margin-bottom: 0.5rem;
257
+ }
258
+
259
+ .job-location {
260
+ color: #6c757d;
261
+ font-size: 0.875rem;
262
+ }
263
+
264
+ .job-skills {
265
+ margin-top: 0.5rem;
266
+ margin-bottom: 1rem;
267
+ }
268
+
269
+ /* ======= Student Details ======= */
270
+ .student-profile {
271
+ padding: 1.5rem;
272
+ }
273
+
274
+ .student-name {
275
+ font-size: 1.5rem;
276
+ font-weight: 600;
277
+ margin-bottom: 0.5rem;
278
+ }
279
+
280
+ .student-info {
281
+ margin-bottom: 0.5rem;
282
+ }
283
+
284
+ .section-heading {
285
+ font-weight: 600;
286
+ margin-bottom: 0.75rem;
287
+ border-bottom: 1px solid #e9ecef;
288
+ padding-bottom: 0.5rem;
289
+ }
290
+
291
+ /* ======= AI Insights ======= */
292
+ .insights-section {
293
+ background-color: #f8f9fa;
294
+ padding: 1.5rem;
295
+ border-radius: var(--border-radius);
296
+ margin-bottom: 1.5rem;
297
+ }
298
+
299
+ .insights-text {
300
+ white-space: pre-wrap;
301
+ max-height: 500px;
302
+ overflow-y: auto;
303
+ padding: 1rem;
304
+ background-color: white;
305
+ border: 1px solid #dee2e6;
306
+ border-radius: var(--border-radius);
307
+ }
308
+
309
+ /* ======= Button Styles ======= */
310
+ .btn {
311
+ padding: 0.375rem 0.75rem;
312
+ border-radius: var(--border-radius);
313
+ font-weight: 500;
314
+ transition: all 0.2s ease-in-out;
315
+ }
316
+
317
+ .btn-primary {
318
+ background-color: var(--primary-color);
319
+ border-color: var(--primary-color);
320
+ }
321
+
322
+ .btn-primary:hover {
323
+ background-color: var(--primary-dark);
324
+ border-color: var(--primary-dark);
325
+ }
326
+
327
+ .btn-outline-primary {
328
+ color: var(--primary-color);
329
+ border-color: var(--primary-color);
330
+ }
331
+
332
+ .btn-outline-primary:hover {
333
+ background-color: var(--primary-color);
334
+ color: white;
335
+ border-color: var(--primary-color);
336
+ }
337
+
338
+ .btn-sm {
339
+ padding: 0.25rem 0.5rem;
340
+ font-size: 0.875rem;
341
+ }
342
+
343
+ /* ======= Modals ======= */
344
+ .modal-header {
345
+ padding: 1rem;
346
+ border-bottom: 1px solid #dee2e6;
347
+ }
348
+
349
+ .modal-body {
350
+ padding: 1.5rem;
351
+ }
352
+
353
+ .modal-footer {
354
+ padding: 1rem;
355
+ border-top: 1px solid #dee2e6;
356
+ }
357
+
358
+ /* ======= Alerts ======= */
359
+ .alert {
360
+ padding: 1rem;
361
+ margin-bottom: 1rem;
362
+ border-radius: var(--border-radius);
363
+ }
364
+
365
+ /* ======= Spinner ======= */
366
+ .spinner-container {
367
+ display: flex;
368
+ justify-content: center;
369
+ align-items: center;
370
+ padding: 2rem;
371
+ }
372
+
373
+ .spinner-border {
374
+ width: 3rem;
375
+ height: 3rem;
376
+ }
377
+
378
+ /* ======= Responsive Adjustments ======= */
379
+ @media (max-width: 768px) {
380
+ .card-body {
381
+ padding: 1rem;
382
+ }
383
+
384
+ .navbar-brand {
385
+ font-size: 1rem;
386
+ }
387
+
388
+ .stats-value {
389
+ font-size: 1.5rem;
390
+ }
391
+
392
+ .stats-icon {
393
+ font-size: 1.5rem;
394
+ }
395
+
396
+ .table-responsive {
397
+ border: 0;
398
+ }
399
+ }
400
+
401
+ /* ======= Print Styles ======= */
402
+ @media print {
403
+ .navbar, .card-header, .btn, .filter-section {
404
+ display: none !important;
405
+ }
406
+
407
+ .card {
408
+ box-shadow: none !important;
409
+ border: 1px solid #dee2e6 !important;
410
+ }
411
+
412
+ .container-fluid {
413
+ width: 100% !important;
414
+ max-width: none !important;
415
+ }
416
+ }
417
+ </style>
418
+ </head>
419
+ <body>
420
+ <!-- Navigation -->
421
+ <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
422
+ <div class="container-fluid">
423
+ <a class="navbar-brand" href="{{ url_for('dashboard') }}">{{ company_name }} - Recruitment Portal</a>
424
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
425
+ <span class="navbar-toggler-icon"></span>
426
+ </button>
427
+ <div class="collapse navbar-collapse" id="navbarNav">
428
+ <ul class="navbar-nav me-auto">
429
+ <li class="nav-item">
430
+ <a class="nav-link" href="{{ url_for('dashboard') }}">Dashboard</a>
431
+ </li>
432
+ <li class="nav-item">
433
+ <a class="nav-link active" href="{{ url_for('jobs') }}">Job Postings</a>
434
+ </li>
435
+ </ul>
436
+ <ul class="navbar-nav">
437
+ <li class="nav-item">
438
+ <a class="nav-link" href="{{ url_for('logout') }}">
439
+ <i class="bi bi-box-arrow-right"></i> Logout
440
+ </a>
441
+ </li>
442
+ </ul>
443
+ </div>
444
+ </div>
445
+ </nav>
446
+ <!-- Main Content -->
447
+ <div class="container-fluid mt-3">
448
+ <!-- Job Details Header -->
449
+ <div class="card mb-3">
450
+ <div class="card-header bg-primary text-white">
451
+ <div class="d-flex justify-content-between align-items-center">
452
+ <h5 class="card-title mb-0">{{ job.title }}</h5>
453
+ <a href="{{ url_for('jobs') }}" class="btn btn-sm btn-light">
454
+ <i class="bi bi-arrow-left"></i> Back to Jobs
455
+ </a>
456
+ </div>
457
+ </div>
458
+ <div class="card-body">
459
+ <div class="row">
460
+ <div class="col-md-8">
461
+ <h6>Job Description</h6>
462
+ <p>{{ job.description }}</p>
463
+ </div>
464
+ <div class="col-md-4">
465
+ <h6>Job Details</h6>
466
+ <ul class="list-group list-group-flush">
467
+ <li class="list-group-item"><strong>Required Skills:</strong> {{ job.required_skills|join(', ') }}</li>
468
+ <li class="list-group-item"><strong>Minimum CGPA:</strong> {{ job.min_cgpa }}</li>
469
+ <li class="list-group-item"><strong>Experience Level:</strong> {{ job.experience_level }} years</li>
470
+ <li class="list-group-item"><strong>Location:</strong> {{ job.location }}</li>
471
+ <li class="list-group-item"><strong>Posted Date:</strong> {{ job.posted_date }}</li>
472
+ </ul>
473
+ </div>
474
+ </div>
475
+ </div>
476
+ </div>
477
+
478
+ <!-- Eligible Candidates -->
479
+ <div class="card">
480
+ <div class="card-header bg-secondary text-white">
481
+ <div class="d-flex justify-content-between align-items-center">
482
+ <h5 class="card-title mb-0">Eligible Candidates ({{ candidates|length }})</h5>
483
+ <div>
484
+ <button class="btn btn-sm btn-light me-2" id="compareSelectedBtn" disabled>
485
+ <i class="bi bi-bar-chart-line"></i> Compare Selected
486
+ </button>
487
+ <button class="btn btn-sm btn-light" id="exportSelectedBtn" disabled>
488
+ <i class="bi bi-download"></i> Export Selected
489
+ </button>
490
+ </div>
491
+ </div>
492
+ </div>
493
+ <div class="card-body">
494
+ <form id="candidatesForm">
495
+ <div class="table-responsive">
496
+ <table class="table table-striped table-hover">
497
+ <thead>
498
+ <tr>
499
+ <th><input type="checkbox" id="selectAll" class="form-check-input"></th>
500
+ <th>Name</th>
501
+ <th>Department</th>
502
+ <th>CGPA</th>
503
+ <th>Skills</th>
504
+ <th>Projects</th>
505
+ <th>Internships</th>
506
+ <th>Action</th>
507
+ </tr>
508
+ </thead>
509
+ <tbody>
510
+ {% for candidate in candidates %}
511
+ <tr>
512
+ <td><input type="checkbox" name="selected_students" value="{{ candidate.email }}" class="form-check-input candidate-checkbox"></td>
513
+ <td>{{ candidate.full_name }}</td>
514
+ <td>{{ candidate.department }}</td>
515
+ <td>{{ candidate.cgpa }}</td>
516
+ <td>
517
+ <div class="skills-container">
518
+ {% if candidate.programming_languages %}
519
+ {% for skill in candidate.programming_languages.split(',')[:3] %}
520
+ <span class="badge bg-primary">{{ skill.strip() }}</span>
521
+ {% endfor %}
522
+ {% if candidate.programming_languages.split(',')|length > 3 %}
523
+ <span class="badge bg-secondary">+{{ candidate.programming_languages.split(',')|length - 3 }}</span>
524
+ {% endif %}
525
+ {% endif %}
526
+ </div>
527
+ </td>
528
+ <td>{{ candidate.projects | truncate(30) if candidate.projects else 'N/A' }}</td>
529
+ <td>{{ candidate.internships | truncate(30) if candidate.internships else 'N/A' }}</td>
530
+ <td>
531
+ <button type="button" class="btn btn-sm btn-outline-primary view-details-btn" data-email="{{ candidate.email }}">
532
+ <i class="bi bi-eye"></i> Details
533
+ </button>
534
+ </td>
535
+ </tr>
536
+ {% endfor %}
537
+ </tbody>
538
+ </table>
539
+ </div>
540
+ </form>
541
+
542
+ {% if not candidates %}
543
+ <div class="alert alert-info text-center">
544
+ No eligible candidates found for this job posting. Consider adjusting the job requirements.
545
+ </div>
546
+ {% endif %}
547
+ </div>
548
+ </div>
549
+ </div>
550
+
551
+ <!-- Student Details Modal -->
552
+ <div class="modal fade" id="studentDetailsModal" tabindex="-1">
553
+ <div class="modal-dialog modal-lg">
554
+ <div class="modal-content">
555
+ <div class="modal-header bg-primary text-white">
556
+ <h5 class="modal-title">Student Details</h5>
557
+ <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
558
+ </div>
559
+ <div class="modal-body" id="studentDetailsContent">
560
+ <div class="text-center">
561
+ <div class="spinner-border" role="status">
562
+ <span class="visually-hidden">Loading...</span>
563
+ </div>
564
+ </div>
565
+ </div>
566
+ <div class="modal-footer">
567
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
568
+ </div>
569
+ </div>
570
+ </div>
571
+ </div>
572
+
573
+ <!-- AI Insights Modal -->
574
+ <div class="modal fade" id="aiInsightsModal" tabindex="-1">
575
+ <div class="modal-dialog modal-lg">
576
+ <div class="modal-content">
577
+ <div class="modal-header bg-success text-white">
578
+ <h5 class="modal-title">AI Insights</h5>
579
+ <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
580
+ </div>
581
+ <div class="modal-body" id="aiInsightsContent">
582
+ <div class="mb-3">
583
+ <label for="roleInput" class="form-label">Role to analyze for:</label>
584
+ <input type="text" class="form-control" id="roleInput" value="{{ job.title }}">
585
+ </div>
586
+ <div id="insightsResult" class="d-none">
587
+ <div class="alert alert-info">
588
+ <h5>Analysis Results:</h5>
589
+ <div id="insightsText" class="insights-text"></div>
590
+ </div>
591
+ </div>
592
+ <div id="insightsLoading" class="d-none text-center">
593
+ <div class="spinner-border" role="status">
594
+ <span class="visually-hidden">Loading...</span>
595
+ </div>
596
+ <p>Generating insights... This may take a moment.</p>
597
+ </div>
598
+ </div>
599
+ <div class="modal-footer">
600
+ <button type="button" class="btn btn-primary" id="generateInsightsBtn">Generate Insights</button>
601
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
602
+ </div>
603
+ </div>
604
+ </div>
605
+ </div>
606
+
607
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
608
+ <script>
609
+ document.addEventListener('DOMContentLoaded', function() {
610
+ // Handle checkbox selection
611
+ const selectAllCheckbox = document.getElementById('selectAll');
612
+ const candidateCheckboxes = document.querySelectorAll('.candidate-checkbox');
613
+ const compareSelectedBtn = document.getElementById('compareSelectedBtn');
614
+ const exportSelectedBtn = document.getElementById('exportSelectedBtn');
615
+
616
+ selectAllCheckbox.addEventListener('change', function() {
617
+ candidateCheckboxes.forEach(checkbox => {
618
+ checkbox.checked = selectAllCheckbox.checked;
619
+ });
620
+ updateButtonState();
621
+ });
622
+
623
+ candidateCheckboxes.forEach(checkbox => {
624
+ checkbox.addEventListener('change', updateButtonState);
625
+ });
626
+
627
+ function updateButtonState() {
628
+ const selectedCount = document.querySelectorAll('.candidate-checkbox:checked').length;
629
+ compareSelectedBtn.disabled = selectedCount < 2;
630
+ exportSelectedBtn.disabled = selectedCount === 0;
631
+ }
632
+
633
+ // Handle view details button
634
+ const viewDetailsButtons = document.querySelectorAll('.view-details-btn');
635
+ viewDetailsButtons.forEach(button => {
636
+ button.addEventListener('click', function() {
637
+ const email = this.getAttribute('data-email');
638
+ const studentData = findStudentByEmail(email);
639
+ showStudentDetails(studentData);
640
+ });
641
+ });
642
+
643
+ function findStudentByEmail(email) {
644
+ // In a real implementation, you might want to fetch this data from the server
645
+ // For now, we'll use the data we already have on the page
646
+ return {{ candidates|tojson|safe }}.find(student => student.email === email);
647
+ }
648
+
649
+ function showStudentDetails(student) {
650
+ if (!student) return;
651
+
652
+ const modal = new bootstrap.Modal(document.getElementById('studentDetailsModal'));
653
+ const content = document.getElementById('studentDetailsContent');
654
+
655
+ let htmlContent = `
656
+ <div class="row">
657
+ <div class="col-md-6">
658
+ <h5>${student.full_name}</h5>
659
+ <p><strong>Email:</strong> ${student.email}</p>
660
+ <p><strong>Department:</strong> ${student.department}</p>
661
+ <p><strong>CGPA:</strong> ${student.cgpa}</p>
662
+ <p><strong>Backlogs:</strong> ${student.backlogs || 0}</p>
663
+ </div>
664
+ <div class="col-md-6">
665
+ <h6>Skills</h6>
666
+ <div>
667
+ <strong>Programming:</strong> ${student.programming_languages || 'N/A'}
668
+ </div>
669
+ <div>
670
+ <strong>Tools & Technologies:</strong> ${student.tools_technologies || 'N/A'}
671
+ </div>
672
+ <div>
673
+ <strong>Soft Skills:</strong> ${student.soft_skills || 'N/A'}
674
+ </div>
675
+ </div>
676
+ </div>
677
+ <hr>
678
+ <div class="row mt-3">
679
+ <div class="col-md-6">
680
+ <h6>Projects</h6>
681
+ <p>${student.projects || 'No projects listed'}</p>
682
+ </div>
683
+ <div class="col-md-6">
684
+ <h6>Internships</h6>
685
+ <p>${student.internships || 'No internships listed'}</p>
686
+ </div>
687
+ </div>
688
+ <div class="row mt-3">
689
+ <div class="col-md-6">
690
+ <h6>Certifications</h6>
691
+ <p>${student.certifications || 'No certifications listed'}</p>
692
+ </div>
693
+ <div class="col-md-6">
694
+ <h6>Hackathons & Competitions</h6>
695
+ <p>${student.hackathons || 'None listed'}</p>
696
+ </div>
697
+ </div>
698
+ <div class="row mt-3">
699
+ <div class="col-md-6">
700
+ <h6>Preferred Roles</h6>
701
+ <p>${student.preferred_roles || 'Not specified'}</p>
702
+ </div>
703
+ <div class="col-md-6">
704
+ <h6>Preferred Location</h6>
705
+ <p>${student.preferred_location || 'Not specified'}</p>
706
+ </div>
707
+ </div>
708
+ <div class="row mt-3">
709
+ <div class="col-12">
710
+ <h6>Strengths & Weaknesses</h6>
711
+ <p><strong>Strengths:</strong> ${student.strengths || 'Not specified'}</p>
712
+ <p><strong>Weaknesses:</strong> ${student.weaknesses || 'Not specified'}</p>
713
+ </div>
714
+ </div>`;
715
+
716
+ content.innerHTML = htmlContent;
717
+ modal.show();
718
+ }
719
+
720
+ // Handle compare selected button
721
+ compareSelectedBtn.addEventListener('click', function() {
722
+ const selectedEmails = Array.from(document.querySelectorAll('.candidate-checkbox:checked'))
723
+ .map(checkbox => checkbox.value);
724
+
725
+ if (selectedEmails.length < 2) {
726
+ alert('Please select at least 2 candidates to compare.');
727
+ return;
728
+ }
729
+
730
+ // Show AI insights modal
731
+ const modal = new bootstrap.Modal(document.getElementById('aiInsightsModal'));
732
+ modal.show();
733
+ });
734
+
735
+ // Handle generate insights button
736
+ document.getElementById('generateInsightsBtn').addEventListener('click', function() {
737
+ const selectedEmails = Array.from(document.querySelectorAll('.candidate-checkbox:checked'))
738
+ .map(checkbox => checkbox.value);
739
+ const role = document.getElementById('roleInput').value;
740
+
741
+ const loadingDiv = document.getElementById('insightsLoading');
742
+ const resultDiv = document.getElementById('insightsResult');
743
+ const insightsTextDiv = document.getElementById('insightsText');
744
+
745
+ loadingDiv.classList.remove('d-none');
746
+ resultDiv.classList.add('d-none');
747
+
748
+ // Make AJAX request to get AI insights
749
+ const formData = new FormData();
750
+ selectedEmails.forEach(email => {
751
+ formData.append('selected_students', email);
752
+ });
753
+ formData.append('role', role);
754
+
755
+ fetch('/ai_insights', {
756
+ method: 'POST',
757
+ body: formData
758
+ })
759
+ .then(response => response.json())
760
+ .then(data => {
761
+ loadingDiv.classList.add('d-none');
762
+ resultDiv.classList.remove('d-none');
763
+
764
+ if (data.error) {
765
+ insightsTextDiv.innerHTML = `<div class="alert alert-danger">${data.error}</div>`;
766
+ } else {
767
+ // Format the insights with Markdown or HTML
768
+ insightsTextDiv.innerHTML = formatInsights(data.insights);
769
+ }
770
+ })
771
+ .catch(error => {
772
+ loadingDiv.classList.add('d-none');
773
+ resultDiv.classList.remove('d-none');
774
+ insightsTextDiv.innerHTML = `<div class="alert alert-danger">Error: ${error.message}</div>`;
775
+ });
776
+ });
777
+
778
+ function formatInsights(insights) {
779
+ // Convert line breaks to HTML breaks and preserve formatting
780
+ return insights
781
+ .replace(/\n\n/g, '</p><p>')
782
+ .replace(/\n/g, '<br>')
783
+ .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
784
+ .replace(/\*(.*?)\*/g, '<em>$1</em>');
785
+ }
786
+
787
+ // Handle export selected button
788
+ exportSelectedBtn.addEventListener('click', function() {
789
+ const selectedEmails = Array.from(document.querySelectorAll('.candidate-checkbox:checked'))
790
+ .map(checkbox => checkbox.value);
791
+
792
+ if (selectedEmails.length === 0) {
793
+ alert('Please select at least one candidate to export.');
794
+ return;
795
+ }
796
+
797
+ // Get the full student data for selected emails
798
+ const selectedStudents = {{ candidates|tojson|safe }}.filter(
799
+ student => selectedEmails.includes(student.email)
800
+ );
801
+
802
+ // Submit form to export endpoint
803
+ const form = document.createElement('form');
804
+ form.method = 'POST';
805
+ form.action = '/export_filtered';
806
+
807
+ const input = document.createElement('input');
808
+ input.type = 'hidden';
809
+ input.name = 'filtered_students';
810
+ input.value = JSON.stringify(selectedStudents);
811
+
812
+ form.appendChild(input);
813
+ document.body.appendChild(form);
814
+ form.submit();
815
+ document.body.removeChild(form);
816
+ });
817
+ });
818
+ </script>
819
+ </body>
820
+ </html>
templates/jobs.html ADDED
@@ -0,0 +1,547 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Job Postings | Campus Recruitment Portal</title>
7
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
8
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
9
+ <style>
10
+ /* Campus Recruitment Portal - Main Stylesheet
11
+ This file contains styles for all pages in the application */
12
+
13
+ /* ======= Global Styles ======= */
14
+ :root {
15
+ --primary-color: #0d6efd;
16
+ --primary-dark: #0b5ed7;
17
+ --secondary-color: #6c757d;
18
+ --success-color: #198754;
19
+ --info-color: #0dcaf0;
20
+ --warning-color: #ffc107;
21
+ --danger-color: #dc3545;
22
+ --light-color: #f8f9fa;
23
+ --dark-color: #212529;
24
+ --border-radius: 0.375rem;
25
+ --box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
26
+ }
27
+
28
+ body {
29
+ font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
30
+ background-color: #f5f5f5;
31
+ color: #333;
32
+ }
33
+
34
+ /* ======= Typography ======= */
35
+ h1, h2, h3, h4, h5, h6 {
36
+ font-weight: 600;
37
+ margin-bottom: 1rem;
38
+ }
39
+
40
+ .text-primary {
41
+ color: var(--primary-color) !important;
42
+ }
43
+
44
+ /* ======= Layout Components ======= */
45
+ .main-container {
46
+ padding-top: 1.5rem;
47
+ padding-bottom: 2rem;
48
+ }
49
+
50
+ .card {
51
+ border-radius: var(--border-radius);
52
+ box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
53
+ margin-bottom: 1.5rem;
54
+ border: none;
55
+ }
56
+
57
+ .card-header {
58
+ background-color: rgba(0, 0, 0, 0.03);
59
+ border-bottom: 1px solid rgba(0, 0, 0, 0.125);
60
+ padding: 0.75rem 1.25rem;
61
+ }
62
+
63
+ .card-header.bg-primary {
64
+ background-color: var(--primary-color) !important;
65
+ color: white;
66
+ }
67
+
68
+ .card-header.bg-secondary {
69
+ background-color: var(--secondary-color) !important;
70
+ color: white;
71
+ }
72
+
73
+ .card-body {
74
+ padding: 1.25rem;
75
+ }
76
+
77
+ .card-footer {
78
+ padding: 0.75rem 1.25rem;
79
+ background-color: rgba(0, 0, 0, 0.03);
80
+ border-top: 1px solid rgba(0, 0, 0, 0.125);
81
+ }
82
+
83
+ /* ======= Navigation ======= */
84
+ .navbar {
85
+ padding: 0.5rem 1rem;
86
+ box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
87
+ }
88
+
89
+ .navbar-brand {
90
+ font-weight: 600;
91
+ font-size: 1.25rem;
92
+ }
93
+
94
+ .nav-link {
95
+ padding: 0.5rem 1rem;
96
+ transition: all 0.2s ease-in-out;
97
+ }
98
+
99
+ .nav-link:hover {
100
+ opacity: 0.85;
101
+ }
102
+
103
+ .nav-link.active {
104
+ font-weight: 600;
105
+ background-color: rgba(255, 255, 255, 0.1);
106
+ }
107
+
108
+ /* ======= Forms ======= */
109
+ .form-control, .form-select {
110
+ border-radius: var(--border-radius);
111
+ padding: 0.375rem 0.75rem;
112
+ border: 1px solid #ced4da;
113
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
114
+ }
115
+
116
+ .form-control:focus, .form-select:focus {
117
+ border-color: rgba(13, 110, 253, 0.5);
118
+ box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
119
+ }
120
+
121
+ .form-label {
122
+ margin-bottom: 0.5rem;
123
+ font-weight: 500;
124
+ }
125
+
126
+ .form-text {
127
+ color: #6c757d;
128
+ margin-top: 0.25rem;
129
+ }
130
+
131
+ /* ======= Login Page ======= */
132
+ .login-container {
133
+ min-height: 100vh;
134
+ display: flex;
135
+ align-items: center;
136
+ justify-content: center;
137
+ }
138
+
139
+ .login-card {
140
+ width: 100%;
141
+ max-width: 450px;
142
+ box-shadow: var(--box-shadow);
143
+ }
144
+
145
+ .demo-credentials {
146
+ background-color: #f8f9fa;
147
+ padding: 0.75rem;
148
+ border-radius: var(--border-radius);
149
+ margin-top: 1rem;
150
+ }
151
+
152
+ /* ======= Dashboard ======= */
153
+ .dashboard-stats {
154
+ padding: 1.5rem;
155
+ background-color: white;
156
+ box-shadow: var(--box-shadow);
157
+ border-radius: var(--border-radius);
158
+ margin-bottom: 1.5rem;
159
+ }
160
+
161
+ .stats-card {
162
+ text-align: center;
163
+ padding: 1.25rem;
164
+ border: 1px solid rgba(0, 0, 0, 0.125);
165
+ border-radius: var(--border-radius);
166
+ background-color: white;
167
+ }
168
+
169
+ .stats-icon {
170
+ font-size: 2rem;
171
+ margin-bottom: 0.75rem;
172
+ }
173
+
174
+ .stats-value {
175
+ font-size: 2rem;
176
+ font-weight: 600;
177
+ margin-bottom: 0.25rem;
178
+ }
179
+
180
+ .stats-label {
181
+ color: #6c757d;
182
+ font-size: 0.875rem;
183
+ }
184
+
185
+ /* ======= Filter Section ======= */
186
+ .filter-section {
187
+ background-color: white;
188
+ border-radius: var(--border-radius);
189
+ margin-bottom: 1.5rem;
190
+ }
191
+
192
+ .filter-heading {
193
+ font-weight: 600;
194
+ margin-bottom: 1rem;
195
+ }
196
+
197
+ .filter-group {
198
+ margin-bottom: 1.25rem;
199
+ }
200
+
201
+ /* ======= Tables ======= */
202
+ .table {
203
+ margin-bottom: 0;
204
+ }
205
+
206
+ .table-striped tbody tr:nth-of-type(odd) {
207
+ background-color: rgba(0, 0, 0, 0.02);
208
+ }
209
+
210
+ .table th {
211
+ font-weight: 600;
212
+ border-top: none;
213
+ }
214
+
215
+ .table-hover tbody tr:hover {
216
+ background-color: rgba(13, 110, 253, 0.05);
217
+ }
218
+
219
+ /* ======= Badges ======= */
220
+ .badge {
221
+ padding: 0.35em 0.65em;
222
+ font-weight: 500;
223
+ border-radius: 0.25rem;
224
+ margin-right: 0.25rem;
225
+ }
226
+
227
+ .skills-container {
228
+ display: flex;
229
+ flex-wrap: wrap;
230
+ gap: 0.25rem;
231
+ }
232
+
233
+ /* ======= Visualization Section ======= */
234
+ .visualization-card {
235
+ height: 100%;
236
+ }
237
+
238
+ .visualization-chart {
239
+ width: 100%;
240
+ height: auto;
241
+ }
242
+
243
+ /* ======= Job Listings ======= */
244
+ .job-card {
245
+ transition: transform 0.2s ease-in-out;
246
+ height: 100%;
247
+ }
248
+
249
+ .job-card:hover {
250
+ transform: translateY(-5px);
251
+ box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
252
+ }
253
+
254
+ .job-title {
255
+ font-weight: 600;
256
+ margin-bottom: 0.5rem;
257
+ }
258
+
259
+ .job-location {
260
+ color: #6c757d;
261
+ font-size: 0.875rem;
262
+ }
263
+
264
+ .job-skills {
265
+ margin-top: 0.5rem;
266
+ margin-bottom: 1rem;
267
+ }
268
+
269
+ /* ======= Student Details ======= */
270
+ .student-profile {
271
+ padding: 1.5rem;
272
+ }
273
+
274
+ .student-name {
275
+ font-size: 1.5rem;
276
+ font-weight: 600;
277
+ margin-bottom: 0.5rem;
278
+ }
279
+
280
+ .student-info {
281
+ margin-bottom: 0.5rem;
282
+ }
283
+
284
+ .section-heading {
285
+ font-weight: 600;
286
+ margin-bottom: 0.75rem;
287
+ border-bottom: 1px solid #e9ecef;
288
+ padding-bottom: 0.5rem;
289
+ }
290
+
291
+ /* ======= AI Insights ======= */
292
+ .insights-section {
293
+ background-color: #f8f9fa;
294
+ padding: 1.5rem;
295
+ border-radius: var(--border-radius);
296
+ margin-bottom: 1.5rem;
297
+ }
298
+
299
+ .insights-text {
300
+ white-space: pre-wrap;
301
+ max-height: 500px;
302
+ overflow-y: auto;
303
+ padding: 1rem;
304
+ background-color: white;
305
+ border: 1px solid #dee2e6;
306
+ border-radius: var(--border-radius);
307
+ }
308
+
309
+ /* ======= Button Styles ======= */
310
+ .btn {
311
+ padding: 0.375rem 0.75rem;
312
+ border-radius: var(--border-radius);
313
+ font-weight: 500;
314
+ transition: all 0.2s ease-in-out;
315
+ }
316
+
317
+ .btn-primary {
318
+ background-color: var(--primary-color);
319
+ border-color: var(--primary-color);
320
+ }
321
+
322
+ .btn-primary:hover {
323
+ background-color: var(--primary-dark);
324
+ border-color: var(--primary-dark);
325
+ }
326
+
327
+ .btn-outline-primary {
328
+ color: var(--primary-color);
329
+ border-color: var(--primary-color);
330
+ }
331
+
332
+ .btn-outline-primary:hover {
333
+ background-color: var(--primary-color);
334
+ color: white;
335
+ border-color: var(--primary-color);
336
+ }
337
+
338
+ .btn-sm {
339
+ padding: 0.25rem 0.5rem;
340
+ font-size: 0.875rem;
341
+ }
342
+
343
+ /* ======= Modals ======= */
344
+ .modal-header {
345
+ padding: 1rem;
346
+ border-bottom: 1px solid #dee2e6;
347
+ }
348
+
349
+ .modal-body {
350
+ padding: 1.5rem;
351
+ }
352
+
353
+ .modal-footer {
354
+ padding: 1rem;
355
+ border-top: 1px solid #dee2e6;
356
+ }
357
+
358
+ /* ======= Alerts ======= */
359
+ .alert {
360
+ padding: 1rem;
361
+ margin-bottom: 1rem;
362
+ border-radius: var(--border-radius);
363
+ }
364
+
365
+ /* ======= Spinner ======= */
366
+ .spinner-container {
367
+ display: flex;
368
+ justify-content: center;
369
+ align-items: center;
370
+ padding: 2rem;
371
+ }
372
+
373
+ .spinner-border {
374
+ width: 3rem;
375
+ height: 3rem;
376
+ }
377
+
378
+ /* ======= Responsive Adjustments ======= */
379
+ @media (max-width: 768px) {
380
+ .card-body {
381
+ padding: 1rem;
382
+ }
383
+
384
+ .navbar-brand {
385
+ font-size: 1rem;
386
+ }
387
+
388
+ .stats-value {
389
+ font-size: 1.5rem;
390
+ }
391
+
392
+ .stats-icon {
393
+ font-size: 1.5rem;
394
+ }
395
+
396
+ .table-responsive {
397
+ border: 0;
398
+ }
399
+ }
400
+
401
+ /* ======= Print Styles ======= */
402
+ @media print {
403
+ .navbar, .card-header, .btn, .filter-section {
404
+ display: none !important;
405
+ }
406
+
407
+ .card {
408
+ box-shadow: none !important;
409
+ border: 1px solid #dee2e6 !important;
410
+ }
411
+
412
+ .container-fluid {
413
+ width: 100% !important;
414
+ max-width: none !important;
415
+ }
416
+ }
417
+ </style>
418
+ </head>
419
+ <body>
420
+ <!-- Navigation -->
421
+ <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
422
+ <div class="container-fluid">
423
+ <a class="navbar-brand" href="{{ url_for('dashboard') }}">{{ company_name }} - Recruitment Portal</a>
424
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
425
+ <span class="navbar-toggler-icon"></span>
426
+ </button>
427
+ <div class="collapse navbar-collapse" id="navbarNav">
428
+ <ul class="navbar-nav me-auto">
429
+ <li class="nav-item">
430
+ <a class="nav-link" href="{{ url_for('dashboard') }}">Dashboard</a>
431
+ </li>
432
+ <li class="nav-item">
433
+ <a class="nav-link active" href="{{ url_for('jobs') }}">Job Postings</a>
434
+ </li>
435
+ </ul>
436
+ <ul class="navbar-nav">
437
+ <li class="nav-item">
438
+ <a class="nav-link" href="{{ url_for('logout') }}">
439
+ <i class="bi bi-box-arrow-right"></i> Logout
440
+ </a>
441
+ </li>
442
+ </ul>
443
+ </div>
444
+ </div>
445
+ </nav>
446
+
447
+ <!-- Main Content -->
448
+ <div class="container-fluid mt-3">
449
+ <div class="row">
450
+ <!-- Post New Job Form -->
451
+ <div class="col-md-4">
452
+ <div class="card mb-3">
453
+ <div class="card-header bg-primary text-white">
454
+ <h5 class="card-title mb-0">Post New Job</h5>
455
+ </div>
456
+ <div class="card-body">
457
+ <form method="POST" action="{{ url_for('jobs') }}">
458
+ <div class="mb-3">
459
+ <label class="form-label">Job Title</label>
460
+ <input type="text" class="form-control" name="title" required>
461
+ </div>
462
+
463
+ <div class="mb-3">
464
+ <label class="form-label">Job Description</label>
465
+ <textarea class="form-control" name="description" rows="4" required></textarea>
466
+ </div>
467
+
468
+ <div class="mb-3">
469
+ <label class="form-label">Required Skills</label>
470
+ <select class="form-select" name="required_skills" multiple size="5" required>
471
+ {% for skill in skills %}
472
+ <option value="{{ skill }}">{{ skill }}</option>
473
+ {% endfor %}
474
+ </select>
475
+ <small class="form-text text-muted">Hold Ctrl/Cmd to select multiple</small>
476
+ </div>
477
+
478
+ <div class="mb-3">
479
+ <label class="form-label">Minimum CGPA</label>
480
+ <input type="number" class="form-control" name="min_cgpa" min="0" max="10" step="0.1" value="7.0">
481
+ </div>
482
+
483
+ <div class="mb-3">
484
+ <label class="form-label">Experience Level (years)</label>
485
+ <input type="number" class="form-control" name="experience_level" min="0" max="5" step="1" value="0">
486
+ </div>
487
+
488
+ <div class="mb-3">
489
+ <label class="form-label">Location</label>
490
+ <input type="text" class="form-control" name="location" required>
491
+ </div>
492
+
493
+ <div class="d-grid">
494
+ <button type="submit" class="btn btn-primary">Post Job</button>
495
+ </div>
496
+ </form>
497
+ </div>
498
+ </div>
499
+ </div>
500
+
501
+ <!-- Job Listings -->
502
+ <div class="col-md-8">
503
+ <div class="card mb-3">
504
+ <div class="card-header bg-primary text-white">
505
+ <h5 class="card-title mb-0">Current Job Postings</h5>
506
+ </div>
507
+ <div class="card-body">
508
+ {% if jobs %}
509
+ <div class="row row-cols-1 row-cols-md-2 g-4">
510
+ {% for job in jobs %}
511
+ <div class="col">
512
+ <div class="card h-100">
513
+ <div class="card-header bg-light">
514
+ <h5 class="card-title mb-0">{{ job.title }}</h5>
515
+ </div>
516
+ <div class="card-body">
517
+ <p class="card-text">{{ job.description|truncate(100) }}</p>
518
+ <ul class="list-group list-group-flush mb-3">
519
+ <li class="list-group-item"><strong>Skills:</strong> {{ job.required_skills|join(', ') }}</li>
520
+ <li class="list-group-item"><strong>Min. CGPA:</strong> {{ job.min_cgpa }}</li>
521
+ <li class="list-group-item"><strong>Experience:</strong> {{ job.experience_level }} year(s)</li>
522
+ <li class="list-group-item"><strong>Location:</strong> {{ job.location }}</li>
523
+ <li class="list-group-item"><strong>Posted:</strong> {{ job.posted_date }}</li>
524
+ </ul>
525
+ <div class="d-grid">
526
+ <a href="https://pranit144-job-applicant.static.hf.space" class="btn btn-primary">View Applicants</a>
527
+ </div>
528
+ </div>
529
+ </div>
530
+ </div>
531
+ {% endfor %}
532
+ </div>
533
+ {% else %}
534
+ <div class="alert alert-info">
535
+ No job postings yet. Use the form to create your first job posting.
536
+ </div>
537
+ {% endif %}
538
+ </div>
539
+ </div>
540
+ </div>
541
+ </div>
542
+ </div>
543
+
544
+ <!-- JavaScript -->
545
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
546
+ </body>
547
+ </html>