Download index.html from VethaNarayananG/Multimodal-Agent: direct link, hf CLI and curl.
- Browser
- Download file 5.81 kB
-
https://huggingface.co/spaces/VethaNarayananG/Multimodal-Agent/resolve/main/index.html
- Command line
-
hf download hf://spaces/VethaNarayananG/Multimodal-Agent/index.html
-
curl -L -o index.html https://huggingface.co/spaces/VethaNarayananG/Multimodal-Agent/resolve/main/index.html
5.81 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>Multimodal Assistant</title> | |
| <style> | |
| body { font-family: 'Segoe UI', sans-serif; max-width: 750px; margin: 30px auto; background:#0f0f0f; color:#eee; } | |
| h2 { text-align:center; } | |
| #chat { border: 1px solid #333; border-radius: 8px; padding: 15px; height: 450px; overflow-y: auto; background:#1a1a1a; } | |
| .msg { margin: 10px 0; line-height:1.4; } | |
| .msg b { color:#7dd3fc; } | |
| .msg.user b { color:#fca5a5; } | |
| .msg img { max-width: 250px; border-radius:6px; display:block; margin-top:6px; } | |
| #controls { display:flex; gap:8px; margin-top:12px; flex-wrap:wrap; } | |
| #userInput { flex:1; padding:10px; border-radius:6px; border:1px solid #333; background:#1a1a1a; color:#eee; min-width:200px; } | |
| button, select { padding:10px 14px; border-radius:6px; border:none; background:#3b82f6; color:white; cursor:pointer; } | |
| button:hover { background:#2563eb; } | |
| #status { font-size:12px; color:#888; margin-top:6px; } | |
| #tokenBar { display:flex; gap:8px; margin-bottom:12px; } | |
| #tokenInput { flex:1; padding:8px; border-radius:6px; border:1px solid #333; background:#1a1a1a; color:#eee; } | |
| </style> | |
| </head> | |
| <body> | |
| <h2>🧠 My Multimodal Assistant</h2> | |
| <div id="tokenBar"> | |
| <input type="password" id="tokenInput" placeholder="Paste your HF token here (not saved, session only)"> | |
| <button onclick="saveToken()">Set Token</button> | |
| </div> | |
| <div id="chat"></div> | |
| <div id="controls"> | |
| <select id="mode"> | |
| <option value="chat">💬 Chat / Ask about image</option> | |
| <option value="image">🎨 Generate an image</option> | |
| </select> | |
| <input type="text" id="userInput" placeholder="Type your message..."> | |
| <input type="file" id="imageInput" accept="image/*"> | |
| <button onclick="send()">Send</button> | |
| </div> | |
| <div id="status"></div> | |
| <script> | |
| let HF_TOKEN = ""; // set at runtime, never committed to the file | |
| function saveToken() { | |
| HF_TOKEN = document.getElementById("tokenInput").value.trim(); | |
| document.getElementById("tokenInput").value = ""; | |
| document.getElementById("tokenInput").placeholder = HF_TOKEN | |
| ? "✅ Token set for this session" | |
| : "Paste your HF token here"; | |
| } | |
| const chatBox = document.getElementById("chat"); | |
| const statusBox = document.getElementById("status"); | |
| let history = []; | |
| function addMessage(role, html) { | |
| const div = document.createElement("div"); | |
| div.className = "msg" + (role === "You" ? " user" : ""); | |
| div.innerHTML = `<b>${role}:</b> ${html}`; | |
| chatBox.appendChild(div); | |
| chatBox.scrollTop = chatBox.scrollHeight; | |
| } | |
| function toBase64(file) { | |
| return new Promise((resolve, reject) => { | |
| const reader = new FileReader(); | |
| reader.onload = () => resolve(reader.result); | |
| reader.onerror = reject; | |
| reader.readAsDataURL(file); | |
| }); | |
| } | |
| async function send() { | |
| if (!HF_TOKEN) { | |
| alert("Please set your Hugging Face token first (top of the page)."); | |
| return; | |
| } | |
| const text = document.getElementById("userInput").value.trim(); | |
| const file = document.getElementById("imageInput").files[0]; | |
| const mode = document.getElementById("mode").value; | |
| if (!text && !file) return; | |
| if (mode === "image") { | |
| await generateImage(text); | |
| } else { | |
| await chatWithModel(text, file); | |
| } | |
| document.getElementById("userInput").value = ""; | |
| document.getElementById("imageInput").value = ""; | |
| } | |
| async function chatWithModel(text, file) { | |
| let content = [{ type: "text", text: text || "Describe this image." }]; | |
| let userDisplay = text; | |
| if (file) { | |
| const base64 = await toBase64(file); | |
| content.push({ type: "image_url", image_url: { url: base64 } }); | |
| userDisplay += `<img src="${base64}">`; | |
| } | |
| addMessage("You", userDisplay); | |
| statusBox.textContent = "Thinking..."; | |
| const model = file | |
| ? "Qwen/Qwen2.5-VL-7B-Instruct" | |
| : "meta-llama/Llama-3.3-70B-Instruct"; | |
| history.push({ role: "user", content: content }); | |
| try { | |
| const res = await fetch("https://router.huggingface.co/v1/chat/completions", { | |
| method: "POST", | |
| headers: { | |
| "Authorization": `Bearer ${HF_TOKEN}`, | |
| "Content-Type": "application/json" | |
| }, | |
| body: JSON.stringify({ model: model, messages: history }) | |
| }); | |
| const data = await res.json(); | |
| if (data.error) throw new Error(data.error.message || JSON.stringify(data.error)); | |
| const reply = data.choices[0].message.content; | |
| addMessage("AI", reply); | |
| history.push({ role: "assistant", content: reply }); | |
| statusBox.textContent = ""; | |
| } catch (err) { | |
| addMessage("AI", "⚠️ Error: " + err.message); | |
| statusBox.textContent = ""; | |
| } | |
| } | |
| async function generateImage(prompt) { | |
| addMessage("You", prompt); | |
| statusBox.textContent = "Generating image (can take 10–30s)..."; | |
| try { | |
| const res = await fetch( | |
| "https://router.huggingface.co/hf-inference/models/black-forest-labs/FLUX.1-schnell", | |
| { | |
| method: "POST", | |
| headers: { | |
| "Authorization": `Bearer ${HF_TOKEN}`, | |
| "Content-Type": "application/json" | |
| }, | |
| body: JSON.stringify({ inputs: prompt }) | |
| } | |
| ); | |
| if (!res.ok) { | |
| const errText = await res.text(); | |
| throw new Error(errText); | |
| } | |
| const blob = await res.blob(); | |
| const url = URL.createObjectURL(blob); | |
| addMessage("AI", `<img src="${url}">`); | |
| statusBox.textContent = ""; | |
| } catch (err) { | |
| addMessage("AI", "⚠️ Error: " + err.message); | |
| statusBox.textContent = ""; | |
| } | |
| } | |
| document.getElementById("userInput").addEventListener("keydown", e => { | |
| if (e.key === "Enter") send(); | |
| }); | |
| </script> | |
| </body> | |
| </html> |