File size: 2,969 Bytes
de2a6e9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
"""Bounded, model-independent API input contracts (no network or model imports)."""
import json
import math

MAX_IMAGE_PIXELS = 16_000_000
MAX_CAPTIONS = 100
MAX_COORDINATES = 100
MAX_TOP_K = 20


def top_k_value(value):
    if isinstance(value, bool) or not isinstance(value, (int, float)):
        raise ValueError("top_k must be an integer from 1 to 20.")
    if not math.isfinite(value) or int(value) != value or not 1 <= value <= MAX_TOP_K:
        raise ValueError("top_k must be an integer from 1 to 20.")
    return int(value)


def _records(raw):
    if not isinstance(raw, str) or len(raw) > 50_000:
        raise ValueError("Input must be a JSON string no longer than 50000 characters.")
    try:
        rows = json.loads(raw)
    except (json.JSONDecodeError, RecursionError) as exc:
        raise ValueError("Input is not valid JSON.") from exc
    if not isinstance(rows, list) or not 1 <= len(rows) <= 100:
        raise ValueError("Provide a JSON array containing 1 to 100 candidates.")
    return rows


def _identifier(value, index):
    if value is None:
        value = str(index)
    if not isinstance(value, str) or not value.strip() or len(value) > 120:
        raise ValueError("Each id must be a nonempty string with at most 120 characters.")
    return value


def caption_rows(raw):
    output = []
    for index, row in enumerate(_records(raw)):
        if isinstance(row, str):
            row = {"id": str(index), "text": row}
        if not isinstance(row, dict) or not set(row) <= {"id", "text"}:
            raise ValueError('Captions must be strings or objects with "id" and "text".')
        caption = row.get("text")
        if not isinstance(caption, str) or not caption.strip() or len(caption) > 500:
            raise ValueError("Each caption must contain 1 to 500 characters.")
        output.append({"id": _identifier(row.get("id"), index), "text": caption.strip()})
    if len({row["id"] for row in output}) != len(output):
        raise ValueError("Candidate ids must be unique.")
    return output


def coordinate_rows(raw):
    output = []
    for index, row in enumerate(_records(raw)):
        if not isinstance(row, dict) or not set(row) <= {"id", "lat", "lon"}:
            raise ValueError('Coordinates must be objects with "id", "lat", and "lon".')
        for key, bound in (("lat", 90), ("lon", 180)):
            number = row.get(key)
            if isinstance(number, bool) or not isinstance(number, (int, float)):
                raise ValueError(f"{key} must be a finite number.")
            if not math.isfinite(number) or not -bound <= number <= bound:
                raise ValueError(f"{key} must lie within [-{bound}, {bound}].")
        output.append({"id": _identifier(row.get("id"), index),
                       "lat": float(row["lat"]), "lon": float(row["lon"])})
    if len({row["id"] for row in output}) != len(output):
        raise ValueError("Candidate ids must be unique.")
    return output