Feat: save room even if llm failed to properly guess; fix prompt
This commit is contained in:
@ -50,7 +50,7 @@
|
|||||||
{{template "teamlist" .Room.RedTeam}}
|
{{template "teamlist" .Room.RedTeam}}
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
<div id="systembox">
|
<div id="systembox" style="overflow-y: auto; max-height: 100px;">
|
||||||
Server says: <br>
|
Server says: <br>
|
||||||
<ul>
|
<ul>
|
||||||
{{range .Room.LogJournal}}
|
{{range .Room.LogJournal}}
|
||||||
|
@ -248,7 +248,6 @@ func listRooms(allRooms bool) []*models.Room {
|
|||||||
log.Warn("failed to unmarshal room", "error", err)
|
log.Warn("failed to unmarshal room", "error", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
log.Debug("consider room for list", "room", room, "key", key)
|
|
||||||
if room.IsPublic || allRooms {
|
if room.IsPublic || allRooms {
|
||||||
publicRooms = append(publicRooms, room)
|
publicRooms = append(publicRooms, room)
|
||||||
}
|
}
|
||||||
|
@ -79,11 +79,11 @@ func HandleFrontLogin(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
http.SetCookie(w, cookie)
|
http.SetCookie(w, cookie)
|
||||||
tmpl, err := template.ParseGlob("components/*.html")
|
// tmpl, err := template.ParseGlob("components/*.html")
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
abortWithError(w, err.Error())
|
// abortWithError(w, err.Error())
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
// check if that user was already in db
|
// check if that user was already in db
|
||||||
userstate, err := loadState(cleanName)
|
userstate, err := loadState(cleanName)
|
||||||
if err != nil || userstate == nil {
|
if err != nil || userstate == nil {
|
||||||
@ -120,9 +120,10 @@ func HandleFrontLogin(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := tmpl.ExecuteTemplate(w, "base", fi); err != nil {
|
// if err := tmpl.ExecuteTemplate(w, "base", fi); err != nil {
|
||||||
log.Error("failed to execute base template", "error", err)
|
// log.Error("failed to execute base template", "error", err)
|
||||||
}
|
// }
|
||||||
|
http.Redirect(w, r, "/", 302)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeCookie(username string, remote string) (*http.Cookie, error) {
|
func makeCookie(username string, remote string) (*http.Cookie, error) {
|
||||||
|
@ -78,7 +78,7 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) {
|
|||||||
Actor: fi.State.Username,
|
Actor: fi.State.Username,
|
||||||
ActorColor: string(fi.State.Team),
|
ActorColor: string(fi.State.Team),
|
||||||
WordColor: string(color),
|
WordColor: string(color),
|
||||||
Action: "guessed",
|
Action: models.ActionTypeGuess,
|
||||||
Word: word,
|
Word: word,
|
||||||
}
|
}
|
||||||
fi.Room.ActionHistory = append(fi.Room.ActionHistory, action)
|
fi.Room.ActionHistory = append(fi.Room.ActionHistory, action)
|
||||||
@ -103,8 +103,8 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) {
|
|||||||
action := models.Action{
|
action := models.Action{
|
||||||
Actor: fi.State.Username,
|
Actor: fi.State.Username,
|
||||||
ActorColor: string(fi.State.Team),
|
ActorColor: string(fi.State.Team),
|
||||||
WordColor: "black",
|
WordColor: models.WordColorBlack,
|
||||||
Action: "game over",
|
Action: models.ActionTypeGameOver,
|
||||||
}
|
}
|
||||||
fi.Room.OpenedThisTurn = 0
|
fi.Room.OpenedThisTurn = 0
|
||||||
fi.Room.ThisTurnLimit = 0
|
fi.Room.ThisTurnLimit = 0
|
||||||
@ -124,8 +124,8 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) {
|
|||||||
action := models.Action{
|
action := models.Action{
|
||||||
Actor: fi.State.Username,
|
Actor: fi.State.Username,
|
||||||
ActorColor: string(fi.State.Team),
|
ActorColor: string(fi.State.Team),
|
||||||
WordColor: "blue",
|
WordColor: models.WordColorBlue,
|
||||||
Action: "game over",
|
Action: models.ActionTypeGameOver,
|
||||||
}
|
}
|
||||||
fi.Room.OpenedThisTurn = 0
|
fi.Room.OpenedThisTurn = 0
|
||||||
fi.Room.ThisTurnLimit = 0
|
fi.Room.ThisTurnLimit = 0
|
||||||
@ -139,8 +139,8 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) {
|
|||||||
action := models.Action{
|
action := models.Action{
|
||||||
Actor: fi.State.Username,
|
Actor: fi.State.Username,
|
||||||
ActorColor: string(fi.State.Team),
|
ActorColor: string(fi.State.Team),
|
||||||
WordColor: "red",
|
WordColor: models.WordColorRed,
|
||||||
Action: "game over",
|
Action: models.ActionTypeGameOver,
|
||||||
}
|
}
|
||||||
fi.Room.OpenedThisTurn = 0
|
fi.Room.OpenedThisTurn = 0
|
||||||
fi.Room.ThisTurnLimit = 0
|
fi.Room.ThisTurnLimit = 0
|
||||||
|
@ -153,9 +153,7 @@ func HandleStartGame(w http.ResponseWriter, r *http.Request) {
|
|||||||
Actor: fi.State.Username,
|
Actor: fi.State.Username,
|
||||||
ActorColor: string(fi.State.Team),
|
ActorColor: string(fi.State.Team),
|
||||||
WordColor: string(fi.State.Team),
|
WordColor: string(fi.State.Team),
|
||||||
Action: "game started",
|
Action: models.ActionTypeGameStarted,
|
||||||
// Word: clue,
|
|
||||||
// Number: num,
|
|
||||||
}
|
}
|
||||||
fi.Room.ActionHistory = append(fi.Room.ActionHistory, action)
|
fi.Room.ActionHistory = append(fi.Room.ActionHistory, action)
|
||||||
if err := saveFullInfo(fi); err != nil {
|
if err := saveFullInfo(fi); err != nil {
|
||||||
|
195
llmapi/main.go
195
llmapi/main.go
@ -120,105 +120,100 @@ func (b *Bot) StartBot() {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-SignalChanMap[b.BotName]:
|
case <-SignalChanMap[b.BotName]:
|
||||||
botJournalName := models.NotifyJournalPrefix + b.RoomID
|
func() {
|
||||||
b.log.Debug("got signal", "bot-team", b.Team, "bot-role", b.Role)
|
// botJournalName := models.NotifyJournalPrefix + b.RoomID
|
||||||
// get room cards and actions
|
b.log.Debug("got signal", "bot-team", b.Team, "bot-role", b.Role)
|
||||||
room, err := getRoomByID(b.RoomID)
|
// get room cards and actions
|
||||||
if err != nil {
|
room, err := getRoomByID(b.RoomID)
|
||||||
b.log.Error("bot loop", "error", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// form prompt
|
|
||||||
prompt := b.BuildPrompt(room)
|
|
||||||
b.log.Debug("got prompt", "prompt", prompt)
|
|
||||||
broker.Notifier.Notifier <- broker.NotificationEvent{
|
|
||||||
EventName: botJournalName,
|
|
||||||
Payload: prompt,
|
|
||||||
}
|
|
||||||
// call llm
|
|
||||||
llmResp, err := b.CallLLM(prompt)
|
|
||||||
if err != nil {
|
|
||||||
broker.Notifier.Notifier <- broker.NotificationEvent{
|
|
||||||
EventName: botJournalName,
|
|
||||||
Payload: "failed to get bot resp",
|
|
||||||
}
|
|
||||||
b.log.Error("bot loop", "error", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
tempMap, err := b.LLMParser.ParseBytes(llmResp)
|
|
||||||
if err != nil {
|
|
||||||
broker.Notifier.Notifier <- broker.NotificationEvent{
|
|
||||||
EventName: botJournalName,
|
|
||||||
Payload: "failed to parse bot resp",
|
|
||||||
}
|
|
||||||
b.log.Error("bot loop", "error", err, "resp", string(llmResp))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
eventName := models.NotifyBacklogPrefix + room.ID
|
|
||||||
eventPayload := ""
|
|
||||||
switch b.Role {
|
|
||||||
case models.UserRoleMime:
|
|
||||||
mimeResp := MimeResp{}
|
|
||||||
b.log.Info("mime resp log", "mimeResp", tempMap)
|
|
||||||
mimeResp.Clue = tempMap["clue"].(string)
|
|
||||||
mimeResp.Number = tempMap["number"].(string)
|
|
||||||
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
|
|
||||||
eventPayload = mimeResp.Clue + mimeResp.Number
|
|
||||||
guessLimitU64, err := strconv.ParseUint(mimeResp.Number, 10, 8)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.log.Warn("failed to parse bot given limit", "mimeResp", mimeResp, "bot_name", b.BotName)
|
b.log.Error("bot loop", "error", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
room.ThisTurnLimit = uint8(guessLimitU64)
|
eventName := models.NotifyBacklogPrefix + room.ID
|
||||||
case models.UserRoleGuesser:
|
eventPayload := ""
|
||||||
// // deprecated
|
defer func() { // save room
|
||||||
// if err := b.checkGuesses(tempMap, room); err != nil {
|
if err := saveRoom(room); err != nil {
|
||||||
// b.log.Warn("failed to check guess", "mimeResp", tempMap, "bot_name", b.BotName)
|
b.log.Error("failed to save room", "error", err)
|
||||||
// continue
|
return
|
||||||
// }
|
}
|
||||||
guess, ok := tempMap["guess"].(string)
|
broker.Notifier.Notifier <- broker.NotificationEvent{
|
||||||
if !ok || guess == "" {
|
EventName: eventName,
|
||||||
b.log.Warn("failed to parse guess", "mimeResp", tempMap, "bot_name", b.BotName)
|
Payload: eventPayload,
|
||||||
}
|
}
|
||||||
if err := b.checkGuess(guess, room); err != nil {
|
}()
|
||||||
b.log.Warn("failed to check guess", "mimeResp", tempMap, "bot_name", b.BotName, "guess", guess)
|
// form prompt
|
||||||
}
|
prompt := b.BuildPrompt(room)
|
||||||
b.log.Info("mime resp log", "guesserResp", tempMap)
|
b.log.Debug("got prompt", "prompt", prompt)
|
||||||
couldBe, err := convertToSliceOfStrings(tempMap["could_be"])
|
room.LogJournal = append(room.LogJournal, b.BotName+" got prompt: "+prompt)
|
||||||
|
// call llm
|
||||||
|
llmResp, err := b.CallLLM(prompt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.log.Warn("failed to parse could_be", "bot_resp", tempMap, "bot_name", b.BotName)
|
room.LogJournal = append(room.LogJournal, b.BotName+" send call got error: "+err.Error())
|
||||||
|
b.log.Error("bot loop", "error", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
room.LogJournal = append(room.LogJournal, fmt.Sprintf("%s also considered this: %v", b.BotName, couldBe))
|
tempMap, err := b.LLMParser.ParseBytes(llmResp)
|
||||||
eventName = models.NotifyRoomUpdatePrefix + room.ID
|
if err != nil {
|
||||||
eventPayload = ""
|
room.LogJournal = append(room.LogJournal, b.BotName+" parse resp got error: "+err.Error())
|
||||||
// TODO: needs to decide if it wants to open the next cardword or end turn
|
b.log.Error("bot loop", "error", err, "resp", string(llmResp))
|
||||||
// or end turn on limit
|
return
|
||||||
default:
|
}
|
||||||
b.log.Error("unexpected role", "role", b.Role, "resp-map", tempMap)
|
switch b.Role {
|
||||||
continue
|
case models.UserRoleMime:
|
||||||
}
|
mimeResp := MimeResp{}
|
||||||
// save room
|
b.log.Info("mime resp log", "mimeResp", tempMap)
|
||||||
if err := saveRoom(room); err != nil {
|
mimeResp.Clue = tempMap["clue"].(string)
|
||||||
b.log.Error("failed to save room", "error", err)
|
mimeResp.Number = tempMap["number"].(string)
|
||||||
continue
|
action := models.Action{
|
||||||
}
|
Actor: b.BotName,
|
||||||
if botName := room.WhichBotToMove(); botName != "" {
|
ActorColor: b.Team,
|
||||||
b.log.Debug("notifying bot", "name", botName)
|
WordColor: b.Team,
|
||||||
SignalChanMap[botName] <- true
|
Action: "gave clue",
|
||||||
}
|
Word: mimeResp.Clue,
|
||||||
broker.Notifier.Notifier <- broker.NotificationEvent{
|
Number: mimeResp.Number,
|
||||||
EventName: eventName,
|
}
|
||||||
Payload: eventPayload,
|
room.ActionHistory = append(room.ActionHistory, action)
|
||||||
}
|
room.MimeDone = true
|
||||||
continue
|
eventPayload = mimeResp.Clue + mimeResp.Number
|
||||||
|
guessLimitU64, err := strconv.ParseUint(mimeResp.Number, 10, 8)
|
||||||
|
if err != nil {
|
||||||
|
b.log.Warn("failed to parse bot given limit", "mimeResp", mimeResp, "bot_name", b.BotName)
|
||||||
|
}
|
||||||
|
room.ThisTurnLimit = uint8(guessLimitU64)
|
||||||
|
case models.UserRoleGuesser:
|
||||||
|
// // deprecated
|
||||||
|
// if err := b.checkGuesses(tempMap, room); err != nil {
|
||||||
|
// b.log.Warn("failed to check guess", "mimeResp", tempMap, "bot_name", b.BotName)
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
guess, ok := tempMap["guess"].(string)
|
||||||
|
if !ok || guess == "" {
|
||||||
|
b.log.Warn("failed to parse guess", "mimeResp", tempMap, "bot_name", b.BotName)
|
||||||
|
}
|
||||||
|
if err := b.checkGuess(guess, room); err != nil {
|
||||||
|
b.log.Warn("failed to check guess", "mimeResp", tempMap, "bot_name", b.BotName, "guess", guess, "error", err)
|
||||||
|
msg := fmt.Sprintf("failed to check guess", "mimeResp", tempMap, "bot_name", b.BotName, "guess", guess, "error", err)
|
||||||
|
room.LogJournal = append(room.LogJournal, msg)
|
||||||
|
}
|
||||||
|
b.log.Info("mime resp log", "guesserResp", tempMap)
|
||||||
|
couldBe, err := convertToSliceOfStrings(tempMap["could_be"])
|
||||||
|
if err != nil {
|
||||||
|
b.log.Warn("failed to parse could_be", "bot_resp", tempMap, "bot_name", b.BotName)
|
||||||
|
}
|
||||||
|
room.LogJournal = append(room.LogJournal, fmt.Sprintf("%s also considered this: %v", b.BotName, couldBe))
|
||||||
|
eventName = models.NotifyRoomUpdatePrefix + room.ID
|
||||||
|
eventPayload = ""
|
||||||
|
// TODO: needs to decide if it wants to open the next cardword or end turn
|
||||||
|
// or end turn on limit
|
||||||
|
default:
|
||||||
|
b.log.Error("unexpected role", "role", b.Role, "resp-map", tempMap)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if botName := room.WhichBotToMove(); botName != "" {
|
||||||
|
b.log.Debug("notifying bot", "name", botName)
|
||||||
|
SignalChanMap[botName] <- true
|
||||||
|
}
|
||||||
|
}()
|
||||||
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
|
||||||
@ -335,13 +330,19 @@ func saveRoom(room *models.Room) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bot) BuildSimpleGuesserPrompt(room *models.Room) string {
|
func (b *Bot) BuildSimpleGuesserPrompt(room *models.Room) string {
|
||||||
clue := room.ActionHistory[len(room.ActionHistory)-1].Word
|
// find not last action, but the clue
|
||||||
|
// clue := room.ActionHistory[len(room.ActionHistory)-1].Word
|
||||||
|
clueAction, err := room.FetchLastClue()
|
||||||
|
if err != nil {
|
||||||
|
b.log.Error("failed to fetch last clue", "error", err, "room", room, "bot_name", b.BotName)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
// number := room.ActionHistory[len(room.ActionHistory)-1].Number
|
// number := room.ActionHistory[len(room.ActionHistory)-1].Number
|
||||||
words := make([]string, len(room.Cards))
|
words := make([]string, len(room.Cards))
|
||||||
for i, card := range room.Cards {
|
for i, card := range room.Cards {
|
||||||
words[i] = card.Word
|
words[i] = card.Word
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(GuesserSimplePrompt, clue, words)
|
return fmt.Sprintf(GuesserSimplePrompt, clueAction.Word, words)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bot) BuildPrompt(room *models.Room) string {
|
func (b *Bot) BuildPrompt(room *models.Room) string {
|
||||||
|
@ -19,6 +19,15 @@ const (
|
|||||||
WordColorUknown = "stone" // beige
|
WordColorUknown = "stone" // beige
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ActionType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ActionTypeClue = "gave_clue"
|
||||||
|
ActionTypeGuess = "guessed"
|
||||||
|
ActionTypeGameOver = "game_over"
|
||||||
|
ActionTypeGameStarted = "game_started"
|
||||||
|
)
|
||||||
|
|
||||||
func StrToWordColor(s string) WordColor {
|
func StrToWordColor(s string) WordColor {
|
||||||
switch s {
|
switch s {
|
||||||
case "amber", "white":
|
case "amber", "white":
|
||||||
@ -88,6 +97,15 @@ type Room struct {
|
|||||||
LogJournal []string
|
LogJournal []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Room) FetchLastClue() (*Action, error) {
|
||||||
|
for i := len(r.ActionHistory) - 1; i >= 0; i-- {
|
||||||
|
if r.ActionHistory[i].Action == string(ActionTypeClue) {
|
||||||
|
return &r.ActionHistory[i], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errors.New("no clue in history")
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Room) GetPlayerByName(name string) (role UserRole, team UserTeam, found bool) {
|
func (r *Room) GetPlayerByName(name string) (role UserRole, team UserTeam, found bool) {
|
||||||
if r.RedTeam.Mime == name {
|
if r.RedTeam.Mime == name {
|
||||||
return "mime", "red", true
|
return "mime", "red", true
|
||||||
|
Reference in New Issue
Block a user