From 110213a29f93c254da70ea4e0d9b7a1696d46c84 Mon Sep 17 00:00:00 2001 From: xiangjinyu <1376193973@qq.com> Date: Mon, 10 Mar 2025 16:24:07 +0800 Subject: [PATCH] modify main.js to English --- static/main.js | 410 +++++++++++++++++++++++++++++++------------------ 1 file changed, 260 insertions(+), 150 deletions(-) diff --git a/static/main.js b/static/main.js index fbf61ff..5015c34 100644 --- a/static/main.js +++ b/static/main.js @@ -5,7 +5,7 @@ function createTask() { const prompt = promptInput.value.trim(); if (!prompt) { - alert("请输入有效的提示内容"); + alert("Please enter a valid prompt"); promptInput.focus(); return; } @@ -16,7 +16,7 @@ function createTask() { } const container = document.getElementById('task-container'); - container.innerHTML = '
任务初始化中...
'; + container.innerHTML = '
Initializing task...
'; document.getElementById('input-container').classList.add('bottom'); fetch('/tasks', { @@ -28,20 +28,20 @@ function createTask() { }) .then(response => { if (!response.ok) { - return response.json().then(err => { throw new Error(err.detail || '请求失败') }); + return response.json().then(err => { throw new Error(err.detail || 'Request failed') }); } return response.json(); }) .then(data => { if (!data.task_id) { - throw new Error('无效的任务ID'); + throw new Error('Invalid task ID'); } setupSSE(data.task_id); loadHistory(); }) .catch(error => { - container.innerHTML = `
错误: ${error.message}
`; - console.error('创建任务失败:', error); + container.innerHTML = `
Error: ${error.message}
`; + console.error('Failed to create task:', error); }); } @@ -49,13 +49,13 @@ function setupSSE(taskId) { let retryCount = 0; const maxRetries = 3; const retryDelay = 2000; - + function connect() { const eventSource = new EventSource(`/tasks/${taskId}/events`); currentEventSource = eventSource; const container = document.getElementById('task-container'); - + let heartbeatTimer = setInterval(() => { container.innerHTML += '
·
'; }, 5000); @@ -67,13 +67,13 @@ function setupSSE(taskId) { updateTaskStatus(task); }) .catch(error => { - console.error('轮询失败:', error); + console.error('Polling failed:', error); }); }, 10000); if (!eventSource._listenersAdded) { eventSource._listenersAdded = true; - + let lastResultContent = ''; eventSource.addEventListener('status', (event) => { clearInterval(heartbeatTimer); @@ -92,9 +92,9 @@ function setupSSE(taskId) { stepContainer = container.querySelector('.step-container'); } - // 保存result内容 + // Save result content if (data.steps && data.steps.length > 0) { - // 遍历所有步骤,找到最后一个result类型 + // Iterate through all steps, find the last result type for (let i = data.steps.length - 1; i >= 0; i--) { if (data.steps[i].type === 'result') { lastResultContent = data.steps[i].result; @@ -116,24 +116,24 @@ function setupSSE(taskId) { `; }).join(''); - + // Auto-scroll to bottom container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' }); } catch (e) { - console.error('状态更新失败:', e); + console.error('Status update failed:', e); } }); - // 添加对think事件的处理 + // Add handler for think event eventSource.addEventListener('think', (event) => { clearInterval(heartbeatTimer); try { const data = JSON.parse(event.data); container.querySelector('.loading')?.remove(); - + let stepContainer = container.querySelector('.step-container'); if (!stepContainer) { container.innerHTML = '
'; @@ -142,7 +142,7 @@ function setupSSE(taskId) { const content = data.result; const timestamp = new Date().toLocaleTimeString(); - + const step = document.createElement('div'); step.className = 'step-item think'; step.innerHTML = ` @@ -151,34 +151,34 @@ function setupSSE(taskId) {
${content}
`; - + stepContainer.appendChild(step); container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' }); - // 更新任务状态 + // Update task status fetch(`/tasks/${taskId}`) .then(response => response.json()) .then(task => { updateTaskStatus(task); }) .catch(error => { - console.error('状态更新失败:', error); + console.error('Status update failed:', error); }); } catch (e) { - console.error('思考事件处理失败:', e); + console.error('Think event handling failed:', e); } }); - // 添加对tool事件的处理 + // Add handler for tool event eventSource.addEventListener('tool', (event) => { clearInterval(heartbeatTimer); try { const data = JSON.parse(event.data); container.querySelector('.loading')?.remove(); - + let stepContainer = container.querySelector('.step-container'); if (!stepContainer) { container.innerHTML = '
'; @@ -187,7 +187,7 @@ function setupSSE(taskId) { const content = data.result; const timestamp = new Date().toLocaleTimeString(); - + const step = document.createElement('div'); step.className = 'step-item tool'; step.innerHTML = ` @@ -196,34 +196,34 @@ function setupSSE(taskId) {
${content}
`; - + stepContainer.appendChild(step); container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' }); - // 更新任务状态 + // Update task status fetch(`/tasks/${taskId}`) .then(response => response.json()) .then(task => { updateTaskStatus(task); }) .catch(error => { - console.error('状态更新失败:', error); + console.error('Status update failed:', error); }); } catch (e) { - console.error('工具事件处理失败:', e); + console.error('Tool event handling failed:', e); } }); - // 添加对act事件的处理 + // Add handler for act event eventSource.addEventListener('act', (event) => { clearInterval(heartbeatTimer); try { const data = JSON.parse(event.data); container.querySelector('.loading')?.remove(); - + let stepContainer = container.querySelector('.step-container'); if (!stepContainer) { container.innerHTML = '
'; @@ -232,7 +232,7 @@ function setupSSE(taskId) { const content = data.result; const timestamp = new Date().toLocaleTimeString(); - + const step = document.createElement('div'); step.className = 'step-item act'; step.innerHTML = ` @@ -241,35 +241,34 @@ function setupSSE(taskId) {
${content}
`; - + stepContainer.appendChild(step); container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' }); - // 更新任务状态 + // Update task status fetch(`/tasks/${taskId}`) .then(response => response.json()) .then(task => { updateTaskStatus(task); }) .catch(error => { - console.error('状态更新失败:', error); + console.error('Status update failed:', error); }); } catch (e) { - console.error('执行事件处理失败:', e); + console.error('Act event handling failed:', e); } }); - // 添加对run事件的处理 - // 添加对log事件的处理 + // Add handler for log event eventSource.addEventListener('log', (event) => { clearInterval(heartbeatTimer); try { const data = JSON.parse(event.data); container.querySelector('.loading')?.remove(); - + let stepContainer = container.querySelector('.step-container'); if (!stepContainer) { container.innerHTML = '
'; @@ -278,7 +277,7 @@ function setupSSE(taskId) { const content = data.result; const timestamp = new Date().toLocaleTimeString(); - + const step = document.createElement('div'); step.className = 'step-item log'; step.innerHTML = ` @@ -287,24 +286,24 @@ function setupSSE(taskId) {
${content}
`; - + stepContainer.appendChild(step); container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' }); - // 更新任务状态 + // Update task status fetch(`/tasks/${taskId}`) .then(response => response.json()) .then(task => { updateTaskStatus(task); }) .catch(error => { - console.error('状态更新失败:', error); + console.error('Status update failed:', error); }); } catch (e) { - console.error('日志事件处理失败:', e); + console.error('Log event handling failed:', e); } }); @@ -313,7 +312,7 @@ function setupSSE(taskId) { try { const data = JSON.parse(event.data); container.querySelector('.loading')?.remove(); - + let stepContainer = container.querySelector('.step-container'); if (!stepContainer) { container.innerHTML = '
'; @@ -322,7 +321,7 @@ function setupSSE(taskId) { const content = data.result; const timestamp = new Date().toLocaleTimeString(); - + const step = document.createElement('div'); step.className = 'step-item run'; step.innerHTML = ` @@ -331,24 +330,24 @@ function setupSSE(taskId) {
${content}
`; - + stepContainer.appendChild(step); container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' }); - // 更新任务状态 + // Update task status fetch(`/tasks/${taskId}`) .then(response => response.json()) .then(task => { updateTaskStatus(task); }) .catch(error => { - console.error('状态更新失败:', error); + console.error('Status update failed:', error); }); } catch (e) { - console.error('运行事件处理失败:', e); + console.error('Run event handling failed:', e); } }); @@ -363,35 +362,35 @@ function setupSSE(taskId) { container.innerHTML = '
'; stepContainer = container.querySelector('.step-container'); } - + // Create new step element const step = document.createElement('div'); step.className = `step-item ${data.type || 'step'}`; - + // Format content and timestamp const content = data.result; const timestamp = new Date().toLocaleTimeString(); - + step.innerHTML = `
${getEventIcon(data.type)} [${timestamp}] ${getEventLabel(data.type)}:
${content}
`; - + // Add step to container with animation stepContainer.prepend(step); setTimeout(() => { step.classList.add('show'); }, 10); - + // Auto-scroll to bottom container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' }); } catch (e) { - console.error('消息处理失败:', e); + console.error('Message handling failed:', e); } }); @@ -403,13 +402,13 @@ function setupSSE(taskId) { clearInterval(pollInterval); container.innerHTML += `
-
✅ 任务完成
+
✅ Task completed
${lastResultContent}
`; eventSource.close(); currentEventSource = null; - lastResultContent = ''; // 清空结果内容 + lastResultContent = ''; // Clear result content }); eventSource.addEventListener('error', (event) => { @@ -419,17 +418,17 @@ function setupSSE(taskId) { const data = JSON.parse(event.data); container.innerHTML += `
- ❌ 错误: ${data.message} + ❌ Error: ${data.message}
`; eventSource.close(); currentEventSource = null; } catch (e) { - console.error('错误处理失败:', e); + console.error('Error handling failed:', e); } }); } - + container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' @@ -439,30 +438,30 @@ function setupSSE(taskId) { if (isTaskComplete) { return; } - - console.error('SSE连接错误:', err); + + console.error('SSE connection error:', err); clearInterval(heartbeatTimer); clearInterval(pollInterval); eventSource.close(); - + if (retryCount < maxRetries) { retryCount++; container.innerHTML += `
- ⚠ 连接中断,${retryDelay/1000}秒后重试 (${retryCount}/${maxRetries})... + ⚠ Connection lost, retrying in ${retryDelay/1000} seconds (${retryCount}/${maxRetries})...
`; setTimeout(connect, retryDelay); } else { container.innerHTML += `
- ⚠ 连接中断,请尝试刷新页面 + ⚠ Connection lost, please try refreshing the page
`; } }; } - + connect(); } @@ -474,112 +473,223 @@ function getEventIcon(eventType) { case 'result': return '🏁'; case 'error': return '❌'; case 'complete': return '✅'; - case 'warning': return '⚠️'; case 'log': return '📝'; - default: return '⚡'; + case 'run': return '⚙️'; + default: return 'ℹ️'; } } function getEventLabel(eventType) { switch(eventType) { - case 'think': return '思考'; - case 'tool': return '工具执行'; - case 'act': return '执行'; - case 'result': return '结果'; - case 'error': return '错误'; - case 'complete': return '完成'; - case 'warning': return '警告'; - case 'log': return '日志'; - default: return '步骤'; + case 'think': return 'Thinking'; + case 'tool': return 'Using Tool'; + case 'act': return 'Action'; + case 'result': return 'Result'; + case 'error': return 'Error'; + case 'complete': return 'Complete'; + case 'log': return 'Log'; + case 'run': return 'Running'; + default: return 'Info'; } } -function formatContent(content) { - // Remove timestamp and log level prefixes - content = content.replace(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3} \| [A-Z]+\s*\| /gm, ''); - // Format the remaining content - return content - .replace(/\n/g, '
') - .replace(/ /g, '  ') - .replace(/✨ Manus's thoughts:/g, '') - .replace(/🛠️ Manus selected/g, '') - .replace(/🧰 Tools being prepared:/g, '') - .replace(/🔧 Activating tool:/g, '') - .replace(/🎯 Tool/g, '') - .replace(/📝 Oops!/g, '') - .replace(/🏁 Special tool/g, ''); -} - function updateTaskStatus(task) { - const taskCard = document.querySelector(`.task-card[data-task-id="${task.id}"]`); - if (taskCard) { - const statusEl = taskCard.querySelector('.task-meta .status'); - if (statusEl) { - statusEl.className = `status-${task.status ? task.status.toLowerCase() : 'unknown'}`; - statusEl.textContent = task.status || '未知状态'; - } + const statusBar = document.getElementById('status-bar'); + if (!statusBar) return; + + if (task.status === 'completed') { + statusBar.innerHTML = `✅ Task completed`; + } else if (task.status === 'failed') { + statusBar.innerHTML = `❌ Task failed: ${task.error || 'Unknown error'}`; + } else { + statusBar.innerHTML = `⚙️ Task running: ${task.status}`; } } function loadHistory() { fetch('/tasks') - .then(response => { - if (!response.ok) { - return response.text().then(text => { - throw new Error(`请求失败: ${response.status} - ${text.substring(0, 100)}`); + .then(response => { + if (!response.ok) { + throw new Error('Failed to load history'); + } + return response.json(); + }) + .then(tasks => { + const historyContainer = document.getElementById('history-container'); + if (!historyContainer) return; + + historyContainer.innerHTML = ''; + + if (tasks.length === 0) { + historyContainer.innerHTML = '
No recent tasks
'; + return; + } + + const historyList = document.createElement('div'); + historyList.className = 'history-list'; + + tasks.forEach(task => { + const taskItem = document.createElement('div'); + taskItem.className = `history-item ${task.status}`; + taskItem.innerHTML = ` +
${task.prompt}
+
+ ${new Date(task.created_at).toLocaleString()} + ${getStatusIcon(task.status)} +
+ `; + taskItem.addEventListener('click', () => { + loadTask(task.id); + }); + historyList.appendChild(taskItem); }); - } - return response.json(); - }) - .then(tasks => { - const listContainer = document.getElementById('task-list'); - listContainer.innerHTML = tasks.map(task => ` -
-
${task.prompt}
-
- ${new Date(task.created_at).toLocaleString()} - - - ${task.status || '未知状态'} - -
-
- `).join(''); - }) - .catch(error => { - console.error('加载历史记录失败:', error); - const listContainer = document.getElementById('task-list'); - listContainer.innerHTML = `
加载失败: ${error.message}
`; - }); + + historyContainer.appendChild(historyList); + }) + .catch(error => { + console.error('Failed to load history:', error); + const historyContainer = document.getElementById('history-container'); + if (historyContainer) { + historyContainer.innerHTML = `
Failed to load history: ${error.message}
`; + } + }); } -document.addEventListener('DOMContentLoaded', function() { +function getStatusIcon(status) { + switch(status) { + case 'completed': return '✅'; + case 'failed': return '❌'; + case 'running': return '⚙️'; + default: return '⏳'; + } +} + +function loadTask(taskId) { + if (currentEventSource) { + currentEventSource.close(); + currentEventSource = null; + } + + const container = document.getElementById('task-container'); + container.innerHTML = '
Loading task...
'; + document.getElementById('input-container').classList.add('bottom'); + + fetch(`/tasks/${taskId}`) + .then(response => { + if (!response.ok) { + throw new Error('Failed to load task'); + } + return response.json(); + }) + .then(task => { + if (task.status === 'running') { + setupSSE(taskId); + } else { + displayTask(task); + } + }) + .catch(error => { + console.error('Failed to load task:', error); + container.innerHTML = `
Failed to load task: ${error.message}
`; + }); +} + +function displayTask(task) { + const container = document.getElementById('task-container'); + container.innerHTML = ''; + container.classList.add('active'); + const welcomeMessage = document.querySelector('.welcome-message'); if (welcomeMessage) { - welcomeMessage.style.display = 'flex'; + welcomeMessage.style.display = 'none'; } - - // 监听任务容器显示状态 - const taskContainer = document.getElementById('task-container'); - if (taskContainer) { - const observer = new MutationObserver((mutations) => { - mutations.forEach(mutation => { - if (mutation.attributeName === 'class') { - const welcomeMessage = document.querySelector('.welcome-message'); - if (taskContainer.classList.contains('active')) { - if (welcomeMessage) { - welcomeMessage.style.display = 'none'; - } - } else { - if (welcomeMessage) { - welcomeMessage.style.display = 'block'; - } - } - } - }); + + const stepContainer = document.createElement('div'); + stepContainer.className = 'step-container'; + + if (task.steps && task.steps.length > 0) { + task.steps.forEach(step => { + const stepItem = document.createElement('div'); + stepItem.className = `step-item ${step.type || 'step'}`; + + const content = step.result; + const timestamp = new Date(step.timestamp || task.created_at).toLocaleTimeString(); + + stepItem.innerHTML = ` +
+ ${getEventIcon(step.type)} [${timestamp}] ${getEventLabel(step.type)}: +
${content}
+
+ `; + + stepContainer.appendChild(stepItem); }); - - observer.observe(taskContainer, { - attributes: true + } else { + stepContainer.innerHTML = '
No steps recorded for this task
'; + } + + container.appendChild(stepContainer); + + if (task.status === 'completed') { + let lastResultContent = ''; + if (task.steps && task.steps.length > 0) { + for (let i = task.steps.length - 1; i >= 0; i--) { + if (task.steps[i].type === 'result') { + lastResultContent = task.steps[i].result; + break; + } + } + } + + container.innerHTML += ` +
+
✅ Task completed
+
${lastResultContent}
+
+ `; + } else if (task.status === 'failed') { + container.innerHTML += ` +
+ ❌ Error: ${task.error || 'Unknown error'} +
+ `; + } + + updateTaskStatus(task); +} + +// Initialize the app when the DOM is loaded +document.addEventListener('DOMContentLoaded', () => { + loadHistory(); + + // Set up event listeners + document.getElementById('create-task-btn').addEventListener('click', createTask); + document.getElementById('prompt-input').addEventListener('keydown', (e) => { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + createTask(); + } + }); + + // Show history button functionality + const historyToggle = document.getElementById('history-toggle'); + if (historyToggle) { + historyToggle.addEventListener('click', () => { + const historyPanel = document.getElementById('history-panel'); + if (historyPanel) { + historyPanel.classList.toggle('open'); + historyToggle.classList.toggle('active'); + } + }); + } + + // Clear button functionality + const clearButton = document.getElementById('clear-btn'); + if (clearButton) { + clearButton.addEventListener('click', () => { + document.getElementById('prompt-input').value = ''; + document.getElementById('prompt-input').focus(); }); } }); +