managarten/services/mana-matrix-bot/internal/plugin/keyword.go
Till JS 819568c3df feat(infra): consolidate 21 Matrix bots into Go binary + add Go API gateway
Replace 21 separate NestJS Matrix bot processes (~2.1 GB RAM, ~4.2 GB Docker images)
with a single Go binary using plugin architecture (8.6 MB binary, ~30 MB RAM).

New services:
- services/mana-matrix-bot/ — Go Matrix bot with 21 plugins (mautrix-go, Redis sessions)
- services/mana-api-gateway-go/ — Go API gateway (rate limiting, API keys, credit billing)

Deleted:
- 21 services/matrix-*-bot/ directories
- packages/bot-services/ and packages/matrix-bot-common/
- Legacy deploy scripts and CI build jobs

Updated:
- docker-compose.macmini.yml: new Go services, legacy bots removed
- CI/CD: change detection + build jobs for Go services
- Root package.json: new dev:matrix, build:matrix, test:matrix scripts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 21:03:00 +01:00

87 lines
2.3 KiB
Go

package plugin
import "strings"
// KeywordCommand maps keywords to a command name.
type KeywordCommand struct {
Keywords []string // lowercase keywords
Command string // command name to return
}
// KeywordDetector detects commands from natural language keywords.
type KeywordDetector struct {
commands []KeywordCommand
maxLength int
partialMatch bool
}
// KeywordDetectorOption configures the detector.
type KeywordDetectorOption func(*KeywordDetector)
// WithMaxLength sets the max message length to check (default: 60).
func WithMaxLength(n int) KeywordDetectorOption {
return func(d *KeywordDetector) { d.maxLength = n }
}
// WithPartialMatch enables partial word matching.
func WithPartialMatch(enabled bool) KeywordDetectorOption {
return func(d *KeywordDetector) { d.partialMatch = enabled }
}
// NewKeywordDetector creates a new keyword detector.
func NewKeywordDetector(commands []KeywordCommand, opts ...KeywordDetectorOption) *KeywordDetector {
d := &KeywordDetector{
commands: commands,
maxLength: 60,
}
for _, opt := range opts {
opt(d)
}
return d
}
// Detect returns the command name if a keyword matches, or empty string.
func (d *KeywordDetector) Detect(message string) string {
lower := strings.ToLower(strings.TrimSpace(message))
if len(lower) > d.maxLength {
return ""
}
for _, cmd := range d.commands {
for _, kw := range cmd.Keywords {
if d.matches(lower, kw) {
return cmd.Command
}
}
}
return ""
}
// AddCommands appends more commands dynamically.
func (d *KeywordDetector) AddCommands(commands []KeywordCommand) {
d.commands = append(d.commands, commands...)
}
func (d *KeywordDetector) matches(message, keyword string) bool {
// Exact match
if message == keyword {
return true
}
// Prefix match: keyword followed by space
if strings.HasPrefix(message, keyword+" ") {
return true
}
// Partial match
if d.partialMatch && strings.Contains(message, keyword) {
return true
}
return false
}
// CommonKeywords are shared across all bots (German + English).
var CommonKeywords = []KeywordCommand{
{Keywords: []string{"hilfe", "help", "befehle", "commands", "?"}, Command: "help"},
{Keywords: []string{"status", "info"}, Command: "status"},
{Keywords: []string{"abbrechen", "cancel", "stop"}, Command: "cancel"},
}