File size: 4,289 Bytes
367aca7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
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;