Enha: parsing llm resp [WIP]

This commit is contained in:
Grail Finder
2025-05-28 11:00:24 +03:00
parent 6dcc3f0309
commit e8507463e0
2 changed files with 67 additions and 11 deletions

View File

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"golias/broker"
"golias/config" "golias/config"
"golias/models" "golias/models"
"golias/pkg/cache" "golias/pkg/cache"
@ -26,9 +27,22 @@ var (
SignalChanMap = make(map[string]chan bool) SignalChanMap = make(map[string]chan bool)
DoneChanMap = make(map[string]chan bool) DoneChanMap = make(map[string]chan bool)
// got prompt: control character (\\u0000-\\u001F) found while parsing a string at line 4 column 0 // got prompt: control character (\\u0000-\\u001F) found while parsing a string at line 4 column 0
MimePrompt = `we are playing alias;\nyou are a mime (player who gives a clue of one noun word and number of cards you expect them to open) of the red team (people who would guess by your clue want open the red cards);\nplease return your clue, number of cards to open and what words you mean them to find using that clue in json like:\n{\n\"clue\": \"one-word-noun\",\n\"number\": \"number-from-0-to-9\",\n\"word_I_mean_my_team_to_open\": [\"this\", \"that\", ...]\n}\nthe team who openes all their cards first wins.\nplease return json only.\nunopen Blue cards left: %d;\nunopen Red cards left: %d;\nhere is the game info in json:\n%s` MimePrompt = `we are playing alias;\nyou are a mime (player who gives a clue of one noun word and number of cards you expect them to open) of the red team (people who would guess by your clue want open the red cards);\nplease return your clue, number of cards to open and what words you mean them to find using that clue in json like:\n{\n\"clue\": \"one-word-noun\",\n\"number\": \"number-from-0-to-9\",\n\"words_I_mean_my_team_to_open\": [\"this\", \"that\", ...]\n}\nthe team who openes all their cards first wins.\nplease return json only.\nunopen Blue cards left: %d;\nunopen Red cards left: %d;\nhere is the game info in json:\n%s`
GuesserPrompt = `we are playing alias;\nyou are to guess words of the red team (people who would guess by your clue want open the red cards) by given clue and a number of meant guesses;\nplease return your guesses and words that you did not wish to open, but think that they could be also meant by the clue in json like:\n{\n\"guesses\": [\"word1\", \"word2\", ...],\n\"could_be\": [\"this\", \"that\", ...]\n}\nthe team who openes all their cards first wins.\nplease return json only.\nunopen Blue cards left: %d;\nunopen Red cards left: %d;\nhere is the game info in json:\n%s`
// notifier =
) )
type MimeResp struct {
Clue string `json:"clue"`
Number string `json:"number"`
Answer []string `json:"words_I_mean_my_team_to_open"`
}
type GusserResp struct {
Guesses []string `json:"guesses"`
CouldBe []string `json:"could_be"`
}
type Bot struct { type Bot struct {
Role string // gueeser | mime Role string // gueeser | mime
Team string Team string
@ -58,14 +72,49 @@ func (b *Bot) StartBot() {
prompt := b.BuildPrompt(room) prompt := b.BuildPrompt(room)
b.log.Debug("got prompt", "prompt", prompt) b.log.Debug("got prompt", "prompt", prompt)
// call llm // call llm
if err := b.CallLLM(prompt); err != nil { llmResp, err := b.CallLLM(prompt)
if err != nil {
b.log.Error("bot loop", "error", err) b.log.Error("bot loop", "error", err)
return return
} }
// parse response // parse response
// if mime -> give clue // if mime -> give clue
// if guesser -> open card (does opening one card prompting new loop?) // if guesser -> open card (does opening one card prompting new loop?)
// send notification to sse broker // send notification to sse broker
switch b.Role {
case models.UserRoleMime:
// respMap := make(map[string]any)
mimeResp := MimeResp{}
if err := json.Unmarshal(llmResp, &mimeResp); err != nil {
b.log.Error("failed to unmarshal mime resp", "error", err)
return
}
action := models.Action{
Actor: b.BotName,
ActorColor: b.Team,
WordColor: b.Team,
Action: "gave clue",
Word: mimeResp.Clue,
Number: mimeResp.Number,
}
room.ActionHistory = append(room.ActionHistory, action)
room.MimeDone = true
// notify(models.NotifyBacklogPrefix+room.ID, clue+num)
case models.UserRoleGuesser:
gr := GusserResp{}
if err := json.Unmarshal(llmResp, &gr); err != nil {
b.log.Error("failed to unmarshal guesser resp", "error", err)
return
}
default:
b.log.Error("unexpected role", "role", b.Role)
return
}
broker.Notifier.Notifier <- broker.NotificationEvent{
EventName: "",
Payload: "",
}
// update room info
case <-DoneChanMap[b.BotName]: case <-DoneChanMap[b.BotName]:
b.log.Debug("got done signal", "bot-name", b.BotName) b.log.Debug("got done signal", "bot-name", b.BotName)
return return
@ -204,7 +253,7 @@ func (b *Bot) BuildPrompt(room *models.Room) string {
return "" return ""
} }
func (b *Bot) CallLLM(prompt string) error { func (b *Bot) CallLLM(prompt string) ([]byte, error) {
method := "POST" method := "POST"
payload := strings.NewReader(fmt.Sprintf(`{ payload := strings.NewReader(fmt.Sprintf(`{
"model": "deepseek-chat", "model": "deepseek-chat",
@ -225,7 +274,7 @@ func (b *Bot) CallLLM(prompt string) error {
req, err := http.NewRequest(method, b.cfg.LLMConfig.URL, payload) req, err := http.NewRequest(method, b.cfg.LLMConfig.URL, payload)
if err != nil { if err != nil {
b.log.Error("failed to make new request", "error", err, "url", b.cfg.LLMConfig.URL) b.log.Error("failed to make new request", "error", err, "url", b.cfg.LLMConfig.URL)
return err return nil, err
} }
req.Header.Add("Content-Type", "application/json") req.Header.Add("Content-Type", "application/json")
req.Header.Add("Accept", "application/json") req.Header.Add("Accept", "application/json")
@ -233,14 +282,20 @@ func (b *Bot) CallLLM(prompt string) error {
res, err := client.Do(req) res, err := client.Do(req)
if err != nil { if err != nil {
b.log.Error("failed to make request", "error", err, "url", b.cfg.LLMConfig.URL) b.log.Error("failed to make request", "error", err, "url", b.cfg.LLMConfig.URL)
return err return nil, err
} }
defer res.Body.Close() defer res.Body.Close()
body, err := io.ReadAll(res.Body) body, err := io.ReadAll(res.Body)
if err != nil { if err != nil {
b.log.Error("failed to read resp body", "error", err, "url", b.cfg.LLMConfig.URL) b.log.Error("failed to read resp body", "error", err, "url", b.cfg.LLMConfig.URL)
return err return nil, err
} }
b.log.Debug("llm resp", "body", string(body)) b.log.Debug("llm resp", "body", string(body))
return nil // TODO: case where it has other text, not only json
// TODO: how to know which resp it is? mime or guessser?
// resp := &MimeResp{}
// if err := json.Unmarshal(body, &resp); err != nil {
// return nil, err
// }
return body, nil
} }

View File

@ -8,6 +8,7 @@
- add html icons of whos turn it is (like an image of big ? when mime is thinking); - add html icons of whos turn it is (like an image of big ? when mime is thinking);
- there two places for bot to check if its its move: start-game; end-turn; - there two places for bot to check if its its move: start-game; end-turn;
- remove bot button (if game is not running); - remove bot button (if game is not running);
- show in backlog (and with that in prompt to llm) how many cards are left to open, also additional comment: if guess was right;
#### sse points #### sse points
- clue sse update; - clue sse update;