162 lines
4.8 KiB
Go
162 lines
4.8 KiB
Go
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
|
|
}
|
|
}
|