File size: 5,360 Bytes
a5baa63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7dfd62b
a5baa63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55969ce
718aa48
a84172d
7dfd62b
a84172d
718aa48
 
 
 
 
 
7dfd62b
718aa48
 
7dfd62b
718aa48
a5baa63
7dfd62b
 
 
 
 
 
 
718aa48
 
 
 
 
 
 
 
7dfd62b
718aa48
 
357ed9c
a84172d
357ed9c
7dfd62b
 
55969ce
 
357ed9c
55969ce
 
 
 
 
 
 
 
 
 
 
357ed9c
55969ce
 
 
 
 
 
718aa48
 
 
 
 
7dfd62b
a5baa63
 
 
7dfd62b
a84172d
7dfd62b
718aa48
 
 
 
 
 
 
 
7dfd62b
718aa48
 
 
 
a84172d
718aa48
 
 
357ed9c
 
55969ce
718aa48
a84172d
 
a5baa63
 
 
7dfd62b
 
a84172d
 
718aa48
 
 
a5baa63
718aa48
 
55969ce
718aa48
 
 
 
 
a5baa63
718aa48
 
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// === Global Model List ===
const MODEL_LIST = [
  { id: "deepseek/deepseek-chat-v3-0324:free", name: "DeepSeek Chat v3" },
  { id: "google/gemini-2.0-flash-exp:free", name: "Gemini 2.0 Flash" },
  { id: "meta-llama/llama-4-maverick:free", name: "LLaMA 4 Maverick" },
  { id: "microsoft/mai-ds-r1:free", name: "MAI DS R1" },
  { id: "meta-llama/llama-4-scout:free", name: "LLaMA 4 Scout" },
  { id: "google/gemma-3-27b-it:free", name: "Gemma 3 27B" },
  { id: "qwen/qwq-32b:free", name: "Qwen QWQ 32B" },
  { id: "qwen/qwen2.5-vl-72b-instruct:free", name: "Qwen2.5 VL 72B" },
  { id: "qwen/qwen-2.5-72b-instruct:free", name: "Qwen 2.5 72B" },
  { id: "google/gemini-2.5-pro-exp-03-25:free", name: "Gemini 2.5 Pro" },
  { id: "deepseek/deepseek-r1:free", name: "DeepSeek R1" }
];

// === Create Custom Dropdowns ===
function createDropdown(dropdownId) {
  const dropdown = document.getElementById(dropdownId);
  const selected = dropdown.querySelector(".selected");
  const options = dropdown.querySelector(".options");

  MODEL_LIST.forEach(model => {
    const option = document.createElement("div");
    option.className = "p-2 hover:bg-visual_green rounded cursor-pointer";
    option.textContent = model.name;
    option.dataset.value = model.id;
    options.appendChild(option);

    option.addEventListener("click", (e) => {
      e.stopPropagation();
      selected.textContent = model.name;
      dropdown.dataset.value = model.id;
      options.classList.add("hidden");
    });
  });

  selected.addEventListener("click", (e) => {
    e.stopPropagation();
    options.classList.toggle("hidden");
  });

  document.addEventListener("click", () => {
    options.classList.add("hidden");
  });
}

// === Theme, Config and Docs Buttons ===
const themeToggle = document.getElementById("themeToggle");
const toggleConfig = document.getElementById("toggleConfig");
const docsButton = document.getElementById("docsButton");
const configPanel = document.getElementById("configPanel");
const html = document.documentElement;

function setInitialTheme() {
  const savedTheme = localStorage.getItem("theme");
  if (savedTheme === "dark") {
    html.classList.add("dark");
    themeToggle.textContent = "πŸŒ™";
  } else if (savedTheme === "light") {
    html.classList.remove("dark");
    themeToggle.textContent = "β˜€οΈ";
  } else {
    const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
    if (prefersDark) {
      html.classList.add("dark");
      themeToggle.textContent = "πŸŒ™";
    } else {
      html.classList.remove("dark");
      themeToggle.textContent = "β˜€οΈ";
    }
  }
}

setInitialTheme();

themeToggle.addEventListener("click", () => {
  const isDark = html.classList.toggle("dark");
  localStorage.setItem("theme", isDark ? "dark" : "light");
  themeToggle.textContent = isDark ? "πŸŒ™" : "β˜€οΈ";
});

// === Config Panel Behavior ===
toggleConfig.addEventListener("click", () => {
  configPanel.classList.toggle("expanded");
});

// === Show/Hide Loaders ===
function showLoaders() {
  ["A", "B", "C", "D"].forEach(id => {
    const loader = document.getElementById(`loader${id}`);
    loader.classList.remove("hidden");
    loader.innerHTML = `
      <div class="dot bg-aqua"></div>
      <div class="dot bg-aqua animation-delay-150"></div>
      <div class="dot bg-aqua animation-delay-300"></div>
    `;
  });
}

function hideLoaders() {
  ["A", "B", "C", "D"].forEach(id => {
    const loader = document.getElementById(`loader${id}`);
    loader.classList.add("hidden");
    loader.innerHTML = "";
  });
}

// === Chat Handling ===
const chatForm = document.getElementById("chatForm");
const userInput = document.getElementById("userInput");
const chatContainer = document.getElementById("chatContainer");

// Create all dropdowns
createDropdown("modelA");
createDropdown("modelB");
createDropdown("modelC");
createDropdown("aggregator");

// Append Message Function
function appendMessage(role, text) {
  const div = document.createElement("div");
  div.className = `p-3 rounded shadow max-w-2xl ${role === "user" ? "bg-blue text-fg0 self-end" : "bg-green text-fg0 self-start"}`;
  div.innerText = text;
  chatContainer.appendChild(div);
  chatContainer.scrollTop = chatContainer.scrollHeight;
}

// Form Submit Event
chatForm.addEventListener("submit", async (e) => {
  e.preventDefault();
  const prompt = userInput.value.trim();
  if (!prompt) return;

  appendMessage("user", prompt);
  userInput.value = "";

  configPanel.classList.remove("expanded"); // Shrink config
  configPanel.classList.add("minimal"); // Activate minimal mode
  showLoaders(); // Show bouncing dots

  const settings = {
    models: {
      "LLM-A": document.getElementById("modelA").dataset.value,
      "LLM-B": document.getElementById("modelB").dataset.value,
      "LLM-C": document.getElementById("modelC").dataset.value,
    },
    aggregator: document.getElementById("aggregator").dataset.value,
  };

  const response = await fetch("/chat", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ prompt, settings })
  });

  hideLoaders(); // Hide bouncing dots

  if (response.ok) {
    const data = await response.json();
    appendMessage("bot", data.response);
  } else {
    appendMessage("bot", "An error occurred. Please check your model selections.");
  }
});