Context adj
This commit is contained in:
@@ -304,27 +304,31 @@ def start_session(
|
||||
first_asset = (assigned_lesson.get("assets") or [None])[0]
|
||||
first_section = (first_asset.get("sections") or [None])[0] if first_asset else None
|
||||
section_label = first_section["title"] if first_section else first_asset["title"] if first_asset else assigned_lesson["title"]
|
||||
message = (
|
||||
f"Bonjour {student.first_name} ! Aujourd’hui, on travaille la leçon "
|
||||
f"{assigned_lesson['title']}. Regarde la carte « {section_label} ». "
|
||||
"Dis-moi si tu comprends cette partie, ou ce qui te gêne."
|
||||
lesson_context = (
|
||||
f"Leçon courante: {assigned_lesson['title']}\n"
|
||||
f"Fiche courante: {first_asset['title'] if first_asset else 'non précisée'}\n"
|
||||
f"Card courante: {section_label}\n"
|
||||
f"Clé de contexte: {first_section.get('context_key') if first_section else 'non précisée'}\n"
|
||||
"Avancement affiché: début de leçon\n"
|
||||
"Règle: commence directement sur cette card. Ne fais pas de reprise de la dernière séance.\n"
|
||||
)
|
||||
if first_section and first_section.get("context"):
|
||||
lesson_context += f"\nTexte pédagogique de la card courante:\n{first_section['context'].strip()}"
|
||||
lesson_reply = build_lesson_reply(
|
||||
db,
|
||||
student.id,
|
||||
"La séance démarre. Présente la card courante et pose une question de compréhension.",
|
||||
lesson_context,
|
||||
)
|
||||
message = lesson_reply["reply"]
|
||||
previous_messages_count = db.query(models.Message).filter_by(student_id=student.id).count()
|
||||
if previous_messages_count:
|
||||
if previous_messages_count and not assigned_lesson:
|
||||
prompt = (
|
||||
"L’élève revient pour une nouvelle séance. Fais une courte reprise: "
|
||||
"explique où on s’était arrêté la dernière fois à partir de l’historique, "
|
||||
"puis annonce clairement ce qu'on va faire aujourd'hui. Termine par une "
|
||||
"première consigne simple."
|
||||
)
|
||||
if assigned_lesson:
|
||||
first_asset = (assigned_lesson.get("assets") or [None])[0]
|
||||
first_section = (first_asset.get("sections") or [None])[0] if first_asset else None
|
||||
section_label = first_section["title"] if first_section else first_asset["title"] if first_asset else assigned_lesson["title"]
|
||||
prompt += (
|
||||
f" La leçon active choisie par le professeur est: {assigned_lesson['title']}. "
|
||||
f"La carte affichée est: {section_label}. Parle de cette carte, pas d'une ancienne leçon."
|
||||
)
|
||||
message = build_llm_reply(db, student.id, prompt)
|
||||
db.add(models.Message(student_id=student.id, role="assistant", content=message))
|
||||
db.commit()
|
||||
|
||||
@@ -106,7 +106,7 @@ def ensure_student_mastery(db: Session, student: models.Student) -> None:
|
||||
db.commit()
|
||||
|
||||
|
||||
def get_student_context(db: Session, student_id: int) -> str:
|
||||
def get_student_context(db: Session, student_id: int, include_history: bool = True) -> str:
|
||||
student = db.query(models.Student).filter_by(id=student_id).first()
|
||||
mastery = (
|
||||
db.query(models.StudentSkillMastery, models.Skill)
|
||||
@@ -114,13 +114,15 @@ def get_student_context(db: Session, student_id: int) -> str:
|
||||
.filter(models.StudentSkillMastery.student_id == student_id)
|
||||
.all()
|
||||
)
|
||||
recent_messages = (
|
||||
db.query(models.Message)
|
||||
.filter_by(student_id=student_id)
|
||||
.order_by(models.Message.created_at.desc())
|
||||
.limit(6)
|
||||
.all()
|
||||
)
|
||||
recent_messages = []
|
||||
if include_history:
|
||||
recent_messages = (
|
||||
db.query(models.Message)
|
||||
.filter_by(student_id=student_id)
|
||||
.order_by(models.Message.created_at.desc())
|
||||
.limit(6)
|
||||
.all()
|
||||
)
|
||||
|
||||
assignment = db.query(models.StudentProgramAssignment).filter_by(student_id=student_id).first()
|
||||
lesson = get_lesson(assignment.lesson_id) if assignment else None
|
||||
@@ -142,9 +144,10 @@ def get_student_context(db: Session, student_id: int) -> str:
|
||||
lines.append(
|
||||
f"- {skill.label}: score={mastery_row.mastery_score:.1f}, confiance={mastery_row.confidence:.2f}, preuves={mastery_row.evidence_count}"
|
||||
)
|
||||
lines.append("Historique récent:")
|
||||
for message in reversed(recent_messages):
|
||||
lines.append(f"- {message.role}: {message.content}")
|
||||
if include_history:
|
||||
lines.append("Historique récent:")
|
||||
for message in reversed(recent_messages):
|
||||
lines.append(f"- {message.role}: {message.content}")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
@@ -166,7 +169,7 @@ def build_llm_reply(db: Session, student_id: int, user_message: str) -> str:
|
||||
|
||||
|
||||
def build_lesson_reply(db: Session, student_id: int, user_message: str, lesson_context: str) -> dict:
|
||||
context = get_student_context(db, student_id)
|
||||
context = get_student_context(db, student_id, include_history=False)
|
||||
response = client.responses.create(
|
||||
model="gpt-4.1-mini",
|
||||
input=[
|
||||
@@ -177,6 +180,8 @@ def build_lesson_reply(db: Session, student_id: int, user_message: str, lesson_c
|
||||
"content": (
|
||||
"Tu reçois un contexte courant de leçon lié à la card affichée. "
|
||||
"Tu dois parler uniquement de cette card, sauf si l'élève pose une question de clarification immédiate. "
|
||||
"N'utilise pas l'historique des séances précédentes pour choisir le thème de ta réponse. "
|
||||
"Ta réponse visible doit tenir dans une zone de 3 lignes: fais 1 ou 2 phrases très courtes. "
|
||||
"Si la réponse de l'élève montre clairement qu'il a compris la card courante, mets "
|
||||
"`advance_lesson_step` à true. Sinon, mets-le à false. "
|
||||
"Réponds strictement en JSON valide avec les clés `reply` et `advance_lesson_step`. "
|
||||
|
||||
@@ -627,7 +627,7 @@ function TutorApp({ currentUser, onLogout }) {
|
||||
const cleanText = text.trim()
|
||||
if (!cleanText) return ''
|
||||
const sentences = cleanText.match(/[^.!?]+[.!?]+|[^.!?]+$/g) || [cleanText]
|
||||
return sentences.slice(0, 2).join(' ').trim()
|
||||
return sentences.slice(0, 3).join(' ').trim()
|
||||
}
|
||||
|
||||
async function finishSpeechPlayback(debugMessage) {
|
||||
|
||||
@@ -318,10 +318,10 @@ button:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
.avatar {
|
||||
width: 144px;
|
||||
height: 144px;
|
||||
border-radius: 28px;
|
||||
border-radius: 0;
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
box-shadow: 0 10px 20px rgba(245, 158, 11, 0.28);
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
.avatar.speaking { animation: pulse 0.7s infinite alternate; }
|
||||
.avatar-image {
|
||||
@@ -440,7 +440,7 @@ button:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
.lesson-topbar .avatar {
|
||||
width: 92px;
|
||||
height: 92px;
|
||||
border-radius: 20px;
|
||||
border-radius: 0;
|
||||
}
|
||||
.lesson-topbar .avatar-caption {
|
||||
display: none;
|
||||
@@ -454,9 +454,9 @@ button:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
flex-direction: column;
|
||||
gap: 0.6rem;
|
||||
overflow: hidden;
|
||||
background: #eef6ff;
|
||||
border: 1px solid #cfe4ff;
|
||||
border-radius: 18px;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
padding: 1rem;
|
||||
}
|
||||
.lesson-display p {
|
||||
@@ -477,11 +477,12 @@ button:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
font-weight: 700;
|
||||
}
|
||||
.teacher-transcript {
|
||||
max-height: 3.2rem;
|
||||
overflow: auto;
|
||||
min-height: calc(1.35em * 3);
|
||||
max-height: calc(1.35em * 3);
|
||||
overflow: hidden;
|
||||
color: #14213d;
|
||||
font-size: clamp(0.95rem, 1.5vw, 1.08rem);
|
||||
line-height: 1.45;
|
||||
line-height: 1.35;
|
||||
}
|
||||
.lesson-asset-view {
|
||||
min-height: 0;
|
||||
@@ -521,9 +522,9 @@ button:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
min-height: 0;
|
||||
flex: 1 1 auto;
|
||||
object-fit: contain;
|
||||
border: 1px solid #dbeafe;
|
||||
border-radius: 14px;
|
||||
background: white;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
}
|
||||
.lesson-bubble {
|
||||
min-height: 68px;
|
||||
@@ -742,7 +743,7 @@ button:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
.lesson-topbar .avatar {
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
border-radius: 16px;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.lesson-topbar h1 {
|
||||
@@ -761,7 +762,8 @@ button:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
}
|
||||
|
||||
.teacher-transcript {
|
||||
max-height: 2.15rem;
|
||||
min-height: calc(1.35em * 3);
|
||||
max-height: calc(1.35em * 3);
|
||||
font-size: 0.9rem;
|
||||
padding: 0 0.65rem;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user