""" Step 1: Download Kvasir-VQA and convert to the conversation format that Mobile-O's own training code (post_train.py) uses. Mobile-O's format per sample (from post_train.py __getitem__): conversations = [ {"from": "human", "value": "\n"}, {"from": "gpt", "value": ""}, ] und_image = PIL Image (the understanding image) We store this as JSONL with image paths so our custom dataset can load it. Output: data/images/ <- kvasir images as .jpg data/smoke_test.jsonl <- 200 samples for smoke test data/train.jsonl <- all ~58k QA pairs Run: python step1_prepare_data.py """ import json import os from pathlib import Path from datasets import load_dataset from tqdm import tqdm DATA_DIR = Path("data") IMG_DIR = DATA_DIR / "images" TRAIN_JSONL = DATA_DIR / "train.jsonl" SMOKE_JSONL = DATA_DIR / "smoke_test.jsonl" SMOKE_SAMPLES = 200 IMG_DIR.mkdir(parents=True, exist_ok=True) print("Loading Kvasir-VQA from HuggingFace...") ds = load_dataset("SimulaMet-HOST/Kvasir-VQA", split="raw") print(f"Total QA pairs: {len(ds)}") print("Saving images...") seen = set() for row in tqdm(ds, desc="images"): img_id = row["img_id"] if img_id not in seen: row["image"].save(str(IMG_DIR / f"{img_id}.jpg")) seen.add(img_id) print(f"Saved {len(seen)} unique images") print("Building JSONL...") records = [] for row in tqdm(ds, desc="QA pairs"): img_path = str((IMG_DIR / f"{row['img_id']}.jpg").resolve()) records.append({ "image": img_path, "conversations": [ {"from": "human", "value": f"\n{row['question']}"}, {"from": "gpt", "value": row["answer"]}, ] }) with open(TRAIN_JSONL, "w") as f: for r in records: f.write(json.dumps(r) + "\n") print(f"Full train: {len(records)} samples → {TRAIN_JSONL}") with open(SMOKE_JSONL, "w") as f: for r in records[:SMOKE_SAMPLES]: f.write(json.dumps(r) + "\n") print(f"Smoke test: {SMOKE_SAMPLES} samples → {SMOKE_JSONL}") print("\nSample:") print(json.dumps(records[0], indent=2))