|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function submitKey(event) { |
|
event.preventDefault(); |
|
localStorage.setItem("key", document.getElementById("apiKey").value); |
|
document.getElementById("apiKey").blur(); |
|
} |
|
|
|
function submitSystemPrompt(event) { |
|
event.preventDefault(); |
|
localStorage.setItem("system_prompt", document.getElementById("systemPrompt").value); |
|
document.getElementById("systemPrompt").blur(); |
|
} |
|
|
|
var image = ""; |
|
|
|
function submitPrompt(event) { |
|
event.preventDefault(); |
|
|
|
const input = document.getElementById("input").value; |
|
Alpine.store("chat").add("user", input, image); |
|
document.getElementById("input").value = ""; |
|
const key = localStorage.getItem("key"); |
|
const systemPrompt = localStorage.getItem("system_prompt"); |
|
|
|
promptGPT(systemPrompt, key, input); |
|
} |
|
|
|
function readInputImage() { |
|
|
|
if (!this.files || !this.files[0]) return; |
|
|
|
const FR = new FileReader(); |
|
|
|
FR.addEventListener("load", function(evt) { |
|
image = evt.target.result; |
|
}); |
|
|
|
FR.readAsDataURL(this.files[0]); |
|
} |
|
|
|
|
|
async function promptGPT(systemPrompt, key, input) { |
|
const model = document.getElementById("chat-model").value; |
|
|
|
|
|
|
|
document.getElementById("loader").style.display = "block"; |
|
document.getElementById("input").disabled = true; |
|
document.getElementById('messages').scrollIntoView(false) |
|
|
|
messages = Alpine.store("chat").messages(); |
|
|
|
|
|
if (systemPrompt) { |
|
messages.unshift({ |
|
role: "system", |
|
content: systemPrompt |
|
}); |
|
} |
|
|
|
|
|
messages.forEach((message) => { |
|
if (message.image) { |
|
|
|
message.content = [ |
|
{ |
|
"type": "text", |
|
"text": message.content |
|
} |
|
] |
|
message.content.push( |
|
{ |
|
"type": "image_url", |
|
"image_url": { |
|
"url": message.image, |
|
} |
|
} |
|
); |
|
|
|
|
|
delete message.image; |
|
} |
|
}); |
|
|
|
|
|
image = ""; |
|
document.getElementById("input_image").value = null; |
|
document.getElementById("fileName").innerHTML = ""; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const response = await fetch("/v1/chat/completions", { |
|
method: "POST", |
|
headers: { |
|
Authorization: `Bearer ${key}`, |
|
"Content-Type": "application/json", |
|
}, |
|
body: JSON.stringify({ |
|
model: model, |
|
messages: messages, |
|
stream: true, |
|
}), |
|
}); |
|
|
|
if (!response.ok) { |
|
Alpine.store("chat").add( |
|
"assistant", |
|
`<span class='error'>Error: POST /v1/chat/completions ${response.status}</span>`, |
|
); |
|
return; |
|
} |
|
|
|
const reader = response.body |
|
?.pipeThrough(new TextDecoderStream()) |
|
.getReader(); |
|
|
|
if (!reader) { |
|
Alpine.store("chat").add( |
|
"assistant", |
|
`<span class='error'>Error: Failed to decode API response</span>`, |
|
); |
|
return; |
|
} |
|
|
|
|
|
const addToChat = (token) => { |
|
const chatStore = Alpine.store("chat"); |
|
chatStore.add("assistant", token); |
|
|
|
const messages = document.getElementById('messages'); |
|
messages.scrollTop = messages.scrollHeight; |
|
}; |
|
|
|
let buffer = ""; |
|
let contentBuffer = []; |
|
|
|
try { |
|
while (true) { |
|
const { value, done } = await reader.read(); |
|
if (done) break; |
|
|
|
buffer += value; |
|
|
|
let lines = buffer.split("\n"); |
|
buffer = lines.pop(); |
|
|
|
lines.forEach((line) => { |
|
if (line.length === 0 || line.startsWith(":")) return; |
|
if (line === "data: [DONE]") { |
|
return; |
|
} |
|
|
|
if (line.startsWith("data: ")) { |
|
try { |
|
const jsonData = JSON.parse(line.substring(6)); |
|
const token = jsonData.choices[0].delta.content; |
|
|
|
if (token) { |
|
contentBuffer.push(token); |
|
} |
|
} catch (error) { |
|
console.error("Failed to parse line:", line, error); |
|
} |
|
} |
|
}); |
|
|
|
|
|
if (contentBuffer.length > 0) { |
|
addToChat(contentBuffer.join("")); |
|
contentBuffer = []; |
|
} |
|
} |
|
|
|
|
|
if (contentBuffer.length > 0) { |
|
addToChat(contentBuffer.join("")); |
|
} |
|
|
|
|
|
hljs.highlightAll(); |
|
} catch (error) { |
|
console.error("An error occurred while reading the stream:", error); |
|
Alpine.store("chat").add( |
|
"assistant", |
|
`<span class='error'>Error: Failed to process stream</span>`, |
|
); |
|
} finally { |
|
|
|
reader.releaseLock(); |
|
} |
|
|
|
|
|
|
|
document.getElementById("loader").style.display = "none"; |
|
|
|
document.getElementById("input").disabled = false; |
|
|
|
document.getElementById('messages').scrollIntoView(false) |
|
|
|
document.getElementById("input").focus(); |
|
} |
|
|
|
document.getElementById("key").addEventListener("submit", submitKey); |
|
document.getElementById("system_prompt").addEventListener("submit", submitSystemPrompt); |
|
|
|
document.getElementById("prompt").addEventListener("submit", submitPrompt); |
|
document.getElementById("input").focus(); |
|
document.getElementById("input_image").addEventListener("change", readInputImage); |
|
|
|
storeKey = localStorage.getItem("key"); |
|
if (storeKey) { |
|
document.getElementById("apiKey").value = storeKey; |
|
} else { |
|
document.getElementById("apiKey").value = null; |
|
} |
|
|
|
storesystemPrompt = localStorage.getItem("system_prompt"); |
|
if (storesystemPrompt) { |
|
document.getElementById("systemPrompt").value = storesystemPrompt; |
|
} else { |
|
document.getElementById("systemPrompt").value = null; |
|
} |
|
|
|
marked.setOptions({ |
|
highlight: function (code) { |
|
return hljs.highlightAuto(code).value; |
|
}, |
|
}); |
|
|