113 lines
3.2 KiB
Go
113 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"strings"
|
|
)
|
|
|
|
// configuration holds the plugin settings from the System Console.
|
|
type configuration struct {
|
|
OllamaURL string
|
|
DefaultModel string
|
|
SystemPrompt string
|
|
MaxTokens int
|
|
RateLimitPerMinute int
|
|
AllowedUserIDs string
|
|
StopWords string
|
|
}
|
|
|
|
// getConfiguration returns the current configuration, safe for concurrent use.
|
|
func (p *Plugin) getConfiguration() *configuration {
|
|
p.configLock.RLock()
|
|
defer p.configLock.RUnlock()
|
|
return p.configuration
|
|
}
|
|
|
|
// setConfiguration updates the configuration and validates it.
|
|
func (p *Plugin) setConfiguration(c *configuration) error {
|
|
p.configLock.Lock()
|
|
defer p.configLock.Unlock()
|
|
|
|
if c == nil {
|
|
return fmt.Errorf("nil configuration")
|
|
}
|
|
|
|
if err := c.validate(); err != nil {
|
|
return fmt.Errorf("invalid configuration: %w", err)
|
|
}
|
|
|
|
p.configuration = c
|
|
return nil
|
|
}
|
|
|
|
// validate checks that the configuration values are usable.
|
|
func (c *configuration) validate() error {
|
|
if c.OllamaURL == "" {
|
|
return fmt.Errorf("OllamaURL must not be empty")
|
|
}
|
|
u, err := url.Parse(c.OllamaURL)
|
|
if err != nil {
|
|
return fmt.Errorf("OllamaURL is not a valid URL: %w", err)
|
|
}
|
|
if u.Scheme != "http" && u.Scheme != "https" {
|
|
return fmt.Errorf("OllamaURL must use http or https scheme, got %q", u.Scheme)
|
|
}
|
|
if c.DefaultModel == "" {
|
|
return fmt.Errorf("DefaultModel must not be empty")
|
|
}
|
|
if c.MaxTokens < 0 {
|
|
return fmt.Errorf("MaxTokens must not be negative")
|
|
}
|
|
if c.RateLimitPerMinute < 0 {
|
|
return fmt.Errorf("RateLimitPerMinute must not be negative")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// OnConfigurationChange is called by the Mattermost server when the plugin
|
|
// configuration is changed in the System Console.
|
|
func (p *Plugin) OnConfigurationChange() error {
|
|
var c configuration
|
|
|
|
// Load from the System Console settings.
|
|
if err := p.API.LoadPluginConfiguration(&c); err != nil {
|
|
return fmt.Errorf("failed to load plugin configuration: %w", err)
|
|
}
|
|
|
|
if err := p.setConfiguration(&c); err != nil {
|
|
return fmt.Errorf("failed to set configuration: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// allowedUsers returns the set of user IDs allowed to use the plugin.
|
|
// An empty set means all users are allowed.
|
|
func (c *configuration) allowedUsers() map[string]bool {
|
|
if strings.TrimSpace(c.AllowedUserIDs) == "" {
|
|
return nil
|
|
}
|
|
users := make(map[string]bool)
|
|
for _, id := range strings.Split(c.AllowedUserIDs, ",") {
|
|
users[strings.TrimSpace(id)] = true
|
|
}
|
|
return users
|
|
}
|
|
|
|
// stopWordSet returns the set of stop words for the engagement engine.
|
|
func (c *configuration) stopWordSet() map[string]bool {
|
|
if strings.TrimSpace(c.StopWords) == "" {
|
|
return map[string]bool{
|
|
"thanks": true, "thank you": true, "bye": true,
|
|
"goodbye": true, "that's all": true, "done": true,
|
|
"stop": true, "quit": true, "end": true,
|
|
}
|
|
}
|
|
words := make(map[string]bool)
|
|
for _, w := range strings.Split(c.StopWords, ",") {
|
|
words[strings.TrimSpace(strings.ToLower(w))] = true
|
|
}
|
|
return words
|
|
}
|