Fix: cookie; add llm parser interface
This commit is contained in:
@ -142,19 +142,18 @@ func makeCookie(username string, remote string) (*http.Cookie, error) {
|
||||
cookieValue := base64.URLEncoding.EncodeToString([]byte(
|
||||
string(signature) + sessionToken))
|
||||
cookie := &http.Cookie{
|
||||
Name: cookieName,
|
||||
Value: cookieValue,
|
||||
// Secure: true,
|
||||
Name: cookieName,
|
||||
Value: cookieValue,
|
||||
Secure: true,
|
||||
HttpOnly: true,
|
||||
SameSite: http.SameSiteNoneMode,
|
||||
// Domain: cfg.ServerConfig.Host,
|
||||
}
|
||||
log.Info("check remote addr for cookie set",
|
||||
"remote", remote, "session", session)
|
||||
if strings.Contains(remote, "192.168.0") {
|
||||
// cookie.Domain = "192.168.0.101"
|
||||
cookie.Domain = ""
|
||||
cookie.Domain = "192.168.0.106"
|
||||
cookie.SameSite = http.SameSiteLaxMode
|
||||
cookie.Secure = false
|
||||
log.Info("changing cookie domain", "domain", cookie.Domain)
|
||||
}
|
||||
// set ctx?
|
||||
|
@ -254,6 +254,7 @@ func HandleGiveClue(w http.ResponseWriter, r *http.Request) {
|
||||
fi.Room.ActionHistory = append(fi.Room.ActionHistory, action)
|
||||
fi.Room.MimeDone = true
|
||||
notify(models.NotifyBacklogPrefix+fi.Room.ID, clue+num)
|
||||
notifyBotIfNeeded(fi)
|
||||
if err := saveFullInfo(fi); err != nil {
|
||||
abortWithError(w, err.Error())
|
||||
return
|
||||
|
@ -21,7 +21,7 @@ var (
|
||||
DoneChanMap = make(map[string]chan bool)
|
||||
// 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 %s team (people who would guess by your clue want open the %s 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 %s team (people who would guess by your clue want open the %s 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`
|
||||
GuesserPrompt = `we are playing alias;\nyou are to guess words of the %s team (you want open %s cards) by given clue and a number of meant guesses;\nplease return your guesses and words that could be meant by the clue, but you do not wish to open yet, 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`
|
||||
)
|
||||
|
||||
type DSResp struct {
|
||||
@ -37,6 +37,20 @@ type DSResp struct {
|
||||
Object string `json:"object"`
|
||||
}
|
||||
|
||||
type LLMResp struct {
|
||||
Choices []struct {
|
||||
FinishReason string `json:"finish_reason"`
|
||||
Index int `json:"index"`
|
||||
Message struct {
|
||||
Content string `json:"content"`
|
||||
Role string `json:"role"`
|
||||
} `json:"message"`
|
||||
} `json:"choices"`
|
||||
Created int `json:"created"`
|
||||
Model string `json:"model"`
|
||||
Object string `json:"object"`
|
||||
}
|
||||
|
||||
type MimeResp struct {
|
||||
Clue string `json:"clue"`
|
||||
Number string `json:"number"`
|
||||
@ -49,12 +63,13 @@ type GusserResp struct {
|
||||
}
|
||||
|
||||
type Bot struct {
|
||||
Role string // gueeser | mime
|
||||
Team string
|
||||
cfg *config.Config
|
||||
RoomID string // can we get a room from here?
|
||||
BotName string
|
||||
log *slog.Logger
|
||||
Role string // gueeser | mime
|
||||
Team string
|
||||
cfg *config.Config
|
||||
RoomID string // can we get a room from here?
|
||||
BotName string
|
||||
log *slog.Logger
|
||||
LLMParser RespParser
|
||||
// channels for communicaton
|
||||
// channels are not serializable
|
||||
// SignalsCh chan bool
|
||||
@ -82,43 +97,16 @@ func (b *Bot) StartBot() {
|
||||
b.log.Error("bot loop", "error", err)
|
||||
return
|
||||
}
|
||||
dsResp := DSResp{}
|
||||
if err := json.Unmarshal(llmResp, &dsResp); err != nil {
|
||||
b.log.Error("failed to unmarshall", "error", err)
|
||||
return
|
||||
tempMap, err := b.LLMParser.ParseBytes(llmResp)
|
||||
if err != nil {
|
||||
b.log.Error("bot loop", "error", err)
|
||||
continue
|
||||
}
|
||||
if len(dsResp.Choices) == 0 {
|
||||
b.log.Error("empty choices", "dsResp", dsResp)
|
||||
return
|
||||
}
|
||||
text := dsResp.Choices[0].Text
|
||||
li := strings.Index(text, "{")
|
||||
ri := strings.LastIndex(text, "}")
|
||||
if li < 0 || ri < 1 {
|
||||
b.log.Error("not a json", "msg", text)
|
||||
return
|
||||
}
|
||||
sj := text[li : ri+1]
|
||||
// jb, err := json.Marshal(sj)
|
||||
// if err != nil {
|
||||
// b.log.Error("failed to marshal", "error", err, "string-json", sj)
|
||||
// return
|
||||
// }
|
||||
// parse response
|
||||
// if mime -> give clue
|
||||
// if guesser -> open card (does opening one card prompting new loop?)
|
||||
// send notification to sse broker
|
||||
eventName := models.NotifyBacklogPrefix + room.ID
|
||||
eventPayload := ""
|
||||
tempMap := make(map[string]any)
|
||||
switch b.Role {
|
||||
case models.UserRoleMime:
|
||||
// respMap := make(map[string]any)
|
||||
mimeResp := MimeResp{}
|
||||
if err := json.Unmarshal([]byte(sj), &tempMap); err != nil {
|
||||
b.log.Error("failed to unmarshal mime resp", "error", err, "string-json", sj)
|
||||
return
|
||||
}
|
||||
b.log.Info("mime resp log", "mimeResp", tempMap)
|
||||
mimeResp.Clue = tempMap["clue"].(string)
|
||||
mimeResp.Number = tempMap["number"].(string)
|
||||
@ -186,7 +174,7 @@ func (b *Bot) StartBot() {
|
||||
eventName = models.NotifyRoomUpdatePrefix + room.ID
|
||||
eventPayload = ""
|
||||
default:
|
||||
b.log.Error("unexpected role", "role", b.Role, "llmResp", sj)
|
||||
b.log.Error("unexpected role", "role", b.Role, "resp-map", tempMap)
|
||||
return
|
||||
}
|
||||
// save room
|
||||
@ -223,6 +211,11 @@ func NewBot(role, team, name, roomID string, cfg *config.Config) (*Bot, error) {
|
||||
AddSource: true,
|
||||
})),
|
||||
}
|
||||
// there might be a better way
|
||||
bot.LLMParser = NewLCPRespParser(bot.log)
|
||||
if strings.Contains(cfg.LLMConfig.URL, "api.deepseek.com") {
|
||||
bot.LLMParser = NewDeepSeekParser(bot.log)
|
||||
}
|
||||
// add to room
|
||||
room, err := getRoomByID(bot.RoomID)
|
||||
if err != nil {
|
||||
@ -321,7 +314,7 @@ func (b *Bot) BuildPrompt(room *models.Room) string {
|
||||
toText["cards"] = room.Cards
|
||||
}
|
||||
if b.Role == models.UserRoleGuesser {
|
||||
copiedCards := []models.WordCard{}
|
||||
copiedCards := make([]models.WordCard, len(room.Cards))
|
||||
copy(copiedCards, room.Cards)
|
||||
for i, card := range copiedCards {
|
||||
if !card.Revealed {
|
||||
@ -383,6 +376,6 @@ func (b *Bot) CallLLM(prompt string) ([]byte, error) {
|
||||
b.log.Error("failed to read resp body", "error", err, "url", b.cfg.LLMConfig.URL)
|
||||
return nil, err
|
||||
}
|
||||
b.log.Debug("llm resp", "body", string(body))
|
||||
b.log.Debug("llm resp", "body", string(body), "url", b.cfg.LLMConfig.URL)
|
||||
return body, nil
|
||||
}
|
||||
|
88
llmapi/parser.go
Normal file
88
llmapi/parser.go
Normal file
@ -0,0 +1,88 @@
|
||||
package llmapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RespParser interface {
|
||||
ParseBytes(body []byte) (map[string]any, error)
|
||||
}
|
||||
|
||||
// DeepSeekParser: deepseek implementation of RespParser
|
||||
type deepSeekParser struct {
|
||||
log *slog.Logger
|
||||
}
|
||||
|
||||
func NewDeepSeekParser(log *slog.Logger) *deepSeekParser {
|
||||
return &deepSeekParser{log: log}
|
||||
}
|
||||
|
||||
func (p *deepSeekParser) ParseBytes(body []byte) (map[string]any, error) {
|
||||
// parsing logic here
|
||||
dsResp := DSResp{}
|
||||
if err := json.Unmarshal(body, &dsResp); err != nil {
|
||||
p.log.Error("failed to unmarshall", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
if len(dsResp.Choices) == 0 {
|
||||
p.log.Error("empty choices", "dsResp", dsResp)
|
||||
err := fmt.Errorf("empty choices in dsResp")
|
||||
return nil, err
|
||||
}
|
||||
text := dsResp.Choices[0].Text
|
||||
li := strings.Index(text, "{")
|
||||
ri := strings.LastIndex(text, "}")
|
||||
if li < 0 || ri < 1 {
|
||||
p.log.Error("not a json", "msg", text)
|
||||
err := fmt.Errorf("fn: ParseBytes, not a json")
|
||||
return nil, err
|
||||
}
|
||||
sj := text[li : ri+1]
|
||||
respMap := make(map[string]any)
|
||||
if err := json.Unmarshal([]byte(sj), &respMap); err != nil {
|
||||
p.log.Error("failed to unmarshal response", "error", err, "string-json", sj)
|
||||
return nil, err
|
||||
}
|
||||
return respMap, nil
|
||||
}
|
||||
|
||||
// llama.cpp implementation of RespParser
|
||||
type lcpRespParser struct {
|
||||
log *slog.Logger
|
||||
}
|
||||
|
||||
func NewLCPRespParser(log *slog.Logger) *lcpRespParser {
|
||||
return &lcpRespParser{log: log}
|
||||
}
|
||||
|
||||
func (p *lcpRespParser) ParseBytes(body []byte) (map[string]any, error) {
|
||||
// parsing logic here
|
||||
resp := LLMResp{}
|
||||
if err := json.Unmarshal(body, &resp); err != nil {
|
||||
p.log.Error("failed to unmarshal", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
if len(resp.Choices) == 0 {
|
||||
p.log.Error("empty choices", "resp", resp)
|
||||
err := fmt.Errorf("empty choices in resp")
|
||||
return nil, err
|
||||
}
|
||||
text := resp.Choices[0].Message.Content
|
||||
li := strings.Index(text, "{")
|
||||
ri := strings.LastIndex(text, "}")
|
||||
if li < 0 || ri < 1 {
|
||||
p.log.Error("not a json", "msg", text)
|
||||
err := fmt.Errorf("fn: ParseBytes, not a json")
|
||||
return nil, err
|
||||
}
|
||||
sj := text[li : ri+1]
|
||||
respMap := make(map[string]any)
|
||||
if err := json.Unmarshal([]byte(sj), &respMap); err != nil {
|
||||
p.log.Error("failed to unmarshal response", "error", err, "string-json", sj)
|
||||
return nil, err
|
||||
}
|
||||
return respMap, nil
|
||||
}
|
@ -103,6 +103,15 @@ func (r *Room) CanStart() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getGuesser(m map[string]BotPlayer, team UserTeam) string {
|
||||
for k, v := range m {
|
||||
if v.Team == team && v.Role == UserRoleGuesser {
|
||||
return k
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// WhichBotToMove returns bot name that have to move or empty string
|
||||
func (r *Room) WhichBotToMove() string {
|
||||
fmt.Println("looking for bot to move", "team-turn", r.TeamTurn, "mime-done", r.MimeDone, "bot-map", r.BotMap, "is_running", r.IsRunning)
|
||||
@ -116,16 +125,18 @@ func (r *Room) WhichBotToMove() string {
|
||||
if ok {
|
||||
return r.BlueTeam.Mime
|
||||
}
|
||||
} else {
|
||||
return getGuesser(r.BotMap, UserTeamBlue)
|
||||
}
|
||||
// check gussers
|
||||
case UserTeamRed:
|
||||
if !r.MimeDone {
|
||||
_, ok := r.BotMap[r.RedTeam.Mime]
|
||||
if ok {
|
||||
return r.RedTeam.Mime
|
||||
}
|
||||
} else {
|
||||
return getGuesser(r.BotMap, UserTeamRed)
|
||||
}
|
||||
// check gussers
|
||||
default:
|
||||
// how did we got here?
|
||||
return ""
|
||||
|
3
todos.md
3
todos.md
@ -9,6 +9,9 @@
|
||||
- there two places for bot to check if its its move: start-game; end-turn;
|
||||
- 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;
|
||||
- if bot already added; remove add bot button;
|
||||
- hide clue input for mime when it's not their turn;
|
||||
- needs resend to llm btn;
|
||||
|
||||
#### sse points
|
||||
- clue sse update;
|
||||
|
Reference in New Issue
Block a user