package api import ( "io" "log" "net/http" "forge.cadoles.com/wpetit/kouiz/internal/store" "github.com/bornholm/genai/llm" "github.com/bornholm/genai/llm/prompt" "github.com/pkg/errors" "gorm.io/gorm" ) const systemPromptTemplate string = ` Tu es "Panda", un présentateur de jeu télévisé charismatique et plein d'énergie qui anime un jeu de question/réponse en ligne. Ta personnalité est : - Enthousiaste et dynamique : Tu t'exprimes avec beaucoup d'énergie, utilises des exclamations et des expressions colorées - Bienveillant mais taquin : Tu encourages tous les joueurs tout en les chambrant gentiment - Théâtral : Tu dramatises les situations, crées du suspense même pour les scores - Métaphoriquement créatif : Tu utilises des comparaisons amusantes liées au monde du panda, de la nature ou de la culture pop Ton style : - Utilise des expressions comme "Extraordinaire !", "Incroyable retournement de situation !" - Varie tes présentations : parfois comme un commentateur sportif, parfois comme un chroniqueur dramatique - Ajoute des petites blagues ou références pop culture - Maintiens le suspense même pour des écarts de score importants - Format attendu : Présente les situations de manière narrative et engageante. ` const leaderboardPromptTemplate string = ` Fais le bilan des scores du jeu de manière captivante et divertissante en 1 court paragraphe. ## Liste des joueurs {{ range $rank, $player := .Players }} ### {{ $rank }}. {{ $player.Name }} - **Score:** {{ $player.Score }} {{ end }} ` func (h *Handler) getLeaderboardPresentation(w http.ResponseWriter, r *http.Request) { ctx := r.Context() systemPrompt, err := prompt.Template[any](systemPromptTemplate, nil) if err != nil { log.Printf("[ERROR] %+v", errors.WithStack(err)) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } var players []*store.Player err = h.store.Do(ctx, func(db *gorm.DB) error { err := db.Model(&store.Player{}). Select("id", "name", "score"). Order("score DESC").Find(&players). Error if err != nil { return errors.WithStack(err) } return nil }) if err != nil { log.Printf("[ERROR] %+v", errors.WithStack(err)) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } userPrompt, err := prompt.Template(leaderboardPromptTemplate, struct { Players []*store.Player }{ Players: players, }) if err != nil { log.Printf("[ERROR] %+v", errors.WithStack(err)) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } res, err := h.llm.ChatCompletion(ctx, llm.WithMessages( llm.NewMessage(llm.RoleSystem, systemPrompt), llm.NewMessage(llm.RoleUser, userPrompt), ), ) if err != nil { log.Printf("[ERROR] %+v", errors.WithStack(err)) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } if _, err := io.WriteString(w, res.Message().Content()); err != nil { log.Printf("[ERROR] %+v", errors.WithStack(err)) return } } const turnPromptTemplate string = ` Présente le tour de jeu actuel en créant du suspense et en motivant les joueurs à participer en 1 court paragraphe. ## Tour #{{ .Turn.ID }} ### Thématiques disponibles pour ce tour {{ range .Turn.Entries }} #### {{ .Category.Theme }} - **Difficulté:** {{ .Level }} - **Catégorie:** {{ .Category.Name }} - **Description de la catégorie:** {{ .Category.Description }} {{ end }} ` func (h *Handler) getTurnPresentation(w http.ResponseWriter, r *http.Request) { ctx := r.Context() systemPrompt, err := prompt.Template[any](systemPromptTemplate, nil) if err != nil { log.Printf("[ERROR] %+v", errors.WithStack(err)) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } currentTurn, err := h.store.GetQuizTurn(ctx, h.playInterval, h.playPeriod) if err != nil { log.Printf("[ERROR] %+v", errors.WithStack(err)) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } userPrompt, err := prompt.Template(turnPromptTemplate, struct { Turn *store.QuizTurn }{ Turn: currentTurn, }) if err != nil { log.Printf("[ERROR] %+v", errors.WithStack(err)) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } res, err := h.llm.ChatCompletion(ctx, llm.WithMessages( llm.NewMessage(llm.RoleSystem, systemPrompt), llm.NewMessage(llm.RoleUser, userPrompt), ), ) if err != nil { log.Printf("[ERROR] %+v", errors.WithStack(err)) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } if _, err := io.WriteString(w, res.Message().Content()); err != nil { log.Printf("[ERROR] %+v", errors.WithStack(err)) return } }