feat: add voice transcription support to Matrix bots

Add TranscriptionModule and handleAudioMessage to enable voice message
transcription across all Matrix bots. Users can now send voice messages
which are automatically transcribed and processed as text commands.

Affected bots:
- matrix-calendar-bot
- matrix-chat-bot
- matrix-contacts-bot
- matrix-manadeck-bot
- matrix-ollama-bot
- matrix-picture-bot
- matrix-planta-bot
- matrix-presi-bot
- matrix-questions-bot
- matrix-skilltree-bot
- matrix-stats-bot
- matrix-storage-bot
- matrix-tts-bot

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Till-JS 2026-02-01 03:37:30 +01:00
parent 12f1288aec
commit c29939e7bc
30 changed files with 934 additions and 459 deletions

View file

@ -1,10 +1,16 @@
import { Module } from '@nestjs/common';
import { MatrixService } from './matrix.service';
import { SkilltreeModule } from '../skilltree/skilltree.module';
import { SessionModule } from '@manacore/bot-services';
import { SessionModule, TranscriptionModule } from '@manacore/bot-services';
@Module({
imports: [SkilltreeModule, SessionModule.forRoot()],
imports: [
SkilltreeModule,
SessionModule.forRoot(),
TranscriptionModule.register({
sttUrl: process.env.STT_URL || 'http://localhost:3020',
}),
],
providers: [MatrixService],
exports: [MatrixService],
})

View file

@ -9,7 +9,7 @@ import {
COMMON_KEYWORDS,
} from '@manacore/matrix-bot-common';
import { SkilltreeService, Skill, SkillBranch } from '../skilltree/skilltree.service';
import { SessionService } from '@manacore/bot-services';
import { SessionService, TranscriptionService } from '@manacore/bot-services';
import { HELP_MESSAGE } from '../config/configuration';
@Injectable()
@ -54,7 +54,8 @@ export class MatrixService extends BaseMatrixService {
constructor(
configService: ConfigService,
private skilltreeService: SkilltreeService,
private sessionService: SessionService
private sessionService: SessionService,
private readonly transcriptionService: TranscriptionService
) {
super(configService);
}
@ -163,6 +164,30 @@ export class MatrixService extends BaseMatrixService {
}
}
protected override async handleAudioMessage(
roomId: string,
event: MatrixRoomEvent,
_sender: string
): Promise<void> {
try {
const mxcUrl = event.content.url;
if (!mxcUrl) return;
const audioBuffer = await this.downloadMedia(mxcUrl);
const text = await this.transcriptionService.transcribe(audioBuffer);
if (!text) {
await this.sendReply(roomId, event, '<p>Sprachnachricht konnte nicht erkannt werden.</p>');
return;
}
await this.sendMessage(roomId, `<p><em>"${text}"</em></p>`);
await this.handleTextMessage(roomId, event, text);
} catch (error) {
this.logger.error(`Audio transcription error: ${error}`);
await this.sendReply(roomId, event, '<p>Fehler bei der Spracherkennung.</p>');
}
}
private requireAuth(sender: string): string {
const token = this.sessionService.getToken(sender);
if (!token) {