current status

This commit is contained in:
Flummi 2024-01-09 13:14:43 +01:00
parent 1b80d11a2c
commit 2ac0d2de6f
4 changed files with 217 additions and 65 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
node_modules/
conversations/
config.json

10
config.example.json Normal file
View File

@ -0,0 +1,10 @@
{
"api": {
"host": "localhost",
"port": 5001,
"bearer": ""
},
"initiative": [],
"stops": ["###"],
"clients": []
}

34
src/inc/lib.mjs Normal file
View File

@ -0,0 +1,34 @@
import { exec as _exec } from 'node:child_process';
import fetch from 'node-fetch';
export default new class {
exec(cmd) {
return new Promise((resolve, reject) => {
_exec(cmd, { maxBuffer: 5e3 * 1024 }, (err, stdout, stderr) => {
if(err)
return reject(err);
if(stderr)
console.error(stderr);
resolve({ stdout: stdout });
});
});
};
rand(max = 1) {
return ~~(Math.random() * (max - 1) + 1);
};
async getPlayerlist(world, clanid) {
const res = await (await fetch(`https://${world}.freewar.de/freewar/dump_players.php`)).text();
return res.split("\n").map(p => {
const player = p.split("\t");
return {
id: +player[0],
name: player[1],
xp: +player[2],
rasse: player[3],
clanid: +player[4]
};
}).filter(p => p.clanid === clanid)
};
};

View File

@ -2,100 +2,205 @@ import fs from 'node:fs/promises';
import cuffeo from 'cuffeo'; import cuffeo from 'cuffeo';
import fetch from 'node-fetch'; import fetch from 'node-fetch';
import oger from './inc/oger.mjs'; import oger from './inc/oger.mjs';
import lib from './inc/lib.mjs';
import config from '../config.json' assert { type: 'json' }; import config from '../config.json' assert { type: 'json' };
import initials from './inc/initials.json' assert { type: 'json' }; import initials from '../data/initials.json' assert { type: 'json' };
const conversations = new Map(); const conversations = new Map();
const bot = await new cuffeo(config.clients); const bot = await new cuffeo(config.clients);
let last = false; let last = false;
let playerlist = false;
bot.on('message', async e => { bot.on('message', async e => {
if(typeof e.message === 'undefined' || e.message.length <= 2)
return;
console.log(e.user.nick + ": " + e.message); console.log(e.user.nick + ": " + e.message);
const constr = `${e.network}::${e.channelid}`; const constr = `${e.network}::${e.channelid}`;
if(e.message?.match(/^!perf/i)) { if(e.message.match(/^!claninfo/i)) {
return await e.reply(JSON.stringify(await (await fetch(`http://${config.api.host}:${config.api.port}/api/extra/perf`)).json())); playerlist = await lib.getPlayerlist("welt13", 4760);
return await e.reply(
playerlist.map(p => p.name).join(", ")
);
} }
if(e.message?.match(/^!model/i)) { if(e.message.match(/^!gens/i)) {
const perf = await (await fetch(`http://${config.api.host}:${config.api.port}/api/extra/perf`)).json();
return await e.reply(`total_gens: ${perf.total_gens}`);
}
if(e.message.match(/^!model/i)) {
return await e.reply((await (await fetch(`http://${config.api.host}:${config.api.port}/api/v1/model`)).json()).result); return await e.reply((await (await fetch(`http://${config.api.host}:${config.api.port}/api/v1/model`)).json()).result);
} }
if(e.message?.match(/^!channelid/i)) { if(e.message.match(/^!messages/i)) {
try {
const cons = (await fs.readdir("./data/conversations")).filter(f => f.endsWith(".json"));
let messages = 0;
for(const con of cons) {
messages += JSON.parse(await fs.readFile(`./data/conversations/${con}`, 'utf8')).length;
}
let output = [];
output.push(`Nachrichten insgesamt: ${messages}`);
if(cons.includes(constr+'.json')) {
output.push(`Davon in diesem Kanal: ${JSON.parse(await fs.readFile(`./data/conversations/${constr}.json`, 'utf8')).length}`);
}
return await e.reply(output.join(' | '));
} catch(err) {
console.error(err);
return;
}
}
if(e.message.match(/^!gpustat/i)) {
const gpustat = JSON.parse((await lib.exec('gpustat -a --json')).stdout);
const gpu = gpustat.gpus[0];
const output = [
`${gpu['temperature.gpu']}°C, ${gpu['fan.speed']} rpm`,
`${gpu['memory.used']} / ${gpu['memory.total']} MB`,
`${gpu['power.draw']} / ${gpu['enforced.power.limit']} W`
].join(' | ');
return await e.reply(`${gpustat.hostname}: ${gpu.name}\n${output}`);
}
if(e.message.match(/^!channelid/i)) {
return await e.reply(e.channelid); return await e.reply(e.channelid);
} }
if(!conversations.has(constr)) { // get conv from json if(e.message.match(/^!reset/i)) {
try { conversations.set(constr, []);
const tmpcon = JSON.parse(await fs.readFile(`./src/conversations/${constr}.json`, 'utf8')); await fs.writeFile(`./data/conversations/${constr}.json`, JSON.stringify([]));
return await e.reply("Konversation wurde erfolgreich zurückgesetzt.");
}
let conv = conversations.has(constr) ? conversations.get(constr) : [];
if(!conv.length) {
try { // get conv from json
const tmpcon = JSON.parse(await fs.readFile(`./data/conversations/${constr}.json`, 'utf8'));
if(tmpcon) { if(tmpcon) {
conversations.set(constr, tmpcon); conv = tmpcon;
console.log(`Konversation von ${constr} geladen. ${tmpcon.length} Einträge.`); console.log(`Konversation von ${constr} geladen. ${tmpcon.length} Einträge.`);
} }
} catch(err) {} } catch(err) {
console.error(err);
conversations.set(constr, conv);
}
} }
if(e.message?.match(/ra+i+ne+r/i)) { conv.push({
role: 'user',
content: `${e.user.nick} schreibt: ${e.message.trim()}`
});
await fs.writeFile(`./data/conversations/${constr}.json`, JSON.stringify(conv));
conversations.set(constr, conv);
if(last) if(!e.message?.match(/ra+i+ne+r/i)) {
return await e.reply(`ich antworte bereits ${last}!`); if(!config.initiative.includes(constr))
return;
const actcon = []; let probability = 20; // default, 5%
if(conversations.has(constr)) if(e.message.match(/.*\?$/)) {
actcon.push(...conversations.get(constr)); probability = 5; // 20%
else {
actcon.push({
"role": "system",
"content": initials[e.channelid] ? initials[e.channelid].lore : initials['default'].lore
});
actcon.push({
"role": "system",
"content": "eingehende Chatnachrichten sind immer folgendermaßen aufgebaut: \"%USERNAME% schreibt: %COMMAND%\". Du schreibst das aber nicht."
});
} }
if(lib.rand(probability) !== 1) {
return;
}
}
// Rainer matched
if(last)
return await e.reply(`ich antworte bereits ${last}!`);
const actcon = [{
"role": "system",
"content": initials[ initials[constr] ? constr : 'default' ].lore
}, {
"role": "system",
"content": "eingehende Chatnachrichten sind immer folgendermaßen aufgebaut: \"%USERNAME% schreibt: %COMMAND%\". Du schreibst das aber nicht."
}, {
"role": "system",
"content": `Aktuelles Datum und Zeit: ${(new Date()).toLocaleString()}`
}];
if(constr === 'Discord::1143415824539992206') {
if(!playerlist)
playerlist = await lib.getPlayerlist('welt13', 4760);
actcon.push({ actcon.push({
role: 'user', "role": "user",
content: `${e.user.nick} schreibt: ${e.message.trim()}` "content": "Unser Clan besteht aus folgenden Mitgliedern:\n" + playerlist.map(p => `${p.name}: ${p.xp} XP, Rasse: ${p.rasse}`).join("\n")
}); });
const opts = {
method: 'POST',
port: 5001,
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${config.api.bearer}`
},
body: JSON.stringify({
mode: "chat",
instruction_template: "Alpaca",
stream: false,
max_tokens: 1024,
stop: ['###', ' <|endoftext|>', '---'],
messages: actcon
})
};
last = e.user.nick;
const res = await (await fetch(`http://${config.api.host}:${config.api.port}/v1/chat/completions`, opts)).json();
if(res.choices[0]?.message) {
if(res.choices[0].message.length <= 2)
return await e.reply('ich habe dazu nichts zu sagen, du Birne.');
res.choices[0].message.content = res.choices[0].message.content.split(/(###|---)/)[0];
actcon.push(res.choices[0].message);
conversations.set(constr, actcon);
console.log("Rainer: " + res.choices[0].message.content.trim());
last = false;
await fs.writeFile(`./src/conversations/${constr}.json`, JSON.stringify(conversations.get(constr)));
return await e.reply(res.choices[0].message.content.trim());
}
last = false;
} }
actcon.push(...conv, {
role: 'user',
content: `${e.user.nick} schreibt: ${e.message.trim()}`
});
const opts = {
method: 'POST',
port: 5001,
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${config.api.bearer}`
},
body: JSON.stringify({
mode: "chat",
instruction_template: "Alpaca",
stream: false,
max_tokens: 768,
stop: config.stops,
messages: actcon
})
};
last = e.user.nick;
let res;
try {
res = await (await fetch(`http://${config.api.host}:${config.api.port}/v1/chat/completions`, opts)).json();
} catch(err) {
last = false;
return await e.reply('Backend ist gerade offline. Sorreh.');
}
if(res?.choices?.[0]?.message) {
if(res.choices[0].message.length <= 2)
return await e.reply('ich habe dazu nichts zu sagen, du Birne.');
res.choices[0].message.content = res.choices[0].message.content.split(/(###|---|ASSISTANT)/)[0];
res.choices[0].message.content = res.choices[0].message.content.replace(/^Rainer( schreibt| antwortet)?: /, '');
conv.push(res.choices[0].message);
conversations.set(constr, conv);
await fs.writeFile(`./data/conversations/${constr}.json`, JSON.stringify(conv));
console.log("Rainer: " + res.choices[0].message.content.trim());
try {
if(initials[constr] && initials[constr].langmod === 'oger')
await e.reply(oger(res.choices[0].message.content.trim()));
else
await e.reply(res.choices[0].message.content.trim());
} catch(err) {
await e.reply('ups, kann ich nicht schreiben, wäre zu viel gewesen.');
}
}
else {
await e.reply('Hilfe, Fehler!');
}
last = false;
return;
}); });