import { Client } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js"; // Global Application State Management const STATE = { reasoningEffort: "medium", maxTokens: 2048, temperature: 0.7, uploadedFiles: [], // Current prompt attachments conversationHistory: [], // Sent to StepFun API gradioClient: null, isThinking: false }; // DOM Elements hooks const dom = { effortRadioButtons: document.querySelectorAll('input[name="reasoning-effort"]'), maxTokensSlider: document.getElementById("max-tokens-slider"), maxTokensVal: document.getElementById("max-tokens-val"), temperatureSlider: document.getElementById("temperature-slider"), temperatureVal: document.getElementById("temperature-val"), // Sidebar Drawer and Overlay Elements (Mobile & Minimalist) sidebarRight: document.getElementById("sidebar-right"), sidebarOverlay: document.getElementById("sidebar-overlay"), btnToggleRight: document.getElementById("btn-toggle-right"), btnCloseDrawer: document.getElementById("btn-close-drawer"), // Viewports studioDashboard: document.getElementById("studio-dashboard"), chatThreadContainer: document.getElementById("chat-thread-container"), chatMessagesFeed: document.getElementById("chat-messages-feed"), // Main Console Box Elements (Dashboard view) studioPromptInput: document.getElementById("studio-prompt-input"), innerShelfPreview: document.getElementById("inner-shelf-preview"), studioUploadTrigger: document.getElementById("studio-upload-trigger"), studioSendBtn: document.getElementById("studio-send-button"), studioSpinner: document.getElementById("studio-spinner"), // Mini Console Box Elements (Chat thread view) miniPromptInput: document.getElementById("mini-prompt-input"), miniShelfPreview: document.getElementById("mini-shelf-preview"), miniUploadTrigger: document.getElementById("mini-upload-trigger"), miniSendBtn: document.getElementById("mini-send-button"), miniSpinner: document.getElementById("mini-spinner"), // Core file upload elements fileUploader: document.getElementById("file-uploader"), shelfList: document.getElementById("shelf-list"), dropZone: document.getElementById("drop-zone"), // Action Resets menuNewChat: document.getElementById("menu-new-chat"), clearChatBtn: document.getElementById("clear-chat-button"), // Showcase recipe chips recipeChips: document.querySelectorAll(".recipe-chip") }; // Markdown configuration marked.setOptions({ breaks: true, highlight: function(code, lang) { const language = hljs.getLanguage(lang) ? lang : 'plaintext'; return hljs.highlight(code, { language }).value; } }); // Setup Initial State & Event Handlers async function initializeApp() { // Re-query all DOM elements to ensure they are fully resolved after DOMContentLoaded dom.effortRadioButtons = document.querySelectorAll('input[name="reasoning-effort"]'); dom.maxTokensSlider = document.getElementById("max-tokens-slider"); dom.maxTokensVal = document.getElementById("max-tokens-val"); dom.temperatureSlider = document.getElementById("temperature-slider"); dom.temperatureVal = document.getElementById("temperature-val"); dom.sidebarRight = document.getElementById("sidebar-right"); dom.sidebarOverlay = document.getElementById("sidebar-overlay"); dom.btnToggleRight = document.getElementById("btn-toggle-right"); dom.btnCloseDrawer = document.getElementById("btn-close-drawer"); dom.studioDashboard = document.getElementById("studio-dashboard"); dom.chatThreadContainer = document.getElementById("chat-thread-container"); dom.chatMessagesFeed = document.getElementById("chat-messages-feed"); dom.studioPromptInput = document.getElementById("studio-prompt-input"); dom.innerShelfPreview = document.getElementById("inner-shelf-preview"); dom.studioUploadTrigger = document.getElementById("studio-upload-trigger"); dom.studioSendBtn = document.getElementById("studio-send-button"); dom.studioSpinner = document.getElementById("studio-spinner"); dom.miniPromptInput = document.getElementById("mini-prompt-input"); dom.miniShelfPreview = document.getElementById("mini-shelf-preview"); dom.miniUploadTrigger = document.getElementById("mini-upload-trigger"); dom.miniSendBtn = document.getElementById("mini-send-button"); dom.miniSpinner = document.getElementById("mini-spinner"); dom.fileUploader = document.getElementById("file-uploader"); dom.shelfList = document.getElementById("shelf-list"); dom.dropZone = document.getElementById("drop-zone"); dom.menuNewChat = document.getElementById("menu-new-chat"); dom.clearChatBtn = document.getElementById("clear-chat-button"); dom.recipeChips = document.querySelectorAll(".recipe-chip"); // 1. Connect Gradio Client in background (Non-blocking) Client.connect(window.location.origin) .then(app => { STATE.gradioClient = app; console.log("Successfully connected to Gradio.Server backend."); }) .catch(e => { console.error("Gradio Client Connection Failed:", e); }); // 2. Register Sidebar Drawer Slide Events (Drawer + Overlay) if (dom.btnToggleRight) dom.btnToggleRight.addEventListener("click", () => toggleSettingsDrawer(true)); if (dom.btnCloseDrawer) dom.btnCloseDrawer.addEventListener("click", () => toggleSettingsDrawer(false)); if (dom.sidebarOverlay) dom.sidebarOverlay.addEventListener("click", () => toggleSettingsDrawer(false)); // 3. Register Settings Listeners if (dom.effortRadioButtons) { dom.effortRadioButtons.forEach(radio => { radio.addEventListener("change", (e) => { STATE.reasoningEffort = e.target.value; }); }); } if (dom.maxTokensSlider && dom.maxTokensVal) { dom.maxTokensSlider.addEventListener("input", (e) => { STATE.maxTokens = parseInt(e.target.value); dom.maxTokensVal.textContent = STATE.maxTokens; }); } if (dom.temperatureSlider && dom.temperatureVal) { dom.temperatureSlider.addEventListener("input", (e) => { STATE.temperature = parseFloat(e.target.value); dom.temperatureVal.textContent = STATE.temperature.toFixed(1); }); } // 5. Register File Upload Actions if (dom.studioUploadTrigger) dom.studioUploadTrigger.addEventListener("click", () => dom.fileUploader.click()); if (dom.miniUploadTrigger) dom.miniUploadTrigger.addEventListener("click", () => dom.fileUploader.click()); if (dom.dropZone) dom.dropZone.addEventListener("click", () => dom.fileUploader.click()); if (dom.fileUploader) dom.fileUploader.addEventListener("change", handleFileSelection); // Dropzone Drag-and-Drop animations if (dom.dropZone) { ["dragenter", "dragover"].forEach(eventName => { dom.dropZone.addEventListener(eventName, (e) => { e.preventDefault(); dom.dropZone.classList.add("drag-active"); }, false); }); ["dragleave", "drop"].forEach(eventName => { dom.dropZone.addEventListener(eventName, (e) => { e.preventDefault(); dom.dropZone.classList.remove("drag-active"); }, false); }); dom.dropZone.addEventListener("drop", (e) => { const dt = e.dataTransfer; const files = dt.files; processFiles(files); }); } // 6. Submit Triggers if (dom.studioSendBtn) { dom.studioSendBtn.addEventListener("click", () => triggerPromptSubmission(dom.studioPromptInput)); } if (dom.miniSendBtn) { dom.miniSendBtn.addEventListener("click", () => triggerPromptSubmission(dom.miniPromptInput)); } if (dom.studioPromptInput) { dom.studioPromptInput.addEventListener("keydown", (e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); triggerPromptSubmission(dom.studioPromptInput); } }); } if (dom.miniPromptInput) { dom.miniPromptInput.addEventListener("keydown", (e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); triggerPromptSubmission(dom.miniPromptInput); } }); } // 7. Resets if (dom.menuNewChat) dom.menuNewChat.addEventListener("click", resetSandbox); if (dom.clearChatBtn) dom.clearChatBtn.addEventListener("click", resetSandbox); // 8. Recipe Chips Console Setup if (dom.recipeChips) { dom.recipeChips.forEach(chip => { chip.addEventListener("click", () => { const recipeType = chip.getAttribute("data-recipe"); loadRecipe(recipeType); }); }); } // Auto-expand input textareas [dom.studioPromptInput, dom.miniPromptInput].forEach(textarea => { if (textarea) { textarea.addEventListener("input", () => { textarea.style.height = "auto"; textarea.style.height = (textarea.scrollHeight) + "px"; }); } }); } // Drawer Toggler Action function toggleSettingsDrawer(open) { if (open) { if (dom.sidebarRight) dom.sidebarRight.classList.remove("collapsed"); if (dom.sidebarOverlay) dom.sidebarOverlay.classList.add("active"); } else { if (dom.sidebarRight) dom.sidebarRight.classList.add("collapsed"); if (dom.sidebarOverlay) dom.sidebarOverlay.classList.remove("active"); } } // Handle File Select & Base64 Encoder function handleFileSelection(e) { processFiles(e.target.files); } function processFiles(files) { if (!files.length) return; Array.from(files).forEach(file => { const reader = new FileReader(); reader.onload = (event) => { const fileData = { id: Math.random().toString(36).substring(2, 9), name: file.name, type: file.type, size: (file.size / 1024 / 1024).toFixed(2) + " MB", base64: event.target.result }; STATE.uploadedFiles.push(fileData); updateShelfUI(); }; reader.readAsDataURL(file); }); } // Update UI Attachment Previews function updateShelfUI() { if (dom.shelfList) dom.shelfList.innerHTML = ""; if (dom.innerShelfPreview) dom.innerShelfPreview.innerHTML = ""; if (dom.miniShelfPreview) dom.miniShelfPreview.innerHTML = ""; if (STATE.uploadedFiles.length === 0) { if (dom.shelfList) dom.shelfList.innerHTML = `