403 lines
11 KiB
JavaScript
403 lines
11 KiB
JavaScript
let currentFeature = null;
|
||
let interviewId = null;
|
||
let conversationKey = 'default';
|
||
|
||
function showFeature(feature) {
|
||
document.querySelectorAll('.tool-section').forEach(section => {
|
||
section.style.display = 'none';
|
||
});
|
||
|
||
document.querySelectorAll('.feature-card').forEach(card => {
|
||
card.style.transform = '';
|
||
card.style.boxShadow = '';
|
||
});
|
||
|
||
if (feature === null) {
|
||
currentFeature = null;
|
||
return;
|
||
}
|
||
|
||
const featureCard = document.querySelector(`.feature-card[onclick="showFeature('${feature}')"]`);
|
||
if (featureCard) {
|
||
featureCard.style.transform = 'translateY(-5px)';
|
||
featureCard.style.boxShadow = '0 10px 30px rgba(102, 126, 234, 0.3)';
|
||
}
|
||
|
||
currentFeature = feature;
|
||
|
||
const sectionMap = {
|
||
'resume': 'resume-section',
|
||
'interview': 'interview-section',
|
||
'feedback': 'interview-section'
|
||
};
|
||
|
||
const targetSection = sectionMap[feature];
|
||
if (targetSection) {
|
||
document.getElementById(targetSection).style.display = 'block';
|
||
|
||
if (feature === 'interview' || feature === 'feedback') {
|
||
resetInterview();
|
||
} else if (feature === 'resume') {
|
||
document.getElementById('resume-result').style.display = 'none';
|
||
}
|
||
}
|
||
}
|
||
|
||
function showLoading(show) {
|
||
document.getElementById('loading-overlay').style.display = show ? 'flex' : 'none';
|
||
}
|
||
|
||
async function optimizeResume() {
|
||
const targetPosition = document.getElementById('target-position').value.trim();
|
||
const resumeContent = document.getElementById('resume-content').value.trim();
|
||
|
||
if (!resumeContent) {
|
||
alert('请输入简历内容');
|
||
return;
|
||
}
|
||
|
||
showLoading(true);
|
||
|
||
try {
|
||
const response = await fetch('/api/resume/optimize', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
resume_content: resumeContent,
|
||
target_position: targetPosition
|
||
})
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.error) {
|
||
alert(data.error);
|
||
return;
|
||
}
|
||
|
||
const suggestionsDiv = document.getElementById('resume-suggestions');
|
||
suggestionsDiv.innerHTML = formatSuggestions(data.suggestions);
|
||
document.getElementById('resume-result').style.display = 'block';
|
||
|
||
} catch (error) {
|
||
alert('优化失败:' + error.message);
|
||
} finally {
|
||
showLoading(false);
|
||
}
|
||
}
|
||
|
||
function formatSuggestions(text) {
|
||
if (!text) return '<p>未能生成优化建议,请重试。</p>';
|
||
|
||
let html = text
|
||
.replace(/\n\n/g, '</p><p>')
|
||
.replace(/\n/g, '<br>');
|
||
|
||
return '<p>' + html + '</p>';
|
||
}
|
||
|
||
async function startInterview() {
|
||
const jobPosition = document.getElementById('job-position').value.trim();
|
||
|
||
if (!jobPosition) {
|
||
alert('请输入目标岗位');
|
||
return;
|
||
}
|
||
|
||
const difficulty = document.querySelector('input[name="difficulty"]:checked').value;
|
||
|
||
showLoading(true);
|
||
|
||
try {
|
||
const response = await fetch('/api/interview/start', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
job_position: jobPosition,
|
||
difficulty: difficulty
|
||
})
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.error) {
|
||
alert(data.error);
|
||
return;
|
||
}
|
||
|
||
interviewId = data.interview_id;
|
||
|
||
document.getElementById('interview-setup').style.display = 'none';
|
||
document.getElementById('interview-active').style.display = 'flex';
|
||
|
||
document.getElementById('current-position').textContent = '目标岗位:' + data.job_position;
|
||
updatePhaseBadge(data.phase);
|
||
|
||
const messagesContainer = document.getElementById('interview-messages');
|
||
messagesContainer.innerHTML = '';
|
||
|
||
addInterviewMessage(data.question, 'interviewer');
|
||
|
||
} catch (error) {
|
||
alert('开始面试失败:' + error.message);
|
||
} finally {
|
||
showLoading(false);
|
||
}
|
||
}
|
||
|
||
function updatePhaseBadge(phase) {
|
||
const phaseMap = {
|
||
'intro': '自我介绍',
|
||
'professional': '专业能力',
|
||
'scenario': '情景假设',
|
||
'career': '职业规划',
|
||
'closing': '面试结束'
|
||
};
|
||
|
||
document.getElementById('current-phase').textContent = phaseMap[phase] || phase;
|
||
}
|
||
|
||
function addInterviewMessage(content, type) {
|
||
if (!content) return;
|
||
|
||
const messagesContainer = document.getElementById('interview-messages');
|
||
const messageDiv = document.createElement('div');
|
||
messageDiv.className = 'message ' + type;
|
||
messageDiv.textContent = content;
|
||
messagesContainer.appendChild(messageDiv);
|
||
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
||
}
|
||
|
||
async function submitAnswer() {
|
||
const answerInput = document.getElementById('answer-input');
|
||
const answer = answerInput.value.trim();
|
||
|
||
if (!answer) {
|
||
alert('请输入你的回答');
|
||
return;
|
||
}
|
||
|
||
addInterviewMessage(answer, 'candidate');
|
||
answerInput.value = '';
|
||
|
||
showLoading(true);
|
||
|
||
try {
|
||
const response = await fetch('/api/interview/answer', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
interview_id: interviewId,
|
||
answer: answer,
|
||
request_feedback: false
|
||
})
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.error) {
|
||
alert(data.error);
|
||
return;
|
||
}
|
||
|
||
if (data.ended) {
|
||
showFinalFeedback(data.conversation_history);
|
||
} else if (data.question) {
|
||
addInterviewMessage(data.question, 'interviewer');
|
||
updatePhaseBadge(data.phase);
|
||
}
|
||
|
||
} catch (error) {
|
||
alert('提交回答失败:' + error.message);
|
||
} finally {
|
||
showLoading(false);
|
||
}
|
||
}
|
||
|
||
async function requestFeedback() {
|
||
const answerInput = document.getElementById('answer-input');
|
||
const answer = answerInput.value.trim();
|
||
|
||
if (!answer) {
|
||
alert('请先输入你的回答');
|
||
return;
|
||
}
|
||
|
||
addInterviewMessage(answer, 'candidate');
|
||
answerInput.value = '';
|
||
|
||
showLoading(true);
|
||
|
||
try {
|
||
const response = await fetch('/api/interview/answer', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
interview_id: interviewId,
|
||
answer: answer,
|
||
request_feedback: true
|
||
})
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.error) {
|
||
alert(data.error);
|
||
return;
|
||
}
|
||
|
||
if (data.feedback) {
|
||
addInterviewMessage(data.feedback, 'feedback');
|
||
}
|
||
|
||
} catch (error) {
|
||
alert('获取反馈失败:' + error.message);
|
||
} finally {
|
||
showLoading(false);
|
||
}
|
||
}
|
||
|
||
async function endInterview() {
|
||
const messages = [];
|
||
document.querySelectorAll('.interview-messages .message').forEach(msg => {
|
||
messages.push({
|
||
role: msg.classList.contains('interviewer') ? 'assistant' : 'user',
|
||
content: msg.textContent
|
||
});
|
||
});
|
||
|
||
showLoading(true);
|
||
|
||
try {
|
||
const response = await fetch('/api/interview/feedback', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
interview_id: interviewId,
|
||
conversation_history: messages
|
||
})
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.error) {
|
||
alert(data.error);
|
||
return;
|
||
}
|
||
|
||
showFinalFeedback(data.feedback);
|
||
|
||
} catch (error) {
|
||
alert('获取反馈失败:' + error.message);
|
||
} finally {
|
||
showLoading(false);
|
||
}
|
||
}
|
||
|
||
function showFinalFeedback(feedbackData) {
|
||
document.getElementById('interview-active').style.display = 'none';
|
||
document.getElementById('interview-feedback').style.display = 'block';
|
||
|
||
const feedbackContent = document.getElementById('feedback-content');
|
||
|
||
if (typeof feedbackData === 'string') {
|
||
feedbackContent.innerHTML = formatSuggestions(feedbackData);
|
||
} else {
|
||
let html = '<h4>面试综合评估</h4>';
|
||
feedbackData.forEach(msg => {
|
||
html += `<p><strong>${msg.role === 'assistant' ? '面试官' : '你'}:</strong>${msg.content}</p>`;
|
||
});
|
||
feedbackContent.innerHTML = html;
|
||
}
|
||
}
|
||
|
||
function resetInterview() {
|
||
interviewId = null;
|
||
document.getElementById('interview-setup').style.display = 'block';
|
||
document.getElementById('interview-active').style.display = 'none';
|
||
document.getElementById('interview-feedback').style.display = 'none';
|
||
document.getElementById('interview-messages').innerHTML = '';
|
||
document.getElementById('answer-input').value = '';
|
||
document.getElementById('job-position').value = '';
|
||
}
|
||
|
||
async function sendChatMessage() {
|
||
const chatInput = document.getElementById('chat-input');
|
||
const message = chatInput.value.trim();
|
||
|
||
if (!message) {
|
||
return;
|
||
}
|
||
|
||
const messagesContainer = document.getElementById('chat-messages');
|
||
|
||
const userMessageDiv = document.createElement('div');
|
||
userMessageDiv.className = 'chat-message user';
|
||
userMessageDiv.textContent = message;
|
||
messagesContainer.appendChild(userMessageDiv);
|
||
|
||
chatInput.value = '';
|
||
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
||
|
||
showLoading(true);
|
||
|
||
try {
|
||
const response = await fetch('/api/chat', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
message: message,
|
||
system_type: 'general_assistant',
|
||
conversation_key: conversationKey
|
||
})
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.error) {
|
||
alert(data.error);
|
||
return;
|
||
}
|
||
|
||
const assistantMessageDiv = document.createElement('div');
|
||
assistantMessageDiv.className = 'chat-message assistant';
|
||
assistantMessageDiv.textContent = data.response;
|
||
messagesContainer.appendChild(assistantMessageDiv);
|
||
|
||
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
||
|
||
} catch (error) {
|
||
alert('发送消息失败:' + error.message);
|
||
} finally {
|
||
showLoading(false);
|
||
}
|
||
}
|
||
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
document.getElementById('chat-input').addEventListener('keypress', function(e) {
|
||
if (e.key === 'Enter' && !e.shiftKey) {
|
||
e.preventDefault();
|
||
sendChatMessage();
|
||
}
|
||
});
|
||
|
||
document.getElementById('answer-input').addEventListener('keypress', function(e) {
|
||
if (e.key === 'Enter' && !e.shiftKey) {
|
||
e.preventDefault();
|
||
submitAnswer();
|
||
}
|
||
});
|
||
});
|