Hirely-Backend / backend /test_websocket.html
NaikPranav11's picture
Initial clean deployment
1207440
Raw
History Blame Contribute Delete
12.2 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Interview WebSocket Test</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 50px auto;
padding: 20px;
background: #f5f5f5;
}
.container {
background: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
color: #333;
margin-bottom: 20px;
}
.status {
padding: 10px;
margin: 10px 0;
border-radius: 5px;
font-weight: bold;
}
.status.connected {
background: #d4edda;
color: #155724;
}
.status.disconnected {
background: #f8d7da;
color: #721c24;
}
.status.connecting {
background: #fff3cd;
color: #856404;
}
button {
background: #007bff;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
margin: 5px;
font-size: 14px;
}
button:hover {
background: #0056b3;
}
button:disabled {
background: #ccc;
cursor: not-allowed;
}
.messages {
margin-top: 20px;
max-height: 400px;
overflow-y: auto;
border: 1px solid #ddd;
padding: 10px;
border-radius: 5px;
background: #f9f9f9;
}
.message {
padding: 8px;
margin: 5px 0;
border-radius: 3px;
font-size: 13px;
}
.message.sent {
background: #e3f2fd;
border-left: 3px solid #2196f3;
}
.message.received {
background: #f1f8e9;
border-left: 3px solid #8bc34a;
}
.message.error {
background: #ffebee;
border-left: 3px solid #f44336;
}
.timestamp {
color: #666;
font-size: 11px;
}
input {
width: 100%;
padding: 10px;
margin: 10px 0;
border: 1px solid #ddd;
border-radius: 5px;
box-sizing: border-box;
}
.question-box {
background: #fff3cd;
padding: 15px;
margin: 15px 0;
border-radius: 5px;
border-left: 4px solid #ffc107;
}
.score-box {
background: #d4edda;
padding: 15px;
margin: 15px 0;
border-radius: 5px;
border-left: 4px solid #28a745;
}
</style>
</head>
<body>
<div class="container">
<h1>🤖 AI Interview WebSocket Test</h1>
<div id="status" class="status disconnected">Disconnected</div>
<div>
<input type="text" id="sessionId" placeholder="Session ID (leave empty to create new)">
<button id="connectBtn" onclick="connect()">Connect</button>
<button id="disconnectBtn" onclick="disconnect()" disabled>Disconnect</button>
</div>
<div style="margin-top: 20px;">
<button id="startBtn" onclick="startInterview()" disabled>Start Interview</button>
<button id="pingBtn" onclick="sendPing()" disabled>Send Ping</button>
<button id="endBtn" onclick="endInterview()" disabled>End Interview</button>
</div>
<div id="questionBox" class="question-box" style="display: none;">
<h3>Current Question:</h3>
<p id="currentQuestion"></p>
<input type="text" id="answerInput" placeholder="Type your answer here...">
<button onclick="submitAnswer()">Submit Answer</button>
</div>
<div id="scoreBox" class="score-box" style="display: none;">
<h3>Latest Scores:</h3>
<div id="scores"></div>
</div>
<div class="messages" id="messages"></div>
</div>
<script>
let ws = null;
let currentQuestionNumber = 0;
const API_BASE = 'http://localhost:8000/api/v1';
const WS_BASE = 'ws://localhost:8000/api/v1';
function updateStatus(status, className) {
const statusEl = document.getElementById('status');
statusEl.textContent = status;
statusEl.className = 'status ' + className;
}
function addMessage(text, type = 'received') {
const messagesEl = document.getElementById('messages');
const messageEl = document.createElement('div');
messageEl.className = 'message ' + type;
const timestamp = new Date().toLocaleTimeString();
messageEl.innerHTML = `
<div>${text}</div>
<div class="timestamp">${timestamp}</div>
`;
messagesEl.appendChild(messageEl);
messagesEl.scrollTop = messagesEl.scrollHeight;
}
async function createSession() {
try {
// For testing, we'll use a hardcoded token
// In production, get this from login
const token = localStorage.getItem('hirely_token') || 'test_token';
const response = await fetch(`${API_BASE}/ai-interview/session/create?interview_id=1`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`
}
});
if (!response.ok) {
throw new Error('Failed to create session');
}
const data = await response.json();
return data.session_id;
} catch (error) {
addMessage('Error creating session: ' + error.message, 'error');
return null;
}
}
async function connect() {
let sessionId = document.getElementById('sessionId').value.trim();
if (!sessionId) {
addMessage('Creating new session...', 'sent');
sessionId = await createSession();
if (!sessionId) return;
document.getElementById('sessionId').value = sessionId;
addMessage('Session created: ' + sessionId, 'received');
}
updateStatus('Connecting...', 'connecting');
addMessage('Connecting to WebSocket...', 'sent');
const token = localStorage.getItem('hirely_token') || 'test_token';
const wsUrl = `${WS_BASE}/ai-interview/ws/${sessionId}?token=${token}`;
ws = new WebSocket(wsUrl);
ws.onopen = () => {
updateStatus('Connected', 'connected');
addMessage('✅ Connected to WebSocket!', 'received');
document.getElementById('connectBtn').disabled = true;
document.getElementById('disconnectBtn').disabled = false;
document.getElementById('startBtn').disabled = false;
document.getElementById('pingBtn').disabled = false;
document.getElementById('endBtn').disabled = false;
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
handleMessage(data);
};
ws.onerror = (error) => {
addMessage('❌ WebSocket error: ' + error, 'error');
};
ws.onclose = () => {
updateStatus('Disconnected', 'disconnected');
addMessage('WebSocket closed', 'error');
document.getElementById('connectBtn').disabled = false;
document.getElementById('disconnectBtn').disabled = true;
document.getElementById('startBtn').disabled = true;
document.getElementById('pingBtn').disabled = true;
document.getElementById('endBtn').disabled = true;
};
}
function disconnect() {
if (ws) {
ws.close();
ws = null;
}
}
function handleMessage(data) {
const type = data.type;
addMessage(`📨 Received: ${type}`, 'received');
switch(type) {
case 'welcome':
addMessage(`Message: ${data.message}`, 'received');
break;
case 'question':
currentQuestionNumber = data.question_number;
document.getElementById('currentQuestion').textContent = data.question;
document.getElementById('questionBox').style.display = 'block';
addMessage(`Question ${data.question_number}: ${data.question}`, 'received');
break;
case 'answer_scored':
const scores = data.scores;
document.getElementById('scores').innerHTML = `
<p>Clarity: ${scores.clarity}</p>
<p>Relevance: ${scores.relevance}</p>
<p>Conciseness: ${scores.conciseness}</p>
<p>Communication: ${scores.communication}</p>
`;
document.getElementById('scoreBox').style.display = 'block';
addMessage(`Scores received for Q${data.question_number}`, 'received');
break;
case 'interview_completed':
addMessage(`✅ Interview completed! Overall score: ${data.overall_score}`, 'received');
document.getElementById('questionBox').style.display = 'none';
break;
case 'pong':
addMessage('🏓 Pong received', 'received');
break;
case 'status':
addMessage(`Status: ${data.status}`, 'received');
break;
case 'error':
addMessage(`Error: ${data.message}`, 'error');
break;
}
}
function startInterview() {
if (!ws) return;
addMessage('Starting interview...', 'sent');
ws.send(JSON.stringify({
type: 'start_interview'
}));
}
function submitAnswer() {
if (!ws) return;
const answer = document.getElementById('answerInput').value;
if (!answer.trim()) {
alert('Please enter an answer');
return;
}
addMessage(`Submitting answer: "${answer}"`, 'sent');
ws.send(JSON.stringify({
type: 'answer_submitted',
question_number: currentQuestionNumber,
answer: answer
}));
document.getElementById('answerInput').value = '';
}
function sendPing() {
if (!ws) return;
addMessage('Sending ping...', 'sent');
ws.send(JSON.stringify({
type: 'ping'
}));
}
function endInterview() {
if (!ws) return;
addMessage('Ending interview...', 'sent');
ws.send(JSON.stringify({
type: 'end_interview'
}));
}
</script>
</body>
</html>