Spaces:
Running
Running
import * as webllm from "https://esm.run/@mlc-ai/web-llm"; | |
// Global variables and configuration | |
let selectedModel = "Phi-3.5-vision-instruct-q4f16_1-MLC"; | |
let uploadedBase64Image = ""; | |
let modelInitialized = false; | |
// Callback function to update initialization progress | |
function initProgressCallback(report) { | |
document.getElementById("download-status").textContent = report.text; | |
document.getElementById("download-status").classList.remove("hidden"); | |
} | |
// Function to append messages to the chat box | |
function appendMessage(message, role = "user") { | |
const chatBox = document.getElementById("chat-box"); | |
const container = document.createElement("div"); | |
container.classList.add("message-container", role); | |
const newMessage = document.createElement("div"); | |
newMessage.classList.add("message"); | |
newMessage.textContent = message; | |
container.appendChild(newMessage); | |
chatBox.appendChild(container); | |
chatBox.scrollTop = chatBox.scrollHeight; // Scroll to the latest message | |
} | |
// Function to update the last message | |
function updateLastMessage(content) { | |
const messageDoms = document.querySelectorAll(".message"); | |
const lastMessageDom = messageDoms[messageDoms.length - 1]; | |
lastMessageDom.textContent = content; | |
} | |
// Function to check if both image and model are ready and enable the Send button | |
function checkIfReadyToSend() { | |
if (uploadedBase64Image && modelInitialized) { | |
document.getElementById("send").disabled = false; | |
} | |
} | |
// Main function to initialize the engine and process images | |
async function main() { | |
if (!uploadedBase64Image) { | |
alert("Please upload an image first!"); | |
return; | |
} | |
// Initialize the engine configuration | |
const engineConfig = { | |
initProgressCallback: initProgressCallback, | |
logLevel: "INFO", | |
}; | |
const chatOpts = { | |
context_window_size: 6144, | |
}; | |
// Create the engine | |
const engine = await webllm.CreateMLCEngine(selectedModel, engineConfig, chatOpts); | |
// Indicate that the model is initialized | |
modelInitialized = true; | |
checkIfReadyToSend(); // Check if we can enable the Send button now | |
// Construct chat messages with the uploaded image | |
const messages = [ | |
{ | |
role: "user", | |
content: [ | |
{ type: "text", text: "Describe the uploaded image." }, | |
{ type: "image_url", image_url: { url: uploadedBase64Image } }, | |
], | |
}, | |
]; | |
// Send the chat request | |
const request = { stream: false, messages: messages }; | |
const reply = await engine.chat.completions.create(request); | |
// Get the reply and display it | |
const replyMessage = await engine.getMessage(); | |
appendMessage(replyMessage, "assistant"); | |
document.getElementById("send").disabled = false; | |
console.log(reply); | |
} | |
// Handle file uploads | |
document.getElementById("image-input").addEventListener("change", async function(event) { | |
const file = event.target.files[0]; | |
if (file) { | |
uploadedBase64Image = await imageFileToBase64(file); | |
console.log("Image uploaded and converted to base64"); | |
checkIfReadyToSend(); // Check if we can enable the Send button now | |
} | |
}); | |
// Set up UI bindings and event listeners | |
document.getElementById("download").addEventListener("click", async function () { | |
selectedModel = document.getElementById("model-selection").value; | |
await main(); // Initialize and run the model | |
}); | |
document.getElementById("send").addEventListener("click", function () { | |
const input = document.getElementById("user-input").value.trim(); | |
if (input.length === 0) return; | |
appendMessage(input, "user"); | |
document.getElementById("user-input").value = ""; | |
document.getElementById("user-input").setAttribute("placeholder", "Generating..."); | |
// Additional logic for new user questions can be added here | |
}); | |
// Populate model selection dropdown | |
const availableModels = ["Phi-3.5-vision-instruct-q4f16_1-MLC", "Phi-3.5-vision-instruct-q4f32_1-MLC"]; | |
availableModels.forEach((modelId) => { | |
const option = document.createElement("option"); | |
option.value = modelId; | |
option.textContent = modelId; | |
document.getElementById("model-selection").appendChild(option); | |
}); | |
document.getElementById("model-selection").value = selectedModel; | |