ubumuntu-api / api /data /exercises.py
Macbook
Deploy with Groq Whisper ASR
4ac15b2
"""
Speech Therapy Exercises Database
Categories: Fundamentals, Speech Practice
Languages: English (en), French (fr)
"""
from typing import List, Dict, Optional
from pydantic import BaseModel
from enum import Enum
class ExerciseType(str, Enum):
# Fundamentals
PHONEME = "phoneme"
# Speech Practice
WORD_REPETITION = "word_repetition"
SENTENCE_READING = "sentence_reading"
TONGUE_TWISTER = "tongue_twister"
class Difficulty(str, Enum):
EASY = "easy"
MEDIUM = "medium"
HARD = "hard"
class Category(BaseModel):
id: str
name: Dict[str, str]
description: Dict[str, str]
icon: str
subcategories: List[str]
class Exercise(BaseModel):
id: str
type: ExerciseType
category: str
subcategory: str
difficulty: Difficulty
title: Dict[str, str]
target_text: Dict[str, str]
instructions: Dict[str, str]
phoneme_focus: Optional[List[str]] = None
# =============================================================================
# CATEGORIES
# =============================================================================
CATEGORIES: List[Dict] = [
{
"id": "fundamentals",
"name": {"en": "Fundamentals", "fr": "Fondamentaux"},
"description": {
"en": "Master specific sounds and phonemes",
"fr": "Maîtrisez des sons et phonèmes spécifiques"
},
"icon": "🎯",
"subcategories": ["phoneme"]
},
{
"id": "speech_practice",
"name": {"en": "Speech Practice", "fr": "Pratique de la Parole"},
"description": {
"en": "Practice words, sentences, and tongue twisters",
"fr": "Pratiquez des mots, des phrases et des virelangues"
},
"icon": "📖",
"subcategories": ["word_repetition", "sentence_reading", "tongue_twister"]
}
]
SUBCATEGORIES: Dict[str, Dict] = {
"phoneme": {
"name": {"en": "Phoneme Practice", "fr": "Pratique des Phonèmes"},
"description": {"en": "Master specific sounds like R, S, TH", "fr": "Maîtrisez des sons spécifiques comme R, S, CH"}
},
"word_repetition": {
"name": {"en": "Word Repetition", "fr": "Répétition de Mots"},
"description": {"en": "Repeat words clearly", "fr": "Répétez les mots clairement"}
},
"sentence_reading": {
"name": {"en": "Sentence Reading", "fr": "Lecture de Phrases"},
"description": {"en": "Read complete sentences", "fr": "Lisez des phrases complètes"}
},
"tongue_twister": {
"name": {"en": "Tongue Twisters", "fr": "Virelangues"},
"description": {"en": "Challenge yourself with tricky phrases", "fr": "Défiez-vous avec des phrases difficiles"}
}
}
# =============================================================================
# EXERCISES DATABASE
# =============================================================================
EXERCISES: List[Dict] = [
# =========================================================================
# FUNDAMENTALS - Phoneme Practice
# =========================================================================
{
"id": "phon-r-001",
"type": "phoneme",
"category": "fundamentals",
"subcategory": "phoneme",
"difficulty": "medium",
"title": {"en": "R Sound Practice", "fr": "Pratique du Son R"},
"target_text": {"en": "Run, red, rain, rabbit, river", "fr": "Rue, rouge, rire, rat, rivière"},
"instructions": {"en": "Focus on the 'R' sound at the beginning of each word. Let your tongue vibrate slightly.", "fr": "Concentrez-vous sur le son 'R' au début de chaque mot. Laissez votre langue vibrer légèrement."},
"phoneme_focus": ["R"]
},
{
"id": "phon-s-001",
"type": "phoneme",
"category": "fundamentals",
"subcategory": "phoneme",
"difficulty": "easy",
"title": {"en": "S Sound Practice", "fr": "Pratique du Son S"},
"target_text": {"en": "Sun, see, song, seven, smile", "fr": "Sol, sac, sept, soir, sourire"},
"instructions": {"en": "Make a hissing sound like a snake. Keep your tongue behind your teeth.", "fr": "Faites un son sifflant comme un serpent. Gardez la langue derrière les dents."},
"phoneme_focus": ["S"]
},
{
"id": "phon-th-001",
"type": "phoneme",
"category": "fundamentals",
"subcategory": "phoneme",
"difficulty": "hard",
"title": {"en": "TH Sound Practice", "fr": "Pratique du Son TH"},
"target_text": {"en": "Think, this, that, three, thank", "fr": "Think, this, that, three, thank"},
"instructions": {"en": "Put your tongue between your teeth and blow air. This sound doesn't exist in French!", "fr": "Mettez la langue entre les dents et soufflez. Ce son n'existe pas en français!"},
"phoneme_focus": ["TH"]
},
{
"id": "phon-l-001",
"type": "phoneme",
"category": "fundamentals",
"subcategory": "phoneme",
"difficulty": "easy",
"title": {"en": "L Sound Practice", "fr": "Pratique du Son L"},
"target_text": {"en": "Love, light, look, lion, lake", "fr": "Lune, livre, lac, lion, lait"},
"instructions": {"en": "Touch the roof of your mouth with the tip of your tongue.", "fr": "Touchez le palais avec le bout de la langue."},
"phoneme_focus": ["L"]
},
{
"id": "phon-ch-001",
"type": "phoneme",
"category": "fundamentals",
"subcategory": "phoneme",
"difficulty": "medium",
"title": {"en": "CH Sound Practice", "fr": "Pratique du Son CH"},
"target_text": {"en": "Chair, cheese, chicken, chocolate, church", "fr": "Chat, chien, chose, chou, chaud"},
"instructions": {"en": "Push air through your teeth with rounded lips.", "fr": "Poussez l'air entre vos dents avec les lèvres arrondies."},
"phoneme_focus": ["CH", "SH"]
},
# =========================================================================
# SPEECH PRACTICE - Word Repetition
# =========================================================================
{
"id": "word-001",
"type": "word_repetition",
"category": "speech_practice",
"subcategory": "word_repetition",
"difficulty": "easy",
"title": {"en": "Greetings", "fr": "Salutations"},
"target_text": {"en": "Hello, Goodbye, Please, Thank you", "fr": "Bonjour, Au revoir, S'il vous plaît, Merci"},
"instructions": {"en": "Say each word clearly with a pause between them.", "fr": "Dites chaque mot clairement avec une pause entre eux."},
},
{
"id": "word-002",
"type": "word_repetition",
"category": "speech_practice",
"subcategory": "word_repetition",
"difficulty": "easy",
"title": {"en": "Numbers 1-10", "fr": "Chiffres 1-10"},
"target_text": {"en": "One, two, three, four, five, six, seven, eight, nine, ten", "fr": "Un, deux, trois, quatre, cinq, six, sept, huit, neuf, dix"},
"instructions": {"en": "Count clearly and steadily. Don't rush!", "fr": "Comptez clairement et régulièrement. Ne vous précipitez pas!"},
},
{
"id": "word-003",
"type": "word_repetition",
"category": "speech_practice",
"subcategory": "word_repetition",
"difficulty": "medium",
"title": {"en": "Days of the Week", "fr": "Jours de la Semaine"},
"target_text": {"en": "Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday", "fr": "Lundi, Mardi, Mercredi, Jeudi, Vendredi, Samedi, Dimanche"},
"instructions": {"en": "Say each day with emphasis on the first syllable.", "fr": "Dites chaque jour en accentuant la première syllabe."},
},
# =========================================================================
# SPEECH PRACTICE - Sentence Reading
# =========================================================================
{
"id": "sent-001",
"type": "sentence_reading",
"category": "speech_practice",
"subcategory": "sentence_reading",
"difficulty": "easy",
"title": {"en": "Simple Introduction", "fr": "Introduction Simple"},
"target_text": {"en": "Hello, my name is... Nice to meet you!", "fr": "Bonjour, je m'appelle... Enchanté!"},
"instructions": {"en": "Replace '...' with your name. Speak clearly and smile!", "fr": "Remplacez '...' par votre nom. Parlez clairement et souriez!"},
},
{
"id": "sent-002",
"type": "sentence_reading",
"category": "speech_practice",
"subcategory": "sentence_reading",
"difficulty": "easy",
"title": {"en": "How Are You?", "fr": "Comment Allez-Vous?"},
"target_text": {"en": "How are you today? I am fine, thank you.", "fr": "Comment allez-vous aujourd'hui? Je vais bien, merci."},
"instructions": {"en": "Practice this common conversation with natural intonation.", "fr": "Pratiquez cette conversation courante avec une intonation naturelle."},
},
{
"id": "sent-003",
"type": "sentence_reading",
"category": "speech_practice",
"subcategory": "sentence_reading",
"difficulty": "medium",
"title": {"en": "Weather Talk", "fr": "Parler de la Météo"},
"target_text": {"en": "The weather is beautiful today. The sun is shining brightly.", "fr": "Il fait beau aujourd'hui. Le soleil brille."},
"instructions": {"en": "Read the sentences with expression. Sound happy about the weather!", "fr": "Lisez avec expression. Montrez que vous êtes content du temps!"},
},
{
"id": "sent-004",
"type": "sentence_reading",
"category": "speech_practice",
"subcategory": "sentence_reading",
"difficulty": "hard",
"title": {"en": "At the Restaurant", "fr": "Au Restaurant"},
"target_text": {"en": "I would like to order the fish, please. Could I also have some water?", "fr": "Je voudrais commander le poisson, s'il vous plaît. Puis-je aussi avoir de l'eau?"},
"instructions": {"en": "Practice polite restaurant phrases. Speak clearly to be understood.", "fr": "Pratiquez les phrases polies au restaurant. Parlez clairement pour être compris."},
},
# =========================================================================
# SPEECH PRACTICE - Tongue Twisters
# =========================================================================
{
"id": "twist-001",
"type": "tongue_twister",
"category": "speech_practice",
"subcategory": "tongue_twister",
"difficulty": "medium",
"title": {"en": "She Sells Seashells", "fr": "Les Chaussettes de l'Archiduchesse"},
"target_text": {"en": "She sells seashells by the seashore", "fr": "Les chaussettes de l'archiduchesse sont-elles sèches ou archi-sèches"},
"instructions": {"en": "Start slowly, then try to speed up while staying clear.", "fr": "Commencez lentement, puis essayez d'accélérer tout en restant clair."},
"phoneme_focus": ["S", "SH"]
},
{
"id": "twist-002",
"type": "tongue_twister",
"category": "speech_practice",
"subcategory": "tongue_twister",
"difficulty": "hard",
"title": {"en": "Peter Piper", "fr": "Un Chasseur"},
"target_text": {"en": "Peter Piper picked a peck of pickled peppers", "fr": "Un chasseur sachant chasser sait chasser sans son chien"},
"instructions": {"en": "Focus on the 'P' sounds. Keep your lips tight.", "fr": "Concentrez-vous sur les sons 'CH'. Gardez la langue stable."},
"phoneme_focus": ["P"]
},
{
"id": "twist-003",
"type": "tongue_twister",
"category": "speech_practice",
"subcategory": "tongue_twister",
"difficulty": "hard",
"title": {"en": "Red Lorry Yellow Lorry", "fr": "Trois Tortues"},
"target_text": {"en": "Red lorry, yellow lorry, red lorry, yellow lorry", "fr": "Trois tortues trottaient sur trois toits très étroits"},
"instructions": {"en": "Practice the R and L sounds alternating. This is challenging!", "fr": "Pratiquez les sons T et R en alternance. C'est un défi!"},
"phoneme_focus": ["R", "L"]
},
{
"id": "twist-004",
"type": "tongue_twister",
"category": "speech_practice",
"subcategory": "tongue_twister",
"difficulty": "medium",
"title": {"en": "Unique New York", "fr": "Panier Piano"},
"target_text": {"en": "Unique New York, you know you need unique New York", "fr": "Piano panier, panier piano"},
"instructions": {"en": "Focus on the 'N' and 'Y' sounds.", "fr": "Concentrez-vous sur les sons 'P' et 'N'."},
"phoneme_focus": ["N", "Y"]
},
]
def get_all_categories() -> List[Dict]:
"""Return all exercise categories."""
return CATEGORIES
def get_subcategory_info(subcategory_id: str) -> Optional[Dict]:
"""Return information about a specific subcategory."""
return SUBCATEGORIES.get(subcategory_id)
def get_all_exercises(language: str = "en") -> List[Dict]:
"""Return all exercises in the specified language."""
exercises = []
for ex in EXERCISES:
exercises.append({
"id": ex["id"],
"type": ex["type"],
"category": ex["category"],
"subcategory": ex["subcategory"],
"difficulty": ex["difficulty"],
"title": ex["title"].get(language, ex["title"]["en"]),
"target_text": ex["target_text"].get(language, ex["target_text"]["en"]),
"instructions": ex["instructions"].get(language, ex["instructions"]["en"]),
"phoneme_focus": ex.get("phoneme_focus", [])
})
return exercises
def get_exercises_by_category(category: str, language: str = "en") -> List[Dict]:
"""Return exercises filtered by category."""
all_exercises = get_all_exercises(language)
return [ex for ex in all_exercises if ex["category"] == category]
def get_exercises_by_subcategory(subcategory: str, language: str = "en") -> List[Dict]:
"""Return exercises filtered by subcategory."""
all_exercises = get_all_exercises(language)
return [ex for ex in all_exercises if ex["subcategory"] == subcategory]
def get_exercises_by_difficulty(difficulty: str, language: str = "en") -> List[Dict]:
"""Return exercises filtered by difficulty."""
all_exercises = get_all_exercises(language)
return [ex for ex in all_exercises if ex["difficulty"] == difficulty]
def get_exercise_by_id(exercise_id: str, language: str = "en") -> Optional[Dict]:
"""Return a specific exercise by ID."""
all_exercises = get_all_exercises(language)
for ex in all_exercises:
if ex["id"] == exercise_id:
return ex
return None