Skip to content

Layoutprompter

LayoutPrompter Pydantic AI agent package.

ConditionType

Bases: StrEnum

Canonical condition names used by layout generation interfaces.

Source code in lib/laygen/src/laygen/common/conditions.py
 9
10
11
12
13
14
15
16
17
18
19
20
21
class ConditionType(StrEnum):
    """Canonical condition names used by layout generation interfaces."""

    unconditional = auto()
    label = auto()
    label_size = auto()
    completion = auto()
    refinement = auto()
    text = auto()
    content_image = auto()
    relation = auto()
    hierarchical = auto()
    retrieval = auto()

LayoutPrompter

Bases: BaseLayoutAgent[LayoutPrompterOutput]

High-level LayoutPrompter Pydantic AI agent.

Parameters:

Name Type Description Default
config LayoutPrompterConfig

Runtime prompt, retrieval, parser, and model settings.

required

Raises:

Type Description
ValueError

If the config contains an unsupported mode.

Examples:

>>> import numpy as np
>>> from pydantic_ai.models.test import TestModel
>>> model = TestModel(custom_output_args={"elements": []})
>>> agent = LayoutPrompter(LayoutPrompterConfig(model=model, num_prompt=1))
>>> isinstance(agent, LayoutPrompter)
True
Source code in models/layoutprompter/src/layoutprompter/agent.py
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
class LayoutPrompter(BaseLayoutAgent[LayoutPrompterOutput]):
    """High-level LayoutPrompter Pydantic AI agent.

    Args:
        config: Runtime prompt, retrieval, parser, and model settings.

    Raises:
        ValueError: If the config contains an unsupported mode.

    Examples:
        >>> import numpy as np
        >>> from pydantic_ai.models.test import TestModel
        >>> model = TestModel(custom_output_args={"elements": []})
        >>> agent = LayoutPrompter(LayoutPrompterConfig(model=model, num_prompt=1))
        >>> isinstance(agent, LayoutPrompter)
        True
    """

    def __init__(self, config: LayoutPrompterConfig) -> None:
        """Create a LayoutPrompter runner from runtime config.

        Args:
            config: Agent configuration.

        Raises:
            ValueError: If a config mode cannot be normalized.
        """
        self.config = config
        super().__init__(
            model=self.config.model,
            model_env_var=DEFAULT_MODEL_ENV_VAR,
            raw_response_type=LayoutPrompterOutput,
            instructions=INSTRUCTIONS,
        )
        self.serializer = create_serializer(
            self.config.dataset,
            self.config.task,
            self.config.input_format,
            self.config.output_format,
        )
        self.parser = Parser(self.config.dataset, self.config.output_format)

    def build_prompt(
        self, train_data: Sequence[LayoutRecord], test_data: LayoutRecord
    ) -> str:
        """Select exemplars and build the final LayoutPrompter prompt.

        Args:
            train_data: Candidate exemplar records with `labels`, `bboxes`, and
                `discrete_gold_bboxes` tensors.
            test_data: Test record containing task-specific constraints.

        Returns:
            The final few-shot prompt sent to the configured model.

        Raises:
            KeyError: If required record fields are missing.

        Examples:
            >>> import numpy as np
            >>> from pydantic_ai.models.test import TestModel
            >>> record = {
            ...     "labels": np.asarray([0]),
            ...     "bboxes": np.asarray([[1, 2, 3, 4]]),
            ...     "discrete_gold_bboxes": np.asarray([[1, 2, 3, 4]]),
            ... }
            >>> agent = LayoutPrompter(
            ...     LayoutPrompterConfig(model=TestModel(), shuffle=False, num_prompt=1)
            ... )
            >>> "Element Type Constraint" in agent.build_prompt([record], record)
            True
        """
        selector = create_selector(
            self.config.task,
            train_data,
            self.config.candidate_size,
            self.config.num_prompt,
            shuffle=self.config.shuffle,
            seed=self.config.seed,
        )
        exemplars = selector(test_data)
        return build_prompt(
            self.serializer,
            exemplars,
            test_data,
            self.config.dataset,
            max_length=self.config.max_length,
        )

    def run_sync(
        self, train_data: Sequence[LayoutRecord], test_data: LayoutRecord
    ) -> LayoutGenerationOutput:
        """Run the Pydantic AI model and return the common layout schema.

        Args:
            train_data: Candidate exemplar records.
            test_data: Test record containing task-specific constraints.

        Returns:
            A `LayoutGenerationOutput` with normalized center `xywh` boxes.

        Raises:
            RuntimeError: If the model output cannot be parsed.

        Examples:
            >>> import numpy as np
            >>> from pydantic_ai.models.test import TestModel
            >>> model = TestModel(custom_output_args={"elements": []})
            >>> record = {
            ...     "labels": np.asarray([0]),
            ...     "bboxes": np.asarray([[1, 2, 3, 4]]),
            ...     "discrete_gold_bboxes": np.asarray([[1, 2, 3, 4]]),
            ... }
            >>> agent = LayoutPrompter(LayoutPrompterConfig(model=model, num_prompt=1))
            >>> agent.run_sync([record], record).labels.shape[0]
            1
        """
        prompt = self.build_prompt(train_data, test_data)
        raw = self.run_raw_sync(
            prompt,
            model_settings=ModelSettings(
                temperature=self.config.temperature,
                top_p=self.config.top_p,
            ),
        )
        return self.parser.parse_one(raw)

    def __call__(
        self,
        *,
        train_data: Sequence[LayoutRecord],
        test_data: LayoutRecord,
        batch_size: int = 1,
        seed: int | None = None,
        generator: np.random.Generator | None = None,
        condition_type: ConditionType | str | None = None,
        labels: Int[np.ndarray, "batch elements"] | LayoutRecordPayload | None = None,
        bbox: Float[np.ndarray, "batch elements 4"] | LayoutRecordPayload | None = None,
        mask: Bool[np.ndarray, "batch elements"] | LayoutRecordPayload | None = None,
        num_elements: int
        | list[int]
        | Int[np.ndarray, "batch"]
        | LayoutRecordPayload
        | None = None,
        box_format: BoxFormat | str = BoxFormat.xywh,
        normalized: bool = True,
        canvas_size: tuple[int, int] | None = None,
        num_inference_steps: int | None = None,
        output_type: OutputType | str = OutputType.DATACLASS,
        return_intermediates: bool = False,
    ) -> LayoutGenerationOutput | LayoutOutputDict:
        """Expose the shared generation signature for LayoutPrompter.

        Args:
            train_data: Candidate exemplar records.
            test_data: Test record containing task-specific constraints.
            batch_size: Accepted for shared interface compatibility.
            seed: Accepted for shared interface compatibility.
            generator: Accepted for shared interface compatibility.
            condition_type: Accepted for shared interface compatibility.
            labels: Accepted for shared interface compatibility.
            bbox: Accepted for shared interface compatibility.
            mask: Accepted for shared interface compatibility.
            num_elements: Accepted for shared interface compatibility.
            box_format: Public input box format name; validated at the boundary.
            normalized: Accepted for shared interface compatibility.
            canvas_size: Accepted for shared interface compatibility.
            num_inference_steps: Accepted for shared interface compatibility.
            output_type: `dataclass` for `LayoutGenerationOutput`, or `dict`.
            return_intermediates: Accepted for shared interface compatibility.

        Returns:
            A `LayoutGenerationOutput` or dictionary representation.

        Raises:
            ValueError: If `box_format` or `output_type` is unsupported.

        Examples:
            >>> import numpy as np
            >>> from pydantic_ai.models.test import TestModel
            >>> model = TestModel(custom_output_args={"elements": []})
            >>> record = {
            ...     "labels": np.asarray([0]),
            ...     "bboxes": np.asarray([[1, 2, 3, 4]]),
            ...     "discrete_gold_bboxes": np.asarray([[1, 2, 3, 4]]),
            ... }
            >>> agent = LayoutPrompter(LayoutPrompterConfig(model=model, num_prompt=1))
            >>> isinstance(agent(train_data=[record], test_data=record), LayoutGenerationOutput)
            True
        """
        if condition_type is not None:
            normalize_condition_type(condition_type)
        del (
            batch_size,
            seed,
            generator,
            condition_type,
            labels,
            bbox,
            mask,
            num_elements,
            normalized,
            canvas_size,
            num_inference_steps,
            return_intermediates,
        )
        normalize_box_format(box_format)
        normalized_output_type = normalize_output_type(output_type)
        output = self.run_sync(train_data, test_data)
        if normalized_output_type is OutputType.DATACLASS:
            return output
        if normalized_output_type is OutputType.DICT:
            return self.output_to_dict(output)
        assert_never(normalized_output_type)

    def save_pretrained(self, save_directory: str | os.PathLike[str]) -> None:
        """Persist the dataset and prompt configuration.

        Args:
            save_directory: Target directory for `layoutprompter_config.json`.

        Returns:
            None.

        Raises:
            OSError: If the directory or config file cannot be written.

        Examples:
            >>> from tempfile import TemporaryDirectory
            >>> from pydantic_ai.models.test import TestModel
            >>> agent = LayoutPrompter(LayoutPrompterConfig(model=TestModel()))
            >>> with TemporaryDirectory() as tmpdir:
            ...     agent.save_pretrained(tmpdir)
        """
        path = Path(save_directory)
        path.mkdir(parents=True, exist_ok=True)
        config = asdict(self.config)
        config["model"] = None
        config["dataset"] = str(self.config.dataset)
        config["condition_type"] = str(self.config.condition_type)
        config["input_format"] = str(self.config.input_format)
        config["output_format"] = str(self.config.output_format)
        (path / "layoutprompter_config.json").write_text(
            json.dumps(config, indent=2, sort_keys=True) + "\n",
            encoding="utf-8",
        )

    @classmethod
    def from_pretrained(
        cls,
        pretrained_model_name_or_path: str | os.PathLike[str],
        *,
        model: ModelLike = None,
    ) -> "LayoutPrompter":
        """Load a saved LayoutPrompter dataset and prompt configuration.

        Args:
            pretrained_model_name_or_path: Directory containing
                `layoutprompter_config.json`.
            model: Replacement Pydantic AI model or model string.

        Returns:
            A configured `LayoutPrompter` instance.

        Raises:
            OSError: If the config file cannot be read.
            ValueError: If saved config modes are unsupported.

        Examples:
            >>> from tempfile import TemporaryDirectory
            >>> from pydantic_ai.models.test import TestModel
            >>> model = TestModel(custom_output_args={"elements": []})
            >>> agent = LayoutPrompter(LayoutPrompterConfig(model=model))
            >>> with TemporaryDirectory() as tmpdir:
            ...     agent.save_pretrained(tmpdir)
            ...     loaded = LayoutPrompter.from_pretrained(tmpdir, model=model)
            >>> isinstance(loaded, LayoutPrompter)
            True
        """
        path = Path(pretrained_model_name_or_path) / "layoutprompter_config.json"
        config_data = json.loads(path.read_text(encoding="utf-8"))
        config_data["model"] = model
        return cls(LayoutPrompterConfig(**config_data))

    @staticmethod
    def _resolve_model(model: ModelLike = None) -> ModelLike:
        if model is not None:
            return model
        return (
            os.getenv(DEFAULT_MODEL_ENV_VAR)
            or os.getenv("PYDANTIC_AI_MODEL")
            or DEFAULT_MODEL
        )

    def resolve_model(self, model: ModelLike = None) -> ModelLike:
        """Resolve constructor or per-call model with LayoutPrompter defaults."""
        return self._resolve_model(model)

__init__

__init__(config: LayoutPrompterConfig) -> None

Create a LayoutPrompter runner from runtime config.

Parameters:

Name Type Description Default
config LayoutPrompterConfig

Agent configuration.

required

Raises:

Type Description
ValueError

If a config mode cannot be normalized.

Source code in models/layoutprompter/src/layoutprompter/agent.py
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
def __init__(self, config: LayoutPrompterConfig) -> None:
    """Create a LayoutPrompter runner from runtime config.

    Args:
        config: Agent configuration.

    Raises:
        ValueError: If a config mode cannot be normalized.
    """
    self.config = config
    super().__init__(
        model=self.config.model,
        model_env_var=DEFAULT_MODEL_ENV_VAR,
        raw_response_type=LayoutPrompterOutput,
        instructions=INSTRUCTIONS,
    )
    self.serializer = create_serializer(
        self.config.dataset,
        self.config.task,
        self.config.input_format,
        self.config.output_format,
    )
    self.parser = Parser(self.config.dataset, self.config.output_format)

build_prompt

build_prompt(
    train_data: Sequence[LayoutRecord],
    test_data: LayoutRecord,
) -> str

Select exemplars and build the final LayoutPrompter prompt.

Parameters:

Name Type Description Default
train_data Sequence[LayoutRecord]

Candidate exemplar records with labels, bboxes, and discrete_gold_bboxes tensors.

required
test_data LayoutRecord

Test record containing task-specific constraints.

required

Returns:

Type Description
str

The final few-shot prompt sent to the configured model.

Raises:

Type Description
KeyError

If required record fields are missing.

Examples:

>>> import numpy as np
>>> from pydantic_ai.models.test import TestModel
>>> record = {
...     "labels": np.asarray([0]),
...     "bboxes": np.asarray([[1, 2, 3, 4]]),
...     "discrete_gold_bboxes": np.asarray([[1, 2, 3, 4]]),
... }
>>> agent = LayoutPrompter(
...     LayoutPrompterConfig(model=TestModel(), shuffle=False, num_prompt=1)
... )
>>> "Element Type Constraint" in agent.build_prompt([record], record)
True
Source code in models/layoutprompter/src/layoutprompter/agent.py
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
def build_prompt(
    self, train_data: Sequence[LayoutRecord], test_data: LayoutRecord
) -> str:
    """Select exemplars and build the final LayoutPrompter prompt.

    Args:
        train_data: Candidate exemplar records with `labels`, `bboxes`, and
            `discrete_gold_bboxes` tensors.
        test_data: Test record containing task-specific constraints.

    Returns:
        The final few-shot prompt sent to the configured model.

    Raises:
        KeyError: If required record fields are missing.

    Examples:
        >>> import numpy as np
        >>> from pydantic_ai.models.test import TestModel
        >>> record = {
        ...     "labels": np.asarray([0]),
        ...     "bboxes": np.asarray([[1, 2, 3, 4]]),
        ...     "discrete_gold_bboxes": np.asarray([[1, 2, 3, 4]]),
        ... }
        >>> agent = LayoutPrompter(
        ...     LayoutPrompterConfig(model=TestModel(), shuffle=False, num_prompt=1)
        ... )
        >>> "Element Type Constraint" in agent.build_prompt([record], record)
        True
    """
    selector = create_selector(
        self.config.task,
        train_data,
        self.config.candidate_size,
        self.config.num_prompt,
        shuffle=self.config.shuffle,
        seed=self.config.seed,
    )
    exemplars = selector(test_data)
    return build_prompt(
        self.serializer,
        exemplars,
        test_data,
        self.config.dataset,
        max_length=self.config.max_length,
    )

run_sync

run_sync(
    train_data: Sequence[LayoutRecord],
    test_data: LayoutRecord,
) -> LayoutGenerationOutput

Run the Pydantic AI model and return the common layout schema.

Parameters:

Name Type Description Default
train_data Sequence[LayoutRecord]

Candidate exemplar records.

required
test_data LayoutRecord

Test record containing task-specific constraints.

required

Returns:

Type Description
LayoutGenerationOutput

A LayoutGenerationOutput with normalized center xywh boxes.

Raises:

Type Description
RuntimeError

If the model output cannot be parsed.

Examples:

>>> import numpy as np
>>> from pydantic_ai.models.test import TestModel
>>> model = TestModel(custom_output_args={"elements": []})
>>> record = {
...     "labels": np.asarray([0]),
...     "bboxes": np.asarray([[1, 2, 3, 4]]),
...     "discrete_gold_bboxes": np.asarray([[1, 2, 3, 4]]),
... }
>>> agent = LayoutPrompter(LayoutPrompterConfig(model=model, num_prompt=1))
>>> agent.run_sync([record], record).labels.shape[0]
1
Source code in models/layoutprompter/src/layoutprompter/agent.py
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
def run_sync(
    self, train_data: Sequence[LayoutRecord], test_data: LayoutRecord
) -> LayoutGenerationOutput:
    """Run the Pydantic AI model and return the common layout schema.

    Args:
        train_data: Candidate exemplar records.
        test_data: Test record containing task-specific constraints.

    Returns:
        A `LayoutGenerationOutput` with normalized center `xywh` boxes.

    Raises:
        RuntimeError: If the model output cannot be parsed.

    Examples:
        >>> import numpy as np
        >>> from pydantic_ai.models.test import TestModel
        >>> model = TestModel(custom_output_args={"elements": []})
        >>> record = {
        ...     "labels": np.asarray([0]),
        ...     "bboxes": np.asarray([[1, 2, 3, 4]]),
        ...     "discrete_gold_bboxes": np.asarray([[1, 2, 3, 4]]),
        ... }
        >>> agent = LayoutPrompter(LayoutPrompterConfig(model=model, num_prompt=1))
        >>> agent.run_sync([record], record).labels.shape[0]
        1
    """
    prompt = self.build_prompt(train_data, test_data)
    raw = self.run_raw_sync(
        prompt,
        model_settings=ModelSettings(
            temperature=self.config.temperature,
            top_p=self.config.top_p,
        ),
    )
    return self.parser.parse_one(raw)

__call__

__call__(
    *,
    train_data: Sequence[LayoutRecord],
    test_data: LayoutRecord,
    batch_size: int = 1,
    seed: int | None = None,
    generator: Generator | None = None,
    condition_type: ConditionType | str | None = None,
    labels: Int[ndarray, "batch elements"]
    | LayoutRecordPayload
    | None = None,
    bbox: Float[ndarray, "batch elements 4"]
    | LayoutRecordPayload
    | None = None,
    mask: Bool[ndarray, "batch elements"]
    | LayoutRecordPayload
    | None = None,
    num_elements: int
    | list[int]
    | Int[ndarray, "batch"]
    | LayoutRecordPayload
    | None = None,
    box_format: BoxFormat | str = BoxFormat.xywh,
    normalized: bool = True,
    canvas_size: tuple[int, int] | None = None,
    num_inference_steps: int | None = None,
    output_type: OutputType | str = OutputType.DATACLASS,
    return_intermediates: bool = False,
) -> LayoutGenerationOutput | LayoutOutputDict

Expose the shared generation signature for LayoutPrompter.

Parameters:

Name Type Description Default
train_data Sequence[LayoutRecord]

Candidate exemplar records.

required
test_data LayoutRecord

Test record containing task-specific constraints.

required
batch_size int

Accepted for shared interface compatibility.

1
seed int | None

Accepted for shared interface compatibility.

None
generator Generator | None

Accepted for shared interface compatibility.

None
condition_type ConditionType | str | None

Accepted for shared interface compatibility.

None
labels Int[ndarray, 'batch elements'] | LayoutRecordPayload | None

Accepted for shared interface compatibility.

None
bbox Float[ndarray, 'batch elements 4'] | LayoutRecordPayload | None

Accepted for shared interface compatibility.

None
mask Bool[ndarray, 'batch elements'] | LayoutRecordPayload | None

Accepted for shared interface compatibility.

None
num_elements int | list[int] | Int[ndarray, 'batch'] | LayoutRecordPayload | None

Accepted for shared interface compatibility.

None
box_format BoxFormat | str

Public input box format name; validated at the boundary.

xywh
normalized bool

Accepted for shared interface compatibility.

True
canvas_size tuple[int, int] | None

Accepted for shared interface compatibility.

None
num_inference_steps int | None

Accepted for shared interface compatibility.

None
output_type OutputType | str

dataclass for LayoutGenerationOutput, or dict.

DATACLASS
return_intermediates bool

Accepted for shared interface compatibility.

False

Returns:

Type Description
LayoutGenerationOutput | LayoutOutputDict

A LayoutGenerationOutput or dictionary representation.

Raises:

Type Description
ValueError

If box_format or output_type is unsupported.

Examples:

>>> import numpy as np
>>> from pydantic_ai.models.test import TestModel
>>> model = TestModel(custom_output_args={"elements": []})
>>> record = {
...     "labels": np.asarray([0]),
...     "bboxes": np.asarray([[1, 2, 3, 4]]),
...     "discrete_gold_bboxes": np.asarray([[1, 2, 3, 4]]),
... }
>>> agent = LayoutPrompter(LayoutPrompterConfig(model=model, num_prompt=1))
>>> isinstance(agent(train_data=[record], test_data=record), LayoutGenerationOutput)
True
Source code in models/layoutprompter/src/layoutprompter/agent.py
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
def __call__(
    self,
    *,
    train_data: Sequence[LayoutRecord],
    test_data: LayoutRecord,
    batch_size: int = 1,
    seed: int | None = None,
    generator: np.random.Generator | None = None,
    condition_type: ConditionType | str | None = None,
    labels: Int[np.ndarray, "batch elements"] | LayoutRecordPayload | None = None,
    bbox: Float[np.ndarray, "batch elements 4"] | LayoutRecordPayload | None = None,
    mask: Bool[np.ndarray, "batch elements"] | LayoutRecordPayload | None = None,
    num_elements: int
    | list[int]
    | Int[np.ndarray, "batch"]
    | LayoutRecordPayload
    | None = None,
    box_format: BoxFormat | str = BoxFormat.xywh,
    normalized: bool = True,
    canvas_size: tuple[int, int] | None = None,
    num_inference_steps: int | None = None,
    output_type: OutputType | str = OutputType.DATACLASS,
    return_intermediates: bool = False,
) -> LayoutGenerationOutput | LayoutOutputDict:
    """Expose the shared generation signature for LayoutPrompter.

    Args:
        train_data: Candidate exemplar records.
        test_data: Test record containing task-specific constraints.
        batch_size: Accepted for shared interface compatibility.
        seed: Accepted for shared interface compatibility.
        generator: Accepted for shared interface compatibility.
        condition_type: Accepted for shared interface compatibility.
        labels: Accepted for shared interface compatibility.
        bbox: Accepted for shared interface compatibility.
        mask: Accepted for shared interface compatibility.
        num_elements: Accepted for shared interface compatibility.
        box_format: Public input box format name; validated at the boundary.
        normalized: Accepted for shared interface compatibility.
        canvas_size: Accepted for shared interface compatibility.
        num_inference_steps: Accepted for shared interface compatibility.
        output_type: `dataclass` for `LayoutGenerationOutput`, or `dict`.
        return_intermediates: Accepted for shared interface compatibility.

    Returns:
        A `LayoutGenerationOutput` or dictionary representation.

    Raises:
        ValueError: If `box_format` or `output_type` is unsupported.

    Examples:
        >>> import numpy as np
        >>> from pydantic_ai.models.test import TestModel
        >>> model = TestModel(custom_output_args={"elements": []})
        >>> record = {
        ...     "labels": np.asarray([0]),
        ...     "bboxes": np.asarray([[1, 2, 3, 4]]),
        ...     "discrete_gold_bboxes": np.asarray([[1, 2, 3, 4]]),
        ... }
        >>> agent = LayoutPrompter(LayoutPrompterConfig(model=model, num_prompt=1))
        >>> isinstance(agent(train_data=[record], test_data=record), LayoutGenerationOutput)
        True
    """
    if condition_type is not None:
        normalize_condition_type(condition_type)
    del (
        batch_size,
        seed,
        generator,
        condition_type,
        labels,
        bbox,
        mask,
        num_elements,
        normalized,
        canvas_size,
        num_inference_steps,
        return_intermediates,
    )
    normalize_box_format(box_format)
    normalized_output_type = normalize_output_type(output_type)
    output = self.run_sync(train_data, test_data)
    if normalized_output_type is OutputType.DATACLASS:
        return output
    if normalized_output_type is OutputType.DICT:
        return self.output_to_dict(output)
    assert_never(normalized_output_type)

save_pretrained

save_pretrained(
    save_directory: str | PathLike[str],
) -> None

Persist the dataset and prompt configuration.

Parameters:

Name Type Description Default
save_directory str | PathLike[str]

Target directory for layoutprompter_config.json.

required

Returns:

Type Description
None

None.

Raises:

Type Description
OSError

If the directory or config file cannot be written.

Examples:

>>> from tempfile import TemporaryDirectory
>>> from pydantic_ai.models.test import TestModel
>>> agent = LayoutPrompter(LayoutPrompterConfig(model=TestModel()))
>>> with TemporaryDirectory() as tmpdir:
...     agent.save_pretrained(tmpdir)
Source code in models/layoutprompter/src/layoutprompter/agent.py
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
def save_pretrained(self, save_directory: str | os.PathLike[str]) -> None:
    """Persist the dataset and prompt configuration.

    Args:
        save_directory: Target directory for `layoutprompter_config.json`.

    Returns:
        None.

    Raises:
        OSError: If the directory or config file cannot be written.

    Examples:
        >>> from tempfile import TemporaryDirectory
        >>> from pydantic_ai.models.test import TestModel
        >>> agent = LayoutPrompter(LayoutPrompterConfig(model=TestModel()))
        >>> with TemporaryDirectory() as tmpdir:
        ...     agent.save_pretrained(tmpdir)
    """
    path = Path(save_directory)
    path.mkdir(parents=True, exist_ok=True)
    config = asdict(self.config)
    config["model"] = None
    config["dataset"] = str(self.config.dataset)
    config["condition_type"] = str(self.config.condition_type)
    config["input_format"] = str(self.config.input_format)
    config["output_format"] = str(self.config.output_format)
    (path / "layoutprompter_config.json").write_text(
        json.dumps(config, indent=2, sort_keys=True) + "\n",
        encoding="utf-8",
    )

from_pretrained classmethod

from_pretrained(
    pretrained_model_name_or_path: str | PathLike[str],
    *,
    model: ModelLike = None,
) -> "LayoutPrompter"

Load a saved LayoutPrompter dataset and prompt configuration.

Parameters:

Name Type Description Default
pretrained_model_name_or_path str | PathLike[str]

Directory containing layoutprompter_config.json.

required
model ModelLike

Replacement Pydantic AI model or model string.

None

Returns:

Type Description
'LayoutPrompter'

A configured LayoutPrompter instance.

Raises:

Type Description
OSError

If the config file cannot be read.

ValueError

If saved config modes are unsupported.

Examples:

>>> from tempfile import TemporaryDirectory
>>> from pydantic_ai.models.test import TestModel
>>> model = TestModel(custom_output_args={"elements": []})
>>> agent = LayoutPrompter(LayoutPrompterConfig(model=model))
>>> with TemporaryDirectory() as tmpdir:
...     agent.save_pretrained(tmpdir)
...     loaded = LayoutPrompter.from_pretrained(tmpdir, model=model)
>>> isinstance(loaded, LayoutPrompter)
True
Source code in models/layoutprompter/src/layoutprompter/agent.py
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
@classmethod
def from_pretrained(
    cls,
    pretrained_model_name_or_path: str | os.PathLike[str],
    *,
    model: ModelLike = None,
) -> "LayoutPrompter":
    """Load a saved LayoutPrompter dataset and prompt configuration.

    Args:
        pretrained_model_name_or_path: Directory containing
            `layoutprompter_config.json`.
        model: Replacement Pydantic AI model or model string.

    Returns:
        A configured `LayoutPrompter` instance.

    Raises:
        OSError: If the config file cannot be read.
        ValueError: If saved config modes are unsupported.

    Examples:
        >>> from tempfile import TemporaryDirectory
        >>> from pydantic_ai.models.test import TestModel
        >>> model = TestModel(custom_output_args={"elements": []})
        >>> agent = LayoutPrompter(LayoutPrompterConfig(model=model))
        >>> with TemporaryDirectory() as tmpdir:
        ...     agent.save_pretrained(tmpdir)
        ...     loaded = LayoutPrompter.from_pretrained(tmpdir, model=model)
        >>> isinstance(loaded, LayoutPrompter)
        True
    """
    path = Path(pretrained_model_name_or_path) / "layoutprompter_config.json"
    config_data = json.loads(path.read_text(encoding="utf-8"))
    config_data["model"] = model
    return cls(LayoutPrompterConfig(**config_data))

resolve_model

resolve_model(model: ModelLike = None) -> ModelLike

Resolve constructor or per-call model with LayoutPrompter defaults.

Source code in models/layoutprompter/src/layoutprompter/agent.py
441
442
443
def resolve_model(self, model: ModelLike = None) -> ModelLike:
    """Resolve constructor or per-call model with LayoutPrompter defaults."""
    return self._resolve_model(model)

LayoutPrompterConfig dataclass

Runtime configuration for LayoutPrompter prompt generation.

Parameters:

Name Type Description Default
dataset SupportedDataset | str

Dataset vocabulary to use. Public strings are normalized to LayoutPrompterDataset.

publaynet
condition_type ConditionType | str

Public condition name or release alias.

label
input_format PromptFormat | str

Prompt input format, either seq or html.

SEQ
output_format PromptFormat | str

Model output format, either seq or html.

SEQ
candidate_size int

Number of training candidates to keep before retrieval. -1 keeps all candidates.

DEFAULT_CANDIDATE_SIZE
num_prompt int

Maximum number of few-shot exemplars in each prompt.

DEFAULT_NUM_PROMPT
shuffle bool

Whether to shuffle selected exemplars after ranking.

True
seed int | None

Optional deterministic seed for exemplar selection.

None
max_length int

Maximum prompt length used while adding exemplars.

DEFAULT_MAX_LENGTH
temperature float

Model sampling temperature passed to Pydantic AI.

DEFAULT_TEMPERATURE
top_p float

Nucleus sampling value passed to Pydantic AI.

DEFAULT_TOP_P
model ModelLike

Pydantic AI model instance or model string.

None

Raises:

Type Description
ValueError

If a dataset, condition, or prompt format is unsupported.

Examples:

>>> from pydantic_ai.models.test import TestModel
>>> config = LayoutPrompterConfig(
...     dataset="webui",
...     condition_type="label",
...     model=TestModel(custom_output_args={"elements": []}),
... )
>>> config.task
'gent'
Source code in models/layoutprompter/src/layoutprompter/agent.py
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
@dataclass(frozen=True)
class LayoutPrompterConfig:
    """Runtime configuration for LayoutPrompter prompt generation.

    Args:
        dataset: Dataset vocabulary to use. Public strings are normalized to
            `LayoutPrompterDataset`.
        condition_type: Public condition name or release alias.
        input_format: Prompt input format, either `seq` or `html`.
        output_format: Model output format, either `seq` or `html`.
        candidate_size: Number of training candidates to keep before retrieval.
            `-1` keeps all candidates.
        num_prompt: Maximum number of few-shot exemplars in each prompt.
        shuffle: Whether to shuffle selected exemplars after ranking.
        seed: Optional deterministic seed for exemplar selection.
        max_length: Maximum prompt length used while adding exemplars.
        temperature: Model sampling temperature passed to Pydantic AI.
        top_p: Nucleus sampling value passed to Pydantic AI.
        model: Pydantic AI model instance or model string.

    Raises:
        ValueError: If a dataset, condition, or prompt format is unsupported.

    Examples:
        >>> from pydantic_ai.models.test import TestModel
        >>> config = LayoutPrompterConfig(
        ...     dataset="webui",
        ...     condition_type="label",
        ...     model=TestModel(custom_output_args={"elements": []}),
        ... )
        >>> config.task
        'gent'
    """

    dataset: SupportedDataset | str = DatasetName.publaynet
    condition_type: ConditionType | str = ConditionType.label
    input_format: PromptFormat | str = PromptFormat.SEQ
    output_format: PromptFormat | str = PromptFormat.SEQ
    candidate_size: int = DEFAULT_CANDIDATE_SIZE
    num_prompt: int = DEFAULT_NUM_PROMPT
    shuffle: bool = True
    seed: int | None = None
    max_length: int = DEFAULT_MAX_LENGTH
    temperature: float = DEFAULT_TEMPERATURE
    top_p: float = DEFAULT_TOP_P
    model: ModelLike = None

    def __post_init__(self) -> None:
        """Normalize public string modes to enums at the config boundary."""
        object.__setattr__(self, "dataset", normalize_dataset(self.dataset))
        object.__setattr__(
            self, "condition_type", normalize_condition_type(self.condition_type)
        )
        object.__setattr__(
            self, "input_format", normalize_prompt_format(self.input_format)
        )
        object.__setattr__(
            self, "output_format", normalize_prompt_format(self.output_format)
        )

    @property
    def task(self) -> LayoutPrompterTask:
        """Return the released task key."""
        condition_type = normalize_condition_type(self.condition_type)
        try:
            return TASK_ALIASES[condition_type]
        except KeyError as exc:
            raise ValueError(
                f"Unsupported LayoutPrompter condition_type: {condition_type}"
            ) from exc

task property

task: LayoutPrompterTask

Return the released task key.

__post_init__

__post_init__() -> None

Normalize public string modes to enums at the config boundary.

Source code in models/layoutprompter/src/layoutprompter/agent.py
122
123
124
125
126
127
128
129
130
131
132
133
def __post_init__(self) -> None:
    """Normalize public string modes to enums at the config boundary."""
    object.__setattr__(self, "dataset", normalize_dataset(self.dataset))
    object.__setattr__(
        self, "condition_type", normalize_condition_type(self.condition_type)
    )
    object.__setattr__(
        self, "input_format", normalize_prompt_format(self.input_format)
    )
    object.__setattr__(
        self, "output_format", normalize_prompt_format(self.output_format)
    )

LayoutPrompterDataset

Bases: StrEnum

LayoutPrompter-only dataset names absent from the shared registry.

Source code in models/layoutprompter/src/layoutprompter/enums.py
 8
 9
10
11
12
class LayoutPrompterDataset(StrEnum):
    """LayoutPrompter-only dataset names absent from the shared registry."""

    posterlayout = auto()
    webui = auto()

LayoutPrompterTask

Bases: StrEnum

Released task keys supported by LayoutPrompter.

Source code in models/layoutprompter/src/layoutprompter/enums.py
29
30
31
32
33
34
35
36
37
38
class LayoutPrompterTask(StrEnum):
    """Released task keys supported by LayoutPrompter."""

    gent = auto()
    gents = auto()
    genr = auto()
    completion = auto()
    refinement = auto()
    content = auto()
    text = auto()

OutputType

Bases: StrEnum

Supported return containers for the shared call interface.

Source code in models/layoutprompter/src/layoutprompter/enums.py
22
23
24
25
26
class OutputType(StrEnum):
    """Supported return containers for the shared call interface."""

    DATACLASS = auto()
    DICT = auto()

PromptFormat

Bases: StrEnum

Supported LayoutPrompter prompt encodings.

Source code in models/layoutprompter/src/layoutprompter/enums.py
15
16
17
18
19
class PromptFormat(StrEnum):
    """Supported LayoutPrompter prompt encodings."""

    SEQ = auto()
    HTML = auto()

LayoutPrompterOutput

Bases: BaseModel

Structured output requested from the Pydantic AI model.

Source code in models/layoutprompter/src/layoutprompter/schemas.py
32
33
34
35
class LayoutPrompterOutput(BaseModel):
    """Structured output requested from the Pydantic AI model."""

    elements: list[LayoutElement] = Field(default_factory=list)

agent

Pydantic AI wrapper for LayoutPrompter.

LayoutPrompterConfig dataclass

Runtime configuration for LayoutPrompter prompt generation.

Parameters:

Name Type Description Default
dataset SupportedDataset | str

Dataset vocabulary to use. Public strings are normalized to LayoutPrompterDataset.

publaynet
condition_type ConditionType | str

Public condition name or release alias.

label
input_format PromptFormat | str

Prompt input format, either seq or html.

SEQ
output_format PromptFormat | str

Model output format, either seq or html.

SEQ
candidate_size int

Number of training candidates to keep before retrieval. -1 keeps all candidates.

DEFAULT_CANDIDATE_SIZE
num_prompt int

Maximum number of few-shot exemplars in each prompt.

DEFAULT_NUM_PROMPT
shuffle bool

Whether to shuffle selected exemplars after ranking.

True
seed int | None

Optional deterministic seed for exemplar selection.

None
max_length int

Maximum prompt length used while adding exemplars.

DEFAULT_MAX_LENGTH
temperature float

Model sampling temperature passed to Pydantic AI.

DEFAULT_TEMPERATURE
top_p float

Nucleus sampling value passed to Pydantic AI.

DEFAULT_TOP_P
model ModelLike

Pydantic AI model instance or model string.

None

Raises:

Type Description
ValueError

If a dataset, condition, or prompt format is unsupported.

Examples:

>>> from pydantic_ai.models.test import TestModel
>>> config = LayoutPrompterConfig(
...     dataset="webui",
...     condition_type="label",
...     model=TestModel(custom_output_args={"elements": []}),
... )
>>> config.task
'gent'
Source code in models/layoutprompter/src/layoutprompter/agent.py
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
@dataclass(frozen=True)
class LayoutPrompterConfig:
    """Runtime configuration for LayoutPrompter prompt generation.

    Args:
        dataset: Dataset vocabulary to use. Public strings are normalized to
            `LayoutPrompterDataset`.
        condition_type: Public condition name or release alias.
        input_format: Prompt input format, either `seq` or `html`.
        output_format: Model output format, either `seq` or `html`.
        candidate_size: Number of training candidates to keep before retrieval.
            `-1` keeps all candidates.
        num_prompt: Maximum number of few-shot exemplars in each prompt.
        shuffle: Whether to shuffle selected exemplars after ranking.
        seed: Optional deterministic seed for exemplar selection.
        max_length: Maximum prompt length used while adding exemplars.
        temperature: Model sampling temperature passed to Pydantic AI.
        top_p: Nucleus sampling value passed to Pydantic AI.
        model: Pydantic AI model instance or model string.

    Raises:
        ValueError: If a dataset, condition, or prompt format is unsupported.

    Examples:
        >>> from pydantic_ai.models.test import TestModel
        >>> config = LayoutPrompterConfig(
        ...     dataset="webui",
        ...     condition_type="label",
        ...     model=TestModel(custom_output_args={"elements": []}),
        ... )
        >>> config.task
        'gent'
    """

    dataset: SupportedDataset | str = DatasetName.publaynet
    condition_type: ConditionType | str = ConditionType.label
    input_format: PromptFormat | str = PromptFormat.SEQ
    output_format: PromptFormat | str = PromptFormat.SEQ
    candidate_size: int = DEFAULT_CANDIDATE_SIZE
    num_prompt: int = DEFAULT_NUM_PROMPT
    shuffle: bool = True
    seed: int | None = None
    max_length: int = DEFAULT_MAX_LENGTH
    temperature: float = DEFAULT_TEMPERATURE
    top_p: float = DEFAULT_TOP_P
    model: ModelLike = None

    def __post_init__(self) -> None:
        """Normalize public string modes to enums at the config boundary."""
        object.__setattr__(self, "dataset", normalize_dataset(self.dataset))
        object.__setattr__(
            self, "condition_type", normalize_condition_type(self.condition_type)
        )
        object.__setattr__(
            self, "input_format", normalize_prompt_format(self.input_format)
        )
        object.__setattr__(
            self, "output_format", normalize_prompt_format(self.output_format)
        )

    @property
    def task(self) -> LayoutPrompterTask:
        """Return the released task key."""
        condition_type = normalize_condition_type(self.condition_type)
        try:
            return TASK_ALIASES[condition_type]
        except KeyError as exc:
            raise ValueError(
                f"Unsupported LayoutPrompter condition_type: {condition_type}"
            ) from exc

task property

task: LayoutPrompterTask

Return the released task key.

__post_init__

__post_init__() -> None

Normalize public string modes to enums at the config boundary.

Source code in models/layoutprompter/src/layoutprompter/agent.py
122
123
124
125
126
127
128
129
130
131
132
133
def __post_init__(self) -> None:
    """Normalize public string modes to enums at the config boundary."""
    object.__setattr__(self, "dataset", normalize_dataset(self.dataset))
    object.__setattr__(
        self, "condition_type", normalize_condition_type(self.condition_type)
    )
    object.__setattr__(
        self, "input_format", normalize_prompt_format(self.input_format)
    )
    object.__setattr__(
        self, "output_format", normalize_prompt_format(self.output_format)
    )

LayoutPrompter

Bases: BaseLayoutAgent[LayoutPrompterOutput]

High-level LayoutPrompter Pydantic AI agent.

Parameters:

Name Type Description Default
config LayoutPrompterConfig

Runtime prompt, retrieval, parser, and model settings.

required

Raises:

Type Description
ValueError

If the config contains an unsupported mode.

Examples:

>>> import numpy as np
>>> from pydantic_ai.models.test import TestModel
>>> model = TestModel(custom_output_args={"elements": []})
>>> agent = LayoutPrompter(LayoutPrompterConfig(model=model, num_prompt=1))
>>> isinstance(agent, LayoutPrompter)
True
Source code in models/layoutprompter/src/layoutprompter/agent.py
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
class LayoutPrompter(BaseLayoutAgent[LayoutPrompterOutput]):
    """High-level LayoutPrompter Pydantic AI agent.

    Args:
        config: Runtime prompt, retrieval, parser, and model settings.

    Raises:
        ValueError: If the config contains an unsupported mode.

    Examples:
        >>> import numpy as np
        >>> from pydantic_ai.models.test import TestModel
        >>> model = TestModel(custom_output_args={"elements": []})
        >>> agent = LayoutPrompter(LayoutPrompterConfig(model=model, num_prompt=1))
        >>> isinstance(agent, LayoutPrompter)
        True
    """

    def __init__(self, config: LayoutPrompterConfig) -> None:
        """Create a LayoutPrompter runner from runtime config.

        Args:
            config: Agent configuration.

        Raises:
            ValueError: If a config mode cannot be normalized.
        """
        self.config = config
        super().__init__(
            model=self.config.model,
            model_env_var=DEFAULT_MODEL_ENV_VAR,
            raw_response_type=LayoutPrompterOutput,
            instructions=INSTRUCTIONS,
        )
        self.serializer = create_serializer(
            self.config.dataset,
            self.config.task,
            self.config.input_format,
            self.config.output_format,
        )
        self.parser = Parser(self.config.dataset, self.config.output_format)

    def build_prompt(
        self, train_data: Sequence[LayoutRecord], test_data: LayoutRecord
    ) -> str:
        """Select exemplars and build the final LayoutPrompter prompt.

        Args:
            train_data: Candidate exemplar records with `labels`, `bboxes`, and
                `discrete_gold_bboxes` tensors.
            test_data: Test record containing task-specific constraints.

        Returns:
            The final few-shot prompt sent to the configured model.

        Raises:
            KeyError: If required record fields are missing.

        Examples:
            >>> import numpy as np
            >>> from pydantic_ai.models.test import TestModel
            >>> record = {
            ...     "labels": np.asarray([0]),
            ...     "bboxes": np.asarray([[1, 2, 3, 4]]),
            ...     "discrete_gold_bboxes": np.asarray([[1, 2, 3, 4]]),
            ... }
            >>> agent = LayoutPrompter(
            ...     LayoutPrompterConfig(model=TestModel(), shuffle=False, num_prompt=1)
            ... )
            >>> "Element Type Constraint" in agent.build_prompt([record], record)
            True
        """
        selector = create_selector(
            self.config.task,
            train_data,
            self.config.candidate_size,
            self.config.num_prompt,
            shuffle=self.config.shuffle,
            seed=self.config.seed,
        )
        exemplars = selector(test_data)
        return build_prompt(
            self.serializer,
            exemplars,
            test_data,
            self.config.dataset,
            max_length=self.config.max_length,
        )

    def run_sync(
        self, train_data: Sequence[LayoutRecord], test_data: LayoutRecord
    ) -> LayoutGenerationOutput:
        """Run the Pydantic AI model and return the common layout schema.

        Args:
            train_data: Candidate exemplar records.
            test_data: Test record containing task-specific constraints.

        Returns:
            A `LayoutGenerationOutput` with normalized center `xywh` boxes.

        Raises:
            RuntimeError: If the model output cannot be parsed.

        Examples:
            >>> import numpy as np
            >>> from pydantic_ai.models.test import TestModel
            >>> model = TestModel(custom_output_args={"elements": []})
            >>> record = {
            ...     "labels": np.asarray([0]),
            ...     "bboxes": np.asarray([[1, 2, 3, 4]]),
            ...     "discrete_gold_bboxes": np.asarray([[1, 2, 3, 4]]),
            ... }
            >>> agent = LayoutPrompter(LayoutPrompterConfig(model=model, num_prompt=1))
            >>> agent.run_sync([record], record).labels.shape[0]
            1
        """
        prompt = self.build_prompt(train_data, test_data)
        raw = self.run_raw_sync(
            prompt,
            model_settings=ModelSettings(
                temperature=self.config.temperature,
                top_p=self.config.top_p,
            ),
        )
        return self.parser.parse_one(raw)

    def __call__(
        self,
        *,
        train_data: Sequence[LayoutRecord],
        test_data: LayoutRecord,
        batch_size: int = 1,
        seed: int | None = None,
        generator: np.random.Generator | None = None,
        condition_type: ConditionType | str | None = None,
        labels: Int[np.ndarray, "batch elements"] | LayoutRecordPayload | None = None,
        bbox: Float[np.ndarray, "batch elements 4"] | LayoutRecordPayload | None = None,
        mask: Bool[np.ndarray, "batch elements"] | LayoutRecordPayload | None = None,
        num_elements: int
        | list[int]
        | Int[np.ndarray, "batch"]
        | LayoutRecordPayload
        | None = None,
        box_format: BoxFormat | str = BoxFormat.xywh,
        normalized: bool = True,
        canvas_size: tuple[int, int] | None = None,
        num_inference_steps: int | None = None,
        output_type: OutputType | str = OutputType.DATACLASS,
        return_intermediates: bool = False,
    ) -> LayoutGenerationOutput | LayoutOutputDict:
        """Expose the shared generation signature for LayoutPrompter.

        Args:
            train_data: Candidate exemplar records.
            test_data: Test record containing task-specific constraints.
            batch_size: Accepted for shared interface compatibility.
            seed: Accepted for shared interface compatibility.
            generator: Accepted for shared interface compatibility.
            condition_type: Accepted for shared interface compatibility.
            labels: Accepted for shared interface compatibility.
            bbox: Accepted for shared interface compatibility.
            mask: Accepted for shared interface compatibility.
            num_elements: Accepted for shared interface compatibility.
            box_format: Public input box format name; validated at the boundary.
            normalized: Accepted for shared interface compatibility.
            canvas_size: Accepted for shared interface compatibility.
            num_inference_steps: Accepted for shared interface compatibility.
            output_type: `dataclass` for `LayoutGenerationOutput`, or `dict`.
            return_intermediates: Accepted for shared interface compatibility.

        Returns:
            A `LayoutGenerationOutput` or dictionary representation.

        Raises:
            ValueError: If `box_format` or `output_type` is unsupported.

        Examples:
            >>> import numpy as np
            >>> from pydantic_ai.models.test import TestModel
            >>> model = TestModel(custom_output_args={"elements": []})
            >>> record = {
            ...     "labels": np.asarray([0]),
            ...     "bboxes": np.asarray([[1, 2, 3, 4]]),
            ...     "discrete_gold_bboxes": np.asarray([[1, 2, 3, 4]]),
            ... }
            >>> agent = LayoutPrompter(LayoutPrompterConfig(model=model, num_prompt=1))
            >>> isinstance(agent(train_data=[record], test_data=record), LayoutGenerationOutput)
            True
        """
        if condition_type is not None:
            normalize_condition_type(condition_type)
        del (
            batch_size,
            seed,
            generator,
            condition_type,
            labels,
            bbox,
            mask,
            num_elements,
            normalized,
            canvas_size,
            num_inference_steps,
            return_intermediates,
        )
        normalize_box_format(box_format)
        normalized_output_type = normalize_output_type(output_type)
        output = self.run_sync(train_data, test_data)
        if normalized_output_type is OutputType.DATACLASS:
            return output
        if normalized_output_type is OutputType.DICT:
            return self.output_to_dict(output)
        assert_never(normalized_output_type)

    def save_pretrained(self, save_directory: str | os.PathLike[str]) -> None:
        """Persist the dataset and prompt configuration.

        Args:
            save_directory: Target directory for `layoutprompter_config.json`.

        Returns:
            None.

        Raises:
            OSError: If the directory or config file cannot be written.

        Examples:
            >>> from tempfile import TemporaryDirectory
            >>> from pydantic_ai.models.test import TestModel
            >>> agent = LayoutPrompter(LayoutPrompterConfig(model=TestModel()))
            >>> with TemporaryDirectory() as tmpdir:
            ...     agent.save_pretrained(tmpdir)
        """
        path = Path(save_directory)
        path.mkdir(parents=True, exist_ok=True)
        config = asdict(self.config)
        config["model"] = None
        config["dataset"] = str(self.config.dataset)
        config["condition_type"] = str(self.config.condition_type)
        config["input_format"] = str(self.config.input_format)
        config["output_format"] = str(self.config.output_format)
        (path / "layoutprompter_config.json").write_text(
            json.dumps(config, indent=2, sort_keys=True) + "\n",
            encoding="utf-8",
        )

    @classmethod
    def from_pretrained(
        cls,
        pretrained_model_name_or_path: str | os.PathLike[str],
        *,
        model: ModelLike = None,
    ) -> "LayoutPrompter":
        """Load a saved LayoutPrompter dataset and prompt configuration.

        Args:
            pretrained_model_name_or_path: Directory containing
                `layoutprompter_config.json`.
            model: Replacement Pydantic AI model or model string.

        Returns:
            A configured `LayoutPrompter` instance.

        Raises:
            OSError: If the config file cannot be read.
            ValueError: If saved config modes are unsupported.

        Examples:
            >>> from tempfile import TemporaryDirectory
            >>> from pydantic_ai.models.test import TestModel
            >>> model = TestModel(custom_output_args={"elements": []})
            >>> agent = LayoutPrompter(LayoutPrompterConfig(model=model))
            >>> with TemporaryDirectory() as tmpdir:
            ...     agent.save_pretrained(tmpdir)
            ...     loaded = LayoutPrompter.from_pretrained(tmpdir, model=model)
            >>> isinstance(loaded, LayoutPrompter)
            True
        """
        path = Path(pretrained_model_name_or_path) / "layoutprompter_config.json"
        config_data = json.loads(path.read_text(encoding="utf-8"))
        config_data["model"] = model
        return cls(LayoutPrompterConfig(**config_data))

    @staticmethod
    def _resolve_model(model: ModelLike = None) -> ModelLike:
        if model is not None:
            return model
        return (
            os.getenv(DEFAULT_MODEL_ENV_VAR)
            or os.getenv("PYDANTIC_AI_MODEL")
            or DEFAULT_MODEL
        )

    def resolve_model(self, model: ModelLike = None) -> ModelLike:
        """Resolve constructor or per-call model with LayoutPrompter defaults."""
        return self._resolve_model(model)

__init__

__init__(config: LayoutPrompterConfig) -> None

Create a LayoutPrompter runner from runtime config.

Parameters:

Name Type Description Default
config LayoutPrompterConfig

Agent configuration.

required

Raises:

Type Description
ValueError

If a config mode cannot be normalized.

Source code in models/layoutprompter/src/layoutprompter/agent.py
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
def __init__(self, config: LayoutPrompterConfig) -> None:
    """Create a LayoutPrompter runner from runtime config.

    Args:
        config: Agent configuration.

    Raises:
        ValueError: If a config mode cannot be normalized.
    """
    self.config = config
    super().__init__(
        model=self.config.model,
        model_env_var=DEFAULT_MODEL_ENV_VAR,
        raw_response_type=LayoutPrompterOutput,
        instructions=INSTRUCTIONS,
    )
    self.serializer = create_serializer(
        self.config.dataset,
        self.config.task,
        self.config.input_format,
        self.config.output_format,
    )
    self.parser = Parser(self.config.dataset, self.config.output_format)

build_prompt

build_prompt(
    train_data: Sequence[LayoutRecord],
    test_data: LayoutRecord,
) -> str

Select exemplars and build the final LayoutPrompter prompt.

Parameters:

Name Type Description Default
train_data Sequence[LayoutRecord]

Candidate exemplar records with labels, bboxes, and discrete_gold_bboxes tensors.

required
test_data LayoutRecord

Test record containing task-specific constraints.

required

Returns:

Type Description
str

The final few-shot prompt sent to the configured model.

Raises:

Type Description
KeyError

If required record fields are missing.

Examples:

>>> import numpy as np
>>> from pydantic_ai.models.test import TestModel
>>> record = {
...     "labels": np.asarray([0]),
...     "bboxes": np.asarray([[1, 2, 3, 4]]),
...     "discrete_gold_bboxes": np.asarray([[1, 2, 3, 4]]),
... }
>>> agent = LayoutPrompter(
...     LayoutPrompterConfig(model=TestModel(), shuffle=False, num_prompt=1)
... )
>>> "Element Type Constraint" in agent.build_prompt([record], record)
True
Source code in models/layoutprompter/src/layoutprompter/agent.py
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
def build_prompt(
    self, train_data: Sequence[LayoutRecord], test_data: LayoutRecord
) -> str:
    """Select exemplars and build the final LayoutPrompter prompt.

    Args:
        train_data: Candidate exemplar records with `labels`, `bboxes`, and
            `discrete_gold_bboxes` tensors.
        test_data: Test record containing task-specific constraints.

    Returns:
        The final few-shot prompt sent to the configured model.

    Raises:
        KeyError: If required record fields are missing.

    Examples:
        >>> import numpy as np
        >>> from pydantic_ai.models.test import TestModel
        >>> record = {
        ...     "labels": np.asarray([0]),
        ...     "bboxes": np.asarray([[1, 2, 3, 4]]),
        ...     "discrete_gold_bboxes": np.asarray([[1, 2, 3, 4]]),
        ... }
        >>> agent = LayoutPrompter(
        ...     LayoutPrompterConfig(model=TestModel(), shuffle=False, num_prompt=1)
        ... )
        >>> "Element Type Constraint" in agent.build_prompt([record], record)
        True
    """
    selector = create_selector(
        self.config.task,
        train_data,
        self.config.candidate_size,
        self.config.num_prompt,
        shuffle=self.config.shuffle,
        seed=self.config.seed,
    )
    exemplars = selector(test_data)
    return build_prompt(
        self.serializer,
        exemplars,
        test_data,
        self.config.dataset,
        max_length=self.config.max_length,
    )

run_sync

run_sync(
    train_data: Sequence[LayoutRecord],
    test_data: LayoutRecord,
) -> LayoutGenerationOutput

Run the Pydantic AI model and return the common layout schema.

Parameters:

Name Type Description Default
train_data Sequence[LayoutRecord]

Candidate exemplar records.

required
test_data LayoutRecord

Test record containing task-specific constraints.

required

Returns:

Type Description
LayoutGenerationOutput

A LayoutGenerationOutput with normalized center xywh boxes.

Raises:

Type Description
RuntimeError

If the model output cannot be parsed.

Examples:

>>> import numpy as np
>>> from pydantic_ai.models.test import TestModel
>>> model = TestModel(custom_output_args={"elements": []})
>>> record = {
...     "labels": np.asarray([0]),
...     "bboxes": np.asarray([[1, 2, 3, 4]]),
...     "discrete_gold_bboxes": np.asarray([[1, 2, 3, 4]]),
... }
>>> agent = LayoutPrompter(LayoutPrompterConfig(model=model, num_prompt=1))
>>> agent.run_sync([record], record).labels.shape[0]
1
Source code in models/layoutprompter/src/layoutprompter/agent.py
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
def run_sync(
    self, train_data: Sequence[LayoutRecord], test_data: LayoutRecord
) -> LayoutGenerationOutput:
    """Run the Pydantic AI model and return the common layout schema.

    Args:
        train_data: Candidate exemplar records.
        test_data: Test record containing task-specific constraints.

    Returns:
        A `LayoutGenerationOutput` with normalized center `xywh` boxes.

    Raises:
        RuntimeError: If the model output cannot be parsed.

    Examples:
        >>> import numpy as np
        >>> from pydantic_ai.models.test import TestModel
        >>> model = TestModel(custom_output_args={"elements": []})
        >>> record = {
        ...     "labels": np.asarray([0]),
        ...     "bboxes": np.asarray([[1, 2, 3, 4]]),
        ...     "discrete_gold_bboxes": np.asarray([[1, 2, 3, 4]]),
        ... }
        >>> agent = LayoutPrompter(LayoutPrompterConfig(model=model, num_prompt=1))
        >>> agent.run_sync([record], record).labels.shape[0]
        1
    """
    prompt = self.build_prompt(train_data, test_data)
    raw = self.run_raw_sync(
        prompt,
        model_settings=ModelSettings(
            temperature=self.config.temperature,
            top_p=self.config.top_p,
        ),
    )
    return self.parser.parse_one(raw)

__call__

__call__(
    *,
    train_data: Sequence[LayoutRecord],
    test_data: LayoutRecord,
    batch_size: int = 1,
    seed: int | None = None,
    generator: Generator | None = None,
    condition_type: ConditionType | str | None = None,
    labels: Int[ndarray, "batch elements"]
    | LayoutRecordPayload
    | None = None,
    bbox: Float[ndarray, "batch elements 4"]
    | LayoutRecordPayload
    | None = None,
    mask: Bool[ndarray, "batch elements"]
    | LayoutRecordPayload
    | None = None,
    num_elements: int
    | list[int]
    | Int[ndarray, "batch"]
    | LayoutRecordPayload
    | None = None,
    box_format: BoxFormat | str = BoxFormat.xywh,
    normalized: bool = True,
    canvas_size: tuple[int, int] | None = None,
    num_inference_steps: int | None = None,
    output_type: OutputType | str = OutputType.DATACLASS,
    return_intermediates: bool = False,
) -> LayoutGenerationOutput | LayoutOutputDict

Expose the shared generation signature for LayoutPrompter.

Parameters:

Name Type Description Default
train_data Sequence[LayoutRecord]

Candidate exemplar records.

required
test_data LayoutRecord

Test record containing task-specific constraints.

required
batch_size int

Accepted for shared interface compatibility.

1
seed int | None

Accepted for shared interface compatibility.

None
generator Generator | None

Accepted for shared interface compatibility.

None
condition_type ConditionType | str | None

Accepted for shared interface compatibility.

None
labels Int[ndarray, 'batch elements'] | LayoutRecordPayload | None

Accepted for shared interface compatibility.

None
bbox Float[ndarray, 'batch elements 4'] | LayoutRecordPayload | None

Accepted for shared interface compatibility.

None
mask Bool[ndarray, 'batch elements'] | LayoutRecordPayload | None

Accepted for shared interface compatibility.

None
num_elements int | list[int] | Int[ndarray, 'batch'] | LayoutRecordPayload | None

Accepted for shared interface compatibility.

None
box_format BoxFormat | str

Public input box format name; validated at the boundary.

xywh
normalized bool

Accepted for shared interface compatibility.

True
canvas_size tuple[int, int] | None

Accepted for shared interface compatibility.

None
num_inference_steps int | None

Accepted for shared interface compatibility.

None
output_type OutputType | str

dataclass for LayoutGenerationOutput, or dict.

DATACLASS
return_intermediates bool

Accepted for shared interface compatibility.

False

Returns:

Type Description
LayoutGenerationOutput | LayoutOutputDict

A LayoutGenerationOutput or dictionary representation.

Raises:

Type Description
ValueError

If box_format or output_type is unsupported.

Examples:

>>> import numpy as np
>>> from pydantic_ai.models.test import TestModel
>>> model = TestModel(custom_output_args={"elements": []})
>>> record = {
...     "labels": np.asarray([0]),
...     "bboxes": np.asarray([[1, 2, 3, 4]]),
...     "discrete_gold_bboxes": np.asarray([[1, 2, 3, 4]]),
... }
>>> agent = LayoutPrompter(LayoutPrompterConfig(model=model, num_prompt=1))
>>> isinstance(agent(train_data=[record], test_data=record), LayoutGenerationOutput)
True
Source code in models/layoutprompter/src/layoutprompter/agent.py
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
def __call__(
    self,
    *,
    train_data: Sequence[LayoutRecord],
    test_data: LayoutRecord,
    batch_size: int = 1,
    seed: int | None = None,
    generator: np.random.Generator | None = None,
    condition_type: ConditionType | str | None = None,
    labels: Int[np.ndarray, "batch elements"] | LayoutRecordPayload | None = None,
    bbox: Float[np.ndarray, "batch elements 4"] | LayoutRecordPayload | None = None,
    mask: Bool[np.ndarray, "batch elements"] | LayoutRecordPayload | None = None,
    num_elements: int
    | list[int]
    | Int[np.ndarray, "batch"]
    | LayoutRecordPayload
    | None = None,
    box_format: BoxFormat | str = BoxFormat.xywh,
    normalized: bool = True,
    canvas_size: tuple[int, int] | None = None,
    num_inference_steps: int | None = None,
    output_type: OutputType | str = OutputType.DATACLASS,
    return_intermediates: bool = False,
) -> LayoutGenerationOutput | LayoutOutputDict:
    """Expose the shared generation signature for LayoutPrompter.

    Args:
        train_data: Candidate exemplar records.
        test_data: Test record containing task-specific constraints.
        batch_size: Accepted for shared interface compatibility.
        seed: Accepted for shared interface compatibility.
        generator: Accepted for shared interface compatibility.
        condition_type: Accepted for shared interface compatibility.
        labels: Accepted for shared interface compatibility.
        bbox: Accepted for shared interface compatibility.
        mask: Accepted for shared interface compatibility.
        num_elements: Accepted for shared interface compatibility.
        box_format: Public input box format name; validated at the boundary.
        normalized: Accepted for shared interface compatibility.
        canvas_size: Accepted for shared interface compatibility.
        num_inference_steps: Accepted for shared interface compatibility.
        output_type: `dataclass` for `LayoutGenerationOutput`, or `dict`.
        return_intermediates: Accepted for shared interface compatibility.

    Returns:
        A `LayoutGenerationOutput` or dictionary representation.

    Raises:
        ValueError: If `box_format` or `output_type` is unsupported.

    Examples:
        >>> import numpy as np
        >>> from pydantic_ai.models.test import TestModel
        >>> model = TestModel(custom_output_args={"elements": []})
        >>> record = {
        ...     "labels": np.asarray([0]),
        ...     "bboxes": np.asarray([[1, 2, 3, 4]]),
        ...     "discrete_gold_bboxes": np.asarray([[1, 2, 3, 4]]),
        ... }
        >>> agent = LayoutPrompter(LayoutPrompterConfig(model=model, num_prompt=1))
        >>> isinstance(agent(train_data=[record], test_data=record), LayoutGenerationOutput)
        True
    """
    if condition_type is not None:
        normalize_condition_type(condition_type)
    del (
        batch_size,
        seed,
        generator,
        condition_type,
        labels,
        bbox,
        mask,
        num_elements,
        normalized,
        canvas_size,
        num_inference_steps,
        return_intermediates,
    )
    normalize_box_format(box_format)
    normalized_output_type = normalize_output_type(output_type)
    output = self.run_sync(train_data, test_data)
    if normalized_output_type is OutputType.DATACLASS:
        return output
    if normalized_output_type is OutputType.DICT:
        return self.output_to_dict(output)
    assert_never(normalized_output_type)

save_pretrained

save_pretrained(
    save_directory: str | PathLike[str],
) -> None

Persist the dataset and prompt configuration.

Parameters:

Name Type Description Default
save_directory str | PathLike[str]

Target directory for layoutprompter_config.json.

required

Returns:

Type Description
None

None.

Raises:

Type Description
OSError

If the directory or config file cannot be written.

Examples:

>>> from tempfile import TemporaryDirectory
>>> from pydantic_ai.models.test import TestModel
>>> agent = LayoutPrompter(LayoutPrompterConfig(model=TestModel()))
>>> with TemporaryDirectory() as tmpdir:
...     agent.save_pretrained(tmpdir)
Source code in models/layoutprompter/src/layoutprompter/agent.py
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
def save_pretrained(self, save_directory: str | os.PathLike[str]) -> None:
    """Persist the dataset and prompt configuration.

    Args:
        save_directory: Target directory for `layoutprompter_config.json`.

    Returns:
        None.

    Raises:
        OSError: If the directory or config file cannot be written.

    Examples:
        >>> from tempfile import TemporaryDirectory
        >>> from pydantic_ai.models.test import TestModel
        >>> agent = LayoutPrompter(LayoutPrompterConfig(model=TestModel()))
        >>> with TemporaryDirectory() as tmpdir:
        ...     agent.save_pretrained(tmpdir)
    """
    path = Path(save_directory)
    path.mkdir(parents=True, exist_ok=True)
    config = asdict(self.config)
    config["model"] = None
    config["dataset"] = str(self.config.dataset)
    config["condition_type"] = str(self.config.condition_type)
    config["input_format"] = str(self.config.input_format)
    config["output_format"] = str(self.config.output_format)
    (path / "layoutprompter_config.json").write_text(
        json.dumps(config, indent=2, sort_keys=True) + "\n",
        encoding="utf-8",
    )

from_pretrained classmethod

from_pretrained(
    pretrained_model_name_or_path: str | PathLike[str],
    *,
    model: ModelLike = None,
) -> "LayoutPrompter"

Load a saved LayoutPrompter dataset and prompt configuration.

Parameters:

Name Type Description Default
pretrained_model_name_or_path str | PathLike[str]

Directory containing layoutprompter_config.json.

required
model ModelLike

Replacement Pydantic AI model or model string.

None

Returns:

Type Description
'LayoutPrompter'

A configured LayoutPrompter instance.

Raises:

Type Description
OSError

If the config file cannot be read.

ValueError

If saved config modes are unsupported.

Examples:

>>> from tempfile import TemporaryDirectory
>>> from pydantic_ai.models.test import TestModel
>>> model = TestModel(custom_output_args={"elements": []})
>>> agent = LayoutPrompter(LayoutPrompterConfig(model=model))
>>> with TemporaryDirectory() as tmpdir:
...     agent.save_pretrained(tmpdir)
...     loaded = LayoutPrompter.from_pretrained(tmpdir, model=model)
>>> isinstance(loaded, LayoutPrompter)
True
Source code in models/layoutprompter/src/layoutprompter/agent.py
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
@classmethod
def from_pretrained(
    cls,
    pretrained_model_name_or_path: str | os.PathLike[str],
    *,
    model: ModelLike = None,
) -> "LayoutPrompter":
    """Load a saved LayoutPrompter dataset and prompt configuration.

    Args:
        pretrained_model_name_or_path: Directory containing
            `layoutprompter_config.json`.
        model: Replacement Pydantic AI model or model string.

    Returns:
        A configured `LayoutPrompter` instance.

    Raises:
        OSError: If the config file cannot be read.
        ValueError: If saved config modes are unsupported.

    Examples:
        >>> from tempfile import TemporaryDirectory
        >>> from pydantic_ai.models.test import TestModel
        >>> model = TestModel(custom_output_args={"elements": []})
        >>> agent = LayoutPrompter(LayoutPrompterConfig(model=model))
        >>> with TemporaryDirectory() as tmpdir:
        ...     agent.save_pretrained(tmpdir)
        ...     loaded = LayoutPrompter.from_pretrained(tmpdir, model=model)
        >>> isinstance(loaded, LayoutPrompter)
        True
    """
    path = Path(pretrained_model_name_or_path) / "layoutprompter_config.json"
    config_data = json.loads(path.read_text(encoding="utf-8"))
    config_data["model"] = model
    return cls(LayoutPrompterConfig(**config_data))

resolve_model

resolve_model(model: ModelLike = None) -> ModelLike

Resolve constructor or per-call model with LayoutPrompter defaults.

Source code in models/layoutprompter/src/layoutprompter/agent.py
441
442
443
def resolve_model(self, model: ModelLike = None) -> ModelLike:
    """Resolve constructor or per-call model with LayoutPrompter defaults."""
    return self._resolve_model(model)

normalize_prompt_format

normalize_prompt_format(
    prompt_format: PromptFormat | str,
) -> PromptFormat

Return a prompt-format enum from a public string value.

Source code in models/layoutprompter/src/layoutprompter/agent.py
59
60
61
62
63
64
def normalize_prompt_format(prompt_format: PromptFormat | str) -> PromptFormat:
    """Return a prompt-format enum from a public string value."""
    try:
        return PromptFormat(prompt_format)
    except ValueError as exc:
        raise ValueError(f"Unsupported prompt format: {prompt_format}") from exc

normalize_output_type

normalize_output_type(
    output_type: OutputType | str,
) -> OutputType

Return an output-type enum from a public string value.

Source code in models/layoutprompter/src/layoutprompter/agent.py
67
68
69
70
71
72
def normalize_output_type(output_type: OutputType | str) -> OutputType:
    """Return an output-type enum from a public string value."""
    try:
        return OutputType(output_type)
    except ValueError as exc:
        raise ValueError(f"Unsupported output_type: {output_type}") from exc

arrays

Array normalization helpers for LayoutPrompter's numpy-only pipeline.

as_int_array

as_int_array(
    value: ArrayInputScalar
    | Int[ndarray, "..."]
    | Float[ndarray, "..."]
    | Bool[ndarray, "..."]
    | Sequence[ArrayInputScalar]
    | Sequence[Sequence[ArrayInputScalar]],
) -> Int[np.ndarray, "..."]

Return an integer numpy array from an array-like record value.

Source code in models/layoutprompter/src/layoutprompter/arrays.py
14
15
16
17
18
19
20
21
22
23
def as_int_array(
    value: ArrayInputScalar
    | Int[np.ndarray, "..."]
    | Float[np.ndarray, "..."]
    | Bool[np.ndarray, "..."]
    | Sequence[ArrayInputScalar]
    | Sequence[Sequence[ArrayInputScalar]],
) -> Int[np.ndarray, "..."]:
    """Return an integer numpy array from an array-like record value."""
    return np.asarray(value, dtype=np.int64)

as_float_array

as_float_array(
    value: ArrayInputScalar
    | Int[ndarray, "..."]
    | Float[ndarray, "..."]
    | Bool[ndarray, "..."]
    | Sequence[ArrayInputScalar]
    | Sequence[Sequence[ArrayInputScalar]],
) -> Float[np.ndarray, "..."]

Return a float numpy array from an array-like record value.

Source code in models/layoutprompter/src/layoutprompter/arrays.py
26
27
28
29
30
31
32
33
34
35
def as_float_array(
    value: ArrayInputScalar
    | Int[np.ndarray, "..."]
    | Float[np.ndarray, "..."]
    | Bool[np.ndarray, "..."]
    | Sequence[ArrayInputScalar]
    | Sequence[Sequence[ArrayInputScalar]],
) -> Float[np.ndarray, "..."]:
    """Return a float numpy array from an array-like record value."""
    return np.asarray(value, dtype=np.float32)

data

Dataset constants used by LayoutPrompter prompts and parsing.

normalize_dataset

normalize_dataset(
    dataset: SupportedDataset | str,
) -> SupportedDataset

Return a supported dataset enum from a public string value.

Source code in models/layoutprompter/src/layoutprompter/data.py
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
def normalize_dataset(dataset: SupportedDataset | str) -> SupportedDataset:
    """Return a supported dataset enum from a public string value."""
    if isinstance(dataset, DatasetName | LayoutPrompterDataset):
        return dataset
    try:
        shared_dataset = normalize_dataset_name(dataset)
    except ValueError:
        pass
    else:
        if shared_dataset in DATASET_LABELS:
            return shared_dataset
    try:
        return LayoutPrompterDataset(dataset)
    except ValueError as exc:
        raise ValueError(f"Unsupported dataset: {dataset}") from exc

id2label

id2label(dataset: SupportedDataset | str) -> dict[int, str]

Return public 0-based dataset-local label mapping.

Source code in models/layoutprompter/src/layoutprompter/data.py
72
73
74
def id2label(dataset: SupportedDataset | str) -> dict[int, str]:
    """Return public 0-based dataset-local label mapping."""
    return dict(enumerate(DATASET_LABELS[normalize_dataset(dataset)]))

label2id

label2id(dataset: SupportedDataset | str) -> dict[str, int]

Return public 0-based dataset-local label ids.

Source code in models/layoutprompter/src/layoutprompter/data.py
77
78
79
def label2id(dataset: SupportedDataset | str) -> dict[str, int]:
    """Return public 0-based dataset-local label ids."""
    return {label: index for index, label in id2label(dataset).items()}

enums

Closed string vocabularies used by the LayoutPrompter package.

LayoutPrompterDataset

Bases: StrEnum

LayoutPrompter-only dataset names absent from the shared registry.

Source code in models/layoutprompter/src/layoutprompter/enums.py
 8
 9
10
11
12
class LayoutPrompterDataset(StrEnum):
    """LayoutPrompter-only dataset names absent from the shared registry."""

    posterlayout = auto()
    webui = auto()

PromptFormat

Bases: StrEnum

Supported LayoutPrompter prompt encodings.

Source code in models/layoutprompter/src/layoutprompter/enums.py
15
16
17
18
19
class PromptFormat(StrEnum):
    """Supported LayoutPrompter prompt encodings."""

    SEQ = auto()
    HTML = auto()

OutputType

Bases: StrEnum

Supported return containers for the shared call interface.

Source code in models/layoutprompter/src/layoutprompter/enums.py
22
23
24
25
26
class OutputType(StrEnum):
    """Supported return containers for the shared call interface."""

    DATACLASS = auto()
    DICT = auto()

LayoutPrompterTask

Bases: StrEnum

Released task keys supported by LayoutPrompter.

Source code in models/layoutprompter/src/layoutprompter/enums.py
29
30
31
32
33
34
35
36
37
38
class LayoutPrompterTask(StrEnum):
    """Released task keys supported by LayoutPrompter."""

    gent = auto()
    gents = auto()
    genr = auto()
    completion = auto()
    refinement = auto()
    content = auto()
    text = auto()

normalize_layoutprompter_task

normalize_layoutprompter_task(
    task: LayoutPrompterTask | str,
) -> LayoutPrompterTask

Return a LayoutPrompter task enum from a public or release string.

Source code in models/layoutprompter/src/layoutprompter/enums.py
41
42
43
44
45
46
47
48
def normalize_layoutprompter_task(
    task: LayoutPrompterTask | str,
) -> LayoutPrompterTask:
    """Return a LayoutPrompter task enum from a public or release string."""
    try:
        return LayoutPrompterTask(task)
    except ValueError as exc:
        raise ValueError(f"Unsupported LayoutPrompter task: {task}") from exc

parsing

Prediction parsing for seq/html LayoutPrompter outputs.

Parser

Bases: BaseResponseParser[LayoutGenerationOutput]

Parse raw or structured predictions into the common output schema.

Source code in models/layoutprompter/src/layoutprompter/parsing.py
 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
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
class Parser(BaseResponseParser[LayoutGenerationOutput]):
    """Parse raw or structured predictions into the common output schema."""

    def __init__(
        self, dataset: SupportedDataset | str, output_format: PromptFormat | str
    ) -> None:
        """Create a parser for one dataset and output format."""
        self.dataset = normalize_dataset(dataset)
        try:
            self.output_format = PromptFormat(output_format)
        except ValueError as exc:
            raise ValueError(f"Unsupported output format: {output_format}") from exc

        self.id2label = id2label(self.dataset)
        self.label2id = label2id(self.dataset)
        self.canvas_size = CANVAS_SIZE[self.dataset]

    def __call__(
        self, text: str, *, canvas_size: int | None = None
    ) -> LayoutGenerationOutput:
        """Parse repaired provider text through the shared parser protocol."""
        del canvas_size
        return self.parse_one(self.repair_response_text(text))

    def parse_one(
        self, prediction: str | LayoutPrompterOutput
    ) -> LayoutGenerationOutput:
        """Parse one prediction into ``LayoutGenerationOutput``."""
        if isinstance(prediction, LayoutPrompterOutput):
            labels, pixel_ltwh = self._extract_from_structured(prediction)
        elif self.output_format is PromptFormat.SEQ:
            labels, pixel_ltwh = self._extract_from_seq(prediction)
        elif self.output_format is PromptFormat.HTML:
            labels, pixel_ltwh = self._extract_from_html(prediction)
        else:
            assert_never(self.output_format)
        bbox = _normalize_ltwh(pixel_ltwh, canvas_size=self.canvas_size)[None, ...]
        label_tensor = labels.astype(np.int64, copy=False)[None, ...]
        mask = np.ones_like(label_tensor, dtype=np.bool_)
        return LayoutGenerationOutput(
            bbox=bbox, labels=label_tensor, mask=mask, id2label=self.id2label
        )

    def parse_many(self, predictions: list[str]) -> list[LayoutGenerationOutput]:
        """Parse all valid string predictions and skip malformed ones."""
        parsed: list[LayoutGenerationOutput] = []
        for prediction in predictions:
            try:
                parsed.append(self.parse_one(prediction))
            except (KeyError, RuntimeError, ValueError):
                continue
        return parsed

    def parse_vendor_compatible(
        self, prediction: str
    ) -> tuple[Int[np.ndarray, "elements"], Float[np.ndarray, "elements 4"]]:
        """Parse string output as checkpoint-compatible normalized top-left ``xywh``."""
        if self.output_format is PromptFormat.SEQ:
            labels, pixel_ltwh = self._extract_from_seq_vendor(prediction)
        elif self.output_format is PromptFormat.HTML:
            labels, pixel_ltwh = self._extract_from_html(prediction)
        else:
            assert_never(self.output_format)
        width, height = self.canvas_size
        scale = np.asarray((width, height, width, height), dtype=np.float32)
        return labels, pixel_ltwh / scale

    def _extract_from_structured(
        self, prediction: LayoutPrompterOutput
    ) -> tuple[Int[np.ndarray, "elements"], Float[np.ndarray, "elements 4"]]:
        labels: list[int] = []
        bboxes: list[list[int]] = []
        for element in prediction.elements:
            labels.append(self.label2id[element.label])
            bboxes.append(
                [
                    element.bbox.left,
                    element.bbox.top,
                    element.bbox.width,
                    element.bbox.height,
                ]
            )
        return np.asarray(labels, dtype=np.int64), np.asarray(bboxes, dtype=np.float32)

    def _extract_from_html(
        self, prediction: str
    ) -> tuple[Int[np.ndarray, "elements"], Float[np.ndarray, "elements 4"]]:
        labels = re.findall(r'<div class="(.*?)"', prediction)[1:]
        left = re.findall(r"left:\s*(\d+)px", prediction)[1:]
        top = re.findall(r"top:\s*(\d+)px", prediction)[1:]
        width = re.findall(r"width:\s*(\d+)px", prediction)[1:]
        height = re.findall(r"height:\s*(\d+)px", prediction)[1:]
        if not (len(labels) == len(left) == len(top) == len(width) == len(height)):
            raise RuntimeError("HTML prediction has mismatched label and bbox counts")

        label_array = np.asarray(
            [self.label2id[label.strip().lower()] for label in labels], dtype=np.int64
        )
        bbox_array = np.asarray(
            [
                [
                    int(left[index]),
                    int(top[index]),
                    int(width[index]),
                    int(height[index]),
                ]
                for index in range(len(labels))
            ],
            dtype=np.float32,
        )
        return label_array, bbox_array

    def _extract_from_seq(
        self, prediction: str
    ) -> tuple[Int[np.ndarray, "elements"], Float[np.ndarray, "elements 4"]]:
        labels = sorted(self.label2id, key=len, reverse=True)
        pattern = (
            r"("
            + "|".join(re.escape(label) for label in labels)
            + r")\s+\d+\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)"
        )
        matches = re.findall(pattern, prediction.lower())
        if not matches:
            raise RuntimeError("No seq layout elements parsed")

        label_array = np.asarray(
            [self.label2id[item[0]] for item in matches], dtype=np.int64
        )
        bbox_array = np.asarray(
            [
                [int(item[1]), int(item[2]), int(item[3]), int(item[4])]
                for item in matches
            ],
            dtype=np.float32,
        )
        return label_array, bbox_array

    def _extract_from_seq_vendor(
        self, prediction: str
    ) -> tuple[Int[np.ndarray, "elements"], Float[np.ndarray, "elements 4"]]:
        labels = sorted(self.label2id, key=len, reverse=True)
        pattern = (
            r"("
            + "|".join(re.escape(label) for label in labels)
            + r")\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)"
        )
        matches = re.findall(pattern, prediction.lower())
        if not matches:
            raise RuntimeError("No seq layout elements parsed")

        label_array = np.asarray(
            [self.label2id[item[0]] for item in matches], dtype=np.int64
        )
        bbox_array = np.asarray(
            [
                [int(item[1]), int(item[2]), int(item[3]), int(item[4])]
                for item in matches
            ],
            dtype=np.float32,
        )
        return label_array, bbox_array

__init__

__init__(
    dataset: SupportedDataset | str,
    output_format: PromptFormat | str,
) -> None

Create a parser for one dataset and output format.

Source code in models/layoutprompter/src/layoutprompter/parsing.py
27
28
29
30
31
32
33
34
35
36
37
38
39
def __init__(
    self, dataset: SupportedDataset | str, output_format: PromptFormat | str
) -> None:
    """Create a parser for one dataset and output format."""
    self.dataset = normalize_dataset(dataset)
    try:
        self.output_format = PromptFormat(output_format)
    except ValueError as exc:
        raise ValueError(f"Unsupported output format: {output_format}") from exc

    self.id2label = id2label(self.dataset)
    self.label2id = label2id(self.dataset)
    self.canvas_size = CANVAS_SIZE[self.dataset]

__call__

__call__(
    text: str, *, canvas_size: int | None = None
) -> LayoutGenerationOutput

Parse repaired provider text through the shared parser protocol.

Source code in models/layoutprompter/src/layoutprompter/parsing.py
41
42
43
44
45
46
def __call__(
    self, text: str, *, canvas_size: int | None = None
) -> LayoutGenerationOutput:
    """Parse repaired provider text through the shared parser protocol."""
    del canvas_size
    return self.parse_one(self.repair_response_text(text))

parse_one

parse_one(
    prediction: str | LayoutPrompterOutput,
) -> LayoutGenerationOutput

Parse one prediction into LayoutGenerationOutput.

Source code in models/layoutprompter/src/layoutprompter/parsing.py
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
def parse_one(
    self, prediction: str | LayoutPrompterOutput
) -> LayoutGenerationOutput:
    """Parse one prediction into ``LayoutGenerationOutput``."""
    if isinstance(prediction, LayoutPrompterOutput):
        labels, pixel_ltwh = self._extract_from_structured(prediction)
    elif self.output_format is PromptFormat.SEQ:
        labels, pixel_ltwh = self._extract_from_seq(prediction)
    elif self.output_format is PromptFormat.HTML:
        labels, pixel_ltwh = self._extract_from_html(prediction)
    else:
        assert_never(self.output_format)
    bbox = _normalize_ltwh(pixel_ltwh, canvas_size=self.canvas_size)[None, ...]
    label_tensor = labels.astype(np.int64, copy=False)[None, ...]
    mask = np.ones_like(label_tensor, dtype=np.bool_)
    return LayoutGenerationOutput(
        bbox=bbox, labels=label_tensor, mask=mask, id2label=self.id2label
    )

parse_many

parse_many(
    predictions: list[str],
) -> list[LayoutGenerationOutput]

Parse all valid string predictions and skip malformed ones.

Source code in models/layoutprompter/src/layoutprompter/parsing.py
67
68
69
70
71
72
73
74
75
def parse_many(self, predictions: list[str]) -> list[LayoutGenerationOutput]:
    """Parse all valid string predictions and skip malformed ones."""
    parsed: list[LayoutGenerationOutput] = []
    for prediction in predictions:
        try:
            parsed.append(self.parse_one(prediction))
        except (KeyError, RuntimeError, ValueError):
            continue
    return parsed

parse_vendor_compatible

parse_vendor_compatible(
    prediction: str,
) -> tuple[
    Int[np.ndarray, "elements"],
    Float[np.ndarray, "elements 4"],
]

Parse string output as checkpoint-compatible normalized top-left xywh.

Source code in models/layoutprompter/src/layoutprompter/parsing.py
77
78
79
80
81
82
83
84
85
86
87
88
89
def parse_vendor_compatible(
    self, prediction: str
) -> tuple[Int[np.ndarray, "elements"], Float[np.ndarray, "elements 4"]]:
    """Parse string output as checkpoint-compatible normalized top-left ``xywh``."""
    if self.output_format is PromptFormat.SEQ:
        labels, pixel_ltwh = self._extract_from_seq_vendor(prediction)
    elif self.output_format is PromptFormat.HTML:
        labels, pixel_ltwh = self._extract_from_html(prediction)
    else:
        assert_never(self.output_format)
    width, height = self.canvas_size
    scale = np.asarray((width, height, width, height), dtype=np.float32)
    return labels, pixel_ltwh / scale

records

Typed record keys used by LayoutPrompter serializers and selectors.

LayoutRecordKey

Bases: StrEnum

Closed key set for dict-like layout records.

Source code in models/layoutprompter/src/layoutprompter/records.py
15
16
17
18
19
20
21
22
23
24
25
26
class LayoutRecordKey(StrEnum):
    """Closed key set for dict-like layout records."""

    id = auto()
    labels = auto()
    bboxes = auto()
    discrete_bboxes = auto()
    discrete_gold_bboxes = auto()
    discrete_content_bboxes = auto()
    relations = auto()
    text = auto()
    embedding = auto()

LayoutRecord

Bases: TypedDict

Structured LayoutPrompter record accepted by prompt and selector code.

Source code in models/layoutprompter/src/layoutprompter/records.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class LayoutRecord(TypedDict, total=False):
    """Structured LayoutPrompter record accepted by prompt and selector code."""

    id: NotRequired[str]
    labels: npt.ArrayLike | Sequence[int]
    bboxes: npt.ArrayLike | Sequence[Sequence[int | float]]
    discrete_bboxes: NotRequired[npt.ArrayLike | Sequence[Sequence[int | float]]]
    discrete_gold_bboxes: npt.ArrayLike | Sequence[Sequence[int | float]]
    discrete_content_bboxes: NotRequired[
        npt.ArrayLike | Sequence[Sequence[int | float]]
    ]
    relations: NotRequired[npt.ArrayLike | Sequence[Sequence[int | float]]]
    text: NotRequired[str]
    embedding: NotRequired[npt.ArrayLike | Sequence[Sequence[int | float]]]

record_value

record_value(
    data: LayoutRecordInput, key: LayoutRecordKey
) -> (
    LayoutRecordScalar
    | Int[np.ndarray, ...]
    | Float[np.ndarray, ...]
    | Bool[np.ndarray, ...]
    | Sequence[int | float | str | bool | None]
    | Sequence[Sequence[int | float | str | bool | None]]
)

Return a layout-record value by enum key.

Source code in models/layoutprompter/src/layoutprompter/records.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
def record_value(
    data: LayoutRecordInput, key: LayoutRecordKey
) -> (
    LayoutRecordScalar
    | Int[np.ndarray, ...]
    | Float[np.ndarray, ...]
    | Bool[np.ndarray, ...]
    | Sequence[int | float | str | bool | None]
    | Sequence[Sequence[int | float | str | bool | None]]
):
    """Return a layout-record value by enum key."""
    return cast(
        LayoutRecordScalar
        | Int[np.ndarray, "..."]
        | Float[np.ndarray, "..."]
        | Bool[np.ndarray, "..."]
        | Sequence[int | float | str | bool | None]
        | Sequence[Sequence[int | float | str | bool | None]],
        data[key.value],
    )

optional_record_value

optional_record_value(
    data: LayoutRecordInput,
    key: LayoutRecordKey,
    default: LayoutRecordScalar
    | Int[ndarray, ...]
    | Float[ndarray, ...]
    | Bool[ndarray, ...]
    | Sequence[int | float | str | bool | None]
    | Sequence[Sequence[int | float | str | bool | None]],
) -> (
    LayoutRecordScalar
    | Int[np.ndarray, ...]
    | Float[np.ndarray, ...]
    | Bool[np.ndarray, ...]
    | Sequence[int | float | str | bool | None]
    | Sequence[Sequence[int | float | str | bool | None]]
)

Return a layout-record value by enum key, or a default.

Source code in models/layoutprompter/src/layoutprompter/records.py
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
def optional_record_value(
    data: LayoutRecordInput,
    key: LayoutRecordKey,
    default: LayoutRecordScalar
    | Int[np.ndarray, ...]
    | Float[np.ndarray, ...]
    | Bool[np.ndarray, ...]
    | Sequence[int | float | str | bool | None]
    | Sequence[Sequence[int | float | str | bool | None]],
) -> (
    LayoutRecordScalar
    | Int[np.ndarray, ...]
    | Float[np.ndarray, ...]
    | Bool[np.ndarray, ...]
    | Sequence[int | float | str | bool | None]
    | Sequence[Sequence[int | float | str | bool | None]]
):
    """Return a layout-record value by enum key, or a default."""
    return cast(
        LayoutRecordScalar
        | Int[np.ndarray, "..."]
        | Float[np.ndarray, "..."]
        | Bool[np.ndarray, "..."]
        | Sequence[int | float | str | bool | None]
        | Sequence[Sequence[int | float | str | bool | None]],
        data.get(key.value, default),
    )

schemas

Pydantic schemas for LayoutPrompter structured output.

PixelBBox

Bases: BaseModel

Top-left pixel xywh bbox emitted by the language model.

Source code in models/layoutprompter/src/layoutprompter/schemas.py
10
11
12
13
14
15
16
class PixelBBox(BaseModel):
    """Top-left pixel ``xywh`` bbox emitted by the language model."""

    left: int = Field(ge=0)
    top: int = Field(ge=0)
    width: int = Field(ge=0)
    height: int = Field(ge=0)

LayoutElement

Bases: BaseModel

One predicted layout element.

Source code in models/layoutprompter/src/layoutprompter/schemas.py
19
20
21
22
23
24
25
26
27
28
29
class LayoutElement(BaseModel):
    """One predicted layout element."""

    label: str
    bbox: PixelBBox

    @field_validator("label")
    @classmethod
    def normalize_label(cls, value: str) -> str:
        """Normalize model-produced labels for dataset lookup."""
        return re.sub(r"\s+\d+$", "", value.strip().lower())

normalize_label classmethod

normalize_label(value: str) -> str

Normalize model-produced labels for dataset lookup.

Source code in models/layoutprompter/src/layoutprompter/schemas.py
25
26
27
28
29
@field_validator("label")
@classmethod
def normalize_label(cls, value: str) -> str:
    """Normalize model-produced labels for dataset lookup."""
    return re.sub(r"\s+\d+$", "", value.strip().lower())

LayoutPrompterOutput

Bases: BaseModel

Structured output requested from the Pydantic AI model.

Source code in models/layoutprompter/src/layoutprompter/schemas.py
32
33
34
35
class LayoutPrompterOutput(BaseModel):
    """Structured output requested from the Pydantic AI model."""

    elements: list[LayoutElement] = Field(default_factory=list)

selection

Exemplar selection strategies for LayoutPrompter prompt construction.

ExemplarSelection dataclass

Bases: BaseExemplarSelector[LayoutRecord]

Base selector with candidate truncation and zero-size filtering.

Source code in models/layoutprompter/src/layoutprompter/selection.py
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
@dataclass
class ExemplarSelection(BaseExemplarSelector[LayoutRecord]):
    """Base selector with candidate truncation and zero-size filtering."""

    train_data: Sequence[LayoutRecord]
    candidate_size: int
    num_prompt: int
    shuffle: bool = True
    seed: int | None = None
    generator: random.Random = field(init=False, repr=False)

    def __post_init__(self) -> None:
        """Normalize candidate records and initialize deterministic randomness."""
        self.generator = random.Random(self.seed)
        self.train_data = list(self.train_data)
        if self.candidate_size > 0:
            self.generator.shuffle(self.train_data)
            self.train_data = self.train_data[: self.candidate_size]

    def __call__(self, test_data: LayoutRecord) -> list[LayoutRecord]:
        """Return selected exemplars for a test sample."""
        raise NotImplementedError

    def _is_filter(self, data: LayoutRecord) -> bool:
        bboxes = as_float_array(record_value(data, K.discrete_gold_bboxes))
        return bool(np.any(bboxes[:, 2:] == 0))

    def _retrieve_exemplars(
        self, scores: list[tuple[int, float]]
    ) -> list[LayoutRecord]:
        ranked_scores = sorted(scores, key=lambda item: item[1], reverse=True)
        exemplars: list[LayoutRecord] = []
        for index, _score in ranked_scores:
            if not self._is_filter(self.train_data[index]):
                exemplars.append(self.train_data[index])
                if len(exemplars) == self.num_prompt:
                    break
        if self.shuffle:
            self.generator.shuffle(exemplars)
        return exemplars

__post_init__

__post_init__() -> None

Normalize candidate records and initialize deterministic randomness.

Source code in models/layoutprompter/src/layoutprompter/selection.py
41
42
43
44
45
46
47
def __post_init__(self) -> None:
    """Normalize candidate records and initialize deterministic randomness."""
    self.generator = random.Random(self.seed)
    self.train_data = list(self.train_data)
    if self.candidate_size > 0:
        self.generator.shuffle(self.train_data)
        self.train_data = self.train_data[: self.candidate_size]

__call__

__call__(test_data: LayoutRecord) -> list[LayoutRecord]

Return selected exemplars for a test sample.

Source code in models/layoutprompter/src/layoutprompter/selection.py
49
50
51
def __call__(self, test_data: LayoutRecord) -> list[LayoutRecord]:
    """Return selected exemplars for a test sample."""
    raise NotImplementedError

GenTypeExemplarSelection dataclass

Bases: ExemplarSelection

Select exemplars by element-type multiset similarity.

Source code in models/layoutprompter/src/layoutprompter/selection.py
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
class GenTypeExemplarSelection(ExemplarSelection):
    """Select exemplars by element-type multiset similarity."""

    @override
    def __call__(self, test_data: LayoutRecord) -> list[LayoutRecord]:
        """Return exemplars ranked by label overlap."""
        test_labels = as_int_array(record_value(test_data, K.labels))
        scores = [
            (
                index,
                labels_similarity(
                    as_int_array(record_value(train_data, K.labels)), test_labels
                ),
            )
            for index, train_data in enumerate(self.train_data)
        ]
        return self._retrieve_exemplars(scores)

__call__

__call__(test_data: LayoutRecord) -> list[LayoutRecord]

Return exemplars ranked by label overlap.

Source code in models/layoutprompter/src/layoutprompter/selection.py
75
76
77
78
79
80
81
82
83
84
85
86
87
88
@override
def __call__(self, test_data: LayoutRecord) -> list[LayoutRecord]:
    """Return exemplars ranked by label overlap."""
    test_labels = as_int_array(record_value(test_data, K.labels))
    scores = [
        (
            index,
            labels_similarity(
                as_int_array(record_value(train_data, K.labels)), test_labels
            ),
        )
        for index, train_data in enumerate(self.train_data)
    ]
    return self._retrieve_exemplars(scores)

GenTypeSizeExemplarSelection dataclass

Bases: ExemplarSelection

Select exemplars by labels and element sizes.

Source code in models/layoutprompter/src/layoutprompter/selection.py
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
class GenTypeSizeExemplarSelection(ExemplarSelection):
    """Select exemplars by labels and element sizes."""

    labels_weight = BALANCED_LABEL_WEIGHT
    bboxes_weight = BALANCED_BBOX_WEIGHT

    @override
    def __call__(self, test_data: LayoutRecord) -> list[LayoutRecord]:
        """Return exemplars ranked by label and size similarity."""
        test_labels = as_int_array(record_value(test_data, K.labels))
        test_bboxes = as_float_array(record_value(test_data, K.bboxes))[:, 2:]
        scores = []
        for index, train_data in enumerate(self.train_data):
            score = labels_bboxes_similarity(
                as_int_array(record_value(train_data, K.labels)),
                as_float_array(record_value(train_data, K.bboxes))[:, 2:],
                test_labels,
                test_bboxes,
                self.labels_weight,
                self.bboxes_weight,
            )
            scores.append((index, score))
        return self._retrieve_exemplars(scores)

__call__

__call__(test_data: LayoutRecord) -> list[LayoutRecord]

Return exemplars ranked by label and size similarity.

Source code in models/layoutprompter/src/layoutprompter/selection.py
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
@override
def __call__(self, test_data: LayoutRecord) -> list[LayoutRecord]:
    """Return exemplars ranked by label and size similarity."""
    test_labels = as_int_array(record_value(test_data, K.labels))
    test_bboxes = as_float_array(record_value(test_data, K.bboxes))[:, 2:]
    scores = []
    for index, train_data in enumerate(self.train_data):
        score = labels_bboxes_similarity(
            as_int_array(record_value(train_data, K.labels)),
            as_float_array(record_value(train_data, K.bboxes))[:, 2:],
            test_labels,
            test_bboxes,
            self.labels_weight,
            self.bboxes_weight,
        )
        scores.append((index, score))
    return self._retrieve_exemplars(scores)

GenRelationExemplarSelection dataclass

Bases: GenTypeExemplarSelection

Select relation-conditioned exemplars by label similarity.

Source code in models/layoutprompter/src/layoutprompter/selection.py
116
117
class GenRelationExemplarSelection(GenTypeExemplarSelection):
    """Select relation-conditioned exemplars by label similarity."""

CompletionExemplarSelection dataclass

Bases: ExemplarSelection

Select layout-completion exemplars by the first visible element.

Source code in models/layoutprompter/src/layoutprompter/selection.py
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
class CompletionExemplarSelection(ExemplarSelection):
    """Select layout-completion exemplars by the first visible element."""

    labels_weight = BBOX_ONLY_LABEL_WEIGHT
    bboxes_weight = BBOX_ONLY_BBOX_WEIGHT

    @override
    def __call__(self, test_data: LayoutRecord) -> list[LayoutRecord]:
        """Return exemplars ranked by the first partial element."""
        test_labels = as_int_array(record_value(test_data, K.labels))[:1]
        test_bboxes = as_float_array(record_value(test_data, K.bboxes))[:1, :]
        scores = []
        for index, train_data in enumerate(self.train_data):
            score = labels_bboxes_similarity(
                as_int_array(record_value(train_data, K.labels))[:1],
                as_float_array(record_value(train_data, K.bboxes))[:1, :],
                test_labels,
                test_bboxes,
                self.labels_weight,
                self.bboxes_weight,
            )
            scores.append((index, score))
        return self._retrieve_exemplars(scores)

__call__

__call__(test_data: LayoutRecord) -> list[LayoutRecord]

Return exemplars ranked by the first partial element.

Source code in models/layoutprompter/src/layoutprompter/selection.py
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
@override
def __call__(self, test_data: LayoutRecord) -> list[LayoutRecord]:
    """Return exemplars ranked by the first partial element."""
    test_labels = as_int_array(record_value(test_data, K.labels))[:1]
    test_bboxes = as_float_array(record_value(test_data, K.bboxes))[:1, :]
    scores = []
    for index, train_data in enumerate(self.train_data):
        score = labels_bboxes_similarity(
            as_int_array(record_value(train_data, K.labels))[:1],
            as_float_array(record_value(train_data, K.bboxes))[:1, :],
            test_labels,
            test_bboxes,
            self.labels_weight,
            self.bboxes_weight,
        )
        scores.append((index, score))
    return self._retrieve_exemplars(scores)

RefinementExemplarSelection dataclass

Bases: ExemplarSelection

Select refinement exemplars by labels and noisy boxes.

Source code in models/layoutprompter/src/layoutprompter/selection.py
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
class RefinementExemplarSelection(ExemplarSelection):
    """Select refinement exemplars by labels and noisy boxes."""

    labels_weight = BALANCED_LABEL_WEIGHT
    bboxes_weight = BALANCED_BBOX_WEIGHT

    @override
    def __call__(self, test_data: LayoutRecord) -> list[LayoutRecord]:
        """Return exemplars ranked by noisy layout similarity."""
        test_labels = as_int_array(record_value(test_data, K.labels))
        test_bboxes = as_float_array(record_value(test_data, K.bboxes))
        scores = []
        for index, train_data in enumerate(self.train_data):
            score = labels_bboxes_similarity(
                as_int_array(record_value(train_data, K.labels)),
                as_float_array(record_value(train_data, K.bboxes)),
                test_labels,
                test_bboxes,
                self.labels_weight,
                self.bboxes_weight,
            )
            scores.append((index, score))
        return self._retrieve_exemplars(scores)

__call__

__call__(test_data: LayoutRecord) -> list[LayoutRecord]

Return exemplars ranked by noisy layout similarity.

Source code in models/layoutprompter/src/layoutprompter/selection.py
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
@override
def __call__(self, test_data: LayoutRecord) -> list[LayoutRecord]:
    """Return exemplars ranked by noisy layout similarity."""
    test_labels = as_int_array(record_value(test_data, K.labels))
    test_bboxes = as_float_array(record_value(test_data, K.bboxes))
    scores = []
    for index, train_data in enumerate(self.train_data):
        score = labels_bboxes_similarity(
            as_int_array(record_value(train_data, K.labels)),
            as_float_array(record_value(train_data, K.bboxes)),
            test_labels,
            test_bboxes,
            self.labels_weight,
            self.bboxes_weight,
        )
        scores.append((index, score))
    return self._retrieve_exemplars(scores)

ContentAwareExemplarSelection dataclass

Bases: ExemplarSelection

Select poster exemplars by content-mask IoU.

Source code in models/layoutprompter/src/layoutprompter/selection.py
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
class ContentAwareExemplarSelection(ExemplarSelection):
    """Select poster exemplars by content-mask IoU."""

    @override
    def __call__(self, test_data: LayoutRecord) -> list[LayoutRecord]:
        """Return exemplars ranked by content-mask IoU."""
        test_mask = self._to_binary_mask(
            as_float_array(record_value(test_data, K.discrete_content_bboxes))
        )
        scores = []
        for index, train_data in enumerate(self.train_data):
            train_mask = self._to_binary_mask(
                as_float_array(record_value(train_data, K.discrete_content_bboxes))
            )
            intersection = np.logical_and(train_mask, test_mask).sum()
            union = np.logical_or(train_mask, test_mask).sum()
            scores.append((index, float((intersection + 1) / (union + 1))))
        return self._retrieve_exemplars(scores)

    def _to_binary_mask(
        self, content_bboxes: Float[np.ndarray, "elements 4"]
    ) -> Bool[np.ndarray, "height width"]:
        width, height = POSTER_MASK_SIZE
        mask = np.zeros((height, width), dtype=np.bool_)
        for left, top, box_width, box_height in content_bboxes.astype(
            np.int64
        ).tolist():
            mask[top : top + box_height, left : left + box_width] = True
        return mask

__call__

__call__(test_data: LayoutRecord) -> list[LayoutRecord]

Return exemplars ranked by content-mask IoU.

Source code in models/layoutprompter/src/layoutprompter/selection.py
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
@override
def __call__(self, test_data: LayoutRecord) -> list[LayoutRecord]:
    """Return exemplars ranked by content-mask IoU."""
    test_mask = self._to_binary_mask(
        as_float_array(record_value(test_data, K.discrete_content_bboxes))
    )
    scores = []
    for index, train_data in enumerate(self.train_data):
        train_mask = self._to_binary_mask(
            as_float_array(record_value(train_data, K.discrete_content_bboxes))
        )
        intersection = np.logical_and(train_mask, test_mask).sum()
        union = np.logical_or(train_mask, test_mask).sum()
        scores.append((index, float((intersection + 1) / (union + 1))))
    return self._retrieve_exemplars(scores)

TextToLayoutExemplarSelection dataclass

Bases: ExemplarSelection

Select text-to-layout exemplars by embedding dot product.

Source code in models/layoutprompter/src/layoutprompter/selection.py
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
class TextToLayoutExemplarSelection(ExemplarSelection):
    """Select text-to-layout exemplars by embedding dot product."""

    @override
    def __call__(self, test_data: LayoutRecord) -> list[LayoutRecord]:
        """Return exemplars ranked by text embedding similarity."""
        test_embedding = as_float_array(record_value(test_data, K.embedding))
        scores = [
            (
                index,
                float(
                    np.sum(
                        as_float_array(record_value(train_data, K.embedding))
                        * test_embedding
                    )
                ),
            )
            for index, train_data in enumerate(self.train_data)
        ]
        return self._retrieve_exemplars(scores)

__call__

__call__(test_data: LayoutRecord) -> list[LayoutRecord]

Return exemplars ranked by text embedding similarity.

Source code in models/layoutprompter/src/layoutprompter/selection.py
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
@override
def __call__(self, test_data: LayoutRecord) -> list[LayoutRecord]:
    """Return exemplars ranked by text embedding similarity."""
    test_embedding = as_float_array(record_value(test_data, K.embedding))
    scores = [
        (
            index,
            float(
                np.sum(
                    as_float_array(record_value(train_data, K.embedding))
                    * test_embedding
                )
            ),
        )
        for index, train_data in enumerate(self.train_data)
    ]
    return self._retrieve_exemplars(scores)

create_selector

create_selector(
    task: LayoutPrompterTask | str,
    train_data: Sequence[LayoutRecord],
    candidate_size: int,
    num_prompt: int,
    *,
    shuffle: bool = True,
    seed: int | None = None,
) -> ExemplarSelection

Create a selector for a LayoutPrompter task.

Source code in models/layoutprompter/src/layoutprompter/selection.py
234
235
236
237
238
239
240
241
242
243
244
245
246
247
def create_selector(
    task: LayoutPrompterTask | str,
    train_data: Sequence[LayoutRecord],
    candidate_size: int,
    num_prompt: int,
    *,
    shuffle: bool = True,
    seed: int | None = None,
) -> ExemplarSelection:
    """Create a selector for a LayoutPrompter task."""
    normalized_task = normalize_layoutprompter_task(task)
    return SELECTOR_MAP[normalized_task](
        train_data, candidate_size, num_prompt, shuffle=shuffle, seed=seed
    )

serialization

Prompt serialization ported from the LayoutPrompter notebooks.

Serializer dataclass

Base serializer for seq/html prompt examples.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
@dataclass
class Serializer:
    """Base serializer for seq/html prompt examples."""

    task_type: ClassVar[str] = ""
    constraint_type: ClassVar[tuple[str, ...]] = ()

    input_format: PromptFormat
    output_format: PromptFormat
    index2label: dict[int, str]
    canvas_width: int
    canvas_height: int
    add_index_token: bool = True
    add_sep_token: bool = True
    sep_token: str = "|"
    add_unk_token: bool = False
    unk_token: str = "<unk>"

    def __post_init__(self) -> None:
        """Normalize public string formats to enums."""
        self.input_format = _normalize_prompt_format(self.input_format, name="input")
        self.output_format = _normalize_prompt_format(self.output_format, name="output")

    def build_input(self, data: LayoutRecord) -> str:
        """Serialize test constraints."""
        if self.input_format is PromptFormat.SEQ:
            return self._build_seq_input(data)
        if self.input_format is PromptFormat.HTML:
            return self._build_html_input(data)
        assert_never(self.input_format)

    def build_output(
        self,
        data: LayoutRecord,
        label_key: LayoutRecordKey = K.labels,
        bbox_key: LayoutRecordKey = K.discrete_gold_bboxes,
    ) -> str:
        """Serialize an exemplar output layout."""
        if self.output_format is PromptFormat.SEQ:
            return self._build_seq_output(data, label_key, bbox_key)
        if self.output_format is PromptFormat.HTML:
            return self._build_html_output(data, label_key, bbox_key)
        assert_never(self.output_format)

    def _build_seq_input(self, data: LayoutRecord) -> str:
        raise NotImplementedError

    def _build_html_input(self, data: LayoutRecord) -> str:
        raise NotImplementedError

    def _build_seq_output(
        self, data: LayoutRecord, label_key: LayoutRecordKey, bbox_key: LayoutRecordKey
    ) -> str:
        labels = as_int_array(record_value(data, label_key))
        bboxes = as_float_array(record_value(data, bbox_key))
        tokens: list[str] = []
        for index in range(len(labels)):
            tokens.append(self.index2label[int(labels[index])])
            if self.add_index_token:
                tokens.append(str(index))
            tokens.extend(str(int(value)) for value in bboxes[index].tolist())
            if self.add_sep_token and index < len(labels) - 1:
                tokens.append(self.sep_token)
        return " ".join(tokens)

    def _build_html_output(
        self, data: LayoutRecord, label_key: LayoutRecordKey, bbox_key: LayoutRecordKey
    ) -> str:
        labels = as_int_array(record_value(data, label_key))
        bboxes = as_float_array(record_value(data, bbox_key))
        template = HTML_TEMPLATE_WITH_INDEX if self.add_index_token else HTML_TEMPLATE
        html = [HTML_PREFIX.format(self.canvas_width, self.canvas_height)]
        for index in range(len(labels)):
            element: list[str] = [self.index2label[int(labels[index])]]
            if self.add_index_token:
                element.append(str(index))
            element.extend(str(int(value)) for value in bboxes[index].tolist())
            html.append(template.format(*element))
        html.append(HTML_SUFFIX)
        return "".join(html)

__post_init__

__post_init__() -> None

Normalize public string formats to enums.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
73
74
75
76
def __post_init__(self) -> None:
    """Normalize public string formats to enums."""
    self.input_format = _normalize_prompt_format(self.input_format, name="input")
    self.output_format = _normalize_prompt_format(self.output_format, name="output")

build_input

build_input(data: LayoutRecord) -> str

Serialize test constraints.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
78
79
80
81
82
83
84
def build_input(self, data: LayoutRecord) -> str:
    """Serialize test constraints."""
    if self.input_format is PromptFormat.SEQ:
        return self._build_seq_input(data)
    if self.input_format is PromptFormat.HTML:
        return self._build_html_input(data)
    assert_never(self.input_format)

build_output

build_output(
    data: LayoutRecord,
    label_key: LayoutRecordKey = K.labels,
    bbox_key: LayoutRecordKey = K.discrete_gold_bboxes,
) -> str

Serialize an exemplar output layout.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
86
87
88
89
90
91
92
93
94
95
96
97
def build_output(
    self,
    data: LayoutRecord,
    label_key: LayoutRecordKey = K.labels,
    bbox_key: LayoutRecordKey = K.discrete_gold_bboxes,
) -> str:
    """Serialize an exemplar output layout."""
    if self.output_format is PromptFormat.SEQ:
        return self._build_seq_output(data, label_key, bbox_key)
    if self.output_format is PromptFormat.HTML:
        return self._build_html_output(data, label_key, bbox_key)
    assert_never(self.output_format)

GenTypeSerializer dataclass

Bases: Serializer

Serializer for element-type conditioned generation.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
class GenTypeSerializer(Serializer):
    """Serializer for element-type conditioned generation."""

    task_type = "generation conditioned on given element types"
    constraint_type = ("Element Type Constraint: ",)

    @override
    def _build_seq_input(self, data: LayoutRecord) -> str:
        tokens: list[str] = []
        labels = as_int_array(record_value(data, K.labels))
        for index in range(len(labels)):
            tokens.append(self.index2label[int(labels[index])])
            if self.add_index_token:
                tokens.append(str(index))
            if self.add_unk_token:
                tokens += [self.unk_token] * 4
            if self.add_sep_token and index < len(labels) - 1:
                tokens.append(self.sep_token)
        return " ".join(tokens)

    @override
    def _build_html_input(self, data: LayoutRecord) -> str:
        html = [HTML_PREFIX.format(self.canvas_width, self.canvas_height)]
        labels = as_int_array(record_value(data, K.labels))
        for index in range(len(labels)):
            label = self.index2label[int(labels[index])]
            if self.add_unk_token:
                bbox = [self.unk_token] * 4
                element = (
                    [label, str(index), *bbox]
                    if self.add_index_token
                    else [label, *bbox]
                )
                html.append(
                    (
                        HTML_TEMPLATE_WITH_INDEX
                        if self.add_index_token
                        else HTML_TEMPLATE
                    ).format(*element)
                )
            elif self.add_index_token:
                html.append(f'<div class="{label}" style="index: {index}"></div>\n')
            else:
                html.append(f'<div class="{label}"></div>\n')
        html.append(HTML_SUFFIX)
        return "".join(html)

    @override
    def build_input(self, data: LayoutRecord) -> str:
        """Serialize type constraints with the task prefix."""
        return self.constraint_type[0] + super().build_input(data)

build_input

build_input(data: LayoutRecord) -> str

Serialize type constraints with the task prefix.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
184
185
186
187
@override
def build_input(self, data: LayoutRecord) -> str:
    """Serialize type constraints with the task prefix."""
    return self.constraint_type[0] + super().build_input(data)

GenTypeSizeSerializer dataclass

Bases: GenTypeSerializer

Serializer for element-type and size conditioned generation.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
class GenTypeSizeSerializer(GenTypeSerializer):
    """Serializer for element-type and size conditioned generation."""

    task_type = "generation conditioned on given element types and sizes"
    constraint_type = ("Element Type and Size Constraint: ",)

    @override
    def _build_seq_input(self, data: LayoutRecord) -> str:
        tokens: list[str] = []
        labels = as_int_array(record_value(data, K.labels))
        bboxes = as_float_array(record_value(data, K.discrete_gold_bboxes))
        for index in range(len(labels)):
            tokens.append(self.index2label[int(labels[index])])
            if self.add_index_token:
                tokens.append(str(index))
            if self.add_unk_token:
                tokens += [self.unk_token] * 2
            tokens.extend(str(int(value)) for value in bboxes[index].tolist()[2:])
            if self.add_sep_token and index < len(labels) - 1:
                tokens.append(self.sep_token)
        return " ".join(tokens)

    @override
    def _build_html_input(self, data: LayoutRecord) -> str:
        html = [HTML_PREFIX.format(self.canvas_width, self.canvas_height)]
        labels = as_int_array(record_value(data, K.labels))
        bboxes = as_float_array(record_value(data, K.discrete_gold_bboxes))
        for index in range(len(labels)):
            label = self.index2label[int(labels[index])]
            width, height = [int(value) for value in bboxes[index].tolist()[2:]]
            if self.add_index_token:
                html.append(
                    f'<div class="{label}" style="index: {index}; width: {width}px; height: {height}px"></div>\n'
                )
            else:
                html.append(
                    f'<div class="{label}" style="width: {width}px; height: {height}px"></div>\n'
                )
        html.append(HTML_SUFFIX)
        return "".join(html)

GenRelationSerializer dataclass

Bases: GenTypeSerializer

Serializer for relation-conditioned generation.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
class GenRelationSerializer(GenTypeSerializer):
    """Serializer for relation-conditioned generation."""

    task_type = (
        "generation conditioned on given element relationships\n"
        "'A left B' means that the center coordinate of A is to the left of the center coordinate of B. "
        "'A right B' means that the center coordinate of A is to the right of the center coordinate of B. "
        "'A top B' means that the center coordinate of A is above the center coordinate of B. "
        "'A bottom B' means that the center coordinate of A is below the center coordinate of B. "
        "'A center B' means that the center coordinate of A and the center coordinate of B are very close. "
        "'A smaller B' means that the area of A is smaller than the ares of B. "
        "'A larger B' means that the area of A is larger than the ares of B. "
        "'A equal B' means that the area of A and the ares of B are very close. "
        "Here, center coordinate = (left + width / 2, top + height / 2), area = width * height"
    )
    constraint_type = ("Element Type Constraint: ", "Element Relationship Constraint: ")
    relation_types = (
        "smaller",
        "equal",
        "larger",
        "top",
        "center",
        "bottom",
        "left",
        "right",
    )

    @override
    def build_input(self, data: LayoutRecord) -> str:
        """Serialize type and relation constraints."""
        type_constraints = self.constraint_type[0] + super(
            GenTypeSerializer, self
        ).build_input(data)
        relations = as_int_array(
            optional_record_value(data, K.relations, np.empty((0, 5), dtype=np.int64))
        )
        if len(relations) == 0:
            return type_constraints
        relation_tokens: list[str] = []
        for index, relation in enumerate(relations):
            label_j, index_j, label_i, index_i, relation_type = [
                int(value) for value in relation
            ]
            relation_tokens.append(
                "canvas" if label_i < 0 else f"{self.index2label[label_i]} {index_i}"
            )
            relation_tokens.append(self.relation_types[relation_type])
            relation_tokens.append(
                "canvas" if label_j < 0 else f"{self.index2label[label_j]} {index_j}"
            )
            if self.add_sep_token and index < len(relations) - 1:
                relation_tokens.append(self.sep_token)
        return (
            type_constraints
            + "\n"
            + self.constraint_type[1]
            + " ".join(relation_tokens)
        )

build_input

build_input(data: LayoutRecord) -> str

Serialize type and relation constraints.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
@override
def build_input(self, data: LayoutRecord) -> str:
    """Serialize type and relation constraints."""
    type_constraints = self.constraint_type[0] + super(
        GenTypeSerializer, self
    ).build_input(data)
    relations = as_int_array(
        optional_record_value(data, K.relations, np.empty((0, 5), dtype=np.int64))
    )
    if len(relations) == 0:
        return type_constraints
    relation_tokens: list[str] = []
    for index, relation in enumerate(relations):
        label_j, index_j, label_i, index_i, relation_type = [
            int(value) for value in relation
        ]
        relation_tokens.append(
            "canvas" if label_i < 0 else f"{self.index2label[label_i]} {index_i}"
        )
        relation_tokens.append(self.relation_types[relation_type])
        relation_tokens.append(
            "canvas" if label_j < 0 else f"{self.index2label[label_j]} {index_j}"
        )
        if self.add_sep_token and index < len(relations) - 1:
            relation_tokens.append(self.sep_token)
    return (
        type_constraints
        + "\n"
        + self.constraint_type[1]
        + " ".join(relation_tokens)
    )

CompletionSerializer dataclass

Bases: Serializer

Serializer for layout completion.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
class CompletionSerializer(Serializer):
    """Serializer for layout completion."""

    task_type = "layout completion"
    constraint_type = ("Partial Layout: ",)

    @override
    def _build_seq_input(self, data: LayoutRecord) -> str:
        return self._build_seq_output(
            {
                K.labels.value: as_int_array(record_value(data, K.labels))[:1],
                K.bboxes.value: as_float_array(record_value(data, K.discrete_bboxes))[
                    :1
                ],
            },
            K.labels,
            K.bboxes,
        )

    @override
    def _build_html_input(self, data: LayoutRecord) -> str:
        return self._build_html_output(
            {
                K.labels.value: as_int_array(record_value(data, K.labels))[:1],
                K.bboxes.value: as_float_array(record_value(data, K.discrete_bboxes))[
                    :1
                ],
            },
            K.labels,
            K.bboxes,
        )

    @override
    def build_input(self, data: LayoutRecord) -> str:
        """Serialize partial layout constraints with the task prefix."""
        return self.constraint_type[0] + super().build_input(data)

build_input

build_input(data: LayoutRecord) -> str

Serialize partial layout constraints with the task prefix.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
324
325
326
327
@override
def build_input(self, data: LayoutRecord) -> str:
    """Serialize partial layout constraints with the task prefix."""
    return self.constraint_type[0] + super().build_input(data)

RefinementSerializer dataclass

Bases: Serializer

Serializer for noisy-layout refinement.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
class RefinementSerializer(Serializer):
    """Serializer for noisy-layout refinement."""

    task_type = "layout refinement"
    constraint_type = ("Noise Layout: ",)

    @override
    def _build_seq_input(self, data: LayoutRecord) -> str:
        return self._build_seq_output(data, K.labels, K.discrete_bboxes)

    @override
    def _build_html_input(self, data: LayoutRecord) -> str:
        return self._build_html_output(data, K.labels, K.discrete_bboxes)

    @override
    def build_input(self, data: LayoutRecord) -> str:
        """Serialize noisy layout constraints with the task prefix."""
        return self.constraint_type[0] + super().build_input(data)

build_input

build_input(data: LayoutRecord) -> str

Serialize noisy layout constraints with the task prefix.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
344
345
346
347
@override
def build_input(self, data: LayoutRecord) -> str:
    """Serialize noisy layout constraints with the task prefix."""
    return self.constraint_type[0] + super().build_input(data)

TextToLayoutSerializer dataclass

Bases: Serializer

Serializer for text-to-layout prompts.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
class TextToLayoutSerializer(Serializer):
    """Serializer for text-to-layout prompts."""

    task_type = (
        "text-to-layout\n"
        "There are ten optional element types, including: image, icon, logo, background, title, description, text, link, input, button. "
        "Please do not exceed the boundaries of the canvas. "
        "Besides, do not generate elements at the edge of the canvas, that is, reduce top: 0px and left: 0px predictions as much as possible."
    )
    constraint_type = ("Text: ",)

    @override
    def _build_seq_input(self, data: LayoutRecord) -> str:
        return str(record_value(data, K.text))

    @override
    def _build_html_input(self, data: LayoutRecord) -> str:
        return self._build_seq_input(data)

    @override
    def build_input(self, data: LayoutRecord) -> str:
        """Serialize text input with the task prefix."""
        return self.constraint_type[0] + super().build_input(data)

build_input

build_input(data: LayoutRecord) -> str

Serialize text input with the task prefix.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
369
370
371
372
@override
def build_input(self, data: LayoutRecord) -> str:
    """Serialize text input with the task prefix."""
    return self.constraint_type[0] + super().build_input(data)

ContentAwareSerializer dataclass

Bases: GenTypeSerializer

Serializer for content-aware poster layout generation.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
class ContentAwareSerializer(GenTypeSerializer):
    """Serializer for content-aware poster layout generation."""

    task_type = (
        "content-aware layout generation\n"
        "Please place the following elements to avoid salient content, and underlay must be the background of text or logo."
    )
    constraint_type = ("Content Constraint: ", "Element Type Constraint: ")

    @override
    def _build_seq_input(self, data: LayoutRecord) -> str:
        content_tokens = []
        content_bboxes = as_float_array(record_value(data, K.discrete_content_bboxes))
        for index, bbox in enumerate(content_bboxes):
            left, top, width, height = [int(value) for value in bbox.tolist()]
            content_tokens.append(
                f"left {left}px, top {top}px, width {width}px, height {height}px"
            )
            if self.add_sep_token and index < len(content_bboxes) - 1:
                content_tokens.append(self.sep_token)
        return (
            self.constraint_type[0]
            + " ".join(content_tokens)
            + "\n"
            + self.constraint_type[1]
            + GenTypeSerializer._build_seq_input(self, data)
        )

    @override
    def build_input(self, data: LayoutRecord) -> str:
        """Serialize content masks and element type constraints."""
        return Serializer.build_input(self, data)

build_input

build_input(data: LayoutRecord) -> str

Serialize content masks and element type constraints.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
403
404
405
406
@override
def build_input(self, data: LayoutRecord) -> str:
    """Serialize content masks and element type constraints."""
    return Serializer.build_input(self, data)

create_serializer

create_serializer(
    dataset: SupportedDataset | str,
    task: LayoutPrompterTask | str,
    input_format: PromptFormat | str,
    output_format: PromptFormat | str,
    *,
    add_index_token: bool = True,
    add_sep_token: bool = True,
    add_unk_token: bool = False,
) -> Serializer

Create a task serializer.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
def create_serializer(
    dataset: SupportedDataset | str,
    task: LayoutPrompterTask | str,
    input_format: PromptFormat | str,
    output_format: PromptFormat | str,
    *,
    add_index_token: bool = True,
    add_sep_token: bool = True,
    add_unk_token: bool = False,
) -> Serializer:
    """Create a task serializer."""
    normalized_dataset = normalize_dataset(dataset)
    width, height = CANVAS_SIZE[normalized_dataset]
    normalized_task = normalize_layoutprompter_task(task)
    return SERIALIZER_MAP[normalized_task](
        input_format=_normalize_prompt_format(input_format, name="input"),
        output_format=_normalize_prompt_format(output_format, name="output"),
        index2label=id2label(normalized_dataset),
        canvas_width=width,
        canvas_height=height,
        add_index_token=add_index_token,
        add_sep_token=add_sep_token,
        add_unk_token=add_unk_token,
    )

build_prompt

build_prompt(
    serializer: Serializer,
    exemplars: Sequence[LayoutRecord],
    test_data: LayoutRecord,
    dataset: SupportedDataset | str,
    *,
    max_length: int = DEFAULT_MAX_LENGTH,
    separator_in_samples: str = "\n",
    separator_between_samples: str = "\n\n",
) -> str

Build the final few-shot LayoutPrompter prompt.

Source code in models/layoutprompter/src/layoutprompter/serialization.py
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
def build_prompt(
    serializer: Serializer,
    exemplars: Sequence[LayoutRecord],
    test_data: LayoutRecord,
    dataset: SupportedDataset | str,
    *,
    max_length: int = DEFAULT_MAX_LENGTH,
    separator_in_samples: str = "\n",
    separator_between_samples: str = "\n\n",
) -> str:
    """Build the final few-shot LayoutPrompter prompt."""
    normalized_dataset = normalize_dataset(dataset)
    prompt = [
        PREAMBLE.format(
            serializer.task_type,
            LAYOUT_DOMAIN[normalized_dataset],
            *CANVAS_SIZE[normalized_dataset],
        )
    ]
    for exemplar in exemplars:
        sample = (
            serializer.build_input(exemplar)
            + separator_in_samples
            + serializer.build_output(exemplar)
        )
        if len(separator_between_samples.join(prompt) + sample) <= max_length:
            prompt.append(sample)
        else:
            break
    prompt.append(serializer.build_input(test_data) + separator_in_samples)
    return separator_between_samples.join(prompt)

similarity

Similarity functions ported from LayoutPrompter exemplar selection.

labels_similarity

labels_similarity(
    labels_1: Int[ndarray, "elements"],
    labels_2: Int[ndarray, "elements"],
) -> float

Compute the reference multiset label overlap score.

Source code in models/layoutprompter/src/layoutprompter/similarity.py
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def labels_similarity(
    labels_1: Int[np.ndarray, "elements"], labels_2: Int[np.ndarray, "elements"]
) -> float:
    """Compute the reference multiset label overlap score."""
    values_1 = [int(value) for value in labels_1.reshape(-1).tolist()]
    values_2 = [int(value) for value in labels_2.reshape(-1).tolist()]
    counts_1 = Counter(values_1)
    counts_2 = Counter(values_2)
    intersection = sum(
        2 * min(counts_1[key], counts_2[key])
        for key in counts_1.keys() & counts_2.keys()
    )
    union = len(values_1) + len(values_2)
    return intersection / union if union else 0.0

bboxes_similarity

bboxes_similarity(
    labels_1: Int[ndarray, "elements_1"],
    bboxes_1: Float[ndarray, "elements_1 4"],
    labels_2: Int[ndarray, "elements_2"],
    bboxes_2: Float[ndarray, "elements_2 4"],
) -> float

Compute LayoutPrompter's label-masked bbox matching score.

Source code in models/layoutprompter/src/layoutprompter/similarity.py
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
def bboxes_similarity(
    labels_1: Int[np.ndarray, "elements_1"],
    bboxes_1: Float[np.ndarray, "elements_1 4"],
    labels_2: Int[np.ndarray, "elements_2"],
    bboxes_2: Float[np.ndarray, "elements_2 4"],
) -> float:
    """Compute LayoutPrompter's label-masked bbox matching score."""
    if len(labels_1) == 0 or len(labels_2) == 0:
        return 0.0
    distance = np.linalg.norm(bboxes_1[:, None, :] - bboxes_2[None, :, :], axis=-1) * 2
    scores = np.power(0.5, distance)
    scores = scores * (labels_1[:, None] == labels_2[None, :])
    row_count, col_count = scores.shape
    if row_count <= col_count:
        best = max(
            sum(float(scores[row, col]) for row, col in enumerate(cols))
            for cols in permutations(range(col_count), row_count)
        )
        return best / row_count
    best = max(
        sum(float(scores[row, col]) for col, row in enumerate(rows))
        for rows in permutations(range(row_count), col_count)
    )
    return best / col_count

labels_bboxes_similarity

labels_bboxes_similarity(
    labels_1: Int[ndarray, "elements_1"],
    bboxes_1: Float[ndarray, "elements_1 dims"],
    labels_2: Int[ndarray, "elements_2"],
    bboxes_2: Float[ndarray, "elements_2 dims"],
    labels_weight: float,
    bboxes_weight: float,
) -> float

Combine label and bbox similarities with reference weights.

Source code in models/layoutprompter/src/layoutprompter/similarity.py
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
def labels_bboxes_similarity(
    labels_1: Int[np.ndarray, "elements_1"],
    bboxes_1: Float[np.ndarray, "elements_1 dims"],
    labels_2: Int[np.ndarray, "elements_2"],
    bboxes_2: Float[np.ndarray, "elements_2 dims"],
    labels_weight: float,
    bboxes_weight: float,
) -> float:
    """Combine label and bbox similarities with reference weights."""
    return labels_weight * labels_similarity(
        labels_1, labels_2
    ) + bboxes_weight * bboxes_similarity(
        labels_1,
        bboxes_1,
        labels_2,
        bboxes_2,
    )

vendor_parity

Small deterministic records shared by reference parity scripts and tests.

fixture_records

fixture_records() -> tuple[
    list[LayoutRecord], LayoutRecord
]

Return fixed train/test records shared by reference and local tests.

Source code in models/layoutprompter/src/layoutprompter/vendor_parity.py
12
13
14
15
16
17
18
19
20
def fixture_records() -> tuple[list[LayoutRecord], LayoutRecord]:
    """Return fixed train/test records shared by reference and local tests."""
    train_data = [
        _record("candidate-a", [0, 0], [[4, 5, 20, 10], [40, 50, 15, 20]]),
        _record("candidate-filtered", [0, 2], [[4, 5, 0, 10], [40, 50, 15, 20]]),
        _record("candidate-best", [0, 2], [[8, 10, 20, 15], [70, 80, 10, 12]]),
    ]
    test_data = _record("test", [0, 2], [[12, 16, 24, 32], [60, 80, 12, 16]])
    return train_data, test_data

parser_prediction

parser_prediction() -> str

Return a cached LLM-like response string for parser parity.

Source code in models/layoutprompter/src/layoutprompter/vendor_parity.py
23
24
25
def parser_prediction() -> str:
    """Return a cached LLM-like response string for parser parity."""
    return "text 12 16 24 32 | button 60 80 12 16"