fix sending messages + rename the js
This commit is contained in:
parent
ddf65351ff
commit
3d2d5c6717
1 changed files with 3 additions and 2 deletions
259
lydia.js
Normal file
259
lydia.js
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
import ollama from "ollama";
|
||||
import blessed from "blessed";
|
||||
import { execSync } from "child_process";
|
||||
import toml from "toml";
|
||||
import fs from "fs";
|
||||
|
||||
const config = toml.parse(fs.readFileSync("./config.toml", "utf-8"));
|
||||
|
||||
const assistantname = config.assistant.name;
|
||||
const username = config.user.name;
|
||||
const assistantface = config.assistant.assistantface;
|
||||
const assistantmodel = config.assistant.model;
|
||||
const systemprompt = config.assistant.system_prompt
|
||||
.replace("${name}", assistantname)
|
||||
.replace("${username}", username);
|
||||
|
||||
const screen = blessed.screen({
|
||||
smartCSR: true,
|
||||
title: assistantname,
|
||||
});
|
||||
|
||||
const faceBox = blessed.box({
|
||||
top: 0,
|
||||
left: 1,
|
||||
width: "100%",
|
||||
height: "90%",
|
||||
scrollable: true,
|
||||
alwaysScroll: true,
|
||||
mouse: true,
|
||||
keys: true,
|
||||
vi: true,
|
||||
tags: true,
|
||||
content: "",
|
||||
});
|
||||
|
||||
const chatBox = blessed.box({
|
||||
top: 9,
|
||||
left: 1,
|
||||
width: "100%",
|
||||
height: "90%",
|
||||
scrollable: true,
|
||||
alwaysScroll: true,
|
||||
mouse: true,
|
||||
keys: true,
|
||||
vi: true,
|
||||
tags: true,
|
||||
content: `go on, tell ${assistantname} something! esc to tab out of chatbox.`,
|
||||
});
|
||||
|
||||
const inputBox = blessed.textbox({
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
width: "100%",
|
||||
height: 3,
|
||||
border: {
|
||||
type: "line",
|
||||
},
|
||||
style: {
|
||||
border: {
|
||||
fg: "cyan",
|
||||
},
|
||||
},
|
||||
inputOnFocus: true,
|
||||
keys: true,
|
||||
mouse: true,
|
||||
placeholder: `go on, tell ${assistantname} something!`,
|
||||
});
|
||||
screen.append(faceBox);
|
||||
screen.append(chatBox);
|
||||
screen.append(inputBox);
|
||||
|
||||
inputBox.focus();
|
||||
|
||||
let chatHistory = [];
|
||||
let currentStreamMessage = "";
|
||||
|
||||
function addMessage(role, content) {
|
||||
let message;
|
||||
if (role === username) {
|
||||
const padding = Math.max(0, chatBox.width - content.length - 5);
|
||||
message = " ".repeat(padding) + content + " <\n";
|
||||
} else {
|
||||
message = `> ${assistantname}: ${content}\n`;
|
||||
}
|
||||
chatHistory.push(message);
|
||||
|
||||
chatBox.setContent(chatHistory.join(""));
|
||||
chatBox.setScrollPerc(100);
|
||||
screen.render();
|
||||
}
|
||||
|
||||
function updateStreamMessage(content) {
|
||||
currentStreamMessage = content;
|
||||
|
||||
// handle the kaomoji
|
||||
let letterIndex = -1;
|
||||
for (let i = 0; i < content.length - 1; i++) {
|
||||
if (/[a-zA-Z]/.test(content[i])) {
|
||||
// If it's capital I, split immediately
|
||||
if (content[i] === "I") {
|
||||
letterIndex = i;
|
||||
break;
|
||||
}
|
||||
// If next character is also a letter, split at two consecutive letters
|
||||
if (/[a-zA-Z]/.test(content[i + 1])) {
|
||||
letterIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (letterIndex !== -1) {
|
||||
const faceContent = content.substring(0, letterIndex).trim();
|
||||
const messageContent = content.substring(letterIndex).trim();
|
||||
|
||||
// only update face if kaomoji is 3+ characters because sometimes the model wont listen
|
||||
if (faceContent.length >= 3) {
|
||||
setFaceBoxContent(faceContent);
|
||||
}
|
||||
|
||||
const tempHistory = [...chatHistory];
|
||||
tempHistory.push(`> ${assistantname}: ${messageContent}\n`);
|
||||
|
||||
chatBox.setContent(tempHistory.join(""));
|
||||
chatBox.setScrollPerc(100);
|
||||
screen.render();
|
||||
} else {
|
||||
// if no letters found yet, just show the entire thing
|
||||
const tempHistory = [...chatHistory];
|
||||
tempHistory.push(`> ${assistantname}: ${content}\n`);
|
||||
|
||||
chatBox.setContent(tempHistory.join(""));
|
||||
chatBox.setScrollPerc(100);
|
||||
screen.render();
|
||||
}
|
||||
}
|
||||
|
||||
function finalizeStreamMessage() {
|
||||
if (currentStreamMessage) {
|
||||
let letterIndex = -1;
|
||||
for (let i = 0; i < currentStreamMessage.length - 1; i++) {
|
||||
if (/[a-zA-Z]/.test(currentStreamMessage[i])) {
|
||||
// complicated kaomoji splitting garboleum
|
||||
if (currentStreamMessage[i] === "I") {
|
||||
letterIndex = i;
|
||||
break;
|
||||
}
|
||||
if (/[a-zA-Z]/.test(currentStreamMessage[i + 1])) {
|
||||
letterIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (letterIndex !== -1) {
|
||||
const messageContent = currentStreamMessage.substring(letterIndex).trim();
|
||||
addMessage(assistantname, messageContent);
|
||||
} else {
|
||||
addMessage(assistantname, currentStreamMessage);
|
||||
}
|
||||
currentStreamMessage = "";
|
||||
}
|
||||
}
|
||||
|
||||
function setFaceBoxContent(content) {
|
||||
try {
|
||||
const figletOutput = execSync(`figlet -f mono9 "${content}"`, {
|
||||
encoding: "utf8",
|
||||
});
|
||||
faceBox.setContent(figletOutput);
|
||||
} catch (err) {
|
||||
faceBox.setContent(content);
|
||||
}
|
||||
screen.render();
|
||||
}
|
||||
|
||||
async function sendMessage(message) {
|
||||
if (!message.trim()) return;
|
||||
//if (message.startsWith("!")) {
|
||||
if (message.trim().startsWith("l!")) {
|
||||
// command handler (if command, dont tell ollama about it, just handle it right here) -- THIS DOES NOT WORK AS OF NOW
|
||||
const commandParts = message.slice(2).split(" ");
|
||||
const command = commandParts[0];
|
||||
const args = commandParts.slice(1).join(" ");
|
||||
|
||||
switch (command) {
|
||||
case "help":
|
||||
chatBox.setContent(
|
||||
"available commands:\n!help - show this help message\n!face <text> - set face to text",
|
||||
);
|
||||
break;
|
||||
case "clear":
|
||||
chatHistory = [];
|
||||
chatBox.setContent("");
|
||||
break;
|
||||
case "face":
|
||||
if (args.trim()) {
|
||||
setFaceBoxContent(args.trim());
|
||||
} else {
|
||||
setFaceBoxContent("=w=");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
chatBox.setContent(`unknown command: ${command}`);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// if not command, pass to ollama
|
||||
addMessage(username, message);
|
||||
|
||||
try {
|
||||
currentStreamMessage = "";
|
||||
|
||||
const response = await ollama.chat({
|
||||
model: assistantmodel,
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content: systemprompt,
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: message,
|
||||
},
|
||||
],
|
||||
stream: true,
|
||||
});
|
||||
|
||||
for await (const part of response) {
|
||||
if (part.message && part.message.content) {
|
||||
currentStreamMessage += part.message.content;
|
||||
updateStreamMessage(currentStreamMessage);
|
||||
}
|
||||
}
|
||||
|
||||
finalizeStreamMessage();
|
||||
} catch (error) {
|
||||
addMessage(assistantname, `Failed to get response: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inputBox.on("submit", async (text) => {
|
||||
if (text.trim()) {
|
||||
inputBox.clearValue();
|
||||
inputBox.focus();
|
||||
await sendMessage(text);
|
||||
}
|
||||
});
|
||||
|
||||
screen.key(["escape", "q", "C-c"], () => {
|
||||
process.exit(0); // KILL lydia!!!!!!!!!!!!!!!!!!!!!!!
|
||||
});
|
||||
|
||||
screen.on("resize", () => {
|
||||
screen.render();
|
||||
});
|
||||
|
||||
setFaceBoxContent(assistantface);
|
||||
Loading…
Add table
Add a link
Reference in a new issue