Skip to content
This repository has been archived by the owner on May 27, 2021. It is now read-only.

Commit

Permalink
Added support for PredefinedResponses
Browse files Browse the repository at this point in the history
It is now possible to skip markov generation if input contain
one of trigger phrases.
  • Loading branch information
lidel committed May 28, 2017
1 parent 2dce32b commit a6c137a
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 19 deletions.
6 changes: 6 additions & 0 deletions meowkov.conf.template
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@
"( ͡° ͜ʖ ͡°)"
],

"PredefinedResponses": {
"meowkov sucks": "/me :'C",
"meowkov rocks": "/me :))",
"are you a bot": "no :-^-)"
},

"DontEndWith": ["as","of","po","by","from","on","for","przez","with","i","w","z","na","or","za","u","o","do","in","to","a","the","dla"],
"Blacklist": []
}
74 changes: 55 additions & 19 deletions meowkov.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ var config struct {
SmileyChance float64
WordsPerMinute int64

Smileys []string
DontEndWith []string
Blacklist []string
Smileys []string
PredefinedResponses map[string]string
DontEndWith []string
Blacklist []string

RoomName string `json:",omitempty"` // deprecated
}
Expand Down Expand Up @@ -115,7 +116,7 @@ func loadConfig(file string) (bool, bool) {
log.Println("Connecting to Redis at " + redisServer)
pool = &redis.Pool{
MaxIdle: 3,
MaxActive: 100,
MaxActive: 10,
Wait: true,
IdleTimeout: 240 * time.Second,
Dial: func() (redis.Conn, error) {
Expand Down Expand Up @@ -245,23 +246,42 @@ func ircLoop() {
}
})

// thin wrapper responsible for sending IRC messages
privmsg := func(source string, nick string, message string, triggeredAt time.Time, prefixWithNick bool) {
response := strings.TrimSpace(message)
typingDelay(response, triggeredAt)
if strings.HasPrefix(response, "/me ") {
con.Action(source, strings.Replace(response, "/me ", "", 1))
} else {
if prefixWithNick {
response = nick + ": " + response
}
con.Privmsg(source, response)
}
}

con.AddCallback("PRIVMSG", func(e *irc.Event) {
// response takes some work, running in a new thread
go func(e *irc.Event) {
start := time.Now()
ownNick := con.GetNick()
source, privateQuery := inputSource(e.Raw, ownNick)
words, seeds := processInput(e.Message(), !privateQuery)
chattiness := calculateChattiness(e.Message(), ownNick, privateQuery)
input := strings.TrimSpace(e.Message())

if response := predefinedResponse(input); response != "" {
bumpLastReaction()
privmsg(source, e.Nick, response, start, !privateQuery)
return // finish processing input
}

// fallback to markov-based generator
words, seeds := processInput(input, !privateQuery)
chattiness := calculateChattiness(input, ownNick, privateQuery)
if react(chattiness) {
bumpLastReaction()
response := generateResponse(words, seeds, int(config.MaxResponseTries))
if chattiness == always {
response = e.Nick + ": " + strings.TrimSpace(response)
}
typingDelay(response, start)
con.Privmsg(source, response)
prefixWithNick := chattiness == always && !privateQuery
privmsg(source, e.Nick, response, start, prefixWithNick)
}
}(e)
})
Expand Down Expand Up @@ -312,6 +332,7 @@ func ircLoop() {
log.Panic("The IRC Loop finished prematurely")
}

// decides if there should be a reaction given current chattiness level
func react(chattiness float64) bool {
return chattiness == always || (chattiness > rand.Float64() && withinReactionRate())
}
Expand Down Expand Up @@ -391,25 +412,27 @@ func processInput(message string, learning bool) (words []string, seed [][]strin
return
}

func parseInput(message string) []string {
if otherMention.MatchString(message) {
message = otherMention.ReplaceAllString(message, "")
}

func parseInput(input string) []string {
var (
tokens = strings.Split(message, " ")
tokens = strings.Split(removeMention(input), " ")
words []string
)

for _, token := range tokens {
if word := normalizeWord(token); len(word) > 0 {
words = append(words, word)
}
}

return append(words, stop)
}

// remove nickname-based prefix used for mentions
func removeMention(message string) string {
if otherMention.MatchString(message) {
return otherMention.ReplaceAllString(message, "")
}
return message
}

// normalizeWord removes various cruft from parsed text.
// The goal is to make corpus more uniform (no duplicate clusters for multiple versions of the same word)
func normalizeWord(word string) string {
Expand All @@ -421,6 +444,19 @@ func normalizeWord(word string) string {
return word
}

// lookup for predefined (static) responses
func predefinedResponse(input string) string {
message := removeMention(input)
for key, val := range config.PredefinedResponses {
if strings.Contains(message, key) {
log.Println("Found PredefinedResponses match at key=" + key)
// TODO: support evaluating val via external script
return val
}
}
return ""
}

func addToCorpus(seeds [][]string) {
corpus := pool.Get()
defer corpus.Close()
Expand Down

0 comments on commit a6c137a

Please sign in to comment.