Tradution en français des prompts
This commit is contained in:
@@ -42,47 +42,54 @@ api_key = config.API_KEY
|
|||||||
|
|
||||||
# --- Modèles pour la Requête 1 ---
|
# --- Modèles pour la Requête 1 ---
|
||||||
class QuestionOnlyItem(BaseModel):
|
class QuestionOnlyItem(BaseModel):
|
||||||
label: str = Field(description="The unique label of the question (e.g., '1.a', 'Exercice 1')")
|
label: str = Field(description="Label unique de la question (par exemple '1.a' ou 'Exercice 1').")
|
||||||
question_content: str = Field(description="The source text of the question, strictly extracted from the enonce file, EXCLUDING the label itself.")
|
question_content: str = Field(description="Texte source de la question, extrait exactement du fichier d’énoncé, SANS le label lui-même.")
|
||||||
|
|
||||||
class ExamQuestions(BaseModel):
|
class ExamQuestions(BaseModel):
|
||||||
questions: list[QuestionOnlyItem]
|
questions: list[QuestionOnlyItem]
|
||||||
|
|
||||||
# --- Modèles pour la Requête 2 ---
|
# --- Modèles pour la Requête 2 ---
|
||||||
class SolutionOnlyItem(BaseModel):
|
class SolutionOnlyItem(BaseModel):
|
||||||
label: str = Field(description="The exact unique label of the question provided in the input.")
|
label: str = Field(description="Label exact de la question fourni en entrée, à conserver sans traduction.")
|
||||||
solution_content: str = Field(description="The source text of the solution, strictly extracted from the correction file.")
|
solution_content: str = Field(description="Texte source de la solution, extrait exactement du fichier de correction.")
|
||||||
|
|
||||||
class ExamSolutions(BaseModel):
|
class ExamSolutions(BaseModel):
|
||||||
solutions: list[SolutionOnlyItem]
|
solutions: list[SolutionOnlyItem]
|
||||||
|
|
||||||
# --- Modèles pour la Requête 3 ---
|
# --- Modèles pour la Requête 3 ---
|
||||||
class ExtractedContext(BaseModel):
|
class ExtractedContext(BaseModel):
|
||||||
target_question_label: str = Field(description="The exact label of the FIRST question that comes immediately AFTER this information in the exam.")
|
target_question_label: str = Field(description="Label exact de la PREMIÈRE question située immédiatement APRÈS cette information dans l’énoncé.")
|
||||||
last_question_label: str = Field(description="The exact label of the LAST question that uses or relies on this information.")
|
last_question_label: str = Field(description="Label exact de la DERNIÈRE question qui utilise cette information.")
|
||||||
context_content: str = Field(description="The source text of the definitions, notations, or hypotheses, extracted from the enonce.")
|
context_content: str = Field(description="Texte source des définitions, notations ou hypothèses, extrait de l’énoncé.")
|
||||||
|
|
||||||
class ExamContext(BaseModel):
|
class ExamContext(BaseModel):
|
||||||
contexts: list[ExtractedContext]
|
contexts: list[ExtractedContext]
|
||||||
|
|
||||||
# --- Modèles pour la Requête 4 (Barèmes) ---
|
# --- Modèles pour la Requête 4 (Barèmes) ---
|
||||||
class RubricItem(BaseModel):
|
class RubricItem(BaseModel):
|
||||||
label: str = Field(description="The exact label of the question.")
|
label: str = Field(description="Label exact de la question, à conserver sans traduction.")
|
||||||
rubric_content: str = Field(description="Le barème détaillé en français.")
|
rubric_content: str = Field(description="Barème détaillé sur 4 points : toutes les consignes, explications et justifications doivent être rédigées en français.")
|
||||||
|
|
||||||
class GroupRubrics(BaseModel):
|
class GroupRubrics(BaseModel):
|
||||||
rubrics: list[RubricItem]
|
rubrics: list[RubricItem]
|
||||||
|
|
||||||
PROMPT_4 = """Je te fournis les questions, le contexte éventuel, et les corrections pour un groupe de questions d'un examen.
|
PROMPT_4 = """Je te fournis les questions, le contexte éventuel, et les corrections pour un groupe de questions d'un examen.
|
||||||
Ta tâche :
|
Ta tâche :
|
||||||
Établir un barème de correction détaillé en français pour CHAQUE question.
|
Établir un barème de correction détaillé pour CHAQUE question.
|
||||||
|
Rédige intégralement en français le contenu de chaque champ `rubric_content`,
|
||||||
|
y compris les consignes de notation, les explications et les justifications,
|
||||||
|
même si certains textes fournis sont dans une autre langue.
|
||||||
|
Conserve les formules mathématiques, les labels exacts des questions et les
|
||||||
|
clés JSON `rubrics`, `label` et `rubric_content` sans les traduire.
|
||||||
Chaque question DOIT être notée sur exactement 4 points. Propose une répartition logique de ces points.
|
Chaque question DOIT être notée sur exactement 4 points. Propose une répartition logique de ces points.
|
||||||
Par exemple :
|
Par exemple :
|
||||||
- Au moins 2 points si le résultat est correct.
|
- Au moins 2 points si le résultat est correct.
|
||||||
- Mettre la moitié des points si le raisonnement est correct mais pas le résultat.
|
- Mettre la moitié des points si le raisonnement est correct mais pas le résultat.
|
||||||
- Retirer 1.5 points si les hypothèses d'un théorème ou d'une question précédente ne sont pas vérifiées.
|
- Retirer 1,5 point si les hypothèses d'un théorème ou d'une question précédente ne sont pas vérifiées.
|
||||||
|
|
||||||
Renvoie le résultat sous forme de liste JSON correspondant aux labels des questions fournies.
|
Renvoie uniquement un objet JSON contenant une liste `rubrics`. Pour chaque
|
||||||
|
question fournie, cette liste contient un objet avec son `label` exact et
|
||||||
|
son barème en français dans `rubric_content`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# --- Modèle fusionné (pour le reste du script) ---
|
# --- Modèle fusionné (pour le reste du script) ---
|
||||||
@@ -102,50 +109,64 @@ class ExamExtraction(BaseModel):
|
|||||||
class GroupedExamExtraction(BaseModel):
|
class GroupedExamExtraction(BaseModel):
|
||||||
groups: list[list[QuestionItem | ContextItem]]
|
groups: list[list[QuestionItem | ContextItem]]
|
||||||
|
|
||||||
PROMPT_1 = """I am providing:
|
PROMPT_1 = """Je te fournis :
|
||||||
1. A PDF of an exam (`enonce.pdf`)
|
1. Le PDF d'un examen (`enonce.pdf`).
|
||||||
2. The source code of the exam questions (`enonce` file)
|
2. Le code source de ses questions (fichier `enonce`).
|
||||||
|
|
||||||
Your task:
|
Ta tâche :
|
||||||
1. Identify all distinct question labels using the PDF document.
|
1. Identifie tous les labels distincts des questions à l'aide du PDF.
|
||||||
These labels should be unique : use `Ex 1 : 1)a)` or `I)1)b)`.
|
Ils doivent être uniques : utilise par exemple `Ex 1 : 1)a)` ou `I)1)b)`.
|
||||||
2. For each label, extract its exact corresponding question text
|
2. Pour chaque label, extrais exactement le texte de la question
|
||||||
from the `enonce` source file. Do not include the label itself
|
correspondante dans le fichier source `enonce`. N'inclus ni le label
|
||||||
in this extracted text (nor LaTeX like `item` nor org-mode list
|
lui-même, ni les commandes de liste LaTeX comme `item`, ni les marques
|
||||||
labelling like `2.`).
|
de liste org-mode comme `2.`.
|
||||||
Return the result as a JSON list in the exact reading order of the document.
|
Ne reformule pas et ne traduis pas le texte extrait ; conserve le LaTeX.
|
||||||
|
Renvoie les questions dans l'ordre exact de lecture du document, dans la
|
||||||
|
liste `questions` de l'objet JSON attendu. Conserve les clés `label` et
|
||||||
|
`question_content`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
PROMPT_2 = """I am providing:
|
PROMPT_2 = """Je te fournis :
|
||||||
1. A JSON list of question labels and their texts extracted from an exam.
|
1. Une liste JSON des labels des questions d'un examen et de leurs textes.
|
||||||
2. The source code of the exam solutions (`correction` file).
|
2. Le code source du corrigé de l'examen (fichier `correction`).
|
||||||
|
|
||||||
Your task:
|
Pour chaque label fourni, extrais exactement le texte de la solution
|
||||||
For each question label provided in the JSON, extract its exact corresponding solution textual
|
correspondante dans le fichier source `correction`. Ne reformule pas et
|
||||||
content from the `correction` source file. Return the result as a JSON list in the exact same order.
|
ne traduis pas le texte extrait ; conserve le LaTeX.
|
||||||
|
Renvoie les solutions dans le même ordre que les questions, dans la liste
|
||||||
|
`solutions` de l'objet JSON attendu. Conserve les clés `label` et
|
||||||
|
`solution_content` ainsi que les labels exacts des questions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
PROMPT_3 = """I am providing:
|
PROMPT_3 = """Je te fournis :
|
||||||
1. A JSON list of question labels and their texts extracted from an exam.
|
1. Une liste JSON des labels des questions d'un examen et de leurs textes.
|
||||||
2. The source code of the exam questions (`enonce` file).
|
2. Le code source des questions de l'examen (fichier `enonce`).
|
||||||
|
|
||||||
Your task:
|
Extrais les informations importantes nécessaires à la compréhension des
|
||||||
Extract important information necessary to understand the questions (e.g., definitions of objects, global notations, hypotheses, context) that are NOT part of the question texts themselves. Often, this information can be in a previous \\item that is not itself a question, but contains the question items.
|
questions, mais qui ne font PAS partie des textes des questions :
|
||||||
|
définitions des objets, notations générales, hypothèses ou contexte.
|
||||||
|
Ces informations figurent souvent dans un \\item précédent qui ne constitue
|
||||||
|
pas lui-même une question, mais contient une liste de questions.
|
||||||
|
|
||||||
For example, given LaTeX code like
|
Par exemple, dans ce code LaTeX :
|
||||||
|
|
||||||
\\item Let N, M be two commutating matrices
|
\\item Soient N et M deux matrices qui commutent.
|
||||||
\\begin{itemize}
|
\\begin{itemize}
|
||||||
\\item Prove that N, M have a common eigenvector
|
\\item Montrer que N et M ont un vecteur propre commun.
|
||||||
\\item Prove that N, M are co-trigonalizable.
|
\\item Montrer que N et M sont simultanément trigonalisables.
|
||||||
\\end{itemize}
|
\\end{itemize}
|
||||||
|
|
||||||
the `Let N, M be two commutating matrices` part is not a question itself, and is important information to understand the next two questions.
|
La phrase « Soient N et M deux matrices qui commutent » n'est pas une
|
||||||
|
question ; elle est nécessaire pour comprendre les deux questions suivantes.
|
||||||
|
|
||||||
For each extracted piece of information, identify:
|
Pour chaque information extraite, identifie :
|
||||||
1. The label of the FIRST question that comes immediately AFTER this information in the exam.
|
1. Le label de la PREMIÈRE question située immédiatement APRÈS cette
|
||||||
2. The label of the LAST question that uses or relies on this information.
|
information dans l'énoncé (`target_question_label`).
|
||||||
Return the result as a JSON list.
|
2. Le label de la DERNIÈRE question qui utilise cette information
|
||||||
|
(`last_question_label`).
|
||||||
|
Conserve le texte source dans `context_content`, sans le reformuler ni le
|
||||||
|
traduire, et conserve le LaTeX ainsi que les labels exacts.
|
||||||
|
Renvoie le résultat dans la liste `contexts` de l'objet JSON attendu.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def find_file(folder: Path, base_name: str) -> Path | None:
|
def find_file(folder: Path, base_name: str) -> Path | None:
|
||||||
@@ -245,7 +266,7 @@ def process_exam(
|
|||||||
role="user",
|
role="user",
|
||||||
parts=[
|
parts=[
|
||||||
types.Part.from_text(text=PROMPT_2),
|
types.Part.from_text(text=PROMPT_2),
|
||||||
types.Part.from_text(text=f"--- EXTRACTED QUESTIONS ---\n{extracted_questions_json}"),
|
types.Part.from_text(text=f"--- QUESTIONS EXTRAITES ---\n{extracted_questions_json}"),
|
||||||
types.Part.from_text(text=f"--- CORRECTION SOURCE ({correction_path.name}) ---\n{correction_text}"),
|
types.Part.from_text(text=f"--- CORRECTION SOURCE ({correction_path.name}) ---\n{correction_text}"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -281,7 +302,7 @@ def process_exam(
|
|||||||
role="user",
|
role="user",
|
||||||
parts=[
|
parts=[
|
||||||
types.Part.from_text(text=PROMPT_3),
|
types.Part.from_text(text=PROMPT_3),
|
||||||
types.Part.from_text(text=f"--- EXTRACTED QUESTIONS ---\n{extracted_questions_json}"),
|
types.Part.from_text(text=f"--- QUESTIONS EXTRAITES ---\n{extracted_questions_json}"),
|
||||||
types.Part.from_text(text=f"--- ENONCE SOURCE ({enonce_path.name}) ---\n{enonce_text}"),
|
types.Part.from_text(text=f"--- ENONCE SOURCE ({enonce_path.name}) ---\n{enonce_text}"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -691,6 +712,7 @@ def process_exam(
|
|||||||
]
|
]
|
||||||
|
|
||||||
config_4 = types.GenerateContentConfig(
|
config_4 = types.GenerateContentConfig(
|
||||||
|
system_instruction="Rédige tous les barèmes et consignes de notation en français. Conserve les clés JSON, les labels et les formules mathématiques.",
|
||||||
temperature=0.2,
|
temperature=0.2,
|
||||||
response_mime_type="application/json",
|
response_mime_type="application/json",
|
||||||
response_json_schema=GroupRubrics.model_json_schema(),
|
response_json_schema=GroupRubrics.model_json_schema(),
|
||||||
|
|||||||
+118
-98
@@ -2,89 +2,97 @@ from pathlib import Path
|
|||||||
import io
|
import io
|
||||||
from . import utils
|
from . import utils
|
||||||
|
|
||||||
main_prompt = """I'm giving you an image of several written answers to an exam.
|
main_prompt = """Je te fournis une image contenant plusieurs réponses manuscrites à un examen.
|
||||||
|
|
||||||
Each answer is separated by a black horizontal line, and underneath,
|
Chaque réponse est séparée de la précédente par une ligne horizontale noire.
|
||||||
to the left, is indicated the ID of the answer, from `01` to `50`.
|
En dessous de cette ligne, à gauche, figure l'identifiant de la réponse,
|
||||||
|
compris entre `01` et `50`.
|
||||||
|
|
||||||
I want you to score each answer, from 0 to 4, you may score half
|
Attribue à chaque réponse une note de 0 à 4. Les demi-points sont autorisés,
|
||||||
points, such as 2.5. Even if a result is wrong, if the reasoning is
|
par exemple 2.5. Même si le résultat est faux, accorde au moins la moitié
|
||||||
correct and could lead to a right answer, you should give at least
|
des points si le raisonnement est correct et pourrait conduire au bon résultat.
|
||||||
half the points.
|
|
||||||
|
|
||||||
You also need to give feedback to the student, in french :
|
Rédige tous les commentaires destinés à l'élève en français. Indique :
|
||||||
- which part of his answer is wrong,
|
- quelle partie de sa réponse est fausse ;
|
||||||
- why is it wrong
|
- pourquoi elle est fausse ;
|
||||||
- possibly, what he should have done instead.
|
- éventuellement, ce qu'il aurait fallu faire à la place.
|
||||||
Your feedback may contain LaTeX fragments written like `$a^2 + b^2 = c^2$`.
|
Les commentaires peuvent contenir des fragments LaTeX, par exemple
|
||||||
|
`$a^2 + b^2 = c^2$`.
|
||||||
|
|
||||||
If your score is not 4, you should always provide some feedback
|
Si la note n'est pas 4, fournis toujours un commentaire expliquant ce qui
|
||||||
explaining what's missing.
|
manque, sauf dans le cas `empty-answer` décrit ci-dessous.
|
||||||
|
|
||||||
For each piece of feedback, if it is related to a specific part of the
|
Lorsqu'un commentaire concerne une erreur située dans une partie précise
|
||||||
answer that is wrong, you may provide a `box_2d`, to locate this
|
de la réponse, tu peux fournir un champ `box_2d` pour la localiser.
|
||||||
specific part of the answer. This `box_2d` should be in the form
|
Ses coordonnées doivent être de la forme [ymin, xmin, ymax, xmax],
|
||||||
[ymin, xmin, ymax, xmax] normalized to 0-1000. If you do not provide
|
normalisées entre 0 et 1000. Sinon, attribue la valeur `null` à `box_2d`.
|
||||||
one, set `box_2d` to `null`.
|
|
||||||
|
|
||||||
If the answer is correct, there is no need to provide feedback. You do
|
Si la réponse est correcte, aucun commentaire n'est nécessaire. Tu n'es pas
|
||||||
not have to give positive feedback, but if you do, do not provide a
|
obligé de faire des commentaires positifs ; si tu en fais, ne leur associe
|
||||||
`box_2d` for it.
|
pas de `box_2d`.
|
||||||
|
|
||||||
For example, if the student says a function is continuous when it
|
Par exemple, si l'élève affirme à tort qu'une fonction est continue,
|
||||||
isn't, provide the coordinates where the word «continuous» is. If a
|
localise le mot « continue ». Si un calcul est faux, localise l'étape où
|
||||||
calculation went wrong, gives the coordinates of the step where it
|
l'erreur apparaît et explique cette erreur dans le commentaire.
|
||||||
goes wrong, and as feedback, what went wrong.
|
|
||||||
|
|
||||||
Avoid giving feedback about confusing letters `n` with `m`, `x` with
|
Évite les commentaires portant sur une confusion entre les lettres `n`
|
||||||
`n` or `h` with `k`. If it looks wrong, assume you read it wrong,
|
et `m`, `x` et `n`, ou `h` et `k`. En cas de doute, suppose que tu as mal
|
||||||
unless the distinction is very important.
|
lu, sauf si la distinction est très importante.
|
||||||
|
|
||||||
In some case, you may find that either
|
Certains cas nécessitent une valeur particulière du champ `error` :
|
||||||
- The student didn't answer the right question. Set the score to 0.
|
- L'élève n'a pas répondu à la bonne question : attribue la note 0 et
|
||||||
Since it could be a labeling error, indicate it by setting `error`
|
indique `wrong-label`, car il peut s'agir d'une erreur de label.
|
||||||
to \"wrong-label\".
|
- La réponse contient aussi une réponse à une autre question de
|
||||||
- You can find an answer to another question of the exercice (taking
|
l'exercice, sur plus de quelques lignes : note la question demandée,
|
||||||
more than a couple of lines). Score the question you are supposed
|
mais indique `additional-answer`.
|
||||||
to score, but set `error` to \"additional-answer\".
|
- La réponse est vide, ou l'élève a seulement recopié l'énoncé : indique
|
||||||
- The answer to the question is empty, or the student has only
|
`empty-answer` et ne fournis aucun commentaire.
|
||||||
rewritten the statement of the question. In this case, set `error`
|
S'il n'y a aucune de ces erreurs, attribue la chaîne vide `""` à `error`.
|
||||||
to \"empty-answer\" and do not provide any kind of feedback.
|
|
||||||
If there's no error, set `error` to `\"\"`.
|
|
||||||
|
|
||||||
You will answer using json describing a list of dictionary with a key
|
Réponds uniquement en JSON, sous la forme d'une liste d'objets contenant
|
||||||
\"id\", and a key \"result\" that contains the \"score\", a list
|
les clés `id` et `result`. L'objet `result` contient `score`, la liste
|
||||||
\"feedback\", and possibly an \"error\". Like this example :
|
`feedback` et `error`. Chaque commentaire contient `text` et `box_2d`.
|
||||||
|
Conserve exactement ces clés, les identifiants et les valeurs techniques
|
||||||
|
de `error` : ne les traduis pas. Le contenu de chaque champ `text` doit
|
||||||
|
être en français, même si certains documents fournis sont dans une autre langue.
|
||||||
|
|
||||||
[{ \"id\": \"01\",
|
Exemple :
|
||||||
\"result\": {\"score\" : 2.5,
|
```json
|
||||||
\"feedback\": [{text: \"Un retour générique. Il faut apprendre le cours.\", box_2d: null},
|
[
|
||||||
{text: \"Non, la fonction n'est pas forcément continue\", pos: [145, 280, 340, 500]}],
|
{
|
||||||
\"error\": \"\"}
|
"id": "01",
|
||||||
|
"result": {
|
||||||
|
"score": 2.5,
|
||||||
|
"feedback": [
|
||||||
|
{"text": "Il manque la vérification des hypothèses du théorème.", "box_2d": null},
|
||||||
|
{"text": "Non, la fonction n'est pas forcément continue.", "box_2d": [145, 280, 340, 500]}
|
||||||
|
],
|
||||||
|
"error": ""
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{ \"id\": \"04\",
|
{
|
||||||
\"result\": {\"score\" : 4.,
|
"id": "04",
|
||||||
\"feedback\" : []
|
"result": {"score": 4.0, "feedback": [], "error": ""}
|
||||||
\"error\": \"\" }
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
```
|
||||||
|
|
||||||
Here is the text of the exercice (or the relevant part of the problem)
|
Voici l'énoncé de l'exercice ou la partie pertinente du problème :
|
||||||
of the exam :
|
|
||||||
|
|
||||||
```
|
```
|
||||||
<<text>>
|
<<text>>
|
||||||
```
|
```
|
||||||
|
|
||||||
Here is a possible correct answer :
|
Voici un corrigé possible :
|
||||||
|
|
||||||
```
|
```
|
||||||
<<corr>>
|
<<corr>>
|
||||||
```
|
```
|
||||||
<<persp>>
|
<<persp>>
|
||||||
|
|
||||||
You are asked to score the question or exercice labeled `<<label>>`,
|
Tu dois noter uniquement la question ou l'exercice portant le label
|
||||||
do not score or give feedback to any other question."""
|
`<<label>>`. Ne note aucune autre question et ne formule aucun commentaire
|
||||||
|
sur les autres questions."""
|
||||||
|
|
||||||
from .utils import get_label_text_content, get_label_sol_content, get_label_persp_content
|
from .utils import get_label_text_content, get_label_sol_content, get_label_persp_content
|
||||||
|
|
||||||
@@ -95,7 +103,7 @@ def make_prompt(input_dir,full_label):
|
|||||||
# print("Debug : l/t/c/p", full_label, text, corr, persp)
|
# print("Debug : l/t/c/p", full_label, text, corr, persp)
|
||||||
|
|
||||||
if persp:
|
if persp:
|
||||||
persp = "\n\nHere are additional scoring instructions : \n\n```\n" + persp +"\n```\n"
|
persp = "\n\nVoici des consignes de notation complémentaires : \n\n```\n" + persp +"\n```\n"
|
||||||
return main_prompt.replace("<<text>>", text).replace("<<corr>>", corr).replace("<<persp>>", persp).replace("<<label>>", full_label)
|
return main_prompt.replace("<<text>>", text).replace("<<corr>>", corr).replace("<<persp>>", persp).replace("<<label>>", full_label)
|
||||||
|
|
||||||
|
|
||||||
@@ -103,17 +111,17 @@ from pydantic import BaseModel, Field, TypeAdapter
|
|||||||
from typing import List, Optional, Tuple
|
from typing import List, Optional, Tuple
|
||||||
|
|
||||||
class FeedbackItem(BaseModel):
|
class FeedbackItem(BaseModel):
|
||||||
text: str = Field(description="Feedback content")
|
text: str = Field(description="Commentaire destiné à l’élève, rédigé en français.")
|
||||||
box_2d: Optional[List[int]] = Field(None, description="box coordinates or null")
|
box_2d: Optional[List[int]] = Field(None, description="Coordonnées [ymin, xmin, ymax, xmax] normalisées entre 0 et 1000, ou null.")
|
||||||
|
|
||||||
class ResultData(BaseModel):
|
class ResultData(BaseModel):
|
||||||
score: float = Field(description="The numeric score")
|
score: float = Field(description="Note numérique de la réponse, sur 4 points.")
|
||||||
feedback: List[FeedbackItem] = Field(description="List of feedback items")
|
feedback: List[FeedbackItem] = Field(description="Liste des commentaires destinés à l’élève, rédigés en français.")
|
||||||
error: str = Field(description="Indicates if an error occurred")
|
error: str = Field(description="Type d’erreur : wrong-label, additional-answer, empty-answer, ou chaîne vide.")
|
||||||
|
|
||||||
class EvaluationEntry(BaseModel):
|
class EvaluationEntry(BaseModel):
|
||||||
id: str = Field(description="Entry identifier")
|
id: str = Field(description="Identifiant exact de la réponse.")
|
||||||
result: ResultData = Field(description="Result details")
|
result: ResultData = Field(description="Note, commentaires en français et éventuelle erreur pour cette réponse.")
|
||||||
|
|
||||||
# These nested definitions do not work with the batch api, unroll them
|
# These nested definitions do not work with the batch api, unroll them
|
||||||
UNROLLED_SCHEMA = {
|
UNROLLED_SCHEMA = {
|
||||||
@@ -121,24 +129,24 @@ UNROLLED_SCHEMA = {
|
|||||||
"items": {
|
"items": {
|
||||||
"type": "OBJECT",
|
"type": "OBJECT",
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {"type": "STRING", "description": "Entry identifier"},
|
"id": {"type": "STRING", "description": "Identifiant exact de la réponse."},
|
||||||
"result": {
|
"result": {
|
||||||
"type": "OBJECT",
|
"type": "OBJECT",
|
||||||
"properties": {
|
"properties": {
|
||||||
"score": {"type": "NUMBER", "description": "The numeric score"},
|
"score": {"type": "NUMBER", "description": "Note numérique de la réponse, sur 4 points."},
|
||||||
"error": {"type": "STRING", "description": "Indicates if an error occurred"},
|
"error": {"type": "STRING", "description": "Type d’erreur : wrong-label, additional-answer, empty-answer, ou chaîne vide."},
|
||||||
"feedback": {
|
"feedback": {
|
||||||
"type": "ARRAY",
|
"type": "ARRAY",
|
||||||
"description": "List of feedback items",
|
"description": "Liste des commentaires destinés à l’élève, rédigés en français.",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "OBJECT",
|
"type": "OBJECT",
|
||||||
"properties": {
|
"properties": {
|
||||||
"text": {"type": "STRING", "description": "Feedback content"},
|
"text": {"type": "STRING", "description": "Commentaire destiné à l’élève, rédigé en français."},
|
||||||
"box_2d": {
|
"box_2d": {
|
||||||
"type": "ARRAY",
|
"type": "ARRAY",
|
||||||
"items": {"type": "INTEGER"},
|
"items": {"type": "INTEGER"},
|
||||||
"nullable": True,
|
"nullable": True,
|
||||||
"description": "box coordinates or null"
|
"description": "Coordonnées [ymin, xmin, ymax, xmax] normalisées entre 0 et 1000, ou null."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["text"]
|
"required": ["text"]
|
||||||
@@ -216,20 +224,27 @@ def request_for_box_correction(pdf_path, original_feedbacks):
|
|||||||
|
|
||||||
localized_feedbacks = [f for f in original_feedbacks if f["box_2d"]]
|
localized_feedbacks = [f for f in original_feedbacks if f["box_2d"]]
|
||||||
|
|
||||||
prompt = f"""
|
prompt = f"""Voici la réponse d'un élève à une question d'examen. Le JSON
|
||||||
Here is a single student's submission to a question in a written exam. The following JSON contains feedback items with bounding boxes (box_2d) that are incorrect. Each piece of feedback is supposed to be related to a piece of the answer that is wrong.
|
ci-dessous contient des commentaires dont les rectangles de localisation
|
||||||
|
(`box_2d`) sont incorrects. Chaque commentaire doit correspondre à la
|
||||||
|
partie de la réponse où se trouve l'erreur signalée.
|
||||||
|
|
||||||
For example, if the student says a function is continuous when it
|
Par exemple, si l'élève affirme à tort qu'une fonction est continue,
|
||||||
isn't, the coordinates should be where the word «continuous» is. If a
|
les coordonnées doivent localiser le mot « continue ». Si un calcul est
|
||||||
calculation went wrong, the coordinates should be where the step where
|
faux, elles doivent localiser l'étape où apparaît l'erreur expliquée dans
|
||||||
it goes wrong, and the feedback is what went wrong.
|
le commentaire.
|
||||||
|
|
||||||
Please analyze the image and return the same feedback json content, but with ONLY the box_2d coordinates corrected for this specific image.
|
Analyse l'image et renvoie le même contenu JSON en corrigeant UNIQUEMENT
|
||||||
Coordinates must be [ymin, xmin, ymax, xmax] scaled to 1000. If a box is invalid/not found, return null for it.
|
les coordonnées `box_2d` pour cette image. Conserve les commentaires en
|
||||||
Original feedback:
|
français à l'identique : ne les reformule pas et ne les traduis pas.
|
||||||
|
Conserve les noms des clés JSON.
|
||||||
|
Les coordonnées doivent être [ymin, xmin, ymax, xmax], normalisées entre
|
||||||
|
0 et 1000. Si la zone est introuvable ou le rectangle invalide, renvoie
|
||||||
|
`null` pour ce rectangle.
|
||||||
|
|
||||||
{json.dumps(localized_feedbacks, indent=2)}
|
Commentaires d'origine :
|
||||||
"""
|
{json.dumps(localized_feedbacks, indent=2, ensure_ascii=False)}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -252,20 +267,21 @@ it goes wrong, and the feedback is what went wrong.
|
|||||||
|
|
||||||
def request_for_wrong_label(pdf_path, label, enonce, labels_txt):
|
def request_for_wrong_label(pdf_path, label, enonce, labels_txt):
|
||||||
|
|
||||||
prompt = f"""This image is a part of the answer of a student to a written exam.
|
prompt = f"""Cette image représente une partie de la réponse d'un élève à un examen.
|
||||||
|
|
||||||
It was initially labeled '{label}' but I suspect this label is wrong. Perhaps the student himself wrote the wrong label.
|
Elle porte initialement le label '{label}', mais je soupçonne une erreur
|
||||||
|
de label. L'élève a peut-être lui-même écrit le mauvais label.
|
||||||
|
|
||||||
You need to analyse this image, and find the label of the question it answers. Do not trust the label written by the student but instead check the content of its answer and the notation he uses to identify the correct label of the question the student answered.
|
Analyse l'image et identifie le label de la question à laquelle cette
|
||||||
|
réponse correspond. Ne te fie pas au label écrit par l'élève : examine
|
||||||
|
le contenu de la réponse et les notations utilisées.
|
||||||
|
|
||||||
Return ONLY the exact label string.
|
Renvoie UNIQUEMENT le label exact, sans le modifier ni le traduire.
|
||||||
|
|
||||||
Here is the full content of the exam :
|
|
||||||
|
|
||||||
|
Voici l'énoncé complet de l'examen :
|
||||||
{enonce}
|
{enonce}
|
||||||
|
|
||||||
Here is a list of all possible labels. You need to answer with one of these :
|
Voici les labels possibles. Ta réponse doit être l'un d'entre eux :
|
||||||
|
|
||||||
{labels_txt}
|
{labels_txt}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -276,22 +292,26 @@ Here is a list of all possible labels. You need to answer with one of these :
|
|||||||
return contents, config
|
return contents, config
|
||||||
|
|
||||||
def request_for_additional_answer(pdf_path, label, enonce, labels_txt):
|
def request_for_additional_answer(pdf_path, label, enonce, labels_txt):
|
||||||
prompt = f"""This image is a part of the answer of a student to a written exam.
|
prompt = f"""Cette image représente une partie de la réponse d'un élève à un examen.
|
||||||
|
|
||||||
It was initially labeled '{label}' but I suspect this image also contains answers to another, or several other questions.
|
Elle porte initialement le label '{label}', mais je soupçonne qu'elle
|
||||||
|
contient aussi des réponses à une ou plusieurs autres questions.
|
||||||
|
|
||||||
You need to analyse this image, and find the list of the labels of the questions it answers. Return ONLY the list of the exact label strings.
|
Analyse l'image et identifie les labels des questions auxquelles elle
|
||||||
|
répond. Renvoie UNIQUEMENT une liste JSON contenant les labels exacts,
|
||||||
|
sans les modifier ni les traduire.
|
||||||
|
|
||||||
If the end of the image only contains the first line of an answer to another question, ignore it.
|
Si le bas de l'image ne contient que la première ligne d'une réponse à
|
||||||
|
une autre question, ignore cette ligne.
|
||||||
Here is the full content of the exam :
|
|
||||||
|
|
||||||
|
Voici l'énoncé complet de l'examen :
|
||||||
{enonce}
|
{enonce}
|
||||||
|
|
||||||
Here is a list of all possible labels. You need to answer with a list one of these :
|
Voici les labels possibles. Chaque élément de ta liste doit être l'un
|
||||||
|
d'entre eux :
|
||||||
{labels_txt}
|
{labels_txt}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
contents = [types.Content(role="user", parts=[
|
contents = [types.Content(role="user", parts=[
|
||||||
types.Part.from_bytes(data=get_single_image_bytes(pdf_path), mime_type="image/jpeg"),
|
types.Part.from_bytes(data=get_single_image_bytes(pdf_path), mime_type="image/jpeg"),
|
||||||
types.Part.from_text(text=prompt)
|
types.Part.from_text(text=prompt)
|
||||||
|
|||||||
Reference in New Issue
Block a user