Added dynamic model loading

This commit is contained in:
2026-01-06 16:04:09 +01:00
parent 6a30a00d45
commit 068b2f5e44
3 changed files with 75 additions and 8 deletions
+1 -2
View File
@@ -21,8 +21,7 @@
<div class="model-select"> <div class="model-select">
<label for="model">Model:</label> <label for="model">Model:</label>
<select id="model"> <select id="model">
<option value="mistral:latest">Mistral</option> <option disabled selected>Loading models...</option>
<option value="femboy:latest">Femboy</option>
</select> </select>
</div> </div>
</div> </div>
+24 -1
View File
@@ -12,6 +12,28 @@ const sendBtn = document.getElementById("send");
let isProcessing = false; let isProcessing = false;
let chatHistory = JSON.parse(localStorage.getItem('chatHistory')) || []; let chatHistory = JSON.parse(localStorage.getItem('chatHistory')) || [];
const displayModels = async () => {
const select = document.getElementById("model");
fetch("/models")
.then(response => response.json())
.then(data => {
// Clear loading option
select.innerHTML = "";
data.models.forEach(model => {
const option = document.createElement("option");
option.value = model.model;
option.textContent = model.name;
select.appendChild(option);
});
})
.catch(err => {
console.error("Failed to load models:", err);
select.innerHTML = `<option>Error loading models</option>`;
});
}
async function post(url, data) { async function post(url, data) {
try { try {
const res = await fetch(url, { const res = await fetch(url, {
@@ -172,7 +194,7 @@ async function sendMessage() {
const loadingMsg = addMessage('', false, true, false); const loadingMsg = addMessage('', false, true, false);
try { try {
const model = document.getElementById("model").value; const model = document.getElementById("model").value;
const res = await post("/chat", { message: msg, model }); const res = await post("/chat", {message: msg, model});
if (messagesDiv.contains(loadingMsg)) { if (messagesDiv.contains(loadingMsg)) {
messagesDiv.removeChild(loadingMsg); messagesDiv.removeChild(loadingMsg);
} }
@@ -230,4 +252,5 @@ msgInput.addEventListener('input', function () {
window.addEventListener('load', () => { window.addEventListener('load', () => {
checkSession(); checkSession();
displayModels()
}); });
+50 -5
View File
@@ -64,38 +64,83 @@ const requireLogin = (req, res, next) => {
next(); next();
}; };
app.get("/models", async (req, res) => {
const response = await fetch("https://ai.krishd.ch/api/tags");
res.json(await response.json());
})
app.post("/chat", requireLogin, async (req, res) => { app.post("/chat", requireLogin, async (req, res) => {
const user = req.session.user; const user = req.session.user;
const { message, model } = req.body; const { message, model } = req.body;
const selectedModel = model || "mistral:latest"; const selectedModel = model || "mistral:latest";
try { try {
if (!chats[user]) chats[user] = []; if (!chats[user]) chats[user] = [];
chats[user].push({ role: "user", content: message }); chats[user].push({ role: "user", content: message });
if (chats[user].length > 20) chats[user] = chats[user].slice(-20); if (chats[user].length > 20) chats[user] = chats[user].slice(-20);
const messagesPayload = chats[user].map(m => ({ const messagesPayload = chats[user].map(m => ({
role: m.role === "bot" ? "assistant" : "user", role: m.role === "bot" ? "assistant" : "user",
content: m.content content: m.content
})); }));
const response = await fetch("https://ai.krishd.ch/api/chat", { const response = await fetch("https://ai.krishd.ch/api/chat", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ body: JSON.stringify({
model: selectedModel, model: selectedModel,
messages: messagesPayload, messages: messagesPayload,
stream: false stream: true
}) })
}); });
const data = await response.json();
const reply = data?.message?.content || "[No response]"; if (!response.ok) {
chats[user].push({ role: "bot", content: reply }); throw new Error(`AI HTTP ${response.status}`);
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
let fullReply = "";
while (true) {
const { value, done } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
let lines = buffer.split("\n");
buffer = lines.pop(); // keep incomplete JSON
for (const line of lines) {
if (!line.trim()) continue;
const json = JSON.parse(line);
if (json.done) {
break;
}
if (json.message?.content) {
fullReply += json.message.content;
}
}
}
chats[user].push({ role: "bot", content: fullReply });
saveChats(); saveChats();
res.json({ reply }); console.log("Reply length:", fullReply.length);
res.json({ reply: fullReply });
} catch (err) { } catch (err) {
console.error("AI chat error:", err); console.error("AI chat error:", err);
res.status(500).json({ error: "AI request failed" }); res.status(500).json({ error: "AI request failed" });
} }
}); });
async function checkSession() { async function checkSession() {
const res = await get('/session'); const res = await get('/session');
if (res.user) { if (res.user) {