This commit is contained in:
2026-09-08 16:41:04 +02:00
parent db4ed2ef31
commit bf05272797
14 changed files with 725 additions and 75 deletions
+90 -17
View File
@@ -10,7 +10,7 @@ import tempfile
import time
import unittest
from concurrent.futures import ThreadPoolExecutor
from contextlib import redirect_stderr
from contextlib import redirect_stderr, redirect_stdout
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import Mock, patch
@@ -714,6 +714,8 @@ class StandardCliTests(unittest.TestCase):
copy_pdf.parent.mkdir(parents=True)
copy_pdf.write_bytes(b"pdf")
with patch.object(module, "ImageReviewer") as reviewer:
reviewer.return_value.completed = True
reviewer.return_value.had_errors = False
self.assertEqual(module.main([str(copy_pdf), "--fullpage"]), 0)
files, output_dir = reviewer.call_args.args[:2]
self.assertEqual(files, [copy_pdf])
@@ -1011,6 +1013,11 @@ class StandardCliTests(unittest.TestCase):
with tempfile.TemporaryDirectory() as directory:
evaluation = Path(directory) / "Exam"
(evaluation / "Copies").mkdir(parents=True)
text_dir = evaluation / "Text"
text_dir.mkdir()
(text_dir / "Ex 1").write_text("Short match", encoding="utf-8")
closest_text = text_dir / "Ex 1 : 1)"
closest_text.write_text("Relevant statement text", encoding="utf-8")
image = evaluation / "Cutleft" / "Copie01_01.jpg"
image.parent.mkdir()
image.write_bytes(b"image")
@@ -1019,39 +1026,105 @@ class StandardCliTests(unittest.TestCase):
Mock(
text=(
'{"name":"Student","list":'
'[{"box_2d":[1,2,3,4],"label":"Wrong"}]}'
'[{"box_2d":[1,2,3,4],"label":"Ex 1 : l)"}]}'
)
),
Mock(
text=(
'{"name":"Student","list":'
'[{"box_2d":[1,2,3,4],"label":"Ex 1"}]}'
'[{"box_2d":[1,2,3,4],"label":"Ex 1 : 1)"}]}'
)
),
]
sleeps = []
module.process_copy_group(
EvaluationWorkspace(evaluation),
"Copie01",
[image],
client=client,
labels_text="Ex 1\n",
names_text="Student\n",
valid_labels={"Ex 1"},
valid_names={"Student", "Unknown", "Continued"},
overwrite=True,
sleep=sleeps.append,
target_interval=0,
)
output = io.StringIO()
with redirect_stdout(output):
module.process_copy_group(
EvaluationWorkspace(evaluation),
"Copie01",
[image],
client=client,
labels_text="Ex 1 : 1)\n",
names_text="Student\n",
valid_labels={"Ex 1 : 1)"},
valid_names={"Student", "Unknown", "Continued"},
overwrite=True,
sleep=sleeps.append,
target_interval=0,
)
self.assertEqual(client.models.generate_content.call_count, 2)
self.assertIn(10, sleeps)
retry_contents = client.models.generate_content.call_args_list[1].kwargs[
"contents"
]
retry_prompt = retry_contents[0].parts[1].text
self.assertIn('"Ex 1 : l)"', retry_prompt)
self.assertIn("CRITICAL RETRY CONSTRAINT: NEVER return", retry_prompt)
self.assertIn("Relevant statement text", retry_prompt)
self.assertIn("`Ex 1 : 1)`", retry_prompt)
self.assertIn(
"Retry context for Copie01_01.jpg: Text/Ex 1 : 1)",
output.getvalue(),
)
self.assertEqual(
read_json(evaluation / "Copies" / "Copie01_01.json")["list"][0][
"label"
],
"Ex 1",
"Ex 1 : 1)",
)
def test_label_detection_marks_a_thrice_repeated_unknown_label(self) -> None:
module = self.modules["gemini_for_labels"]
with tempfile.TemporaryDirectory() as directory:
evaluation = Path(directory) / "Exam"
(evaluation / "Copies").mkdir(parents=True)
(evaluation / "Text").mkdir()
(evaluation / "Text" / "Ex 10").write_text(
"Question 1 text", encoding="utf-8"
)
image = evaluation / "Cutleft" / "Copie42_03.jpg"
image.parent.mkdir()
image.write_bytes(b"image")
repeated = Mock(
text=(
'{"name":"Continued","list":'
'[{"box_2d":[1,2,3,4],"label":"Ex 10 : 1)a)"}]}'
)
)
client = Mock()
client.models.generate_content.side_effect = [
repeated,
repeated,
repeated,
]
output = io.StringIO()
with redirect_stdout(output):
generated = module.process_copy_group(
EvaluationWorkspace(evaluation),
"Copie42",
[image],
client=client,
labels_text="Ex 10 : 1)\nEx 10 : 2)\nEx 10 : 3)\n",
names_text="Student\n",
valid_labels={"Ex 10 : 1)", "Ex 10 : 2)", "Ex 10 : 3)"},
valid_names={"Student", "Unknown", "Continued"},
overwrite=True,
sleep=lambda _seconds: None,
target_interval=0,
)
self.assertEqual(generated, 1)
self.assertEqual(client.models.generate_content.call_count, 3)
seeds = [
call.kwargs["config"].seed
for call in client.models.generate_content.call_args_list
]
self.assertEqual(seeds, [0, 0, 1])
result = read_json(evaluation / "Copies" / "Copie42_03.json")
self.assertEqual(result["list"][0]["label"], "??Ex 10 : 1)a)")
self.assertIn("keeping them with a ?? prefix", output.getvalue())
def test_correction_overwrite_keeps_previous_state_until_a_commit(self) -> None:
module = self.modules["correction"]
with tempfile.TemporaryDirectory() as directory: