# Créer un quiz éducatif

> Créez Pocket Quiz avec SkillKit en trois leçons : une réponse, deux langues, puis un jeu avec sons et score par joueur. Ensuite, publiez-le.

Source: https://docs.thalovant.com/fr/developers/skillkit-tutorial/

---
{/* Last Edit: Codex - 2026-10-05 - Motive: Align the French SkillKit guides with the tested 0.24.2 tutorial and public helpers. */}

Créez **Pocket Quiz**, un jeu vocal qui pose une question, propose trois choix et explique la réponse. Vous allez le faire parler, lui apprendre le français, le transformer en jeu avec des sons et un score distinct pour chaque joueur, puis l'empaqueter pour un hub.

Prévoyez environ 15 minutes pour les deux premières leçons après l’installation des dépendances, puis avancez à votre rythme pour le jeu et le service. Il suffit de reconnaître une méthode Python et une chaîne de texte; le guide explique chaque nouvel élément au moment de l’utiliser.

Chaque leçon ajoute une idée à un programme qui fonctionne. Vous l'exécutez, vous lisez ce qu'il dit, vous changez une chose et vous l'exécutez de nouveau. Aucun hub, aucun compte ni aucun microphone n'est nécessaire avant la toute fin.

## Ce que vous allez créer

Voici une partie du jeu terminé. Ce sont des paroles prononcées, et non des commandes de terminal :

```text
You: play pocket quiz
Quiz: Let’s play Pocket Quiz! Answer with just one, two, or three.
Quiz: Question 1. How many legs does a butterfly have?
      One: Four. Two: Six. Three: Eight.
You: two
Quiz: That’s right! Butterflies are insects, and insects have six legs.
      Say next for the next question, or again to hear this one.
```

| Leçon | Vous ajoutez | Vous voyez |
| --- | --- | --- |
| 1 | Une réponse | Une première phrase, puis la vôtre |
| 2 | L'anglais et le français | La même compétence qui répond dans les deux langues |
| 3 | Le jeu, les sons et les scores | Trois questions, une explication après chaque réponse, un score |

Ensuite, vous construisez le paquet installable et vous le placez sur un hub de test.

## Préparer votre ordinateur

Il vous faut Python **3.11 ou une version plus récente**, un éditeur de texte et un terminal. Les commandes sont pour Bash sous Linux ou macOS; sous Windows, utilisez WSL.

[Téléchargez les leçons](/downloads/skillkit-pocket-quiz.zip?v=7c67a05bb60ea22a), extrayez le fichier ZIP, ouvrez un terminal dans le dossier `skillkit-pocket-quiz` et donnez au projet son propre environnement Python :

```bash
python3 -m venv .venv
source .venv/bin/activate
```

Gardez ce terminal ouvert. Le dossier contient le quiz terminé et `checkpoints.py`, qui crée une nouvelle copie du projet pour chaque leçon et n'écrase jamais une copie que vous avez déjà faite. Les leçons utilisent **SkillKit 0.24.2**. OVOS est la partie qui écoute et qui parle; SkillKit est le petit ensemble de briques que ce code utilise pour travailler avec OVOS.

## Leçon 1 : le faire parler

```bash
python checkpoints.py 1 --install
cd lessons/1/thalovant-skill-pocket-quiz
python -m thalovant_skill_pocket_quiz.replay
```

```text
en-US: Pocket Quiz asks three little questions.
fr-FR: Pocket Quiz asks three little questions.
```

Pour l'instant, c'est toute la compétence. Ouvrez `thalovant_skill_pocket_quiz/__init__.py` :

```python
class PocketQuizSkill(ThalovantSkill):
    def reply(self, utterance, lang, context):
        return "Pocket Quiz asks three little questions."
```

`reply` retourne le texte de ce premier aperçu. La leçon 2 ajoute la méthode qui répond à une commande vocale. Changez la phrase, enregistrez le fichier et relancez le replay. Vos mots reviennent. La ligne française est encore en anglais parce que rien n'est encore traduit; c'est l'objet de la leçon 2.

Lancez maintenant les tests :

```bash
python -m pytest -q
```

Un test échoue : `tests/test_lesson.py` attend encore l'ancienne phrase. Mettez-y aussi votre nouvelle phrase et relancez les tests jusqu'à ce qu'ils réussissent. Quand vous changez ce que dit un programme, son test doit le dire aussi.

## Leçon 2 : lui donner deux langues

```bash
cd ../../..
python checkpoints.py 2 --install
cd lessons/2/thalovant-skill-pocket-quiz
python -m thalovant_skill_pocket_quiz.replay
```

```text
en-US: Pocket Quiz asks three little questions. Say play pocket quiz to play.
fr-FR: Pocket Quiz pose trois petites questions. Dis démarre pocket quiz pour jouer.
```

Deux choses ont changé. La phrase est sortie du code pour aller dans un **fichier de dialogue**, un par langue :

```text
thalovant_skill_pocket_quiz/locale/en-US/dialog/preview.dialog
thalovant_skill_pocket_quiz/locale/fr-FR/dialog/preview.dialog
```

Et la compétence a reçu une **intention** : un fichier de phrases d'exemple. Quand quelqu'un prononce l'une d'elles, OVOS appelle le gestionnaire.

```text
locale/en-US/intents/pocket_quiz.start.intent   →  play pocket quiz
locale/fr-FR/intents/pocket_quiz.start.intent   →  démarre pocket quiz
```

Le code qui les relie est court :

```python
    def reply(self, utterance, lang, context):
        return self.dialog("preview", lang)

    @intent_handler("pocket_quiz.start.intent")
    def handle_start(self, message):
        lang = self.lang_of(message)
        self.speak_to(message, self.reply(self.utterance(message), lang, self.context_of(message)))
```

`self.dialog` choisit la ligne d'une langue. `self.lang_of(message)` lit la langue dans le message : une question en français obtient donc une réponse en français. `self.speak_to(message, text)` la dit dans la pièce d'où vient la demande. Remarquez que le code ne mentionne jamais l'anglais ni le français.

Une variante régionale fonctionne sans autre dossier. Demandez le français canadien :

```bash
python -m thalovant_skill_pocket_quiz.replay fr-CA
```

**Essayez un changement.** Ajoutez `begin pocket quiz` sur sa propre ligne dans le fichier d'intention anglais, puis créez `tests/test_my_phrase.py` :

```python
from thalovant_skill_pocket_quiz import PocketQuizSkill

def test_my_new_start_phrase():
    assert PocketQuizSkill().locale_resources.matches_literal_intent(
        "begin pocket quiz", "pocket_quiz.start", "en-US"
    )
```

Lancez `python -m pytest -q` : un test de plus réussit. Gardez le nom de la compétence dans la phrase, pour qu'elle ait un rôle clair parmi les autres compétences d'un hub.

## Leçon 3 : créer le jeu

```bash
cd ../../..
python checkpoints.py 3 --install
cd lessons/3/thalovant-skill-pocket-quiz
python -m thalovant_skill_pocket_quiz.replay
python -m thalovant_skill_pocket_quiz.replay --lang fr-FR
python -m pytest -q
```

Le replay joue maintenant une partie complète : trois questions, une explication après chaque réponse, le nom de chaque signal sonore et le score. La partie en anglais répond two, one, puis three, et se termine par **3 out of 3**; la partie en français répond deux, un, trois.

La compétence terminée tient en trois fichiers dans le dossier `thalovant_skill_pocket_quiz` :

| Fichier | Rôle |
| --- | --- |
| `__init__.py` | Parler à OVOS : recevoir les commandes, parler, jouer un signal sonore, s'arrêter. |
| `game.py` | Garder les questions et le score, et choisir la réponse suivante. |
| `locale/<language>/questions.json` | Les questions, les choix, les réponses et les explications. |

Ouvrez la première question dans `locale/en-US/questions.json` :

```json
{
  "question": "How many legs does a butterfly have?",
  "choices": ["Four", "Six", "Eight"],
  "answer": 1,
  "explanation": "Butterflies are insects, and insects have six legs."
}
```

Python compte à partir de **zéro** : `"answer": 1` est donc le deuxième choix, Six. Le joueur dit « two »; le jeu compare cette réponse avec la position 1.

**Essayez un changement.** Remplacez une question et son explication dans les deux fichiers de langue. Gardez trois choix et une réponse de 0 à 2, mettez à jour le test qui vérifie cette question et relancez le replay.

### Séparer la partie de chaque joueur

Alex a répondu à deux questions pendant que Sam vient tout juste de commencer. Un seul score partagé mélangerait leurs parties. L'**identifiant de session** de chaque message est le nom inscrit sur la feuille de score de ce joueur : `SessionStateStore`, dans `game.py`, garde une partie par identifiant et oublie une partie après 90 secondes sans réponse. `stop_session` termine la partie d'un joueur; `stop` les termine toutes quand OVOS le demande.

Les tests couvrent deux joueurs en même temps, une partie qui expire, un Stop pour un seul joueur, et une phrase comme « set a timer for one minute » laissée à une autre compétence.

### Entendre les signaux sonores

La compétence fournit trois courts fichiers WAV :

| Signal | Signification |
| --- | --- |
| `correct.wav` | Vous avez trouvé la réponse. |
| `try-again.wav` | Pas cette fois-ci. Écoutez l'explication, puis dites next. |
| `finish.wav` | Le quiz est terminé. |

**Bonne réponse**

<audio controls preload="none" aria-label="Son de bonne réponse"><source src="/downloads/pocket-quiz/correct.wav?v=80ed0c513e4e65b2" type="audio/wav" /></audio>

**Mauvaise réponse**

<audio controls preload="none" aria-label="Son de mauvaise réponse"><source src="/downloads/pocket-quiz/try-again.wav?v=8aa563c977edea33" type="audio/wav" /></audio>

**Quiz terminé**

<audio controls preload="none" aria-label="Son de fin du quiz"><source src="/downloads/pocket-quiz/finish.wav?v=5820260ea37ec8fe" type="audio/wav" /></audio>

Pour les entendre pendant le replay, ajoutez `--play-sounds`. Sur un hub, `self.play_audio(...)` envoie le signal à l'appareil qui a fait la demande, et le paramètre `sounds_enabled` désactive les signaux. `tools/generate_sounds.py` montre comment les signaux ont été créés, si vous voulez d'autres notes.

### Laisser le temps de réfléchir

Ouvrez `locale/fr-FR/dialog/question.ssml` à côté de `question.dialog`. Les deux
contiennent les mêmes mots; le jumeau `.ssml` ajoute `<break time="250ms"/>`
entre les choix. Les fichiers anglais font de même. Une voix compatible fait
une courte pause, tandis que l’écran et le replay gardent du texte ordinaire.

Dans `initialize`, la compétence passe `dialog=self.dialog` à `Quiz`. SkillKit
trouve ainsi la traduction, remplit les valeurs de façon sûre et conserve les
deux formes de parole. Le jeu fonctionne toujours avec un lecteur de texte
ordinaire pendant les replays. Remplacez les trois pauses par `400ms`. Mettez
aussi à jour la pause attendue dans `tests/test_ovos.py` : ce test vérifie que
la question prononcée contient les pauses choisies. Lancez les tests, puis
essayez sur votre haut-parleur de test. L’option sonore du replay joue
seulement les signaux; elle ne synthétise pas ces phrases.
[Le guide vocal](/fr/developers/writing-a-skill/#ajouter-des-pauses-et-guider-la-prononciation)
explique les fichiers jumeaux et les outils Python.

### Le tester comme OVOS l'exécute

Les tests du jeu vérifient si le code a choisi la bonne réponse. `tests/test_ovos.py` vérifie si OVOS transmet la commande et la parole : il démarre la vraie compétence sur un bus de test, envoie `play pocket quiz`, et vérifie que la réponse revient dans la bonne langue et que le signal va au bon joueur. Ce test s'est exécuté avec `pytest` plus haut. [Le guide de référence](/fr/developers/writing-a-skill/#solliciter-le-vrai-bus-ovos) présente plus en détail le bus de test et MiniCroft.

## Le publier

Depuis le dossier de la leçon 3 :

```bash
thalovant-skillkit check
python -m build
```

`check` valide vos ressources et cherche les phrases auxquelles une autre compétence pourrait aussi répondre. Lisez les avertissements avant de continuer. `build` écrit le **wheel** installable et une archive des sources dans `dist/`. Utilisez la [vérification du paquet construit](/fr/developers/writing-a-skill/#vérifier-ce-que-vous-avez-construit) de SkillKit pour confirmer que les questions, les dialogues et les sons sont inclus.

Pour voir le wheel fonctionner hors de votre projet, installez-le dans un environnement jetable et jouez-y une partie en français :

```bash
quiz_wheel="$(pwd)/dist/thalovant_skill_pocket_quiz-0.1.0-py3-none-any.whl"
quiz_check_dir="$(mktemp -d)"
python -m venv "$quiz_check_dir/venv"
"$quiz_check_dir/venv/bin/python" -m pip install --pre "$quiz_wheel"
(
  cd "$quiz_check_dir"
  "$quiz_check_dir/venv/bin/python" -m thalovant_skill_pocket_quiz.replay --lang fr-FR
)
```

### Le placer sur un hub de test

Suivez [Ajouter votre propre compétence](/fr/manage/add-your-own-skill/) pour l'installer à partir d'un paquet publié ou d'un dépôt Git; le hub va le chercher à cet endroit, et non sur votre portable. Ensuite, dites `play pocket quiz`, répondez `two` et dites `next`. Recommencez en français avec `démarre pocket quiz`. Vérifiez les explications, les signaux sonores, le score et Stop, avec deux clients si possible.

## Facultatif : interroger un service de questions

La leçon 4 du téléchargement récupère les questions auprès d'un petit service Web et se replie sur les questions incluses dans le paquet quand le service est lent, erroné ou absent. C'est la forme de toute compétence qui appelle quelque chose en ligne.

```bash
cd ../../..
python checkpoints.py 4 --install
cd lessons/4/thalovant-skill-pocket-quiz
python -m thalovant_skill_pocket_quiz.demo_provider --port 8765
```

Ce terminal sert maintenant des questions. Dans un deuxième terminal, activez le même `.venv`, entrez dans le dossier de la leçon 4 et lancez :

```bash
python -m thalovant_skill_pocket_quiz.replay --provider http://127.0.0.1:8765/questions
```

La première question devient « Which animal is a mammal? ». Arrêtez le service avec **Ctrl+C**, relancez le même replay, et la question du papillon incluse dans le paquet revient. `provider.py` est la partie à lire : le `JsonServiceClient` de SkillKit envoie la requête, limite le temps d'attente et la quantité de données acceptée, et laisse tranquille pendant un moment un service qui échoue. [Garder votre compétence réactive](/fr/developers/skillkit-runtime/#donner-un-budget-de-temps-au-travail-en-ligne) explique ces éléments.

## Ajouter une troisième langue

Copiez `locale/en-US` dans un nouveau dossier, par exemple `locale/es-ES`. Traduisez les questions, les fichiers de dialogue et leurs jumeaux `.ssml`, les phrases d'intention et les mots de réponse, et gardez tels quels les noms entre accolades comme `{score}`. Ajoutez `es-ES` à `locale/supported.json`, puis ajoutez des tests qui jouent une partie dans cette langue. Les variantes régionales comme `fr-CA` fonctionnent déjà sans dossier; ajoutez-en un seulement pour une formulation différente, comme le montre le [guide de référence](/fr/developers/writing-a-skill/#prendre-en-charge-les-variantes-régionales).

## C'est terminé quand

- Les trois leçons s'exécutent et leurs tests réussissent.
- Le quiz explique les bonnes et les mauvaises réponses en anglais et en français.
- Deux joueurs gardent des scores distincts, et Stop ne touche que le joueur qui l'a dit.
- Les signaux sonores jouent lorsqu'ils sont activés; le replay et les tests restent silencieux, sauf si on le leur demande.
- `thalovant-skillkit check` et `python -m build` réussissent, et le wheel joue une partie depuis un autre environnement.
- Un hub de test répond et joue le signal sonore sur le client qui a fait la demande.

## En cas de problème

| Ce que vous voyez | Prochaine étape |
| --- | --- |
| `python3` est introuvable | Installez Python, rouvrez le terminal et vérifiez `python3 --version`. |
| Le dossier de la leçon existe déjà | `checkpoints.py` n'écrase jamais rien; supprimez le dossier ou indiquez un nouveau chemin. |
| Python importe une leçon précédente | Activez le `.venv` de ce projet, entrez dans le dossier de la leçon en cours et relancez `checkpoints.py` avec `--install`. |
| Un dialogue ou une question modifié est ignoré | Redémarrez le replay; les ressources sont mises en cache pendant l'exécution d'un programme. |
| Le replay n'a pas de son | Ajoutez `--play-sounds` et vérifiez la sortie audio de votre ordinateur. Le silence est le comportement par défaut. |
| Une réponse en français revient en anglais | Vérifiez la langue du message et les fichiers `fr-FR`. |
| Le hub ne trouve pas la compétence | Vérifiez son état d'installation, la version du paquet et le point d'entrée dans `pyproject.toml`. |

## Pour aller plus loin

[Ce que SkillKit vous offre](/fr/developers/skillkit-capabilities/) vous aide à choisir un outil selon votre objectif. [Écrire une compétence](/fr/developers/writing-a-skill/) est le guide de référence, et [Garder votre compétence réactive](/fr/developers/skillkit-runtime/) couvre les services, les bibliothèques de sons et les caches.
