mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 21:21:10 +02:00
♻️ refactor: migrate 5 Matrix bots to shared utilities
Migrate bots to use KeywordCommandDetector and UserListMapper from @manacore/matrix-bot-common, reducing duplicate code. KeywordCommandDetector (natural language command detection): - matrix-ollama-bot - matrix-nutriphi-bot - matrix-contacts-bot UserListMapper (number-based reference system): - matrix-presi-bot (decks + themes) - matrix-skilltree-bot (skills) - matrix-contacts-bot (contacts) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
4d8c7f1a7c
commit
f04c27fe26
5 changed files with 325 additions and 246 deletions
|
|
@ -1,23 +1,29 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { BaseMatrixService, MatrixBotConfig, MatrixRoomEvent } from '@manacore/matrix-bot-common';
|
||||
import {
|
||||
BaseMatrixService,
|
||||
MatrixBotConfig,
|
||||
MatrixRoomEvent,
|
||||
KeywordCommandDetector,
|
||||
COMMON_KEYWORDS,
|
||||
UserListMapper,
|
||||
} from '@manacore/matrix-bot-common';
|
||||
import { ContactsService, Contact } from '../contacts/contacts.service';
|
||||
import { SessionService } from '@manacore/bot-services';
|
||||
import { HELP_MESSAGE } from '../config/configuration';
|
||||
|
||||
// Natural language keywords
|
||||
const KEYWORD_COMMANDS: { keywords: string[]; command: string }[] = [
|
||||
{ keywords: ['hilfe', 'help', 'befehle', 'commands'], command: 'help' },
|
||||
// Natural language keyword detector
|
||||
const keywordDetector = new KeywordCommandDetector([
|
||||
...COMMON_KEYWORDS,
|
||||
{ keywords: ['kontakte', 'contacts', 'alle'], command: 'kontakte' },
|
||||
{ keywords: ['favoriten', 'favorites', 'favs'], command: 'favoriten' },
|
||||
{ keywords: ['suche', 'search', 'finde'], command: 'suche' },
|
||||
{ keywords: ['status', 'info'], command: 'status' },
|
||||
];
|
||||
]);
|
||||
|
||||
@Injectable()
|
||||
export class MatrixService extends BaseMatrixService {
|
||||
// Store last shown contacts per user for reference by number
|
||||
private lastContactsList: Map<string, Contact[]> = new Map();
|
||||
// User list mapper for number-based reference
|
||||
private contactsMapper = new UserListMapper<Contact>();
|
||||
|
||||
constructor(
|
||||
configService: ConfigService,
|
||||
|
|
@ -29,9 +35,11 @@ export class MatrixService extends BaseMatrixService {
|
|||
|
||||
protected getConfig(): MatrixBotConfig {
|
||||
return {
|
||||
homeserverUrl: this.configService.get<string>('matrix.homeserverUrl') || 'http://localhost:8008',
|
||||
homeserverUrl:
|
||||
this.configService.get<string>('matrix.homeserverUrl') || 'http://localhost:8008',
|
||||
accessToken: this.configService.get<string>('matrix.accessToken') || '',
|
||||
storagePath: this.configService.get<string>('matrix.storagePath') || './data/bot-storage.json',
|
||||
storagePath:
|
||||
this.configService.get<string>('matrix.storagePath') || './data/bot-storage.json',
|
||||
allowedRooms: this.configService.get<string[]>('matrix.allowedRooms') || [],
|
||||
};
|
||||
}
|
||||
|
|
@ -60,29 +68,20 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
return;
|
||||
}
|
||||
|
||||
const keywordCommand = this.detectKeywordCommand(message);
|
||||
if (keywordCommand) {
|
||||
await this.handleCommand(roomId, event, sender, `!${keywordCommand}`);
|
||||
const detectedCommand = keywordDetector.detect(message);
|
||||
if (detectedCommand) {
|
||||
this.logger.log(`Detected keyword command: ${detectedCommand}`);
|
||||
await this.handleCommand(roomId, event, sender, `!${detectedCommand}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private detectKeywordCommand(message: string): string | null {
|
||||
const lowerMessage = message.toLowerCase().trim();
|
||||
|
||||
if (lowerMessage.length > 30) return null;
|
||||
|
||||
for (const { keywords, command } of KEYWORD_COMMANDS) {
|
||||
for (const keyword of keywords) {
|
||||
if (lowerMessage === keyword || lowerMessage.startsWith(keyword + ' ')) {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private async handleCommand(roomId: string, event: MatrixRoomEvent, sender: string, body: string) {
|
||||
private async handleCommand(
|
||||
roomId: string,
|
||||
event: MatrixRoomEvent,
|
||||
sender: string,
|
||||
body: string
|
||||
) {
|
||||
const [command, ...args] = body.slice(1).split(' ');
|
||||
const argString = args.join(' ');
|
||||
|
||||
|
|
@ -191,12 +190,13 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
}
|
||||
|
||||
// Store for reference
|
||||
this.lastContactsList.set(sender, contacts);
|
||||
this.contactsMapper.setList(sender, contacts);
|
||||
|
||||
let text = `**Deine Kontakte (${result.total}):**\n\n`;
|
||||
for (let i = 0; i < contacts.length; i++) {
|
||||
const c = contacts[i];
|
||||
const name = c.displayName || `${c.firstName || ''} ${c.lastName || ''}`.trim() || 'Unbenannt';
|
||||
const name =
|
||||
c.displayName || `${c.firstName || ''} ${c.lastName || ''}`.trim() || 'Unbenannt';
|
||||
const favIcon = c.isFavorite ? ' ★' : '';
|
||||
const company = c.company ? ` - ${c.company}` : '';
|
||||
text += `**${i + 1}.** ${name}${favIcon}${company}\n`;
|
||||
|
|
@ -215,7 +215,12 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
}
|
||||
}
|
||||
|
||||
private async handleSearch(roomId: string, event: MatrixRoomEvent, sender: string, searchTerm: string) {
|
||||
private async handleSearch(
|
||||
roomId: string,
|
||||
event: MatrixRoomEvent,
|
||||
sender: string,
|
||||
searchTerm: string
|
||||
) {
|
||||
const token = this.sessionService.getToken(sender);
|
||||
if (!token) {
|
||||
await this.sendReply(roomId, event, `Du bist nicht angemeldet. Nutze \`!login\` zuerst.`);
|
||||
|
|
@ -223,12 +228,19 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
}
|
||||
|
||||
if (!searchTerm.trim()) {
|
||||
await this.sendReply(roomId, event, `**Verwendung:** \`!suche [text]\`\n\nBeispiel: \`!suche Max\``);
|
||||
await this.sendReply(
|
||||
roomId,
|
||||
event,
|
||||
`**Verwendung:** \`!suche [text]\`\n\nBeispiel: \`!suche Max\``
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await this.contactsService.getContacts(token, { search: searchTerm, limit: 20 });
|
||||
const result = await this.contactsService.getContacts(token, {
|
||||
search: searchTerm,
|
||||
limit: 20,
|
||||
});
|
||||
const contacts = result.contacts;
|
||||
|
||||
if (contacts.length === 0) {
|
||||
|
|
@ -236,12 +248,13 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
return;
|
||||
}
|
||||
|
||||
this.lastContactsList.set(sender, contacts);
|
||||
this.contactsMapper.setList(sender, contacts);
|
||||
|
||||
let text = `**Suchergebnisse fur "${searchTerm}" (${contacts.length}):**\n\n`;
|
||||
for (let i = 0; i < contacts.length; i++) {
|
||||
const c = contacts[i];
|
||||
const name = c.displayName || `${c.firstName || ''} ${c.lastName || ''}`.trim() || 'Unbenannt';
|
||||
const name =
|
||||
c.displayName || `${c.firstName || ''} ${c.lastName || ''}`.trim() || 'Unbenannt';
|
||||
const favIcon = c.isFavorite ? ' ★' : '';
|
||||
const email = c.email ? ` (${c.email})` : '';
|
||||
text += `**${i + 1}.** ${name}${favIcon}${email}\n`;
|
||||
|
|
@ -274,12 +287,13 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
return;
|
||||
}
|
||||
|
||||
this.lastContactsList.set(sender, contacts);
|
||||
this.contactsMapper.setList(sender, contacts);
|
||||
|
||||
let text = `**Deine Favoriten (${contacts.length}):**\n\n`;
|
||||
for (let i = 0; i < contacts.length; i++) {
|
||||
const c = contacts[i];
|
||||
const name = c.displayName || `${c.firstName || ''} ${c.lastName || ''}`.trim() || 'Unbenannt';
|
||||
const name =
|
||||
c.displayName || `${c.firstName || ''} ${c.lastName || ''}`.trim() || 'Unbenannt';
|
||||
const phone = c.phone || c.mobile || '';
|
||||
text += `**${i + 1}.** ★ ${name}${phone ? ` - ${phone}` : ''}\n`;
|
||||
}
|
||||
|
|
@ -291,7 +305,12 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
}
|
||||
}
|
||||
|
||||
private async handleContactDetails(roomId: string, event: MatrixRoomEvent, sender: string, args: string[]) {
|
||||
private async handleContactDetails(
|
||||
roomId: string,
|
||||
event: MatrixRoomEvent,
|
||||
sender: string,
|
||||
args: string[]
|
||||
) {
|
||||
const token = this.sessionService.getToken(sender);
|
||||
if (!token) {
|
||||
await this.sendReply(roomId, event, `Du bist nicht angemeldet. Nutze \`!login\` zuerst.`);
|
||||
|
|
@ -299,24 +318,26 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
}
|
||||
|
||||
if (args.length < 1) {
|
||||
await this.sendReply(roomId, event, `**Verwendung:** \`!kontakt [nr]\`\n\nNutze \`!kontakte\` um die Liste zu sehen.`);
|
||||
await this.sendReply(
|
||||
roomId,
|
||||
event,
|
||||
`**Verwendung:** \`!kontakt [nr]\`\n\nNutze \`!kontakte\` um die Liste zu sehen.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const index = parseInt(args[0], 10);
|
||||
if (isNaN(index) || index < 1) {
|
||||
await this.sendReply(roomId, event, `Ungultige Nummer.`);
|
||||
const number = parseInt(args[0], 10);
|
||||
const contact = this.contactsMapper.getByNumber(sender, number);
|
||||
|
||||
if (!contact) {
|
||||
await this.sendReply(
|
||||
roomId,
|
||||
event,
|
||||
`Kontakt ${args[0]} nicht gefunden. Nutze \`!kontakte\` zuerst.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const contacts = this.lastContactsList.get(sender);
|
||||
if (!contacts || index > contacts.length) {
|
||||
await this.sendReply(roomId, event, `Kontakt ${index} nicht gefunden. Nutze \`!kontakte\` zuerst.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const contact = contacts[index - 1];
|
||||
|
||||
try {
|
||||
const details = await this.contactsService.getContact(token, contact.id);
|
||||
|
||||
|
|
@ -334,14 +355,19 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
if (details.mobile) text += `**Mobil:** ${details.mobile}\n`;
|
||||
|
||||
if (details.street || details.city) {
|
||||
const address = [details.street, `${details.postalCode || ''} ${details.city || ''}`.trim(), details.country]
|
||||
const address = [
|
||||
details.street,
|
||||
`${details.postalCode || ''} ${details.city || ''}`.trim(),
|
||||
details.country,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(', ');
|
||||
if (address) text += `**Adresse:** ${address}\n`;
|
||||
}
|
||||
|
||||
if (details.website) text += `**Website:** ${details.website}\n`;
|
||||
if (details.birthday) text += `**Geburtstag:** ${new Date(details.birthday).toLocaleDateString('de-DE')}\n`;
|
||||
if (details.birthday)
|
||||
text += `**Geburtstag:** ${new Date(details.birthday).toLocaleDateString('de-DE')}\n`;
|
||||
if (details.notes) text += `\n**Notizen:** ${details.notes}\n`;
|
||||
|
||||
await this.sendReply(roomId, event, text);
|
||||
|
|
@ -351,7 +377,12 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
}
|
||||
}
|
||||
|
||||
private async handleCreateContact(roomId: string, event: MatrixRoomEvent, sender: string, args: string[]) {
|
||||
private async handleCreateContact(
|
||||
roomId: string,
|
||||
event: MatrixRoomEvent,
|
||||
sender: string,
|
||||
args: string[]
|
||||
) {
|
||||
const token = this.sessionService.getToken(sender);
|
||||
if (!token) {
|
||||
await this.sendReply(roomId, event, `Du bist nicht angemeldet. Nutze \`!login\` zuerst.`);
|
||||
|
|
@ -388,7 +419,12 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
}
|
||||
}
|
||||
|
||||
private async handleEditContact(roomId: string, event: MatrixRoomEvent, sender: string, args: string[]) {
|
||||
private async handleEditContact(
|
||||
roomId: string,
|
||||
event: MatrixRoomEvent,
|
||||
sender: string,
|
||||
args: string[]
|
||||
) {
|
||||
const token = this.sessionService.getToken(sender);
|
||||
if (!token) {
|
||||
await this.sendReply(roomId, event, `Du bist nicht angemeldet. Nutze \`!login\` zuerst.`);
|
||||
|
|
@ -404,23 +440,20 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
return;
|
||||
}
|
||||
|
||||
const index = parseInt(args[0], 10);
|
||||
const number = parseInt(args[0], 10);
|
||||
const field = args[1].toLowerCase();
|
||||
const value = args.slice(2).join(' ');
|
||||
|
||||
if (isNaN(index) || index < 1) {
|
||||
await this.sendReply(roomId, event, `Ungultige Nummer.`);
|
||||
const contact = this.contactsMapper.getByNumber(sender, number);
|
||||
if (!contact) {
|
||||
await this.sendReply(
|
||||
roomId,
|
||||
event,
|
||||
`Kontakt ${args[0]} nicht gefunden. Nutze \`!kontakte\` zuerst.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const contacts = this.lastContactsList.get(sender);
|
||||
if (!contacts || index > contacts.length) {
|
||||
await this.sendReply(roomId, event, `Kontakt ${index} nicht gefunden. Nutze \`!kontakte\` zuerst.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const contact = contacts[index - 1];
|
||||
|
||||
const fieldMap: Record<string, string> = {
|
||||
email: 'email',
|
||||
phone: 'phone',
|
||||
|
|
@ -455,7 +488,11 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
|
||||
const mappedField = fieldMap[field];
|
||||
if (!mappedField) {
|
||||
await this.sendReply(roomId, event, `Unbekanntes Feld: ${field}\n\n**Gultige Felder:** email, phone, mobile, company, job, website, street, city, zip, country, notes, birthday`);
|
||||
await this.sendReply(
|
||||
roomId,
|
||||
event,
|
||||
`Unbekanntes Feld: ${field}\n\n**Gultige Felder:** email, phone, mobile, company, job, website, street, city, zip, country, notes, birthday`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -464,15 +501,25 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
[mappedField]: value,
|
||||
});
|
||||
|
||||
const name = updated.displayName || `${updated.firstName || ''} ${updated.lastName || ''}`.trim();
|
||||
await this.sendReply(roomId, event, `Kontakt **${name}** aktualisiert!\n\n**${field}:** ${value}`);
|
||||
const name =
|
||||
updated.displayName || `${updated.firstName || ''} ${updated.lastName || ''}`.trim();
|
||||
await this.sendReply(
|
||||
roomId,
|
||||
event,
|
||||
`Kontakt **${name}** aktualisiert!\n\n**${field}:** ${value}`
|
||||
);
|
||||
} catch (error) {
|
||||
const errorMsg = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
||||
await this.sendReply(roomId, event, `Fehler: ${errorMsg}`);
|
||||
}
|
||||
}
|
||||
|
||||
private async handleDeleteContact(roomId: string, event: MatrixRoomEvent, sender: string, args: string[]) {
|
||||
private async handleDeleteContact(
|
||||
roomId: string,
|
||||
event: MatrixRoomEvent,
|
||||
sender: string,
|
||||
args: string[]
|
||||
) {
|
||||
const token = this.sessionService.getToken(sender);
|
||||
if (!token) {
|
||||
await this.sendReply(roomId, event, `Du bist nicht angemeldet. Nutze \`!login\` zuerst.`);
|
||||
|
|
@ -480,24 +527,27 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
}
|
||||
|
||||
if (args.length < 1) {
|
||||
await this.sendReply(roomId, event, `**Verwendung:** \`!loeschen [nr]\`\n\nNutze \`!kontakte\` um die Liste zu sehen.`);
|
||||
await this.sendReply(
|
||||
roomId,
|
||||
event,
|
||||
`**Verwendung:** \`!loeschen [nr]\`\n\nNutze \`!kontakte\` um die Liste zu sehen.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const index = parseInt(args[0], 10);
|
||||
if (isNaN(index) || index < 1) {
|
||||
await this.sendReply(roomId, event, `Ungultige Nummer.`);
|
||||
const number = parseInt(args[0], 10);
|
||||
const contact = this.contactsMapper.getByNumber(sender, number);
|
||||
if (!contact) {
|
||||
await this.sendReply(
|
||||
roomId,
|
||||
event,
|
||||
`Kontakt ${args[0]} nicht gefunden. Nutze \`!kontakte\` zuerst.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const contacts = this.lastContactsList.get(sender);
|
||||
if (!contacts || index > contacts.length) {
|
||||
await this.sendReply(roomId, event, `Kontakt ${index} nicht gefunden. Nutze \`!kontakte\` zuerst.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const contact = contacts[index - 1];
|
||||
const name = contact.displayName || `${contact.firstName || ''} ${contact.lastName || ''}`.trim();
|
||||
const name =
|
||||
contact.displayName || `${contact.firstName || ''} ${contact.lastName || ''}`.trim();
|
||||
|
||||
try {
|
||||
await this.contactsService.deleteContact(token, contact.id);
|
||||
|
|
@ -508,7 +558,12 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
}
|
||||
}
|
||||
|
||||
private async handleToggleFavorite(roomId: string, event: MatrixRoomEvent, sender: string, args: string[]) {
|
||||
private async handleToggleFavorite(
|
||||
roomId: string,
|
||||
event: MatrixRoomEvent,
|
||||
sender: string,
|
||||
args: string[]
|
||||
) {
|
||||
const token = this.sessionService.getToken(sender);
|
||||
if (!token) {
|
||||
await this.sendReply(roomId, event, `Du bist nicht angemeldet. Nutze \`!login\` zuerst.`);
|
||||
|
|
@ -516,27 +571,29 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
}
|
||||
|
||||
if (args.length < 1) {
|
||||
await this.sendReply(roomId, event, `**Verwendung:** \`!fav [nr]\`\n\nNutze \`!kontakte\` um die Liste zu sehen.`);
|
||||
await this.sendReply(
|
||||
roomId,
|
||||
event,
|
||||
`**Verwendung:** \`!fav [nr]\`\n\nNutze \`!kontakte\` um die Liste zu sehen.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const index = parseInt(args[0], 10);
|
||||
if (isNaN(index) || index < 1) {
|
||||
await this.sendReply(roomId, event, `Ungultige Nummer.`);
|
||||
const number = parseInt(args[0], 10);
|
||||
const contact = this.contactsMapper.getByNumber(sender, number);
|
||||
if (!contact) {
|
||||
await this.sendReply(
|
||||
roomId,
|
||||
event,
|
||||
`Kontakt ${args[0]} nicht gefunden. Nutze \`!kontakte\` zuerst.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const contacts = this.lastContactsList.get(sender);
|
||||
if (!contacts || index > contacts.length) {
|
||||
await this.sendReply(roomId, event, `Kontakt ${index} nicht gefunden. Nutze \`!kontakte\` zuerst.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const contact = contacts[index - 1];
|
||||
|
||||
try {
|
||||
const updated = await this.contactsService.toggleFavorite(token, contact.id);
|
||||
const name = updated.displayName || `${updated.firstName || ''} ${updated.lastName || ''}`.trim();
|
||||
const name =
|
||||
updated.displayName || `${updated.firstName || ''} ${updated.lastName || ''}`.trim();
|
||||
const status = updated.isFavorite ? 'als Favorit markiert ★' : 'aus Favoriten entfernt';
|
||||
await this.sendReply(roomId, event, `**${name}** ${status}`);
|
||||
} catch (error) {
|
||||
|
|
@ -545,7 +602,12 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
}
|
||||
}
|
||||
|
||||
private async handleToggleArchive(roomId: string, event: MatrixRoomEvent, sender: string, args: string[]) {
|
||||
private async handleToggleArchive(
|
||||
roomId: string,
|
||||
event: MatrixRoomEvent,
|
||||
sender: string,
|
||||
args: string[]
|
||||
) {
|
||||
const token = this.sessionService.getToken(sender);
|
||||
if (!token) {
|
||||
await this.sendReply(roomId, event, `Du bist nicht angemeldet. Nutze \`!login\` zuerst.`);
|
||||
|
|
@ -553,27 +615,29 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
}
|
||||
|
||||
if (args.length < 1) {
|
||||
await this.sendReply(roomId, event, `**Verwendung:** \`!archiv [nr]\`\n\nNutze \`!kontakte\` um die Liste zu sehen.`);
|
||||
await this.sendReply(
|
||||
roomId,
|
||||
event,
|
||||
`**Verwendung:** \`!archiv [nr]\`\n\nNutze \`!kontakte\` um die Liste zu sehen.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const index = parseInt(args[0], 10);
|
||||
if (isNaN(index) || index < 1) {
|
||||
await this.sendReply(roomId, event, `Ungultige Nummer.`);
|
||||
const number = parseInt(args[0], 10);
|
||||
const contact = this.contactsMapper.getByNumber(sender, number);
|
||||
if (!contact) {
|
||||
await this.sendReply(
|
||||
roomId,
|
||||
event,
|
||||
`Kontakt ${args[0]} nicht gefunden. Nutze \`!kontakte\` zuerst.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const contacts = this.lastContactsList.get(sender);
|
||||
if (!contacts || index > contacts.length) {
|
||||
await this.sendReply(roomId, event, `Kontakt ${index} nicht gefunden. Nutze \`!kontakte\` zuerst.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const contact = contacts[index - 1];
|
||||
|
||||
try {
|
||||
const updated = await this.contactsService.toggleArchive(token, contact.id);
|
||||
const name = updated.displayName || `${updated.firstName || ''} ${updated.lastName || ''}`.trim();
|
||||
const name =
|
||||
updated.displayName || `${updated.firstName || ''} ${updated.lastName || ''}`.trim();
|
||||
const status = updated.isArchived ? 'archiviert' : 'aus dem Archiv geholt';
|
||||
await this.sendReply(roomId, event, `**${name}** ${status}`);
|
||||
} catch (error) {
|
||||
|
|
@ -582,7 +646,12 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
}
|
||||
}
|
||||
|
||||
private async handleLogin(roomId: string, event: MatrixRoomEvent, sender: string, args: string[]) {
|
||||
private async handleLogin(
|
||||
roomId: string,
|
||||
event: MatrixRoomEvent,
|
||||
sender: string,
|
||||
args: string[]
|
||||
) {
|
||||
if (args.length < 2) {
|
||||
await this.sendReply(
|
||||
roomId,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import {
|
|||
BaseMatrixService,
|
||||
MatrixBotConfig,
|
||||
MatrixRoomEvent,
|
||||
KeywordCommandDetector,
|
||||
COMMON_KEYWORDS,
|
||||
} from '@manacore/matrix-bot-common';
|
||||
import {
|
||||
NutriPhiService,
|
||||
|
|
@ -14,16 +16,16 @@ import {
|
|||
import { SessionService, TranscriptionService } from '@manacore/bot-services';
|
||||
import { HELP_MESSAGE, MEAL_TYPE_LABELS } from '../config/configuration';
|
||||
|
||||
// Natural language keywords that trigger commands (German + English)
|
||||
const KEYWORD_COMMANDS: { keywords: string[]; command: string }[] = [
|
||||
{ keywords: ['hilfe', 'help', 'was kannst du', 'befehle', 'commands'], command: 'help' },
|
||||
// Natural language keyword detector
|
||||
const keywordDetector = new KeywordCommandDetector([
|
||||
...COMMON_KEYWORDS,
|
||||
{ keywords: ['heute', 'today', 'tages', 'tagesübersicht'], command: 'today' },
|
||||
{ keywords: ['woche', 'week', 'wochen', 'wochenübersicht'], command: 'week' },
|
||||
{ keywords: ['ziele', 'goals', 'meine ziele'], command: 'goals' },
|
||||
{ keywords: ['favoriten', 'favorites', 'lieblings'], command: 'favorites' },
|
||||
{ keywords: ['tipps', 'tips', 'empfehlungen', 'ratschläge'], command: 'tips' },
|
||||
{ keywords: ['status', 'verbindung'], command: 'status' },
|
||||
];
|
||||
{ keywords: ['verbindung'], command: 'status' },
|
||||
]);
|
||||
|
||||
@Injectable()
|
||||
export class MatrixService extends BaseMatrixService {
|
||||
|
|
@ -38,9 +40,11 @@ export class MatrixService extends BaseMatrixService {
|
|||
|
||||
protected getConfig(): MatrixBotConfig {
|
||||
return {
|
||||
homeserverUrl: this.configService.get<string>('matrix.homeserverUrl') || 'http://localhost:8008',
|
||||
homeserverUrl:
|
||||
this.configService.get<string>('matrix.homeserverUrl') || 'http://localhost:8008',
|
||||
accessToken: this.configService.get<string>('matrix.accessToken') || '',
|
||||
storagePath: this.configService.get<string>('matrix.storagePath') || './data/bot-storage.json',
|
||||
storagePath:
|
||||
this.configService.get<string>('matrix.storagePath') || './data/bot-storage.json',
|
||||
allowedRooms: this.configService.get<string[]>('matrix.allowedRooms') || [],
|
||||
};
|
||||
}
|
||||
|
|
@ -65,7 +69,7 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
|
||||
// Handle image messages
|
||||
this.client.on('room.message', async (roomId: string, event: any) => {
|
||||
if (event.sender === await this.client.getUserId()) return;
|
||||
if (event.sender === (await this.client.getUserId())) return;
|
||||
|
||||
const content = event.content as {
|
||||
msgtype?: string;
|
||||
|
|
@ -159,32 +163,16 @@ Sag "hilfe" fur alle Befehle!`;
|
|||
}
|
||||
|
||||
// Check for natural language keywords
|
||||
const keywordCommand = this.detectKeywordCommand(message);
|
||||
if (keywordCommand) {
|
||||
await this.handleCommand(roomId, sender, `!${keywordCommand}`);
|
||||
const detectedCommand = keywordDetector.detect(message);
|
||||
if (detectedCommand) {
|
||||
this.logger.log(`Detected keyword command: ${detectedCommand}`);
|
||||
await this.handleCommand(roomId, sender, `!${detectedCommand}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't respond to random messages - only commands
|
||||
}
|
||||
|
||||
private detectKeywordCommand(message: string): string | null {
|
||||
const lowerMessage = message.toLowerCase().trim();
|
||||
|
||||
// Only match if the message is short
|
||||
if (lowerMessage.length > 50) return null;
|
||||
|
||||
for (const { keywords, command } of KEYWORD_COMMANDS) {
|
||||
for (const keyword of keywords) {
|
||||
if (lowerMessage === keyword || lowerMessage.startsWith(keyword + ' ')) {
|
||||
this.logger.log(`Detected keyword "${keyword}" -> command "${command}"`);
|
||||
return command;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private async handleCommand(roomId: string, sender: string, body: string) {
|
||||
const [command, ...args] = body.slice(1).split(' ');
|
||||
const argString = args.join(' ');
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import {
|
|||
BaseMatrixService,
|
||||
MatrixBotConfig,
|
||||
MatrixRoomEvent,
|
||||
KeywordCommandDetector,
|
||||
COMMON_KEYWORDS,
|
||||
} from '@manacore/matrix-bot-common';
|
||||
import { OllamaService } from '../ollama/ollama.service';
|
||||
import { SYSTEM_PROMPTS } from '../config/configuration';
|
||||
|
|
@ -21,13 +23,13 @@ const NON_CHAT_MODELS = ['deepseek-r1:1.5b'];
|
|||
// Models that support vision/image input
|
||||
const VISION_MODELS = ['llava', 'llava:7b', 'llava:13b', 'bakllava', 'moondream'];
|
||||
|
||||
// Natural language keywords that trigger commands (German + English)
|
||||
const KEYWORD_COMMANDS: { keywords: string[]; command: string }[] = [
|
||||
{ keywords: ['hilfe', 'help', 'was kannst du', 'befehle', 'commands'], command: 'help' },
|
||||
// Natural language keyword detector
|
||||
const keywordDetector = new KeywordCommandDetector([
|
||||
...COMMON_KEYWORDS,
|
||||
{ keywords: ['modelle', 'models', 'welche modelle', 'liste modelle'], command: 'models' },
|
||||
{ keywords: ['status', 'verbindung', 'connection', 'online'], command: 'status' },
|
||||
{ keywords: ['verbindung', 'connection', 'online'], command: 'status' },
|
||||
{ keywords: ['lösche verlauf', 'clear', 'neustart', 'reset', 'vergiss alles'], command: 'clear' },
|
||||
];
|
||||
]);
|
||||
|
||||
@Injectable()
|
||||
export class MatrixService extends BaseMatrixService {
|
||||
|
|
@ -42,9 +44,11 @@ export class MatrixService extends BaseMatrixService {
|
|||
|
||||
protected getConfig(): MatrixBotConfig {
|
||||
return {
|
||||
homeserverUrl: this.configService.get<string>('matrix.homeserverUrl') || 'http://localhost:8008',
|
||||
homeserverUrl:
|
||||
this.configService.get<string>('matrix.homeserverUrl') || 'http://localhost:8008',
|
||||
accessToken: this.configService.get<string>('matrix.accessToken') || '',
|
||||
storagePath: this.configService.get<string>('matrix.storagePath') || './data/bot-storage.json',
|
||||
storagePath:
|
||||
this.configService.get<string>('matrix.storagePath') || './data/bot-storage.json',
|
||||
allowedRooms: this.configService.get<string[]>('matrix.allowedRooms') || [],
|
||||
};
|
||||
}
|
||||
|
|
@ -159,9 +163,10 @@ Viel Spass!`;
|
|||
}
|
||||
|
||||
// Check for natural language keywords
|
||||
const keywordCommand = this.detectKeywordCommand(message);
|
||||
if (keywordCommand) {
|
||||
await this.handleCommand(roomId, sender, `!${keywordCommand}`);
|
||||
const detectedCommand = keywordDetector.detect(message);
|
||||
if (detectedCommand) {
|
||||
this.logger.log(`Detected keyword command: ${detectedCommand}`);
|
||||
await this.handleCommand(roomId, sender, `!${detectedCommand}`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -169,23 +174,6 @@ Viel Spass!`;
|
|||
await this.handleChat(roomId, sender, message);
|
||||
}
|
||||
|
||||
private detectKeywordCommand(message: string): string | null {
|
||||
const lowerMessage = message.toLowerCase().trim();
|
||||
|
||||
// Only match if the message is short (likely a command, not a question containing a keyword)
|
||||
if (lowerMessage.length > 50) return null;
|
||||
|
||||
for (const { keywords, command } of KEYWORD_COMMANDS) {
|
||||
for (const keyword of keywords) {
|
||||
if (lowerMessage === keyword || lowerMessage.startsWith(keyword + ' ')) {
|
||||
this.logger.log(`Detected keyword "${keyword}" -> command "${command}"`);
|
||||
return command;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private async handleCommand(roomId: string, sender: string, body: string) {
|
||||
const [command, ...args] = body.slice(1).split(' ');
|
||||
const argString = args.join(' ');
|
||||
|
|
|
|||
|
|
@ -1,15 +1,20 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { BaseMatrixService, MatrixBotConfig, MatrixRoomEvent } from '@manacore/matrix-bot-common';
|
||||
import {
|
||||
BaseMatrixService,
|
||||
MatrixBotConfig,
|
||||
MatrixRoomEvent,
|
||||
UserListMapper,
|
||||
} from '@manacore/matrix-bot-common';
|
||||
import { PresiService, Deck, Theme, SlideContent } from '../presi/presi.service';
|
||||
import { SessionService } from '@manacore/bot-services';
|
||||
import { HELP_MESSAGE } from '../config/configuration';
|
||||
|
||||
@Injectable()
|
||||
export class MatrixService extends BaseMatrixService {
|
||||
// Store last shown items per user for reference by number
|
||||
private lastDecksList: Map<string, Deck[]> = new Map();
|
||||
private lastThemesList: Map<string, Theme[]> = new Map();
|
||||
// User list mappers for number-based reference
|
||||
private decksMapper = new UserListMapper<Deck>();
|
||||
private themesMapper = new UserListMapper<Theme>();
|
||||
|
||||
constructor(
|
||||
configService: ConfigService,
|
||||
|
|
@ -21,9 +26,11 @@ export class MatrixService extends BaseMatrixService {
|
|||
|
||||
protected getConfig(): MatrixBotConfig {
|
||||
return {
|
||||
homeserverUrl: this.configService.get<string>('matrix.homeserverUrl') || 'http://localhost:8008',
|
||||
homeserverUrl:
|
||||
this.configService.get<string>('matrix.homeserverUrl') || 'http://localhost:8008',
|
||||
accessToken: this.configService.get<string>('matrix.accessToken') || '',
|
||||
storagePath: this.configService.get<string>('matrix.storagePath') || './data/bot-storage.json',
|
||||
storagePath:
|
||||
this.configService.get<string>('matrix.storagePath') || './data/bot-storage.json',
|
||||
allowedRooms: this.configService.get<string[]>('matrix.allowedRooms') || [],
|
||||
};
|
||||
}
|
||||
|
|
@ -187,7 +194,7 @@ export class MatrixService extends BaseMatrixService {
|
|||
}
|
||||
|
||||
const decks = result.data || [];
|
||||
this.lastDecksList.set(sender, decks);
|
||||
this.decksMapper.setList(sender, decks);
|
||||
|
||||
if (decks.length === 0) {
|
||||
await this.sendMessage(
|
||||
|
|
@ -211,7 +218,8 @@ export class MatrixService extends BaseMatrixService {
|
|||
|
||||
private async handleDeckDetails(roomId: string, sender: string, numberStr: string) {
|
||||
const token = this.requireAuth(sender);
|
||||
const deck = this.getDeckByNumber(sender, numberStr);
|
||||
const number = parseInt(numberStr, 10);
|
||||
const deck = this.decksMapper.getByNumber(sender, number);
|
||||
|
||||
if (!deck) {
|
||||
await this.sendMessage(roomId, '<p>Ungueltige Nummer. Nutze zuerst <code>!presis</code></p>');
|
||||
|
|
@ -238,7 +246,8 @@ export class MatrixService extends BaseMatrixService {
|
|||
if (d.slides && d.slides.length > 0) {
|
||||
html += '<p><strong>Folien:</strong></p><ol>';
|
||||
for (const slide of d.slides) {
|
||||
const title = slide.content.title || slide.content.body?.substring(0, 30) || `(${slide.content.type})`;
|
||||
const title =
|
||||
slide.content.title || slide.content.body?.substring(0, 30) || `(${slide.content.type})`;
|
||||
html += `<li>${title}</li>`;
|
||||
}
|
||||
html += '</ol>';
|
||||
|
|
@ -267,7 +276,7 @@ export class MatrixService extends BaseMatrixService {
|
|||
return;
|
||||
}
|
||||
|
||||
this.lastDecksList.delete(sender);
|
||||
this.decksMapper.clearList(sender);
|
||||
await this.sendMessage(
|
||||
roomId,
|
||||
`<p>Praesentation <strong>${result.data!.title}</strong> erstellt!</p>
|
||||
|
|
@ -277,7 +286,8 @@ export class MatrixService extends BaseMatrixService {
|
|||
|
||||
private async handleDeleteDeck(roomId: string, sender: string, numberStr: string) {
|
||||
const token = this.requireAuth(sender);
|
||||
const deck = this.getDeckByNumber(sender, numberStr);
|
||||
const number = parseInt(numberStr, 10);
|
||||
const deck = this.decksMapper.getByNumber(sender, number);
|
||||
|
||||
if (!deck) {
|
||||
await this.sendMessage(roomId, '<p>Ungueltige Nummer. Nutze zuerst <code>!presis</code></p>');
|
||||
|
|
@ -291,18 +301,30 @@ export class MatrixService extends BaseMatrixService {
|
|||
return;
|
||||
}
|
||||
|
||||
this.lastDecksList.delete(sender);
|
||||
await this.sendMessage(roomId, `<p>Praesentation <strong>${deck.title}</strong> geloescht.</p>`);
|
||||
this.decksMapper.clearList(sender);
|
||||
await this.sendMessage(
|
||||
roomId,
|
||||
`<p>Praesentation <strong>${deck.title}</strong> geloescht.</p>`
|
||||
);
|
||||
}
|
||||
|
||||
private async handleRenameDeck(roomId: string, sender: string, numberStr: string, newTitle: string) {
|
||||
private async handleRenameDeck(
|
||||
roomId: string,
|
||||
sender: string,
|
||||
numberStr: string,
|
||||
newTitle: string
|
||||
) {
|
||||
if (!newTitle) {
|
||||
await this.sendMessage(roomId, '<p>Verwendung: <code>!umbenennen [nr] Neuer Titel</code></p>');
|
||||
await this.sendMessage(
|
||||
roomId,
|
||||
'<p>Verwendung: <code>!umbenennen [nr] Neuer Titel</code></p>'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const token = this.requireAuth(sender);
|
||||
const deck = this.getDeckByNumber(sender, numberStr);
|
||||
const number = parseInt(numberStr, 10);
|
||||
const deck = this.decksMapper.getByNumber(sender, number);
|
||||
|
||||
if (!deck) {
|
||||
await this.sendMessage(roomId, '<p>Ungueltige Nummer. Nutze zuerst <code>!presis</code></p>');
|
||||
|
|
@ -338,7 +360,8 @@ export class MatrixService extends BaseMatrixService {
|
|||
}
|
||||
|
||||
const token = this.requireAuth(sender);
|
||||
const deck = this.getDeckByNumber(sender, args[0]);
|
||||
const number = parseInt(args[0], 10);
|
||||
const deck = this.decksMapper.getByNumber(sender, number);
|
||||
|
||||
if (!deck) {
|
||||
await this.sendMessage(roomId, '<p>Ungueltige Nummer. Nutze zuerst <code>!presis</code></p>');
|
||||
|
|
@ -412,14 +435,23 @@ export class MatrixService extends BaseMatrixService {
|
|||
);
|
||||
}
|
||||
|
||||
private async handleDeleteSlide(roomId: string, sender: string, deckNumStr: string, slideNumStr: string) {
|
||||
private async handleDeleteSlide(
|
||||
roomId: string,
|
||||
sender: string,
|
||||
deckNumStr: string,
|
||||
slideNumStr: string
|
||||
) {
|
||||
if (!deckNumStr || !slideNumStr) {
|
||||
await this.sendMessage(roomId, '<p>Verwendung: <code>!folieloeschen [presi-nr] [folien-nr]</code></p>');
|
||||
await this.sendMessage(
|
||||
roomId,
|
||||
'<p>Verwendung: <code>!folieloeschen [presi-nr] [folien-nr]</code></p>'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const token = this.requireAuth(sender);
|
||||
const deck = this.getDeckByNumber(sender, deckNumStr);
|
||||
const deckNumber = parseInt(deckNumStr, 10);
|
||||
const deck = this.decksMapper.getByNumber(sender, deckNumber);
|
||||
|
||||
if (!deck) {
|
||||
await this.sendMessage(roomId, '<p>Ungueltige Praesentation-Nummer.</p>');
|
||||
|
|
@ -447,7 +479,10 @@ export class MatrixService extends BaseMatrixService {
|
|||
return;
|
||||
}
|
||||
|
||||
await this.sendMessage(roomId, `<p>Folie ${slideNumStr} aus <strong>${deck.title}</strong> geloescht.</p>`);
|
||||
await this.sendMessage(
|
||||
roomId,
|
||||
`<p>Folie ${slideNumStr} aus <strong>${deck.title}</strong> geloescht.</p>`
|
||||
);
|
||||
}
|
||||
|
||||
// Theme handlers
|
||||
|
|
@ -460,7 +495,7 @@ export class MatrixService extends BaseMatrixService {
|
|||
}
|
||||
|
||||
const themes = result.data || [];
|
||||
this.lastThemesList.set(sender, themes);
|
||||
this.themesMapper.setList(sender, themes);
|
||||
|
||||
if (themes.length === 0) {
|
||||
await this.sendMessage(roomId, '<p>Keine Themes verfuegbar.</p>');
|
||||
|
|
@ -478,15 +513,25 @@ export class MatrixService extends BaseMatrixService {
|
|||
await this.sendMessage(roomId, html);
|
||||
}
|
||||
|
||||
private async handleApplyTheme(roomId: string, sender: string, deckNumStr: string, themeNumStr: string) {
|
||||
private async handleApplyTheme(
|
||||
roomId: string,
|
||||
sender: string,
|
||||
deckNumStr: string,
|
||||
themeNumStr: string
|
||||
) {
|
||||
if (!deckNumStr || !themeNumStr) {
|
||||
await this.sendMessage(roomId, '<p>Verwendung: <code>!theme [presi-nr] [theme-nr]</code></p>');
|
||||
await this.sendMessage(
|
||||
roomId,
|
||||
'<p>Verwendung: <code>!theme [presi-nr] [theme-nr]</code></p>'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const token = this.requireAuth(sender);
|
||||
const deck = this.getDeckByNumber(sender, deckNumStr);
|
||||
const theme = this.getThemeByNumber(sender, themeNumStr);
|
||||
const deckNumber = parseInt(deckNumStr, 10);
|
||||
const themeNumber = parseInt(themeNumStr, 10);
|
||||
const deck = this.decksMapper.getByNumber(sender, deckNumber);
|
||||
const theme = this.themesMapper.getByNumber(sender, themeNumber);
|
||||
|
||||
if (!deck) {
|
||||
await this.sendMessage(roomId, '<p>Ungueltige Praesentation-Nummer.</p>');
|
||||
|
|
@ -494,7 +539,10 @@ export class MatrixService extends BaseMatrixService {
|
|||
}
|
||||
|
||||
if (!theme) {
|
||||
await this.sendMessage(roomId, '<p>Ungueltige Theme-Nummer. Nutze zuerst <code>!themes</code></p>');
|
||||
await this.sendMessage(
|
||||
roomId,
|
||||
'<p>Ungueltige Theme-Nummer. Nutze zuerst <code>!themes</code></p>'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -517,7 +565,8 @@ export class MatrixService extends BaseMatrixService {
|
|||
const numberStr = args[0];
|
||||
|
||||
const token = this.requireAuth(sender);
|
||||
const deck = this.getDeckByNumber(sender, numberStr);
|
||||
const number = parseInt(numberStr, 10);
|
||||
const deck = this.decksMapper.getByNumber(sender, number);
|
||||
|
||||
if (!deck) {
|
||||
await this.sendMessage(roomId, '<p>Ungueltige Nummer. Nutze zuerst <code>!presis</code></p>');
|
||||
|
|
@ -559,7 +608,8 @@ export class MatrixService extends BaseMatrixService {
|
|||
}
|
||||
|
||||
const token = this.requireAuth(sender);
|
||||
const deck = this.getDeckByNumber(sender, numberStr);
|
||||
const number = parseInt(numberStr, 10);
|
||||
const deck = this.decksMapper.getByNumber(sender, number);
|
||||
|
||||
if (!deck) {
|
||||
await this.sendMessage(roomId, '<p>Ungueltige Nummer. Nutze zuerst <code>!presis</code></p>');
|
||||
|
|
@ -595,25 +645,4 @@ export class MatrixService extends BaseMatrixService {
|
|||
|
||||
await this.sendMessage(roomId, html);
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
private getDeckByNumber(sender: string, numberStr: string): Deck | null {
|
||||
const decks = this.lastDecksList.get(sender);
|
||||
if (!decks) return null;
|
||||
|
||||
const index = parseInt(numberStr, 10) - 1;
|
||||
if (isNaN(index) || index < 0 || index >= decks.length) return null;
|
||||
|
||||
return decks[index];
|
||||
}
|
||||
|
||||
private getThemeByNumber(sender: string, numberStr: string): Theme | null {
|
||||
const themes = this.lastThemesList.get(sender);
|
||||
if (!themes) return null;
|
||||
|
||||
const index = parseInt(numberStr, 10) - 1;
|
||||
if (isNaN(index) || index < 0 || index >= themes.length) return null;
|
||||
|
||||
return themes[index];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,19 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { BaseMatrixService, MatrixBotConfig, MatrixRoomEvent } from '@manacore/matrix-bot-common';
|
||||
import {
|
||||
BaseMatrixService,
|
||||
MatrixBotConfig,
|
||||
MatrixRoomEvent,
|
||||
UserListMapper,
|
||||
} from '@manacore/matrix-bot-common';
|
||||
import { SkilltreeService, Skill, SkillBranch } from '../skilltree/skilltree.service';
|
||||
import { SessionService } from '@manacore/bot-services';
|
||||
import { HELP_MESSAGE } from '../config/configuration';
|
||||
|
||||
@Injectable()
|
||||
export class MatrixService extends BaseMatrixService {
|
||||
// Store last shown skills per user for reference by number
|
||||
private lastSkillsList: Map<string, Skill[]> = new Map();
|
||||
// User list mapper for number-based reference
|
||||
private skillsMapper = new UserListMapper<Skill>();
|
||||
|
||||
// Branch name mappings (German/English)
|
||||
private readonly branchMappings: Record<string, SkillBranch> = {
|
||||
|
|
@ -45,9 +50,11 @@ export class MatrixService extends BaseMatrixService {
|
|||
|
||||
protected getConfig(): MatrixBotConfig {
|
||||
return {
|
||||
homeserverUrl: this.configService.get<string>('matrix.homeserverUrl') || 'http://localhost:8008',
|
||||
homeserverUrl:
|
||||
this.configService.get<string>('matrix.homeserverUrl') || 'http://localhost:8008',
|
||||
accessToken: this.configService.get<string>('matrix.accessToken') || '',
|
||||
storagePath: this.configService.get<string>('matrix.storagePath') || './data/bot-storage.json',
|
||||
storagePath:
|
||||
this.configService.get<string>('matrix.storagePath') || './data/bot-storage.json',
|
||||
allowedRooms: this.configService.get<string[]>('matrix.allowedRooms') || [],
|
||||
};
|
||||
}
|
||||
|
|
@ -204,7 +211,7 @@ export class MatrixService extends BaseMatrixService {
|
|||
}
|
||||
|
||||
const skills = result.data?.skills || [];
|
||||
this.lastSkillsList.set(sender, skills);
|
||||
this.skillsMapper.setList(sender, skills);
|
||||
|
||||
if (skills.length === 0) {
|
||||
await this.sendMessage(
|
||||
|
|
@ -222,14 +229,16 @@ export class MatrixService extends BaseMatrixService {
|
|||
html += `<li>${branchIcon} <strong>${skill.name}</strong> - Lvl ${skill.level} (${levelName}) ${progress}</li>`;
|
||||
}
|
||||
html += '</ol>';
|
||||
html += '<p><em>Nutze <code>!skill [nr]</code> fuer Details oder <code>!xp [nr] 50 Aktivitaet</code></em></p>';
|
||||
html +=
|
||||
'<p><em>Nutze <code>!skill [nr]</code> fuer Details oder <code>!xp [nr] 50 Aktivitaet</code></em></p>';
|
||||
|
||||
await this.sendMessage(roomId, html);
|
||||
}
|
||||
|
||||
private async handleSkillDetails(roomId: string, sender: string, numberStr: string) {
|
||||
const token = this.requireAuth(sender);
|
||||
const skill = this.getSkillByNumber(sender, numberStr);
|
||||
const number = parseInt(numberStr, 10);
|
||||
const skill = this.skillsMapper.getByNumber(sender, number);
|
||||
|
||||
if (!skill) {
|
||||
await this.sendMessage(roomId, '<p>Ungueltige Nummer. Nutze zuerst <code>!skills</code></p>');
|
||||
|
|
@ -296,7 +305,7 @@ export class MatrixService extends BaseMatrixService {
|
|||
return;
|
||||
}
|
||||
|
||||
this.lastSkillsList.delete(sender);
|
||||
this.skillsMapper.clearList(sender);
|
||||
const branchIcon = this.getBranchIcon(branch);
|
||||
await this.sendMessage(
|
||||
roomId,
|
||||
|
|
@ -307,7 +316,8 @@ export class MatrixService extends BaseMatrixService {
|
|||
|
||||
private async handleDeleteSkill(roomId: string, sender: string, numberStr: string) {
|
||||
const token = this.requireAuth(sender);
|
||||
const skill = this.getSkillByNumber(sender, numberStr);
|
||||
const number = parseInt(numberStr, 10);
|
||||
const skill = this.skillsMapper.getByNumber(sender, number);
|
||||
|
||||
if (!skill) {
|
||||
await this.sendMessage(roomId, '<p>Ungueltige Nummer. Nutze zuerst <code>!skills</code></p>');
|
||||
|
|
@ -321,7 +331,7 @@ export class MatrixService extends BaseMatrixService {
|
|||
return;
|
||||
}
|
||||
|
||||
this.lastSkillsList.delete(sender);
|
||||
this.skillsMapper.clearList(sender);
|
||||
await this.sendMessage(roomId, `<p>Skill <strong>${skill.name}</strong> geloescht.</p>`);
|
||||
}
|
||||
|
||||
|
|
@ -338,7 +348,8 @@ export class MatrixService extends BaseMatrixService {
|
|||
}
|
||||
|
||||
const token = this.requireAuth(sender);
|
||||
const skill = this.getSkillByNumber(sender, args[0]);
|
||||
const number = parseInt(args[0], 10);
|
||||
const skill = this.skillsMapper.getByNumber(sender, number);
|
||||
|
||||
if (!skill) {
|
||||
await this.sendMessage(roomId, '<p>Ungueltige Nummer. Nutze zuerst <code>!skills</code></p>');
|
||||
|
|
@ -417,9 +428,13 @@ export class MatrixService extends BaseMatrixService {
|
|||
let skillName = '';
|
||||
|
||||
if (numberStr) {
|
||||
const skill = this.getSkillByNumber(sender, numberStr);
|
||||
const number = parseInt(numberStr, 10);
|
||||
const skill = this.skillsMapper.getByNumber(sender, number);
|
||||
if (!skill) {
|
||||
await this.sendMessage(roomId, '<p>Ungueltige Nummer. Nutze zuerst <code>!skills</code></p>');
|
||||
await this.sendMessage(
|
||||
roomId,
|
||||
'<p>Ungueltige Nummer. Nutze zuerst <code>!skills</code></p>'
|
||||
);
|
||||
return;
|
||||
}
|
||||
result = await this.skilltreeService.getSkillActivities(token, skill.id);
|
||||
|
|
@ -459,16 +474,6 @@ export class MatrixService extends BaseMatrixService {
|
|||
}
|
||||
|
||||
// Helper methods
|
||||
private getSkillByNumber(sender: string, numberStr: string): Skill | null {
|
||||
const skills = this.lastSkillsList.get(sender);
|
||||
if (!skills) return null;
|
||||
|
||||
const index = parseInt(numberStr, 10) - 1;
|
||||
if (isNaN(index) || index < 0 || index >= skills.length) return null;
|
||||
|
||||
return skills[index];
|
||||
}
|
||||
|
||||
private getLevelName(level: number): string {
|
||||
const names: Record<number, string> = {
|
||||
0: 'Unbekannt',
|
||||
|
|
@ -494,13 +499,13 @@ export class MatrixService extends BaseMatrixService {
|
|||
|
||||
private getBranchIcon(branch: string): string {
|
||||
const icons: Record<string, string> = {
|
||||
intellect: '🧠', // Brain
|
||||
body: '💪', // Flexed biceps
|
||||
intellect: '🧠', // Brain
|
||||
body: '💪', // Flexed biceps
|
||||
creativity: '🎨', // Artist palette
|
||||
social: '👥', // Busts in silhouette
|
||||
practical: '🔧', // Wrench
|
||||
mindset: '💖', // Heart
|
||||
custom: '⭐', // Star
|
||||
social: '👥', // Busts in silhouette
|
||||
practical: '🔧', // Wrench
|
||||
mindset: '💖', // Heart
|
||||
custom: '⭐', // Star
|
||||
};
|
||||
return icons[branch] || '⭐';
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue