160 lines
4 KiB
Odin
160 lines
4 KiB
Odin
package main
|
|
|
|
import "core:encoding/cbor"
|
|
import "core:encoding/json"
|
|
import "core:fmt"
|
|
import "core:log"
|
|
import "core:math/rand"
|
|
import "core:os"
|
|
import "core:strings"
|
|
import "core:thread"
|
|
import "core:time"
|
|
import di "discord-interactions"
|
|
import client "discord-interactions/odin-http/client"
|
|
|
|
PRODUCE_MARKOV :: #config(PRODUCE_MARKOV, false)
|
|
SEQUENCE_LENGTH :: #config(SEQUENCE_LENGTH, 5)
|
|
|
|
Word :: struct {
|
|
proceeding: map[string]int `json:"p"`,
|
|
}
|
|
|
|
Data :: struct {
|
|
data: [][]string,
|
|
}
|
|
|
|
Dist :: struct {
|
|
word: string,
|
|
sum: int,
|
|
}
|
|
|
|
process_words :: proc(previous_word, next_word: string, word_map: ^map[string]Word) {
|
|
word_entry, found := word_map[previous_word]
|
|
if !found {
|
|
word_entry = Word{}
|
|
}
|
|
word_entry.proceeding[next_word] += 1
|
|
word_map[previous_word] = word_entry
|
|
}
|
|
|
|
word_map: map[string]Word
|
|
|
|
try_find :: proc(input: []string) -> (word: Maybe(Word)) {
|
|
for i in max(0, len(input) - rand.int_max(SEQUENCE_LENGTH) - 1) ..< len(input) {
|
|
concat := strings.join(input[i:], " ")
|
|
found: bool
|
|
word, found = word_map[concat]
|
|
if found {
|
|
break
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
generate :: proc(input: string) -> string {
|
|
generated: [dynamic]string
|
|
|
|
append(&generated, input)
|
|
|
|
maybe_word := try_find(strings.split(input, " "))
|
|
if maybe_word == nil {
|
|
return "aint got nothing for that in the ol' markov chain"
|
|
}
|
|
word := maybe_word.?
|
|
|
|
loop: for {
|
|
dists: [dynamic]Dist
|
|
sum: int
|
|
for next_word, count in word.proceeding {
|
|
sum += count
|
|
append(&dists, Dist{word = next_word, sum = sum})
|
|
}
|
|
|
|
if sum <= 0 {
|
|
break
|
|
}
|
|
|
|
rand_val := rand.int_max(sum)
|
|
|
|
for dist in dists {
|
|
if rand_val < dist.sum {
|
|
append(&generated, dist.word)
|
|
maybe_word = try_find(generated[:])
|
|
if maybe_word == nil {
|
|
break loop
|
|
}
|
|
word = maybe_word.?
|
|
|
|
continue loop
|
|
}
|
|
}
|
|
}
|
|
|
|
return strings.join(generated[:], " ")
|
|
}
|
|
|
|
main :: proc() {
|
|
context.logger = log.create_console_logger(.Info)
|
|
|
|
di.load_config("config.json")
|
|
|
|
when PRODUCE_MARKOV {
|
|
bytes, _ := os.read_entire_file("data.json")
|
|
data: Data
|
|
if err := json.unmarshal(bytes, &data); err != nil {
|
|
log.error(err)
|
|
}
|
|
|
|
for words in data.data {
|
|
for i in 0 ..< len(words) {
|
|
for j in i + 1 ..< min(i + SEQUENCE_LENGTH, len(words)) {
|
|
process_words(strings.join(words[i:j], " "), words[j], &word_map)
|
|
}
|
|
}
|
|
}
|
|
|
|
out, _ := cbor.marshal(word_map)
|
|
os.write_entire_file("markov.cbor", out)
|
|
fmt.println("Produced markov file")
|
|
}
|
|
|
|
markov_bytes, ok := os.read_entire_file("markov.cbor")
|
|
if !ok {
|
|
fmt.eprintln("Failed to read markov cbor")
|
|
}
|
|
cbor.unmarshal(string(markov_bytes), &word_map)
|
|
delete(markov_bytes)
|
|
|
|
di.register_command("lph", proc(interaction: di.Interaction) -> di.Payload {
|
|
thread.create_and_start_with_poly_data(interaction, proc(interaction: di.Interaction) {
|
|
request: client.Request
|
|
client.request_init(&request)
|
|
defer client.request_destroy(&request)
|
|
|
|
client.with_json(
|
|
&request,
|
|
di.Webhook_Payload{content = generate(interaction.data.options[0].value)},
|
|
)
|
|
request.method = .Patch
|
|
|
|
res, err := client.request(
|
|
&request,
|
|
fmt.tprintf(
|
|
"{}/webhooks/{}/{}/messages/@original",
|
|
di.DISCORD_API,
|
|
di.state.application.id,
|
|
interaction.token,
|
|
),
|
|
)
|
|
if err != nil {
|
|
log.error("Failed to send request:", err)
|
|
return
|
|
}
|
|
})
|
|
|
|
return di.Payload{type = 5}
|
|
})
|
|
|
|
di.serve()
|
|
}
|