Files
manus_ai_clone/static/js/main.js
T
2025-11-05 01:03:10 +01:00

422 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ===========================
// State Management
// ===========================
let taskStats = {
total: 0,
successful: 0,
times: [],
};
// Load stats from localStorage
function loadStats() {
const savedStats = localStorage.getItem("taskStats");
if (savedStats) {
taskStats = JSON.parse(savedStats);
updateStatsDisplay();
}
}
// Save stats to localStorage
function saveStats() {
localStorage.setItem("taskStats", JSON.stringify(taskStats));
}
// Update stats display
function updateStatsDisplay() {
document.getElementById("total-tasks").textContent = taskStats.total;
document.getElementById("successful-tasks").textContent =
taskStats.successful;
if (taskStats.times.length > 0) {
const avgTime =
taskStats.times.reduce((a, b) => a + b, 0) / taskStats.times.length;
document.getElementById("avg-time").textContent =
avgTime.toFixed(1) + "s";
}
}
// ===========================
// Main Functions
// ===========================
// Fill prompt textarea with example
function fillPrompt(text) {
document.getElementById("prompt").value = text.trim();
document.getElementById("prompt").focus();
}
// Execute browser automation task
async function executeTask() {
const prompt = document.getElementById("prompt").value.trim();
if (!prompt) {
showNotification("Please enter a task prompt", "error");
return;
}
// Show loading, hide results
showLoading(true);
hideResults();
disableButtons(true);
const startTime = Date.now();
try {
const response = await fetch("/execute", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ prompt }),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
const duration = ((Date.now() - startTime) / 1000).toFixed(1);
// Update stats
taskStats.total++;
if (data.success) {
taskStats.successful++;
}
taskStats.times.push(parseFloat(duration));
saveStats();
updateStatsDisplay();
// Hide loading
showLoading(false);
disableButtons(false);
// Display results
displayResults(data, duration);
// Show notification
if (data.success) {
showNotification("Task completed successfully!", "success");
} else {
showNotification(
"Task failed. Check the output for details.",
"error"
);
}
} catch (error) {
console.error("Error:", error);
showLoading(false);
disableButtons(false);
displayError(error.message);
showNotification("Failed to execute task", "error");
}
}
// Display results
function displayResults(data, duration) {
const resultsSection = document.getElementById("results");
resultsSection.classList.add("active");
// Result title and output
const resultIcon = document.getElementById("result-icon");
const resultTitleText = document.getElementById("result-title-text");
const resultOutput = document.getElementById("result-output");
if (data.success) {
resultIcon.textContent = "✅";
resultIcon.className = "result-icon success-icon";
resultTitleText.textContent = "Success";
resultOutput.textContent =
data.output || "Task completed successfully!";
} else {
resultIcon.textContent = "❌";
resultIcon.className = "result-icon error-icon";
resultTitleText.textContent = "Error";
resultOutput.textContent = data.error || "An unknown error occurred";
}
// Action history
const actionHistoryBox = document.getElementById("action-history-box");
const actionHistory = document.getElementById("action-history");
if (data.action_history && data.action_history.length > 0) {
actionHistoryBox.style.display = "block";
const historyHtml = data.action_history
.map((action, index) => {
const actionDetails = Object.entries(action)
.filter(([key]) => key !== "action")
.map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
.join(", ");
return `
<div class="action-item">
<strong>${
index + 1
}. ${action.action.toUpperCase()}</strong>
${actionDetails ? "<br>" + actionDetails : ""}
</div>
`;
})
.join("");
actionHistory.innerHTML = historyHtml;
} else {
actionHistoryBox.style.display = "none";
}
// Screenshot
const screenshotBox = document.getElementById("screenshot-box");
const screenshot = document.getElementById("screenshot");
if (data.screenshot) {
screenshotBox.style.display = "block";
screenshot.src = "data:image/png;base64," + data.screenshot;
} else {
screenshotBox.style.display = "none";
}
// Scroll to results
setTimeout(() => {
resultsSection.scrollIntoView({ behavior: "smooth", block: "start" });
}, 100);
}
// Display error
function displayError(errorMessage) {
const resultsSection = document.getElementById("results");
resultsSection.classList.add("active");
const resultIcon = document.getElementById("result-icon");
const resultTitleText = document.getElementById("result-title-text");
const resultOutput = document.getElementById("result-output");
resultIcon.textContent = "❌";
resultIcon.className = "result-icon error-icon";
resultTitleText.textContent = "Error";
resultOutput.textContent = `Failed to communicate with server:\n${errorMessage}`;
// Hide action history and screenshot
document.getElementById("action-history-box").style.display = "none";
document.getElementById("screenshot-box").style.display = "none";
}
// Clear results
function clearResults() {
document.getElementById("prompt").value = "";
document.getElementById("results").classList.remove("active");
document.getElementById("action-history-box").style.display = "none";
document.getElementById("screenshot-box").style.display = "none";
showNotification("Results cleared", "info");
}
// ===========================
// UI Helper Functions
// ===========================
// Show/hide loading indicator
function showLoading(show) {
const loading = document.getElementById("loading");
if (show) {
loading.classList.add("active");
} else {
loading.classList.remove("active");
}
}
// Hide results section
function hideResults() {
document.getElementById("results").classList.remove("active");
}
// Disable/enable buttons
function disableButtons(disabled) {
document.querySelectorAll(".btn").forEach((btn) => {
btn.disabled = disabled;
});
}
// Show notification (simple toast)
function showNotification(message, type = "info") {
// Check if notification container exists, create if not
let container = document.getElementById("notification-container");
if (!container) {
container = document.createElement("div");
container.id = "notification-container";
container.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
z-index: 10000;
`;
document.body.appendChild(container);
}
// Create notification element
const notification = document.createElement("div");
notification.className = `notification notification-${type}`;
const icon =
{
success: "✅",
error: "❌",
info: "️",
warning: "⚠️",
}[type] || "️";
const bgColor =
{
success: "#4caf50",
error: "#f44336",
info: "#2196f3",
warning: "#ff9800",
}[type] || "#2196f3";
notification.style.cssText = `
background: ${bgColor};
color: white;
padding: 1rem 1.5rem;
border-radius: 8px;
margin-bottom: 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
display: flex;
align-items: center;
gap: 10px;
min-width: 300px;
animation: slideIn 0.3s ease;
`;
notification.innerHTML = `
<span style="font-size: 1.2rem;">${icon}</span>
<span style="flex: 1;">${message}</span>
`;
container.appendChild(notification);
// Auto remove after 3 seconds
setTimeout(() => {
notification.style.animation = "slideOut 0.3s ease";
setTimeout(() => {
notification.remove();
}, 300);
}, 3000);
}
// ===========================
// Event Listeners
// ===========================
// Initialize on page load
document.addEventListener("DOMContentLoaded", function () {
loadStats();
// Enter key to submit (Shift+Enter for new line)
document.getElementById("prompt").addEventListener("keydown", function (e) {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
executeTask();
}
});
// Add CSS for animations
if (!document.getElementById("notification-animations")) {
const style = document.createElement("style");
style.id = "notification-animations";
style.textContent = `
@keyframes slideIn {
from {
transform: translateX(400px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideOut {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(400px);
opacity: 0;
}
}
`;
document.head.appendChild(style);
}
});
// ===========================
// Utility Functions
// ===========================
// Format date/time
function formatDateTime(date) {
return new Date(date).toLocaleString();
}
// Copy text to clipboard
async function copyToClipboard(text) {
try {
await navigator.clipboard.writeText(text);
showNotification("Copied to clipboard!", "success");
} catch (err) {
showNotification("Failed to copy", "error");
}
}
// Download screenshot
function downloadScreenshot() {
const screenshot = document.getElementById("screenshot");
if (screenshot.src) {
const link = document.createElement("a");
link.href = screenshot.src;
link.download = `manus-ai-screenshot-${Date.now()}.png`;
link.click();
showNotification("Screenshot downloaded", "success");
}
}
// Export results as JSON
function exportResults() {
const resultOutput = document.getElementById("result-output").textContent;
const actionHistory = document.getElementById("action-history").innerHTML;
const data = {
timestamp: new Date().toISOString(),
output: resultOutput,
actionHistory: actionHistory,
stats: taskStats,
};
const blob = new Blob([JSON.stringify(data, null, 2)], {
type: "application/json",
});
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = `manus-ai-results-${Date.now()}.json`;
link.click();
URL.revokeObjectURL(url);
showNotification("Results exported", "success");
}
// Reset stats
function resetStats() {
if (confirm("Are you sure you want to reset all statistics?")) {
taskStats = {
total: 0,
successful: 0,
times: [],
};
saveStats();
updateStatsDisplay();
showNotification("Statistics reset", "info");
}
}