Merge branch 'master' into enha/sse-try
This commit is contained in:
		| @@ -1,7 +1,6 @@ | |||||||
| body{ | body{ | ||||||
|     background-color: #0C1616FF; |     background-color: #0C1616FF; | ||||||
|     color: #8896b2; |     color: #8896b2; | ||||||
|     max-width: 1000px; |  | ||||||
|     min-width: 0px; |     min-width: 0px; | ||||||
|     margin: 2em auto !important; |     margin: 2em auto !important; | ||||||
|     margin-left: auto; |     margin-left: auto; | ||||||
|   | |||||||
										
											Binary file not shown.
										
									
								
							| @@ -10,7 +10,7 @@ import ( | |||||||
|  |  | ||||||
| // the amount of time to wait when pushing a message to | // the amount of time to wait when pushing a message to | ||||||
| // a slow client or a client that closed after `range clients` started. | // a slow client or a client that closed after `range clients` started. | ||||||
| const patience time.Duration = time.Second * 1 | // const patience time.Duration = time.Second * 1 | ||||||
|  |  | ||||||
| type ( | type ( | ||||||
| 	NotificationEvent struct { | 	NotificationEvent struct { | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ | |||||||
|   if (!window.actionHistoryScrollSet) { |   if (!window.actionHistoryScrollSet) { | ||||||
|     htmx.onLoad(function(target) { |     htmx.onLoad(function(target) { | ||||||
|       if (target.id === 'actionHistoryContainer') { |       if (target.id === 'actionHistoryContainer') { | ||||||
|         target.scrollTop = target.scrollHeight; |         target.scrollToBottom(); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
|     window.actionHistoryScrollSet = true; |     window.actionHistoryScrollSet = true; | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| {{define "room"}} | {{define "room"}} | ||||||
| <div id="room-interier" class=space-y-2> | <div id="room-interier" class=space-y-2> | ||||||
|   <div id="meta"> |   <div id="headwrapper" class="grid grid-cols-1 md:grid-cols-5 md:gap-4"> | ||||||
|  |   <div id="meta" class="md:col-span-1 border-2 rounded-lg text-center space-y-2"> | ||||||
|     <p>Hello {{.State.Username}};</p> |     <p>Hello {{.State.Username}};</p> | ||||||
|     <p>Room created by {{.Room.CreatorName}};</p> |     <p>Room created by {{.Room.CreatorName}};</p> | ||||||
|     <p>Room link:</p> |     <p>Room link:</p> | ||||||
| @@ -16,13 +17,13 @@ | |||||||
|     {{end}} |     {{end}} | ||||||
|     <p> |     <p> | ||||||
|       {{if eq .State.Team ""}} |       {{if eq .State.Team ""}} | ||||||
|       join the team! |         you don't have a role! join the team -> | ||||||
|       {{else}} |       {{else}} | ||||||
|       you're on the team <span class="text-{{.State.Team}}-500">{{.State.Team}}</span>! |       you're on the team <span class="text-{{.State.Team}}-500">{{.State.Team}}</span>! | ||||||
|       {{end}} |       {{end}} | ||||||
|     </p> |     </p> | ||||||
|   </div> |   </div> | ||||||
|   <hr /> |   <div id="infopatch"   class="md:col-span-3"> | ||||||
|   {{if .Room.IsRunning}} |   {{if .Room.IsRunning}} | ||||||
|     <p>Turn of the <span class="text-{{.Room.TeamTurn}}-500">{{.Room.TeamTurn}}</span> team</p> |     <p>Turn of the <span class="text-{{.Room.TeamTurn}}-500">{{.Room.TeamTurn}}</span> team</p> | ||||||
| {{template "turntimer" .Room}} | {{template "turntimer" .Room}} | ||||||
| @@ -48,7 +49,18 @@ | |||||||
|     <!-- Right Panel --> |     <!-- Right Panel --> | ||||||
|     {{template "teamlist" .Room.RedTeam}} |     {{template "teamlist" .Room.RedTeam}} | ||||||
|   </div> |   </div> | ||||||
|  |   </div> | ||||||
|  |   </div> | ||||||
|   <hr/> |   <hr/> | ||||||
|  |   <div class="grid grid-cols-1 md:grid-cols-5 md:gap-4"> | ||||||
|  |     <div hx-get="/actionhistory" hx-trigger="sse:backlog_{{.Room.ID}}" class="md:col-span-1"> | ||||||
|  |       {{template "actionhistory" .Room.ActionHistory}} | ||||||
|  |     </div> | ||||||
|  |     <div id="cardtable" class="md:col-span-3"> | ||||||
|  |       {{template "cardtable" .Room}} | ||||||
|  |     </div> | ||||||
|  |     <div class="hidden md:block md:col-span-1"></div> <!-- Spacer --> | ||||||
|  |   </div> | ||||||
|   <div id="systembox" class="overflow-y-auto max-h-96 border-2 border-gray-300 p-4 rounded-lg space-y-2"> |   <div id="systembox" class="overflow-y-auto max-h-96 border-2 border-gray-300 p-4 rounded-lg space-y-2"> | ||||||
|     bot thought: <br> |     bot thought: <br> | ||||||
|     <ul> |     <ul> | ||||||
| @@ -57,13 +69,6 @@ | |||||||
|     {{end}} |     {{end}} | ||||||
|     </ul> |     </ul> | ||||||
|   </div> |   </div> | ||||||
|   <div hx-get="/actionhistory" hx-trigger="sse:backlog_{{.Room.ID}}"> |  | ||||||
|   {{template "actionhistory" .Room.ActionHistory}} |  | ||||||
|   </div> |  | ||||||
|   <hr/> |  | ||||||
|   <div id="cardtable"> |  | ||||||
|     {{template "cardtable" .Room}} |  | ||||||
|   </div> |  | ||||||
|   <div> |   <div> | ||||||
|     {{if .Room.IsRunning}} |     {{if .Room.IsRunning}} | ||||||
|     {{if and (eq .State.Role "guesser") (eq .State.Team .Room.TeamTurn)}} |     {{if and (eq .State.Role "guesser") (eq .State.Team .Room.TeamTurn)}} | ||||||
| @@ -74,7 +79,7 @@ | |||||||
|     {{end}} |     {{end}} | ||||||
|   </div> |   </div> | ||||||
|   <div> |   <div> | ||||||
|     {{if and (eq .State.Username .Room.CreatorName) (.Room.IsRunning)}} |     {{if and (eq .State.Username .Room.CreatorName) (.Room.BotFailed)}} | ||||||
|       <button hx-get="/renotify-bot" hx-swap="none" class="bg-gray-100 text-black px-1 py-1 rounded">Btn in case llm call failed</button> |       <button hx-get="/renotify-bot" hx-swap="none" class="bg-gray-100 text-black px-1 py-1 rounded">Btn in case llm call failed</button> | ||||||
|     {{end}} |     {{end}} | ||||||
|   </div> |   </div> | ||||||
|   | |||||||
| @@ -42,8 +42,9 @@ func HandleShowColor(w http.ResponseWriter, r *http.Request) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	fi, err := getFullInfoByCtx(ctx) | 	fi, err := getFullInfoByCtx(ctx) | ||||||
| 	if err != nil { | 	if err != nil || fi == nil { | ||||||
| 		abortWithError(w, err.Error()) | 		log.Error("failed to fetch fi", "error", err) | ||||||
|  | 		http.Redirect(w, r, "/", 302) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	if err := validateMove(fi, models.UserRoleGuesser); err != nil { | 	if err := validateMove(fi, models.UserRoleGuesser); err != nil { | ||||||
| @@ -206,8 +207,9 @@ func HandleMarkCard(w http.ResponseWriter, r *http.Request) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	fi, err := getFullInfoByCtx(ctx) | 	fi, err := getFullInfoByCtx(ctx) | ||||||
| 	if err != nil { | 	if err != nil || fi == nil { | ||||||
| 		abortWithError(w, err.Error()) | 		log.Error("failed to fetch fi", "error", err) | ||||||
|  | 		http.Redirect(w, r, "/", 302) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	if err := validateMove(fi, models.UserRoleGuesser); err != nil { | 	if err := validateMove(fi, models.UserRoleGuesser); err != nil { | ||||||
| @@ -274,8 +276,9 @@ func HandleMarkCard(w http.ResponseWriter, r *http.Request) { | |||||||
|  |  | ||||||
| func HandleActionHistory(w http.ResponseWriter, r *http.Request) { | func HandleActionHistory(w http.ResponseWriter, r *http.Request) { | ||||||
| 	fi, err := getFullInfoByCtx(r.Context()) | 	fi, err := getFullInfoByCtx(r.Context()) | ||||||
| 	if err != nil { | 	if err != nil || fi == nil { | ||||||
| 		abortWithError(w, err.Error()) | 		log.Error("failed to fetch fi", "error", err) | ||||||
|  | 		http.Redirect(w, r, "/", 302) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	tmpl, err := template.ParseGlob("components/*.html") | 	tmpl, err := template.ParseGlob("components/*.html") | ||||||
| @@ -293,8 +296,9 @@ func HandleAddBot(w http.ResponseWriter, r *http.Request) { | |||||||
| 	team := r.URL.Query().Get("team") | 	team := r.URL.Query().Get("team") | ||||||
| 	role := r.URL.Query().Get("role") | 	role := r.URL.Query().Get("role") | ||||||
| 	fi, err := getFullInfoByCtx(r.Context()) | 	fi, err := getFullInfoByCtx(r.Context()) | ||||||
| 	if err != nil { | 	if err != nil || fi == nil { | ||||||
| 		abortWithError(w, err.Error()) | 		log.Error("failed to fetch fi", "error", err) | ||||||
|  | 		http.Redirect(w, r, "/", 302) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	var botname string | 	var botname string | ||||||
| @@ -319,8 +323,9 @@ func HandleRemoveBot(w http.ResponseWriter, r *http.Request) { | |||||||
| 	botName := r.URL.Query().Get("bot") | 	botName := r.URL.Query().Get("bot") | ||||||
| 	log.Debug("got remove-bot request", "bot_name", botName) | 	log.Debug("got remove-bot request", "bot_name", botName) | ||||||
| 	fi, err := getFullInfoByCtx(r.Context()) | 	fi, err := getFullInfoByCtx(r.Context()) | ||||||
| 	if err != nil { | 	if err != nil || fi == nil { | ||||||
| 		abortWithError(w, err.Error()) | 		log.Error("failed to fetch fi", "error", err) | ||||||
|  | 		http.Redirect(w, r, "/", 302) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	if err := llmapi.RemoveBot(botName, fi.Room); err != nil { | 	if err := llmapi.RemoveBot(botName, fi.Room); err != nil { | ||||||
|   | |||||||
| @@ -72,8 +72,9 @@ func HandleJoinTeam(w http.ResponseWriter, r *http.Request) { | |||||||
| 	} | 	} | ||||||
| 	// get username | 	// get username | ||||||
| 	fi, err := getFullInfoByCtx(r.Context()) | 	fi, err := getFullInfoByCtx(r.Context()) | ||||||
| 	if err != nil { | 	if err != nil || fi == nil { | ||||||
| 		abortWithError(w, err.Error()) | 		log.Error("failed to fetch fi", "error", err) | ||||||
|  | 		http.Redirect(w, r, "/", 302) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	if fi.Room == nil { | 	if fi.Room == nil { | ||||||
| @@ -111,8 +112,9 @@ func HandleJoinTeam(w http.ResponseWriter, r *http.Request) { | |||||||
| func HandleEndTurn(w http.ResponseWriter, r *http.Request) { | func HandleEndTurn(w http.ResponseWriter, r *http.Request) { | ||||||
| 	// get username | 	// get username | ||||||
| 	fi, err := getFullInfoByCtx(r.Context()) | 	fi, err := getFullInfoByCtx(r.Context()) | ||||||
| 	if err != nil { | 	if err != nil || fi == nil { | ||||||
| 		abortWithError(w, err.Error()) | 		log.Error("failed to fetch fi", "error", err) | ||||||
|  | 		http.Redirect(w, r, "/", 302) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	// check if one who pressed it is from the team who has the turn | 	// check if one who pressed it is from the team who has the turn | ||||||
| @@ -143,8 +145,9 @@ func HandleEndTurn(w http.ResponseWriter, r *http.Request) { | |||||||
|  |  | ||||||
| func HandleStartGame(w http.ResponseWriter, r *http.Request) { | func HandleStartGame(w http.ResponseWriter, r *http.Request) { | ||||||
| 	fi, err := getFullInfoByCtx(r.Context()) | 	fi, err := getFullInfoByCtx(r.Context()) | ||||||
| 	if err != nil { | 	if err != nil || fi == nil { | ||||||
| 		abortWithError(w, err.Error()) | 		log.Error("failed to fetch fi", "error", err) | ||||||
|  | 		http.Redirect(w, r, "/", 302) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	// check if enough players | 	// check if enough players | ||||||
| @@ -293,8 +296,9 @@ func HandleGiveClue(w http.ResponseWriter, r *http.Request) { | |||||||
| 	clue := r.PostFormValue("clue") | 	clue := r.PostFormValue("clue") | ||||||
| 	num := r.PostFormValue("number") | 	num := r.PostFormValue("number") | ||||||
| 	fi, err := getFullInfoByCtx(r.Context()) | 	fi, err := getFullInfoByCtx(r.Context()) | ||||||
| 	if err != nil { | 	if err != nil || fi == nil { | ||||||
| 		abortWithError(w, err.Error()) | 		log.Error("failed to fetch fi", "error", err) | ||||||
|  | 		http.Redirect(w, r, "/", 302) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	guessLimitU64, err := strconv.ParseUint(num, 10, 8) | 	guessLimitU64, err := strconv.ParseUint(num, 10, 8) | ||||||
| @@ -360,8 +364,9 @@ func HandleGiveClue(w http.ResponseWriter, r *http.Request) { | |||||||
|  |  | ||||||
| func HandleRenotifyBot(w http.ResponseWriter, r *http.Request) { | func HandleRenotifyBot(w http.ResponseWriter, r *http.Request) { | ||||||
| 	fi, err := getFullInfoByCtx(r.Context()) | 	fi, err := getFullInfoByCtx(r.Context()) | ||||||
| 	if err != nil { | 	if err != nil || fi == nil { | ||||||
| 		abortWithError(w, err.Error()) | 		log.Error("failed to fetch fi", "error", err) | ||||||
|  | 		http.Redirect(w, r, "/", 302) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	notifyBotIfNeeded(fi.Room) | 	notifyBotIfNeeded(fi.Room) | ||||||
|   | |||||||
| @@ -75,8 +75,9 @@ func HandleExit(w http.ResponseWriter, r *http.Request) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	fi, err := getFullInfoByCtx(r.Context()) | 	fi, err := getFullInfoByCtx(r.Context()) | ||||||
| 	if err != nil { | 	if err != nil || fi == nil { | ||||||
| 		abortWithError(w, err.Error()) | 		log.Error("failed to fetch fi", "error", err) | ||||||
|  | 		http.Redirect(w, r, "/", 302) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	if fi.Room.IsRunning { | 	if fi.Room.IsRunning { | ||||||
|   | |||||||
| @@ -25,10 +25,10 @@ var ( | |||||||
| 	DoneChanMap   = make(map[string]chan bool) | 	DoneChanMap   = make(map[string]chan bool) | ||||||
| 	mapMutex      = &sync.RWMutex{} | 	mapMutex      = &sync.RWMutex{} | ||||||
| 	// 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 %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 (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 cards (and other info), you need to choose revealed==false words:\n%s` |  | ||||||
| 	GuesserSimplePrompt   = `we are playing game of alias;\n you were given a clue: \"%s\";\nplease return your guess and words that could be meant by the clue, but you do not wish to open yet, in json like:\n{\n\"guess\": \"most_relevant_word_to_the_clue\",\n\"could_be\": [\"this\", \"that\", ...]\n}\nhere is the words that you can choose from:\n%v` | 	GuesserSimplePrompt   = `we are playing game of alias;\n you were given a clue: \"%s\";\nplease return your guess and words that could be meant by the clue, but you do not wish to open yet, in json like:\n{\n\"guess\": \"most_relevant_word_to_the_clue\",\n\"could_be\": [\"this\", \"that\", ...]\n}\nhere is the words that you can choose from:\n%v` | ||||||
| 	MimeSimplePrompt    = `we are playing alias;\nyou are to give one word clue and a number of words you mean your team to open; your team words: %v;\nhere are the words of opposite team you want to avoid: %v;\nand here is a black word that is critical not to pick: %s;\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-as-string\",\n\"words_I_mean_my_team_to_open\": [\"this\", \"that\", ...]\n}\nplease return json only.\nunopen Blue cards left: %d;\nunopen Red cards left: %d;` | 	MimeSimplePrompt      = `we are playing alias;\nyou are to give one word clue and a number of words you mean your team to open; your team words: %v;\nhere are the words of opposite team you want to avoid: %v;\nand here is a black word that is critical not to pick: %s;\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-as-string\",\n\"words_I_mean_my_team_to_open\": [\"this\", \"that\", ...]\n}\nplease return json only.` | ||||||
|  | 	GuesserSimplePromptRU = `мы играем в alias;\n тебе дана подсказка (clue): \"%s\";\nпожалуйста, верни свою догадку (guess), а также слова, что тоже подходят к подсказке, но ты меньше в них уверен, в формате json; пример:\n{\n\"guess\": \"отгадка\",\n\"could_be\": [\"слово1\", \"слово2\", ...]\n}\nвот список слов из которых нужно выбрать:\n%v` | ||||||
|  | 	MimeSimplePromptRU    = `мы играем в alias;\nтебе нужно дать подсказку одним словом и число слов, что ты подразумевал этой подсказкой; слова твоей комманды: %v;\nслова противоположной комманды, что ты хочешь избежать: %v;\nи вот ЧЕРНОЕ СЛОВО, открыв которое твоя комманда проиграет игру: %s;\nпожалуйста, верни подсказку (одним словом) и количество слов, что ты подразумеваешь в формате json; пример:\n{\n\"clue\": \"подсказка\",\n\"number\": \"число-от-0-до-9-as-string\",\n\"words_I_mean_my_team_to_open\": [\"слово1\", \"слово2\", ...]\n}\nпожалуйста верни только json.` | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func convertToSliceOfStrings(value any) ([]string, error) { | func convertToSliceOfStrings(value any) ([]string, error) { | ||||||
| @@ -188,6 +188,11 @@ func (b *Bot) BotMove() { | |||||||
| 		b.log.Error("bot loop", "error", err) | 		b.log.Error("bot loop", "error", err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | 	if room.BotFailed { | ||||||
|  | 		if err := repo.RoomUnSetBotFailed(context.Background(), room.ID); err != nil { | ||||||
|  | 			b.log.Error("failed to unset bot failed bool", "error", err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	// eventName := models.NotifyBacklogPrefix + room.ID | 	// eventName := models.NotifyBacklogPrefix + room.ID | ||||||
| 	eventName := models.NotifyRoomUpdatePrefix + room.ID | 	eventName := models.NotifyRoomUpdatePrefix + room.ID | ||||||
| 	eventPayload := "" | 	eventPayload := "" | ||||||
| @@ -231,6 +236,9 @@ func (b *Bot) BotMove() { | |||||||
| 			b.log.Warn("failed to write to journal", "entry", lj) | 			b.log.Warn("failed to write to journal", "entry", lj) | ||||||
| 		} | 		} | ||||||
| 		b.log.Error("bot loop", "error", err) | 		b.log.Error("bot loop", "error", err) | ||||||
|  | 		if err := repo.RoomSetBotFailed(context.Background(), room.ID); err != nil { | ||||||
|  | 			b.log.Error("failed to set bot failed bool", "error", err) | ||||||
|  | 		} | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	tempMap, err := b.LLMParser.ParseBytes(llmResp) | 	tempMap, err := b.LLMParser.ParseBytes(llmResp) | ||||||
| @@ -545,6 +553,9 @@ func (b *Bot) BuildSimpleGuesserPrompt(room *models.Room) string { | |||||||
| 		} | 		} | ||||||
| 		words[i] = card.Word | 		words[i] = card.Word | ||||||
| 	} | 	} | ||||||
|  | 	if strings.EqualFold(room.Settings.Language, "ru") { | ||||||
|  | 		return fmt.Sprintf(MimeSimplePromptRU, clueAction.Word, words) | ||||||
|  | 	} | ||||||
| 	return fmt.Sprintf(GuesserSimplePrompt, clueAction.Word, words) | 	return fmt.Sprintf(GuesserSimplePrompt, clueAction.Word, words) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -573,34 +584,20 @@ func (b *Bot) BuildSimpleMimePrompt(room *models.Room) string { | |||||||
| 			theirwords = append(theirwords, card.Word) | 			theirwords = append(theirwords, card.Word) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return fmt.Sprintf(MimeSimplePrompt, ourwords, theirwords, blackWord, room.BlueCounter, room.RedCounter) | 	if strings.EqualFold(room.Settings.Language, "ru") { | ||||||
|  | 		return fmt.Sprintf(MimeSimplePromptRU, ourwords, theirwords, blackWord) | ||||||
|  | 	} | ||||||
|  | 	return fmt.Sprintf(MimeSimplePrompt, ourwords, theirwords, blackWord) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (b *Bot) BuildPrompt(room *models.Room) string { | func (b *Bot) BuildPrompt(room *models.Room) string { | ||||||
| 	if b.Role == "" { | 	if b.Role == "" { | ||||||
| 		return "" | 		return "" | ||||||
| 	} | 	} | ||||||
| 	// toText := make(map[string]any) |  | ||||||
| 	// toText["backlog"] = room.ActionHistory |  | ||||||
| 	// // mime sees all colors; |  | ||||||
| 	// // guesser sees only revealed ones |  | ||||||
| 	// if b.Role == models.UserRoleMime { |  | ||||||
| 	// 	toText["cards"] = room.Cards |  | ||||||
| 	// } |  | ||||||
| 	// data, err := json.Marshal(toText) |  | ||||||
| 	// if err != nil { |  | ||||||
| 	// 	b.log.Error("failed to marshal", "error", err) |  | ||||||
| 	// 	return "" |  | ||||||
| 	// } |  | ||||||
| 	// Escape the JSON string for inclusion in another JSON field |  | ||||||
| 	// escapedData := strings.ReplaceAll(string(data), `"`, `\\"`) |  | ||||||
| 	if b.Role == models.UserRoleMime { | 	if b.Role == models.UserRoleMime { | ||||||
| 		// return fmt.Sprintf(MimeSimplePrompt, b.Team, b.Team, room.BlueCounter, room.RedCounter, escapedData) |  | ||||||
| 		// return fmt.Sprintf(MimePrompt, b.Team, b.Team, room.BlueCounter, room.RedCounter, escapedData) |  | ||||||
| 		return b.BuildSimpleMimePrompt(room) | 		return b.BuildSimpleMimePrompt(room) | ||||||
| 	} | 	} | ||||||
| 	if b.Role == models.UserRoleGuesser { | 	if b.Role == models.UserRoleGuesser { | ||||||
| 		// return fmt.Sprintf(GuesserPrompt, b.Team, b.Team, room.BlueCounter, room.RedCounter, escapedData) |  | ||||||
| 		return b.BuildSimpleGuesserPrompt(room) | 		return b.BuildSimpleGuesserPrompt(room) | ||||||
| 	} | 	} | ||||||
| 	return "" | 	return "" | ||||||
| @@ -666,16 +663,5 @@ func (b *Bot) CallLLM(prompt string) ([]byte, error) { | |||||||
| 		b.log.Debug("llm resp", "body", string(body), "url", b.cfg.LLMConfig.URL, "attempt", attempt) | 		b.log.Debug("llm resp", "body", string(body), "url", b.cfg.LLMConfig.URL, "attempt", attempt) | ||||||
| 		return body, nil | 		return body, nil | ||||||
| 	} | 	} | ||||||
| 	entry := fmt.Sprintf("bot '%s' exceeded attempts to call llm;", b.BotName) |  | ||||||
| 	lj := models.Journal{ |  | ||||||
| 		Entry:    entry, |  | ||||||
| 		Username: b.BotName, |  | ||||||
| 		RoomID:   b.RoomID, |  | ||||||
| 	} |  | ||||||
| 	if err := repo.JournalCreate(context.Background(), &lj); err != nil { |  | ||||||
| 		b.log.Warn("failed to write to journal", "entry", lj) |  | ||||||
| 	} |  | ||||||
| 	// notify room |  | ||||||
| 	// This line should not be reached because each error path returns in the loop. |  | ||||||
| 	return nil, errors.New("unknown error in retry loop") | 	return nil, errors.New("unknown error in retry loop") | ||||||
| } | } | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ CREATE TABLE rooms ( | |||||||
|     mime_done BOOLEAN NOT NULL DEFAULT FALSE, |     mime_done BOOLEAN NOT NULL DEFAULT FALSE, | ||||||
|     is_running BOOLEAN NOT NULL DEFAULT FALSE, |     is_running BOOLEAN NOT NULL DEFAULT FALSE, | ||||||
|     is_over BOOLEAN NOT NULL DEFAULT FALSE, |     is_over BOOLEAN NOT NULL DEFAULT FALSE, | ||||||
|  |     bot_failed BOOLEAN NOT NULL DEFAULT FALSE, | ||||||
|     team_won TEXT NOT NULL DEFAULT '', |     team_won TEXT NOT NULL DEFAULT '', | ||||||
|     room_link TEXT NOT NULL DEFAULT '' |     room_link TEXT NOT NULL DEFAULT '' | ||||||
| ); | ); | ||||||
|   | |||||||
| @@ -178,6 +178,8 @@ type Room struct { | |||||||
| 	BotMap        map[string]BotPlayer `db:"-"` | 	BotMap        map[string]BotPlayer `db:"-"` | ||||||
| 	LogJournal    []Journal            `db:"-"` | 	LogJournal    []Journal            `db:"-"` | ||||||
| 	Settings      GameSettings         `db:"-"` | 	Settings      GameSettings         `db:"-"` | ||||||
|  | 	// | ||||||
|  | 	BotFailed bool `db:"bot_failed"` | ||||||
| } | } | ||||||
|  |  | ||||||
| func (r *Room) FindColor(word string) (WordColor, bool) { | func (r *Room) FindColor(word string) (WordColor, bool) { | ||||||
|   | |||||||
| @@ -15,6 +15,20 @@ type RoomsRepo interface { | |||||||
| 	RoomCreate(ctx context.Context, room *models.Room) error | 	RoomCreate(ctx context.Context, room *models.Room) error | ||||||
| 	RoomDeleteByID(ctx context.Context, id string) error | 	RoomDeleteByID(ctx context.Context, id string) error | ||||||
| 	RoomUpdate(ctx context.Context, room *models.Room) error | 	RoomUpdate(ctx context.Context, room *models.Room) error | ||||||
|  | 	RoomSetBotFailed(ctx context.Context, roomID string) error | ||||||
|  | 	RoomUnSetBotFailed(ctx context.Context, roomID string) error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *RepoProvider) RoomSetBotFailed(ctx context.Context, roomID string) error { | ||||||
|  | 	db := getDB(ctx, p.DB) | ||||||
|  | 	_, err := db.ExecContext(ctx, "UPDATE rooms SET bot_failed = true WHERE id = ?", roomID) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *RepoProvider) RoomUnSetBotFailed(ctx context.Context, roomID string) error { | ||||||
|  | 	db := getDB(ctx, p.DB) | ||||||
|  | 	_, err := db.ExecContext(ctx, "UPDATE rooms SET bot_failed = false WHERE id = ?", roomID) | ||||||
|  | 	return err | ||||||
| } | } | ||||||
|  |  | ||||||
| func (p *RepoProvider) RoomList(ctx context.Context) ([]*models.Room, error) { | func (p *RepoProvider) RoomList(ctx context.Context) ([]*models.Room, error) { | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								todos.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								todos.md
									
									
									
									
									
								
							| @@ -21,8 +21,8 @@ | |||||||
| - redo card .revealed use: it should mean that card is revealed for everybody, while mime should be able to see cards as is; + | - redo card .revealed use: it should mean that card is revealed for everybody, while mime should be able to see cards as is; + | ||||||
| - better styles and fluff; | - better styles and fluff; | ||||||
| - common auth system between sites; | - common auth system between sites; | ||||||
| - signup vs login; | - signup vs login; + | ||||||
| - passwords (to room and to login); | - passwords (to room and to login); + | ||||||
| === | === | ||||||
| - show in backlog (and with that in prompt to llm) how many cards are left to open, also additional comment: if guess was right; | - show in backlog (and with that in prompt to llm) how many cards are left to open, also additional comment: if guess was right; | ||||||
| - gameover to backlog; | - gameover to backlog; | ||||||
| @@ -33,7 +33,7 @@ | |||||||
| - possibly turn markings into parts of names of users (first three letters?); + | - possibly turn markings into parts of names of users (first three letters?); + | ||||||
| - at game creation list languages and support them at backend; + | - at game creation list languages and support them at backend; + | ||||||
| - sql ping goroutine with reconnect on fail; + | - sql ping goroutine with reconnect on fail; + | ||||||
| - player stats: played games, lost, won, rating elo, opened opposite words, opened white words, opened black words. | - player stats: played games, lost, won, rating elo, opened opposite words, opened white words, opened black words. + | ||||||
| - at the end of the game, all colors should be revealed; | - at the end of the game, all colors should be revealed; | ||||||
| - tracing; | - tracing; | ||||||
|  |  | ||||||
| @@ -91,5 +91,5 @@ | |||||||
| - mime sees the clue input out of turn; (eh) | - mime sees the clue input out of turn; (eh) | ||||||
| - there is a problem of two timers, they both could switch turn, but it is not easy to stop them from llmapi or handlers. + | - there is a problem of two timers, they both could switch turn, but it is not easy to stop them from llmapi or handlers. + | ||||||
| - journal still does not work; + | - journal still does not work; + | ||||||
| - lose/win game; then exit room (while being the creator), then press to stats -> cannot find session in db, although cookie in place and session in db; | - lose/win game; then exit room (while being the creator), then press to stats -> cannot find session in db, although cookie in place and session in db; + | ||||||
| - exit endpoints delets player from db; | - exit endpoints delets player from db; + | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Grail Finder
					Grail Finder