Update efficiency 3 pickaxes

This commit is contained in:
2026-01-14 15:56:23 +01:00
parent ce73a84459
commit cc0c682ec9
+236 -165
View File
@@ -7,6 +7,17 @@ import bodyParser from "body-parser";
import Database from "better-sqlite3";
import FileStoreFactory from "session-file-store";
import {exec} from "child_process";
import {performance} from "perf_hooks";
let last = performance.now();
setInterval(() => {
const now = performance.now();
const drift = now - last - 1000;
last = now;
if (drift > 50) {
console.log("EVENT LOOP LAG", Math.round(drift), "ms", new Date().toISOString());
}
}, 1000);
const modelState = new Map();
const app = express();
@@ -14,6 +25,18 @@ const PORT = 3000;
const DB_PATH = "./data/app.db";
const SESSIONS_DIR = path.resolve("sessions");
const UNLOAD_AFTER_MS = 30 * 1000;
let modelsCache = null;
let modelsCacheAt = 0;
const MODELS_TTL_MS = 5 * 60 * 1000;
app.use((req, res, next) => {
const start = Date.now();
res.on("finish", () => {
const ms = Date.now() - start;
if (ms > 50) console.log("SLOW REQ", ms + "ms", req.method, req.url);
});
next();
});
if (!fs.existsSync("./data")) {
fs.mkdirSync("./data", {recursive: true});
@@ -57,212 +80,212 @@ db.prepare(`
CREATE TABLE IF NOT EXISTS users
(
username
TEXT
PRIMARY
KEY,
TEXT
PRIMARY
KEY,
password
TEXT
NOT
NULL
TEXT
NOT
NULL
)
`).run();
db.prepare(`
CREATE TABLE IF NOT EXISTS chats
(
id
INTEGER
PRIMARY
KEY
AUTOINCREMENT,
INTEGER
PRIMARY
KEY
AUTOINCREMENT,
username
TEXT
NOT
NULL,
TEXT
NOT
NULL,
role
TEXT
NOT
NULL,
TEXT
NOT
NULL,
content
TEXT
NOT
NULL,
TEXT
NOT
NULL,
created_at
DATETIME
DEFAULT
CURRENT_TIMESTAMP
DATETIME
DEFAULT
CURRENT_TIMESTAMP
)
`).run();
db.prepare(`
CREATE TABLE IF NOT EXISTS chat_sessions
(
id
INTEGER
PRIMARY
KEY
AUTOINCREMENT,
INTEGER
PRIMARY
KEY
AUTOINCREMENT,
username
TEXT
NOT
NULL,
TEXT
NOT
NULL,
title
TEXT
NOT
NULL,
TEXT
NOT
NULL,
created_at
DATETIME
DEFAULT
CURRENT_TIMESTAMP,
DATETIME
DEFAULT
CURRENT_TIMESTAMP,
updated_at
DATETIME
DEFAULT
CURRENT_TIMESTAMP
DATETIME
DEFAULT
CURRENT_TIMESTAMP
)
`).run();
db.prepare(`
CREATE TABLE IF NOT EXISTS chat_messages
(
id
INTEGER
PRIMARY
KEY
AUTOINCREMENT,
INTEGER
PRIMARY
KEY
AUTOINCREMENT,
chat_id
INTEGER
NOT
NULL,
INTEGER
NOT
NULL,
role
TEXT
NOT
NULL,
TEXT
NOT
NULL,
content
TEXT
NOT
NULL,
TEXT
NOT
NULL,
created_at
DATETIME
DEFAULT
CURRENT_TIMESTAMP,
DATETIME
DEFAULT
CURRENT_TIMESTAMP,
FOREIGN
KEY
(
chat_id
) REFERENCES chat_sessions
(
id
) ON DELETE CASCADE
)
KEY
(
chat_id
) REFERENCES chat_sessions
(
id
) ON DELETE CASCADE
)
`).run();
db.prepare(`
CREATE TABLE IF NOT EXISTS personas
(
id
INTEGER
PRIMARY
KEY
AUTOINCREMENT,
INTEGER
PRIMARY
KEY
AUTOINCREMENT,
username
TEXT
NOT
NULL,
TEXT
NOT
NULL,
name
TEXT
NOT
NULL,
TEXT
NOT
NULL,
pronouns
TEXT,
TEXT,
appearance
TEXT,
TEXT,
background
TEXT,
TEXT,
details
TEXT,
TEXT,
persona_type
TEXT
DEFAULT
'assistant',
TEXT
DEFAULT
'assistant',
created_at
DATETIME
DEFAULT
CURRENT_TIMESTAMP,
DATETIME
DEFAULT
CURRENT_TIMESTAMP,
updated_at
DATETIME
DEFAULT
CURRENT_TIMESTAMP
DATETIME
DEFAULT
CURRENT_TIMESTAMP
)
`).run();
db.prepare(`
CREATE TABLE IF NOT EXISTS user_settings
(
username
TEXT
PRIMARY
KEY,
TEXT
PRIMARY
KEY,
active_persona_id
INTEGER,
INTEGER,
active_user_persona_id
INTEGER,
INTEGER,
FOREIGN
KEY
(
active_persona_id
) REFERENCES personas
(
id
) ON DELETE SET NULL,
KEY
(
active_persona_id
) REFERENCES personas
(
id
) ON DELETE SET NULL,
FOREIGN
KEY
(
active_user_persona_id
) REFERENCES personas
(
id
) ON DELETE SET NULL
)
KEY
(
active_user_persona_id
) REFERENCES personas
(
id
) ON DELETE SET NULL
)
`).run();
db.prepare(`
CREATE TABLE IF NOT EXISTS persona_market
(
id
INTEGER
PRIMARY
KEY
AUTOINCREMENT,
INTEGER
PRIMARY
KEY
AUTOINCREMENT,
persona_id
INTEGER,
INTEGER,
creator_username
TEXT
NOT
NULL,
TEXT
NOT
NULL,
name
TEXT
NOT
NULL,
TEXT
NOT
NULL,
pronouns
TEXT,
TEXT,
appearance
TEXT,
TEXT,
background
TEXT,
TEXT,
details
TEXT,
TEXT,
persona_type
TEXT
DEFAULT
'assistant',
TEXT
DEFAULT
'assistant',
created_at
DATETIME
DEFAULT
CURRENT_TIMESTAMP,
DATETIME
DEFAULT
CURRENT_TIMESTAMP,
updated_at
DATETIME
DEFAULT
CURRENT_TIMESTAMP,
DATETIME
DEFAULT
CURRENT_TIMESTAMP,
UNIQUE
(
persona_id,
creator_username
(
persona_id,
creator_username
)
)
)
`).run();
const insertUserStmt = db.prepare("INSERT INTO users (username, password) VALUES (?, ?)");
@@ -273,7 +296,6 @@ const getLegacyChatsStmt = db.prepare(`
WHERE username = ?
ORDER BY datetime(created_at)
`);
const deleteLegacyChatsStmt = db.prepare("DELETE FROM chats WHERE username = ?");
const insertChatSessionStmt = db.prepare(
"INSERT INTO chat_sessions (username, title) VALUES (?, ?)"
);
@@ -306,10 +328,6 @@ const deleteChatSessionStmt = db.prepare(
"DELETE FROM chat_sessions WHERE id = ? AND username = ?"
);
const deleteAllChatSessionsStmt = db.prepare(
"DELETE FROM chat_sessions WHERE username = ?"
);
const insertChatMessageStmt = db.prepare(
"INSERT INTO chat_messages (chat_id, role, content) VALUES (?, ?, ?)"
);
@@ -326,7 +344,8 @@ const getRecentChatMessagesStmt = db.prepare(`
SELECT role, content
FROM chat_messages
WHERE chat_id = ?
ORDER BY datetime(created_at) DESC LIMIT 20
ORDER BY datetime(created_at) DESC
LIMIT 20
`
)
;
@@ -336,16 +355,26 @@ const deleteChatMessagesStmt = db.prepare(
);
const listPersonasByTypeStmt = db.prepare(`
SELECT id, name, pronouns, appearance, background, details, persona_type, created_at, updated_at
SELECT id,
name,
pronouns,
appearance,
background,
details,
persona_type,
created_at,
updated_at
FROM personas
WHERE username = ? AND persona_type = ?
WHERE username = ?
AND persona_type = ?
ORDER BY datetime(updated_at) DESC
`);
const getPersonaStmt = db.prepare(`
SELECT id, name, pronouns, appearance, background, details, persona_type
FROM personas
WHERE id = ? AND username = ?
WHERE id = ?
AND username = ?
`);
const insertPersonaStmt = db.prepare(
@@ -354,8 +383,14 @@ const insertPersonaStmt = db.prepare(
const updatePersonaStmt = db.prepare(`
UPDATE personas
SET name = ?, pronouns = ?, appearance = ?, background = ?, details = ?, updated_at = CURRENT_TIMESTAMP
WHERE id = ? AND username = ?
SET name = ?,
pronouns = ?,
appearance = ?,
background = ?,
details = ?,
updated_at = CURRENT_TIMESTAMP
WHERE id = ?
AND username = ?
`);
const deletePersonaStmt = db.prepare(
@@ -381,46 +416,73 @@ const setActiveUserPersonaStmt = db.prepare(`
const getActivePersonaStmt = db.prepare(`
SELECT p.id, p.name, p.pronouns, p.appearance, p.background, p.details
FROM user_settings us
JOIN personas p ON p.id = us.active_persona_id
JOIN personas p ON p.id = us.active_persona_id
WHERE us.username = ?
`);
const getActiveUserPersonaStmt = db.prepare(`
SELECT p.id, p.name, p.pronouns, p.appearance, p.background, p.details
FROM user_settings us
JOIN personas p ON p.id = us.active_user_persona_id
JOIN personas p ON p.id = us.active_user_persona_id
WHERE us.username = ?
`);
const listMarketPersonasStmt = db.prepare(`
SELECT id, persona_id, creator_username, name, pronouns, appearance, background, details, persona_type, created_at, updated_at
SELECT id,
persona_id,
creator_username,
name,
pronouns,
appearance,
background,
details,
persona_type,
created_at,
updated_at
FROM persona_market
ORDER BY datetime(updated_at) DESC
`);
const getMarketPersonaStmt = db.prepare(`
SELECT id, persona_id, creator_username, name, pronouns, appearance, background, details, persona_type
SELECT id,
persona_id,
creator_username,
name,
pronouns,
appearance,
background,
details,
persona_type
FROM persona_market
WHERE id = ?
`);
const getMarketPersonaByPersonaIdStmt = db.prepare(`
SELECT id, persona_id, creator_username, name, pronouns, appearance, background, details, persona_type
SELECT id,
persona_id,
creator_username,
name,
pronouns,
appearance,
background,
details,
persona_type
FROM persona_market
WHERE persona_id = ? AND creator_username = ?
WHERE persona_id = ?
AND creator_username = ?
`);
const upsertMarketPersonaStmt = db.prepare(`
INSERT INTO persona_market (persona_id, creator_username, name, pronouns, appearance, background, details, persona_type)
INSERT INTO persona_market (persona_id, creator_username, name, pronouns, appearance, background, details,
persona_type)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(persona_id, creator_username) DO UPDATE SET
name = excluded.name,
pronouns = excluded.pronouns,
appearance = excluded.appearance,
background = excluded.background,
details = excluded.details,
persona_type = excluded.persona_type,
updated_at = CURRENT_TIMESTAMP
ON CONFLICT(persona_id, creator_username) DO UPDATE SET name = excluded.name,
pronouns = excluded.pronouns,
appearance = excluded.appearance,
background = excluded.background,
details = excluded.details,
persona_type = excluded.persona_type,
updated_at = CURRENT_TIMESTAMP
`);
const listPublishedPersonaIdsStmt = db.prepare(`
@@ -475,7 +537,10 @@ app.use(bodyParser.json());
app.use(express.static("public"));
app.use(
session({
store: new FileStore({path: SESSIONS_DIR}),
store: new FileStore({
path: SESSIONS_DIR,
reapInterval: 3600
}),
secret: "-secret-key-here-",
resave: false,
saveUninitialized: false,
@@ -548,12 +613,18 @@ const requireLogin = (req, res, next) => {
app.get("/models", async (req, res) => {
try {
const response = await fetch("https://ai.krishd.ch/api/tags");
if (!response.ok) {
return res.status(500).json({error: "Failed to load models"});
if (modelsCache && (Date.now() - modelsCacheAt) < MODELS_TTL_MS) {
return res.json(modelsCache);
}
res.json(await response.json());
} catch (error) {
const controller = new AbortController();
const t = setTimeout(() => controller.abort(), 4000);
const response = await fetch("https://ai.krishd.ch/api/tags", {signal: controller.signal});
clearTimeout(t);
if (!response.ok) return res.status(500).json({error: "Failed to load models"});
modelsCache = await response.json();
modelsCacheAt = Date.now();
res.json(modelsCache);
} catch (e) {
res.status(500).json({error: "Failed to load models"});
}
});