From aebee54562c12c3c8cf67e873908793c23e6aa82f1406463e608bdea37ac0458 Mon Sep 17 00:00:00 2001 From: aslan Date: Sun, 28 Dec 2025 23:11:33 +0100 Subject: [PATCH] Rework AI --- package.json | 2 +- src/config.preset.json | 10 +++++++++- src/modules/ai/ai.ts | 37 +++++++++++++++++++++++++++++-------- src/modules/ai/alts.ts | 7 ++++++- src/modules/ai/types.ts | 18 +++++++++++++----- src/modules/global.ts | 2 +- src/modules/user/user.ts | 2 +- src/services/ai/ai.ts | 9 ++++++++- src/store/store.ts | 4 ++++ src/store/types.ts | 8 +++++++- 10 files changed, 79 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index bf497c2..586ebc4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "aslobot-matrix", - "version": "0.7.2", + "version": "0.8.0", "description": "", "license": "ISC", "author": "", diff --git a/src/config.preset.json b/src/config.preset.json index dbd7d75..1be2fbf 100644 --- a/src/config.preset.json +++ b/src/config.preset.json @@ -1,5 +1,6 @@ { "baseUrl": "https://", + "server": "", "userId": "@", "authPath": "auth.json", "storePath": "store.json", @@ -25,7 +26,14 @@ "api": { "key": "" }, - "prompt": "Your name is Aslobot. Be concise, try to keep text as short as possible. Be helpful." + "personalities": [ + { + "personality": "You are Aslobot. Be helpful. Be concise, keep text as short as possible.", + "likes": [], + "dislikes": [], + "timeout": 3600000 + } + ] } } } diff --git a/src/modules/ai/ai.ts b/src/modules/ai/ai.ts index d5d4d2c..fd4c8df 100644 --- a/src/modules/ai/ai.ts +++ b/src/modules/ai/ai.ts @@ -3,9 +3,10 @@ import type { ICallbackStore } from "../types.js"; import { config } from "../../config.js"; import { getTextGemini, getImageGemini } from "../../services/ai/ai.js"; import { alts } from "./alts.js"; -import type { IAdminInstructions, IAIAlt } from "./types.js"; +import type { IAIInstructions } from "./types.js"; import { getUserById, getUserName } from "../../helpers.js"; import { prices } from "./prices.js"; +import { state } from "../../store/store.js"; let client: MatrixClient; @@ -34,21 +35,41 @@ const onAI = async (text: string, roomId: string, sender: string) => { return; } + let personality = config.app.ai.personalities[state.personality.index]; + if ( + Date.now() > + state.personality.startTime + (personality?.timeout ?? 0) + ) { + const randomInt = Math.floor( + Math.random() * (config.app.ai.personalities.length + 1), + ); + state.personality = { + index: randomInt, + startTime: Date.now(), + }; + } + + personality = config.app.ai.personalities[state.personality.index]; + let textMod = text.replace("!ai", "").trim().toLowerCase(); let instructions = { prefferedLanguages: ["english", "slovak"], - adminText: config.app.ai.prompt, - alts: alts.map((alt) => ({ - keys: alt.keys, + users: alts.map((alt) => ({ + names: alt.keys, alt: alt.alt, - information: user.information, + backstory: alt.id + ? getUserById(`${alt.id}:${config.server}`).information + : undefined, })), - } as IAdminInstructions; + aiPersonality: personality?.personality ?? "", + aiLikes: personality?.likes ?? "", + aiDislikes: personality?.dislikes ?? "", + } as IAIInstructions; const username = getUserName(user); - textMod = `Admin Instructions:\n${JSON.stringify(instructions)}\nPrompt by ${username}:\n${textMod}`; + textMod = `${username}:\n${textMod}`; - const responseAI = await getTextGemini(textMod); + const responseAI = await getTextGemini(instructions, textMod); user.aiCost += responseAI.tokens * prices.text; diff --git a/src/modules/ai/alts.ts b/src/modules/ai/alts.ts index f7b8ead..6109e4a 100644 --- a/src/modules/ai/alts.ts +++ b/src/modules/ai/alts.ts @@ -2,6 +2,7 @@ import type { IAIAlt } from "./types.js"; const alts: IAIAlt[] = [ { + id: "@coty", keys: [ "satek", "sateg", @@ -22,10 +23,12 @@ const alts: IAIAlt[] = [ alt: "white cat", }, { + id: "@marketing", keys: ["gabor", "gaber", "martin", "marting"], alt: "hedgehog", }, { + id: "@madys", keys: [ "madys", "mandak", @@ -39,10 +42,12 @@ const alts: IAIAlt[] = [ alt: "beaver", }, { + id: "@aslan2142", keys: ["janys", "jano", "janeg", "janek", "aslanek", "aslan", "aslo"], alt: "lion", }, { + id: "@rod", keys: ["marek", "mareg", "macek", "maceg", "rod"], alt: "purple snake", }, @@ -56,7 +61,7 @@ const alts: IAIAlt[] = [ }, { keys: ["mama", "monika", "monik"], - alt: "god's peasant", + alt: "god's peasant woman", }, { keys: ["puk", "pucik", "pucig"], diff --git a/src/modules/ai/types.ts b/src/modules/ai/types.ts index 6fbe64e..c7a64cb 100644 --- a/src/modules/ai/types.ts +++ b/src/modules/ai/types.ts @@ -1,13 +1,21 @@ interface IAIAlt { + id?: string; keys: string[]; alt: string; - information?: string | undefined; } -interface IAdminInstructions { +interface IAIUser { + names: string[]; + alt: string; + backstory?: string | undefined; +} + +interface IAIInstructions { prefferedLanguages: string[]; - adminText: string; - alts: IAIAlt[]; + users: IAIUser[]; + aiPersonality: string; + aiLikes: string; + aiDislikes: string; } -export { type IAIAlt, type IAdminInstructions }; +export { type IAIAlt, type IAIUser, type IAIInstructions }; diff --git a/src/modules/global.ts b/src/modules/global.ts index 97e5f94..c73b2eb 100644 --- a/src/modules/global.ts +++ b/src/modules/global.ts @@ -61,7 +61,7 @@ const onMissingRole = ( client.sendHtmlMessage( roomId, "", - `You are missing the required role.
Your current role is ${userRole}`, + `You don't have a permission to do that!
Your current role is ${userRole}`, ); }; diff --git a/src/modules/user/user.ts b/src/modules/user/user.ts index 502891e..a11011c 100644 --- a/src/modules/user/user.ts +++ b/src/modules/user/user.ts @@ -98,7 +98,7 @@ const onAILeaderboard = (_text: string, roomId: string) => { const cost = user.aiCost; const username = getUserName(user); - return `
  • ${username}: cost ${cost.toFixed(2)}$
  • `; + return `
  • ${username}: ${cost.toFixed(2)}$
  • `; }; const users = state.users.sort( diff --git a/src/services/ai/ai.ts b/src/services/ai/ai.ts index 80961b7..49ba489 100644 --- a/src/services/ai/ai.ts +++ b/src/services/ai/ai.ts @@ -1,15 +1,22 @@ import { GoogleGenAI } from "@google/genai"; import { config } from "../../config.js"; import type { AIResponseImage, AIResponseText } from "./types.js"; +import type { IAIInstructions } from "../../modules/ai/types.js"; const googleAI = new GoogleGenAI({ apiKey: config.app.ai.api.key, }); -const getTextGemini = async (input: string): Promise => { +const getTextGemini = async ( + instructions: IAIInstructions, + input: string, +): Promise => { const response = await googleAI.models.generateContent({ model: "gemini-3-flash-preview", contents: input, + config: { + systemInstruction: JSON.stringify(instructions), + }, }); return { diff --git a/src/store/store.ts b/src/store/store.ts index a892157..1095b2f 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -6,6 +6,10 @@ import type { IState } from "./types.js"; let state: IState = { users: [], + personality: { + index: 0, + startTime: 0, + }, }; const load = () => { diff --git a/src/store/types.ts b/src/store/types.ts index 2af1ecc..9c876c3 100644 --- a/src/store/types.ts +++ b/src/store/types.ts @@ -1,5 +1,6 @@ interface IState { users: IUser[]; + personality: IPersonality; } interface IUser { @@ -16,4 +17,9 @@ interface IUser { type TRole = "NONE" | "USER" | "MODERATOR" | "ADMIN"; -export { type IState, type IUser, type TRole }; +interface IPersonality { + index: number; + startTime: number; +} + +export { type IState, type IUser, type TRole, type IPersonality };