akshit7093's picture
Changes before Firebase Studio auto-run
f4552a1
document.addEventListener('DOMContentLoaded', () => {
const studentSelector = document.getElementById('student-selector');
const generateReportBtn = document.getElementById('generate-report-btn');
const jobApplicationInput = document.getElementById('job-application-input');
const analyzeJobBtn = document.getElementById('analyze-job-btn');
const loadingSpinner = document.getElementById('loading-spinner');
const reportContainer = document.getElementById('report-container');
const jobAnalysisContainer = document.getElementById('job-analysis-container');
const chatbotContainer = document.getElementById('chatbot-container');
const chatForm = document.getElementById('chat-form');
const chatInput = document.getElementById('chat-input');
const chatHistory = document.getElementById('chat-history');
// 1. Populate student dropdown on page load
fetch('/api/students')
.then(response => response.json())
.then(students => {
students.forEach(student => {
const option = document.createElement('option');
option.value = student.enrollment_no;
option.textContent = `${student.name} (${student.enrollment_no})`;
studentSelector.appendChild(option);
});
})
.catch(error => console.error('Error fetching students:', error));
// 2. Enable buttons when inputs are filled
studentSelector.addEventListener('change', () => {
const hasSelection = !!studentSelector.value;
generateReportBtn.disabled = !hasSelection;
chatbotContainer.classList.toggle('hidden', !hasSelection);
reportContainer.classList.add('hidden'); // Hide old report on new selection
chatHistory.innerHTML = ''; // Clear chat history
});
jobApplicationInput.addEventListener('input', () => {
analyzeJobBtn.disabled = !jobApplicationInput.value.trim();
});
// 3. Handle "Generate Report" button click
generateReportBtn.addEventListener('click', () => {
const enrollmentNo = studentSelector.value;
if (!enrollmentNo) return;
loadingSpinner.classList.remove('hidden');
reportContainer.classList.add('hidden');
jobAnalysisContainer.classList.add('hidden');
chatbotContainer.classList.add('hidden');
fetch(`/api/report/${enrollmentNo}`)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(report => {
loadingSpinner.classList.add('hidden');
if (report.error) {
alert(`Error generating report: ${report.error}`);
} else {
displayReport(report);
reportContainer.classList.remove('hidden');
chatbotContainer.classList.remove('hidden');
}
})
.catch(error => {
loadingSpinner.classList.add('hidden');
console.error('Report generation error:', error);
alert(`An unexpected error occurred: ${error.message}`);
});
});
// 4. Handle "Analyze Job Application" button click
analyzeJobBtn.addEventListener('click', () => {
const jobApplicationLink = jobApplicationInput.value.trim();
if (!jobApplicationLink) return;
loadingSpinner.classList.remove('hidden');
reportContainer.classList.add('hidden');
jobAnalysisContainer.classList.add('hidden');
chatbotContainer.classList.add('hidden');
fetch('/api/job-analysis', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ job_application_link: jobApplicationLink })
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
loadingSpinner.classList.add('hidden');
if (data.error) {
alert(`Error analyzing job application: ${data.error}`);
} else {
displayJobAnalysis(data.data); // Access data.data as per API response structure
jobAnalysisContainer.classList.remove('hidden');
}
})
.catch(error => {
loadingSpinner.classList.add('hidden');
console.error('Job analysis error:', error);
alert(`An unexpected error occurred: ${error.message}`);
});
});
// 5. Handle chat form submission
chatForm.addEventListener('submit', (e) => {
e.preventDefault();
const enrollmentNo = studentSelector.value;
const question = chatInput.value.trim();
if (!question || !enrollmentNo) return;
appendMessage(question, 'user');
chatInput.value = '';
appendMessage('Thinking...', 'ai', true); // Show loading indicator
fetch('/api/ask', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ enrollment_no: enrollmentNo, question: question })
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
const loadingElement = chatHistory.querySelector('.loading');
if (loadingElement) {
loadingElement.parentElement.remove();
}
appendMessage(data.answer, 'ai');
})
.catch(error => {
console.error('Chat error:', error);
const loadingElement = chatHistory.querySelector('.loading');
if (loadingElement) {
loadingElement.parentElement.remove();
}
appendMessage('Sorry, an error occurred while fetching the answer.', 'ai');
});
});
// --- Helper Functions ---
function displayReport(report) {
document.getElementById('report-title').textContent = `Performance Report for ${studentSelector.options[studentSelector.selectedIndex].text}`;
document.getElementById('summary-text').textContent = report.overall_summary;
// Display resume analysis
displayResumeAnalysis(report.resume_analysis);
const scoresGrid = document.getElementById('scores-grid');
scoresGrid.innerHTML = '';
report.detailed_scores.forEach(item => {
scoresGrid.innerHTML += `
<div class="score-card">
<div class="parameter">
<span>${item.parameter}</span>
<span class="score">${item.score}/10</span>
</div>
<div class="justification">${item.justification}</div>
</div>
`;
});
const createListItems = (items) => items.map(item => `<li>${item}</li>`).join('');
document.getElementById('strengths-list').innerHTML = createListItems(report.analysis.strengths);
document.getElementById('weaknesses-list').innerHTML = createListItems(report.analysis.weaknesses);
document.getElementById('advice-list').innerHTML = createListItems(report.actionable_advice.recommendations);
// Display YouTube recommendations
displayYouTubeRecommendations(report.youtube_recommendations);
}
function displayResumeAnalysis(resumeAnalysis) {
// Display skills as tags
const skillsContainer = document.getElementById('resume-skills');
skillsContainer.innerHTML = '';
resumeAnalysis.key_skills.forEach(skill => {
const tag = document.createElement('span');
tag.className = 'skill-tag';
tag.textContent = skill;
skillsContainer.appendChild(tag);
});
// Display professional links
const linksContainer = document.getElementById('resume-links');
linksContainer.innerHTML = '';
resumeAnalysis.professional_links.forEach(link => {
const li = document.createElement('li');
const a = document.createElement('a');
a.href = link;
a.target = '_blank';
// Extract domain for display
try {
const url = new URL(link);
a.textContent = url.hostname.replace('www.', '');
} catch (e) {
a.textContent = link;
}
li.appendChild(a);
linksContainer.appendChild(li);
});
// Display missing elements
const missingContainer = document.getElementById('resume-missing');
missingContainer.innerHTML = '';
resumeAnalysis.missing_elements.forEach(item => {
const li = document.createElement('li');
li.className = 'missing-items';
li.textContent = item;
missingContainer.appendChild(li);
});
}
function displayYouTubeRecommendations(recommendations) {
const container = document.getElementById('youtube-recommendations');
container.innerHTML = '';
if (!recommendations || recommendations.length === 0) {
container.innerHTML = '<p>No YouTube recommendations available for this student.</p>';
return;
}
recommendations.forEach(topic => {
// Check if this is a topic with videos or a single video
if (topic.videos && Array.isArray(topic.videos)) {
// This is a topic with multiple videos
const topicSection = document.createElement('div');
topicSection.className = 'topic-section';
const topicHeader = document.createElement('h3');
topicHeader.textContent = topic.topic;
topicSection.appendChild(topicHeader);
const topicReason = document.createElement('p');
topicReason.className = 'topic-reason';
topicReason.textContent = topic.reason;
topicSection.appendChild(topicReason);
const videosContainer = document.createElement('div');
videosContainer.className = 'videos-container';
topic.videos.forEach(video => {
const card = document.createElement('div');
card.className = 'youtube-card';
// Fix URL formatting - remove extra spaces
const embedUrl = (video.embed_url || video.url).replace(/\s+/g, '');
card.innerHTML = `
<div class="youtube-embed">
<iframe src="${embedUrl}"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen></iframe>
</div>
<div class="youtube-info">
<h3 class="youtube-title">${video.title}</h3>
<p class="youtube-reason">${video.reason || video.description}</p>
</div>
`;
videosContainer.appendChild(card);
});
topicSection.appendChild(videosContainer);
container.appendChild(topicSection);
} else {
// This is a single video (fallback case)
const card = document.createElement('div');
card.className = 'youtube-card';
// Fix URL formatting - remove extra spaces
const embedUrl = (topic.embed_url || topic.url).replace(/\s+/g, '');
card.innerHTML = `
<div class="youtube-embed">
<iframe src="${embedUrl}"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen></iframe>
</div>
<div class="youtube-info">
<h3 class="youtube-title">${topic.title}</h3>
<p class="youtube-reason">${topic.reason || topic.description}</p>
</div>
`;
container.appendChild(card);
}
});
}
function displayJobAnalysis(data) {
console.log("Job analysis data:", data); // Debug log
// Display strengths
const strengthsContainer = document.getElementById('job-strengths-list');
strengthsContainer.innerHTML = '';
// Check if strengths exist and is an array
if (data.strengths && Array.isArray(data.strengths)) {
data.strengths.forEach(strength => {
const item = document.createElement('div');
item.className = 'job-strength-item';
item.innerHTML = `
<div class="job-item-aspect">${strength.aspect || 'N/A'}</div>
<div class="job-item-description">${strength.description || 'N/A'}</div>
<div class="job-item-relevance">${strength.relevance || 'N/A'}</div>
`;
strengthsContainer.appendChild(item);
});
} else {
strengthsContainer.innerHTML = '<p>No strengths data available.</p>';
}
// Display weaknesses
const weaknessesContainer = document.getElementById('job-weaknesses-list');
weaknessesContainer.innerHTML = '';
// Check if weaknesses exist and is an array
if (data.weaknesses && Array.isArray(data.weaknesses)) {
data.weaknesses.forEach(weakness => {
const item = document.createElement('div');
item.className = 'job-weakness-item';
item.innerHTML = `
<div class="job-item-aspect">${weakness.aspect || 'N/A'}</div>
<div class="job-item-description">${weakness.description || 'N/A'}</div>
<div class="job-item-importance">Importance: ${weakness.importance || 'N/A'}</div>
<div class="job-item-suggestion">${weakness.improvement_suggestion || 'N/A'}</div>
`;
weaknessesContainer.appendChild(item);
});
} else {
weaknessesContainer.innerHTML = '<p>No weaknesses data available.</p>';
}
// Display enhancement recommendations
const enhancementsContainer = document.getElementById('job-enhancements-list');
enhancementsContainer.innerHTML = '';
// Check if enhancement_recommendations exist and is an array
if (data.enhancement_recommendations && Array.isArray(data.enhancement_recommendations)) {
data.enhancement_recommendations.forEach(rec => {
const item = document.createElement('div');
item.className = 'job-enhancement-item';
item.innerHTML = `
<div class="job-item-aspect">${rec.area || 'N/A'}</div>
<div class="job-item-description">${rec.suggestion || 'N/A'}</div>
<div class="job-item-importance">Priority: ${rec.priority || 'N/A'}</div>
`;
enhancementsContainer.appendChild(item);
});
} else {
enhancementsContainer.innerHTML = '<p>No enhancement recommendations available.</p>';
}
// Display YouTube recommendations
displayJobYouTubeRecommendations(data.video_recommendations);
}
function displayJobYouTubeRecommendations(recommendations) {
const container = document.getElementById('job-youtube-recommendations');
container.innerHTML = '';
if (!recommendations || !Array.isArray(recommendations) || recommendations.length === 0) {
container.innerHTML = '<p>No YouTube recommendations available for this job application.</p>';
return;
}
recommendations.forEach(topic => {
// Check if this is a topic with videos or a single video
if (topic.videos && Array.isArray(topic.videos)) {
// This is a topic with multiple videos
const topicSection = document.createElement('div');
topicSection.className = 'topic-section';
const topicHeader = document.createElement('h3');
topicHeader.textContent = topic.topic || 'Recommended Topic';
topicSection.appendChild(topicHeader);
const topicReason = document.createElement('p');
topicReason.className = 'topic-reason';
topicReason.textContent = topic.reason || 'Recommended to improve your skills';
topicSection.appendChild(topicReason);
const videosContainer = document.createElement('div');
videosContainer.className = 'videos-container';
topic.videos.forEach(video => {
const card = document.createElement('div');
card.className = 'youtube-card';
// Fix URL formatting - remove extra spaces
const embedUrl = (video.embed_url || video.url).replace(/\s+/g, '');
card.innerHTML = `
<div class="youtube-embed">
<iframe src="${embedUrl}"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen></iframe>
</div>
<div class="youtube-info">
<h3 class="youtube-title">${video.title || 'Untitled Video'}</h3>
<p class="youtube-reason">${video.reason || video.description || 'Recommended for skill development'}</p>
</div>
`;
videosContainer.appendChild(card);
});
topicSection.appendChild(videosContainer);
container.appendChild(topicSection);
} else {
// This is a single video (fallback case)
const card = document.createElement('div');
card.className = 'youtube-card';
// Fix URL formatting - remove extra spaces
const embedUrl = (topic.embed_url || topic.url).replace(/\s+/g, '');
card.innerHTML = `
<div class="youtube-embed">
<iframe src="${embedUrl}"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen></iframe>
</div>
<div class="youtube-info">
<h3 class="youtube-title">${topic.title || 'Untitled Video'}</h3>
<p class="youtube-reason">${topic.reason || topic.description || 'Recommended for skill development'}</p>
</div>
`;
container.appendChild(card);
}
});
}
function appendMessage(text, sender, isLoading = false) {
const messageWrapper = document.createElement('div');
messageWrapper.classList.add('chat-message', `${sender}-message`);
const messageP = document.createElement('p');
messageP.textContent = text;
if (isLoading) {
messageP.classList.add('loading');
}
messageWrapper.appendChild(messageP);
chatHistory.appendChild(messageWrapper);
chatHistory.scrollTop = chatHistory.scrollHeight; // Auto-scroll to bottom
}
});