Miscs (Interro 28)
This commit is contained in:
+108
-74
@@ -5,14 +5,11 @@ from pathlib import Path
|
||||
import argparse
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
sys.exit("Usage: python script.py InterroTest/Ex 2/Group_1.jpg OR <InputDir>")
|
||||
|
||||
arg_path = Path(sys.argv[1])
|
||||
tasks = [] # List of tuples: (filepath_str, label_str)
|
||||
results = {}
|
||||
sys.exit("Usage: python script.py 'InterroTest/Ex 2/Group_1.jpg' OR <InputDir> OR 'file1' 'file2'")
|
||||
|
||||
# Parse Arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("paths", nargs="+", help="List of images or directories")
|
||||
parser.add_argument("--overwrite", action="store_true",
|
||||
help="Force redo requests even if output exists")
|
||||
parser.add_argument("--limit", type=int, help="limit calls to gemini rpo integer")
|
||||
@@ -20,28 +17,40 @@ parser.add_argument("--refaire", action="store_true",
|
||||
help="Redo specific copies/labels defined in refaire.json")
|
||||
parser.add_argument("--batch", action="store_true",
|
||||
help="Generate a JSONL file of requests to send to the Gemini Batch API")
|
||||
parser.add_argument("--batch-from", type=str, metavar="LABEL",
|
||||
help="Do live requests before LABEL, and batch requests from LABEL onwards")
|
||||
parser.add_argument("--deal-with-batched", action="store_true",
|
||||
help="Process a JSONL file containing completed batch results")
|
||||
args, _ = parser.parse_known_args()
|
||||
|
||||
tasks = [] # List of tuples: (filepath_str, label_str)
|
||||
results = {}
|
||||
|
||||
|
||||
for path_str in args.paths:
|
||||
arg_path = Path(path_str)
|
||||
|
||||
if arg_path.suffix == ".jpg":
|
||||
INPUT_DIR = str(arg_path.parents[1])
|
||||
FULL_LABEL = arg_path.parent.name
|
||||
tasks.append((str(arg_path), FULL_LABEL))
|
||||
results[FULL_LABEL] = []
|
||||
else:
|
||||
# Directory behaviour
|
||||
INPUT_DIR = str(arg_path)
|
||||
if not arg_path.exists():
|
||||
sys.exit(f"Directory {INPUT_DIR} not found.")
|
||||
print(f"Warning: {path_str} not found. Skipping.")
|
||||
continue
|
||||
|
||||
for sub in arg_path.iterdir():
|
||||
if sub.is_dir() and sub.name.startswith("Ex"):
|
||||
label = sub.name
|
||||
if arg_path.is_file() and arg_path.suffix.lower() == ".jpg":
|
||||
# Handle individual file
|
||||
# Note: assumes structure InterroTest/Ex 2/Group_1.jpg to get parents[1]
|
||||
label = arg_path.parent.name
|
||||
tasks.append((str(arg_path), label))
|
||||
if label not in results:
|
||||
results[label] = []
|
||||
for img in sub.glob("*.jpg"):
|
||||
tasks.append((str(img), label))
|
||||
|
||||
elif arg_path.is_dir():
|
||||
# Handle directory (original behavior)
|
||||
for sub in arg_path.iterdir():
|
||||
if sub.is_dir() and sub.name.startswith("Ex"):
|
||||
label = sub.name
|
||||
if label not in results:
|
||||
results[label] = []
|
||||
for img in sub.glob("*.jpg"):
|
||||
tasks.append((str(img), label))
|
||||
|
||||
my_prompt = """I'm giving you an image of several written answers to an exam.
|
||||
|
||||
@@ -135,17 +144,15 @@ You are asked to score the question or exercice labeled `<<label>>`,
|
||||
do not score or give feedback to any other question."""
|
||||
|
||||
def make_prompt(full_label):
|
||||
# l = full_label.split(" ")
|
||||
# ex_label = l[0] + " " + l[1]
|
||||
# text = (Path(INPUT_DIR) / "Text" / ex_label).read_text()
|
||||
# corr = (Path(INPUT_DIR) / "Sol" / ex_label).read_text()
|
||||
# persp = (Path(INPUT_DIR) / "Persp" / ex_label).read_text()
|
||||
def read_longest_prefix_file(subdir):
|
||||
dir_path = Path(INPUT_DIR) / subdir
|
||||
matches = [f for f in dir_path.iterdir() if f.is_file() and full_label.startswith(f.name)]
|
||||
matches = [f for f in dir_path.iterdir()
|
||||
if f.is_file()
|
||||
and full_label.startswith(f.name)
|
||||
and f.suffix not in [".pdf", ".tex"]]
|
||||
if not matches:
|
||||
return ""
|
||||
return max(matches, key=lambda f: len(f.name)).read_text()
|
||||
return max(matches, key=lambda f: len(f.name)).read_text(encoding="utf-8", errors="replace")
|
||||
|
||||
text = read_longest_prefix_file("Text")
|
||||
corr = read_longest_prefix_file("Sol")
|
||||
@@ -482,7 +489,7 @@ def handle_label_errors(pid, label, res, pdf_path):
|
||||
error_type = res.get("error")
|
||||
|
||||
all_labels = read_all_labels(INPUT_DIR)
|
||||
labels_txt = (Path(INPUT_DIR) / "labels").read_text()
|
||||
labels_txt = (Path(INPUT_DIR) / "labels").read_text(encoding="utf-8", errors="replace")
|
||||
enonce = enonce_total(INPUT_DIR)
|
||||
|
||||
if error_type == "wrong-label":
|
||||
@@ -499,7 +506,7 @@ Here is the full content of the exam :
|
||||
|
||||
{enonce}
|
||||
|
||||
Here is a list of all possible lables. You need to answer with one of these :
|
||||
Here is a list of all possible labels. You need to answer with one of these :
|
||||
|
||||
{labels_txt}
|
||||
"""
|
||||
@@ -780,62 +787,89 @@ if __name__ == "__main__":
|
||||
print(f"Warning: --refaire flag used, but {refaire_path} not found.", file=sys.stderr)
|
||||
|
||||
|
||||
if args.batch:
|
||||
batch_flash_file = Path(INPUT_DIR) / "batch_requests_flash.jsonl"
|
||||
batch_pro_file = Path(INPUT_DIR) / "batch_requests_pro.jsonl"
|
||||
if args.batch or args.batch_from:
|
||||
from utils import read_all_labels
|
||||
all_labels = read_all_labels(INPUT_DIR)
|
||||
|
||||
count_flash = 0
|
||||
count_pro = 0
|
||||
batch_tasks = []
|
||||
if args.batch_from:
|
||||
if args.batch_from not in all_labels:
|
||||
sys.exit(f"Error: Label '{args.batch_from}' not found. Available labels: {all_labels}")
|
||||
|
||||
with open(batch_flash_file, "w", encoding="utf-8") as f_flash, \
|
||||
open(batch_pro_file, "w", encoding="utf-8") as f_pro:
|
||||
target_idx = all_labels.index(args.batch_from)
|
||||
live_tasks = []
|
||||
|
||||
for task in tasks_to_process:
|
||||
file_path, label = task[0], task[1]
|
||||
group_name = os.path.splitext(file_path)[0]
|
||||
json_path = group_name + '.json'
|
||||
lbl = task[1]
|
||||
# Any label found sequentially equal or after `args.batch_from` gets batched
|
||||
if lbl in all_labels and all_labels.index(lbl) >= target_idx:
|
||||
batch_tasks.append(task)
|
||||
else:
|
||||
live_tasks.append(task)
|
||||
|
||||
with open(json_path, 'r') as jf:
|
||||
group_data = json.load(jf)
|
||||
use_flash = len(group_data) >= 4 or group_data[-1][2] <= 500
|
||||
tasks_to_process = live_tasks # Keep live tasks to be run right after
|
||||
else:
|
||||
batch_tasks = tasks_to_process
|
||||
tasks_to_process = [] # Run nothing live if just `--batch`
|
||||
|
||||
image_data = Path(file_path).read_bytes()
|
||||
b64_img = base64.b64encode(image_data).decode("utf-8")
|
||||
if batch_tasks:
|
||||
batch_flash_file = Path(INPUT_DIR) / "batch_requests_flash.jsonl"
|
||||
batch_pro_file = Path(INPUT_DIR) / "batch_requests_pro.jsonl"
|
||||
|
||||
# Format payload matching Gemini Batch API file requirements
|
||||
req = {
|
||||
"key": file_path, # The ID returned in the output file
|
||||
"request": {
|
||||
"contents": [{
|
||||
"role": "user",
|
||||
"parts": [
|
||||
{"inlineData": {"mimeType": "image/jpeg", "data": b64_img}},
|
||||
{"text": make_prompt(label)}
|
||||
]
|
||||
}],
|
||||
"generation_config": {
|
||||
"temperature": 1.0,
|
||||
"topP": 0.95,
|
||||
"maxOutputTokens": 65535,
|
||||
"responseMimeType": "application/json",
|
||||
"responseSchema": UNROLLED_SCHEMA
|
||||
# TypeAdapter(List[EvaluationEntry]).json_schema()
|
||||
count_flash = 0
|
||||
count_pro = 0
|
||||
|
||||
with open(batch_flash_file, "w", encoding="utf-8") as f_flash, \
|
||||
open(batch_pro_file, "w", encoding="utf-8") as f_pro:
|
||||
|
||||
for task in batch_tasks:
|
||||
file_path, label = task[0], task[1]
|
||||
group_name = os.path.splitext(file_path)[0]
|
||||
json_path = group_name + '.json'
|
||||
|
||||
with open(json_path, 'r') as jf:
|
||||
group_data = json.load(jf)
|
||||
use_flash = len(group_data) >= 4 or group_data[-1][2] <= 500
|
||||
|
||||
image_data = Path(file_path).read_bytes()
|
||||
b64_img = base64.b64encode(image_data).decode("utf-8")
|
||||
|
||||
# Format payload matching Gemini Batch API file requirements
|
||||
req = {
|
||||
"key": file_path, # The ID returned in the output file
|
||||
"request": {
|
||||
"contents": [{
|
||||
"role": "user",
|
||||
"parts": [
|
||||
{"inlineData": {"mimeType": "image/jpeg", "data": b64_img}},
|
||||
{"text": make_prompt(label)}
|
||||
]
|
||||
}],
|
||||
"generation_config": {
|
||||
"temperature": 1.0,
|
||||
"topP": 0.95,
|
||||
"maxOutputTokens": 65535,
|
||||
"responseMimeType": "application/json",
|
||||
"responseSchema": UNROLLED_SCHEMA
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if use_flash:
|
||||
f_flash.write(json.dumps(req) + "\n")
|
||||
count_flash += 1
|
||||
else:
|
||||
f_pro.write(json.dumps(req) + "\n")
|
||||
count_pro += 1
|
||||
if use_flash:
|
||||
f_flash.write(json.dumps(req) + "\n")
|
||||
count_flash += 1
|
||||
else:
|
||||
f_pro.write(json.dumps(req) + "\n")
|
||||
count_pro += 1
|
||||
|
||||
print(f"Batch generation complete.")
|
||||
print(f" - {count_flash} requests saved to {batch_flash_file} (for {MODEL_ID_flash})")
|
||||
print(f" - {count_pro} requests saved to {batch_pro_file} (for {MODEL_ID_pro})")
|
||||
print("Upload these files via the File API and create two separate batch jobs.")
|
||||
sys.exit(0)
|
||||
print(f"Batch generation complete.")
|
||||
print(f" - {count_flash} requests saved to {batch_flash_file} (for {MODEL_ID_flash})")
|
||||
print(f" - {count_pro} requests saved to {batch_pro_file} (for {MODEL_ID_pro})")
|
||||
print("Upload these files via the File API and create two separate batch jobs.")
|
||||
|
||||
# If there's no live tasks to do, and we aren't doing a batched ingestion, exit right away
|
||||
if not tasks_to_process and not args.deal_with_batched:
|
||||
sys.exit(0)
|
||||
|
||||
batched_responses = {}
|
||||
if args.deal_with_batched:
|
||||
@@ -883,7 +917,7 @@ if __name__ == "__main__":
|
||||
print("Time elapsed : ", end_time - start_time)
|
||||
print("Requests to pro / flash : ", pro_count, flash_count)
|
||||
if errors_summary:
|
||||
print("\n--- Summary of Exceptions ---", file=sys.stderr)
|
||||
print("\n--- Summary of Exceptions (You can use several images on one instance) ---", file=sys.stderr)
|
||||
for (err, file) in errors_summary:
|
||||
print(err, file=sys.stderr)
|
||||
escaped_path = shlex.quote(str(file))
|
||||
|
||||
Reference in New Issue
Block a user