CoolFace
Apppublic

stevafernandes/Fine-Tuning-HunyuanOCR

sourceHugging Faceapache-2.0updated 1mo agoView on Hugging Face
0likes
common.py69 linesDownload Raw Back to root
1"""Shared constants and helpers for the MuseumSCAT HunyuanOCR fine-tuning pipeline."""2 3import json4import re5 6# Fixed instruction used for training, prediction, and the deployed app.7# It must stay byte-identical across all three, since the model is fine-tuned on it.8PROMPT = (9    "Read the specimen labels in this image. Transcribe the collection date and the "10    "collection locality exactly as written on the labels, using the Danish alphabet "11    '(replace historical umlauts). Answer with JSON only, in the form '12    '{"verbatimDate": "...", "verbatimLocality": "..."}. '13    'Use "MISSING" for a field that is not present on any label.'14)15 16MISSING = "MISSING"17 18# Longest image side, applied when preparing training data and again at19# inference (predict.py and the Space app). Must match the resolution the20# adapter was trained at.21MAX_SIDE = 153622 23 24def target_json(date: str, locality: str) -> str:25    """Serialize a training target. Key order is fixed: date first."""26    return json.dumps(27        {"verbatimDate": date, "verbatimLocality": locality},28        ensure_ascii=False,29    )30 31 32def parse_prediction(text: str) -> dict:33    """Parse a model response into {'verbatimDate': str, 'verbatimLocality': str}.34 35    Scans for the first parseable JSON object anywhere in the text, so exact36    JSON, JSON with surrounding prose, and repeated objects all work. Falls37    back to MISSING for fields that cannot be recovered.38    """39    text = text.strip()40    decoder = json.JSONDecoder()41    for match in re.finditer(r"\{", text):42        try:43            obj, _ = decoder.raw_decode(text, match.start())44        except ValueError:45            continue46        if isinstance(obj, dict):47            date = obj.get("verbatimDate")48            locality = obj.get("verbatimLocality")49            return {50                "verbatimDate": str(date) if date is not None else MISSING,51                "verbatimLocality": str(locality) if locality is not None else MISSING,52            }53    return {"verbatimDate": MISSING, "verbatimLocality": MISSING}54 55 56def normalized_edit_distance(pred: str, truth: str) -> float:57    """Levenshtein distance divided by the length of the longer string (0..1)."""58    if pred == truth:59        return 0.060    if not pred or not truth:61        return 1.062    prev = list(range(len(truth) + 1))63    for i, pc in enumerate(pred, start=1):64        cur = [i]65        for j, tc in enumerate(truth, start=1):66            cur.append(min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + (pc != tc)))67        prev = cur68    return prev[-1] / max(len(pred), len(truth))69