lph-11/main.odin
2025-03-13 18:14:21 +13:00

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()
}