transmis au prof

This commit is contained in:
2026-04-25 21:38:17 +02:00
parent f32f127c9e
commit c75634e3e1
4 changed files with 46 additions and 0 deletions

View File

@@ -37,6 +37,9 @@ Ce projet est un POC de professeur virtuel pour enfants, avec:
- Les options TTS visibles doivent etre libellees `Voix Douce`, `Voix Rigolote`, etc.; la mention "Voix IA non humaine..." est portee par un tooltip.
- Le declenchement manuel de mini-test/exercice doit disparaitre de l'interface eleve; le programme doit etre determine par Professeur TOP.
- A prevoir cote admin: tableau par eleve et prompts/instructions personnalises pour guider Professeur TOP par eleve.
- L'ecran eleve affiche une petite card "Transmis au prof" au-dessus de la zone de saisie pour montrer le texte capte/envoye.
- Le backend ajoute une consigne de tours de parole courts pour que Professeur TOP laisse le temps a l'enfant de repondre.
- Gestion interruption a prevoir: detection de parole pendant TTS, pause audio, transcription, classification pertinent/accidentel, puis reprise courte.
- Le vrai `docker-compose.yml` de production n'est pas dans ce repo. Il est situe un niveau au-dessus sur le serveur.
- La conf nginx reelle route:
- `/api/` vers `tutor-backend:8000`

View File

@@ -20,6 +20,15 @@ Règles :
- Tu enseignes principalement le programme national français niveau primaire/cycle 3.
""".strip()
TURN_TAKING_PROMPT = """
Consignes de rythme oral:
- Fais des tours de parole courts: 1 a 3 phrases maximum, sauf demande explicite.
- Termine souvent par une question ou une consigne courte pour laisser l'enfant parler.
- Ne fais pas de longs monologues: une idee a la fois.
- Si l'eleve t'interrompt, arrete-toi, ecoute son message, puis reprends seulement si c'est utile.
- Si l'interruption semble accidentelle ou hors sujet, reponds tres brievement puis continue.
""".strip()
TTS_PROFILES = [
{
"id": "rigolote",
@@ -130,6 +139,7 @@ def build_llm_reply(db: Session, student_id: int, user_message: str) -> str:
model="gpt-4.1-mini",
input=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "system", "content": TURN_TAKING_PROMPT},
{
"role": "user",
"content": f"Contexte pédagogique:\n{context}\n\nMessage de l'élève:\n{user_message}",

View File

@@ -190,6 +190,7 @@ function TutorApp({ currentUser, onLogout }) {
})
const [messages, setMessages] = useState([])
const [currentInstruction, setCurrentInstruction] = useState('')
const [lastStudentTransmission, setLastStudentTransmission] = useState('')
const [sessionActive, setSessionActive] = useState(false)
const [currentFocusSkill, setCurrentFocusSkill] = useState(null)
const [exerciseStatus, setExerciseStatus] = useState('not-started')
@@ -288,6 +289,7 @@ function TutorApp({ currentUser, onLogout }) {
setSessionActive(false)
setAssessment(null)
setAssessmentAnswer('')
setLastStudentTransmission('')
setCurrentFocusSkill(null)
setExerciseStatus('not-started')
if (selectedStudentId) {
@@ -459,6 +461,7 @@ function TutorApp({ currentUser, onLogout }) {
}),
})
appendMessage('user', `Reponse au mini-test: ${assessmentAnswer}`)
setLastStudentTransmission(assessmentAnswer)
appendMessage('assistant', data.feedback)
setCurrentInstruction(data.feedback)
setExerciseStatus(data.correct ? 'resolved' : 'needs-review')
@@ -492,6 +495,7 @@ function TutorApp({ currentUser, onLogout }) {
setAssessment(null)
setAssessmentAnswer('')
setInput('')
setLastStudentTransmission('')
}
async function toggleSession() {
@@ -617,6 +621,7 @@ function TutorApp({ currentUser, onLogout }) {
throw new Error('Choisis un élève avant denvoyer un message.')
}
appendMessage('user', text)
setLastStudentTransmission(text)
setInput('')
setErrorMessage('')
const data = await apiFetch('/chat', {
@@ -652,6 +657,7 @@ function TutorApp({ currentUser, onLogout }) {
return
}
setLastStudentTransmission(transcript)
if (autoSend && selectedStudentId) {
setVoiceStatus('Texte reconnu, envoi automatique...')
pushAudioDebug('Envoi automatique du message transcrit')
@@ -1008,6 +1014,11 @@ function TutorApp({ currentUser, onLogout }) {
</form>
)}
<section className="student-transmission">
<span>Transmis au prof</span>
<p>{lastStudentTransmission || 'Le texte reconnu par le micro ou envoye au clavier apparaitra ici.'}</p>
</section>
<form onSubmit={assessment ? submitAssessment : sendMessage} className="composer">
<input
value={assessment ? assessmentAnswer : input}

View File

@@ -136,6 +136,28 @@ button:disabled { opacity: 0.5; cursor: not-allowed; }
text-transform: uppercase;
}
.messages { display: none; }
.student-transmission {
flex: 0 0 auto;
border: 1px solid #dbeafe;
border-radius: 14px;
background: #f8fbff;
padding: 0.7rem 0.85rem;
}
.student-transmission span {
display: block;
color: #2563eb;
font-size: 0.78rem;
font-weight: 700;
margin-bottom: 0.25rem;
text-transform: uppercase;
}
.student-transmission p {
margin: 0;
color: #14213d;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.message {
max-width: 92%;
margin-bottom: 0.45rem;