RA.Aid/webui/script.js

163 lines
6.0 KiB
JavaScript

class RAWebUI {
constructor() {
this.messageHistory = [];
this.setupElements();
this.setupEventListeners();
this.connectWebSocket();
}
setupElements() {
this.userInput = document.getElementById('user-input');
this.sendButton = document.getElementById('send-button');
this.chatMessages = document.getElementById('chat-messages');
this.streamOutput = document.getElementById('stream-output');
this.historyList = document.getElementById('history-list');
}
setupEventListeners() {
this.sendButton.addEventListener('click', () => this.sendMessage());
this.userInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
this.sendMessage();
}
});
}
async connectWebSocket() {
try {
// Get the server port from the response header or default to 8080
const serverPort = document.querySelector('meta[name="server-port"]')?.content || '8080';
// Construct WebSocket URL using the server port
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = `${protocol}//${window.location.hostname}:${serverPort}/ws`;
console.log('Attempting to connect to WebSocket URL:', wsUrl);
console.log('Creating new WebSocket connection...');
this.ws = new WebSocket(wsUrl);
this.ws.onopen = () => {
console.log('WebSocket connection established successfully');
console.log('Connected to WebSocket server');
this.sendButton.disabled = false;
};
this.ws.onclose = () => {
console.log('Disconnected from WebSocket server');
this.sendButton.disabled = true;
setTimeout(() => this.connectWebSocket(), 5000);
};
this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
};
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
this.handleServerMessage(data);
};
} catch (error) {
console.error('Failed to connect to WebSocket:', error);
setTimeout(() => this.connectWebSocket(), 5000);
}
}
handleServerMessage(data) {
if (data.type === 'stream_start') {
this.streamOutput.textContent = '';
this.streamOutput.style.display = 'block';
} else if (data.type === 'stream_end') {
this.streamOutput.style.display = 'none';
this.addToHistory(data.request);
} else if (data.type === 'chunk') {
this.handleChunk(data.chunk);
}
}
handleChunk(chunk) {
if (chunk.agent && chunk.agent.messages) {
chunk.agent.messages.forEach(msg => {
if (msg.content) {
if (Array.isArray(msg.content)) {
msg.content.forEach(content => {
if (content.type === 'text' && content.text.trim()) {
this.appendMessage(content.text.trim(), 'system');
}
});
} else if (msg.content.trim()) {
this.appendMessage(msg.content.trim(), 'system');
}
}
});
} else if (chunk.tools && chunk.tools.messages) {
chunk.tools.messages.forEach(msg => {
if (msg.status === 'error' && msg.content) {
this.appendMessage(msg.content.trim(), 'error');
}
});
}
}
appendMessage(content, type) {
const messageDiv = document.createElement('div');
messageDiv.className = `message ${type}-message`;
messageDiv.textContent = content;
this.chatMessages.appendChild(messageDiv);
this.chatMessages.scrollTop = this.chatMessages.scrollHeight;
}
addToHistory(request) {
const historyItem = document.createElement('div');
historyItem.className = 'history-item';
historyItem.textContent = request.slice(0, 50) + (request.length > 50 ? '...' : '');
historyItem.title = request;
historyItem.addEventListener('click', () => {
this.userInput.value = request;
this.userInput.focus();
});
this.historyList.insertBefore(historyItem, this.historyList.firstChild);
this.messageHistory.push(request);
}
sendMessage() {
console.log('Send button clicked');
const message = this.userInput.value.trim();
console.log('Message content:', message);
if (!message) {
console.log('Message is empty, not sending');
return;
}
console.log('WebSocket state:', this.ws.readyState);
if (this.ws.readyState !== WebSocket.OPEN) {
console.error('WebSocket is not connected');
this.appendMessage('Error: WebSocket is not connected. Trying to reconnect...', 'error');
this.connectWebSocket();
return;
}
try {
console.log('Sending message to server');
this.appendMessage(message, 'user');
const payload = { type: 'request', content: message };
console.log('Payload:', payload);
this.ws.send(JSON.stringify(payload));
console.log('Message sent successfully');
this.userInput.value = '';
this.sendButton.disabled = true;
} catch (error) {
console.error('Error sending message:', error);
this.appendMessage(`Error sending message: ${error.message}`, 'error');
this.sendButton.disabled = false;
}
}
}
// Initialize the UI when the page loads
document.addEventListener('DOMContentLoaded', () => {
window.raWebUI = new RAWebUI();
});