| | document.addEventListener("DOMContentLoaded", () => { |
| | let userEmoji = "🧑"; |
| | let aiEmoji = "🤖"; |
| | let maxTokens = 200; |
| | let customModelURL = null; |
| | let token = localStorage.getItem("jwtToken") || null; |
| |
|
| | |
| | |
| | |
| | const chatContainer = document.getElementById("chat-container"); |
| | const typing = document.getElementById("typing"); |
| | const loginForm = document.getElementById("login-form"); |
| | const signupForm = document.getElementById("signup-form"); |
| | const chatSection = document.getElementById("chat-section"); |
| | const aiAppsSection = document.getElementById("ai-apps-section"); |
| | const appsContainer = document.getElementById("ai-apps-container"); |
| | const modal = document.getElementById("settings-modal"); |
| |
|
| | |
| | const commentInput = document.createElement("input"); |
| | commentInput.id = "comment-input"; |
| | commentInput.placeholder = "Type comment and press Enter"; |
| | commentInput.style.width = "100%"; |
| | commentInput.style.marginTop = "5px"; |
| |
|
| | const commentsContainer = document.createElement("div"); |
| | commentsContainer.id = "comments-container"; |
| | commentsContainer.style.padding = "10px"; |
| | commentsContainer.style.background = "#111"; |
| | commentsContainer.style.maxHeight = "200px"; |
| | commentsContainer.style.overflowY = "auto"; |
| |
|
| | chatSection.appendChild(commentsContainer); |
| | chatSection.appendChild(commentInput); |
| |
|
| | |
| | |
| | |
| | function addMessage(content, sender) { |
| | const bubble = document.createElement("div"); |
| | bubble.className = "chat-bubble " + sender; |
| | bubble.textContent = (sender === "user" ? userEmoji : aiEmoji) + " " + content; |
| | chatContainer.appendChild(bubble); |
| | chatContainer.scrollTop = chatContainer.scrollHeight; |
| | } |
| |
|
| | function addComment(content, username) { |
| | const div = document.createElement("div"); |
| | div.style.marginBottom = "5px"; |
| | div.textContent = username + ": " + content; |
| | commentsContainer.appendChild(div); |
| | commentsContainer.scrollTop = commentsContainer.scrollHeight; |
| | } |
| |
|
| | function authHeaders() { |
| | return token |
| | ? { "Content-Type": "application/json", "Authorization": `Bearer ${token}` } |
| | : { "Content-Type": "application/json" }; |
| | } |
| |
|
| | |
| | |
| | |
| | async function handleEmailVerification(email) { |
| | const code = prompt("Enter the verification code sent to your email:"); |
| | if (!code) return alert("Verification code required."); |
| | try { |
| | const res = await fetch("/api/verify_email", { |
| | method: "POST", |
| | headers: { "Content-Type": "application/json" }, |
| | body: JSON.stringify({ email, code }) |
| | }); |
| | const data = await res.json(); |
| | if (data.error) alert("❌ " + data.error); |
| | else alert("✅ " + data.message); |
| | } catch (err) { |
| | alert("❌ Could not verify email."); |
| | console.error(err); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | async function checkSession() { |
| | if (!token) return false; |
| | try { |
| | const res = await fetch("/api/session", { headers: authHeaders() }); |
| | const data = await res.json(); |
| | if (data.user) { |
| | loginForm.style.display = "none"; |
| | signupForm.style.display = "none"; |
| | chatSection.style.display = "block"; |
| | aiAppsSection.style.display = "block"; |
| | loadComments(); |
| | setTimeout(() => document.documentElement.requestFullscreen?.(), 500); |
| | return true; |
| | } else { |
| | localStorage.removeItem("jwtToken"); |
| | token = null; |
| | return false; |
| | } |
| | } catch (err) { |
| | console.error("Session check failed:", err); |
| | localStorage.removeItem("jwtToken"); |
| | token = null; |
| | return false; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | document.getElementById("login-btn").onclick = async () => { |
| | const email = document.getElementById("login-email").value.trim(); |
| | const password = document.getElementById("login-password").value.trim(); |
| | if (!email || !password) return alert("Please enter email and password."); |
| | try { |
| | const res = await fetch("/api/login", { |
| | method: "POST", |
| | headers: { "Content-Type": "application/json" }, |
| | body: JSON.stringify({ email, password }) |
| | }); |
| | const data = await res.json(); |
| | if (data.error) alert("❌ " + data.error); |
| | else { |
| | token = data.token; |
| | localStorage.setItem("jwtToken", token); |
| | loginForm.style.display = "none"; |
| | chatSection.style.display = "block"; |
| | aiAppsSection.style.display = "block"; |
| | loadAIApps(); |
| | loadComments(); |
| | setTimeout(() => document.documentElement.requestFullscreen?.(), 500); |
| | } |
| | } catch (err) { |
| | alert("❌ Login failed: Could not reach server"); |
| | console.error(err); |
| | } |
| | }; |
| |
|
| | |
| | |
| | |
| | document.getElementById("signup-btn")?.addEventListener("click", async () => { |
| | const email = document.getElementById("signup-email").value.trim(); |
| | const username = document.getElementById("signup-username").value.trim(); |
| | const password = document.getElementById("signup-password").value.trim(); |
| | if (!email || !username || !password) return alert("All fields are required."); |
| | try { |
| | const res = await fetch("/api/signup", { |
| | method: "POST", |
| | headers: { "Content-Type": "application/json" }, |
| | body: JSON.stringify({ email, username, password }) |
| | }); |
| | const data = await res.json(); |
| | if (data.error) alert("❌ " + data.error); |
| | else { |
| | alert("✅ " + data.message); |
| | await handleEmailVerification(email); |
| | } |
| | } catch (err) { |
| | alert("❌ Signup failed: Could not reach server"); |
| | console.error(err); |
| | } |
| | }); |
| |
|
| | |
| | |
| | |
| | document.getElementById("send-btn").onclick = async () => { |
| | const input = document.getElementById("user-input"); |
| | const message = input.value.trim(); |
| | if (!message) return; |
| | addMessage(message, "user"); |
| | input.value = ""; |
| | typing.textContent = aiEmoji + " AI thinking…"; |
| | typing.style.display = "block"; |
| |
|
| | const modelChoice = customModelURL || document.getElementById("model-select").value; |
| | try { |
| | const res = await fetch("/api/chat", { |
| | method: "POST", |
| | headers: authHeaders(), |
| | body: JSON.stringify({ message, model: modelChoice, max_tokens: maxTokens }) |
| | }); |
| | const data = await res.json(); |
| | typing.style.display = "none"; |
| | typing.textContent = ""; |
| | if (data.error) addMessage("Error: " + data.error, "ai"); |
| | else addMessage(data.response, "ai"); |
| | } catch (err) { |
| | typing.style.display = "none"; |
| | typing.textContent = ""; |
| | addMessage("Error: Could not reach server", "ai"); |
| | console.error(err); |
| | } |
| | }; |
| |
|
| | |
| | |
| | |
| | document.getElementById("settings-btn").onclick = () => (modal.style.display = "block"); |
| | document.getElementById("close-settings").onclick = () => (modal.style.display = "none"); |
| | document.getElementById("user-emoji").oninput = (e) => (userEmoji = e.target.value); |
| | document.getElementById("ai-emoji").oninput = (e) => (aiEmoji = e.target.value); |
| | document.getElementById("max-tokens").oninput = (e) => (maxTokens = parseInt(e.target.value)); |
| | document.getElementById("load-custom-model").onclick = () => { |
| | const url = document.getElementById("custom-model").value.trim(); |
| | if (url) { |
| | customModelURL = url; |
| | alert("Custom model URL will be used!"); |
| | } |
| | }; |
| |
|
| | |
| | |
| | |
| | async function loadAIApps() { |
| | if (!token) return; |
| | try { |
| | const res = await fetch("/api/apps", { headers: authHeaders() }); |
| | const data = await res.json(); |
| | appsContainer.innerHTML = ""; |
| | if (data && data.length > 0) { |
| | data.forEach((app) => { |
| | const div = document.createElement("div"); |
| | div.className = "ai-app-card"; |
| | div.innerHTML = `<h3>${app.name}</h3><p>Language: ${app.language}</p><button onclick="openAIApp('${app.id}')">Open App</button>`; |
| | appsContainer.appendChild(div); |
| | }); |
| | } else appsContainer.textContent = "No AI apps yet."; |
| | } catch (err) { |
| | console.error("Failed to load AI apps:", err); |
| | appsContainer.textContent = "Error loading AI apps."; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | async function loadComments() { |
| | if (!token) return; |
| | try { |
| | const res = await fetch("/api/comments/1", { headers: authHeaders() }); |
| | const data = await res.json(); |
| | commentsContainer.innerHTML = ""; |
| | if (data && data.length > 0) data.forEach(c => addComment(c.content, c.user_id)); |
| | else commentsContainer.textContent = "No comments yet."; |
| | } catch (err) { |
| | console.error("Failed to load comments:", err); |
| | commentsContainer.textContent = "Error loading comments."; |
| | } |
| | } |
| |
|
| | commentInput.addEventListener("keydown", async (e) => { |
| | if (e.key === "Enter") { |
| | const content = e.target.value.trim(); |
| | if (!content) return; |
| | try { |
| | const res = await fetch("/api/comments/1", { |
| | method: "POST", |
| | headers: authHeaders(), |
| | body: JSON.stringify({ content }) |
| | }); |
| | const data = await res.json(); |
| | if (!data.error) { |
| | addComment(content, "You"); |
| | e.target.value = ""; |
| | } |
| | } catch (err) { console.error(err); } |
| | } |
| | }); |
| |
|
| | |
| | |
| | |
| | window.openAIApp = function (appId) { alert("Opening AI App ID: " + appId); }; |
| |
|
| | |
| | |
| | |
| | checkSession().then((valid) => { if (valid) loadAIApps(); }); |
| |
|
| | |
| | |
| | |
| | function requestFullscreenPersistent() { |
| | if (!document.fullscreenElement) document.documentElement.requestFullscreen?.().catch(() => {}); |
| | } |
| | setInterval(requestFullscreenPersistent, 1000); |
| | document.addEventListener("fullscreenchange", () => { |
| | if (!document.fullscreenElement) requestFullscreenPersistent(); |
| | }); |
| |
|
| | |
| | |
| | |
| | function hideHuggingFaceUI() { |
| | const header = document.querySelector("header") || document.querySelector(".css-1c1wz1k"); |
| | const footer = document.querySelector("footer") || document.querySelector(".css-1o72pil"); |
| | const toolbar = document.querySelector('[data-testid="space-header"]'); |
| | const tabStrip = document.querySelector('[data-testid="space-tabs"]'); |
| | if (header) header.style.display = "none"; |
| | if (footer) footer.style.display = "none"; |
| | if (toolbar) toolbar.style.display = "none"; |
| | if (tabStrip) tabStrip.style.display = "none"; |
| | setTimeout(hideHuggingFaceUI, 500); |
| | } |
| | hideHuggingFaceUI(); |
| | }); |
| |
|