capture-runtime-client 0.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- capture_runtime_client/__init__.py +41 -0
- capture_runtime_client/client.py +852 -0
- capture_runtime_client/codec.py +124 -0
- capture_runtime_client/contracts.py +272 -0
- capture_runtime_client/errors.py +170 -0
- capture_runtime_client/private/__init__.py +1 -0
- capture_runtime_client/private/assets/__init__.py +1 -0
- capture_runtime_client/private/assets/contract-set.json +1 -0
- capture_runtime_client/private/assets/contract-set.sha256 +1 -0
- capture_runtime_client/private/generated_models.py +627 -0
- capture_runtime_client/private/schemas/__init__.py +1 -0
- capture_runtime_client/private/schemas/capture-block.schema.json +151 -0
- capture_runtime_client/private/schemas/capture-document.schema.json +356 -0
- capture_runtime_client/private/schemas/capture-engine.schema.json +40 -0
- capture_runtime_client/private/schemas/capture-event-v2.schema.json +301 -0
- capture_runtime_client/private/schemas/capture-failure-v2.schema.json +40 -0
- capture_runtime_client/private/schemas/capture-operation-v2.schema.json +207 -0
- capture_runtime_client/private/schemas/capture-source.schema.json +34 -0
- capture_runtime_client/private/schemas/error-body-v2.schema.json +34 -0
- capture_runtime_client/private/schemas/error-envelope-v2.schema.json +49 -0
- capture_runtime_client/private/schemas/finalize-ingestion-v2.schema.json +27 -0
- capture_runtime_client/private/schemas/ingestion-v2.schema.json +127 -0
- capture_runtime_client/private/schemas/open-ingestion-v2.schema.json +79 -0
- capture_runtime_client/private/schemas/page-locator.schema.json +49 -0
- capture_runtime_client/private/schemas/partial-capture-v2.schema.json +267 -0
- capture_runtime_client/private/schemas/raw-capture-segment.schema.json +125 -0
- capture_runtime_client/private/schemas/raw-capture.schema.json +260 -0
- capture_runtime_client/private/schemas/report-structuring-failure-v2.schema.json +28 -0
- capture_runtime_client/private/schemas/runtime-artifact-descriptor-v2.schema.json +34 -0
- capture_runtime_client/private/schemas/runtime-installation-v2.schema.json +126 -0
- capture_runtime_client/private/schemas/runtime-installations-v2.schema.json +143 -0
- capture_runtime_client/private/schemas/runtime-model-installation-v2.schema.json +121 -0
- capture_runtime_client/private/schemas/runtime-model-installations-v2.schema.json +138 -0
- capture_runtime_client/private/schemas/runtime-model-option-v2.schema.json +80 -0
- capture_runtime_client/private/schemas/runtime-model-options-v2.schema.json +103 -0
- capture_runtime_client/private/schemas/runtime-ready.schema.json +88 -0
- capture_runtime_client/private/schemas/runtime-requirement-v2.schema.json +120 -0
- capture_runtime_client/private/schemas/runtime-requirements-v2.schema.json +137 -0
- capture_runtime_client/private/schemas/runtime-streaming-capabilities-v2.schema.json +64 -0
- capture_runtime_client/private/schemas/start-capture-v2.schema.json +59 -0
- capture_runtime_client/private/schemas/start-runtime-installation-v2.schema.json +26 -0
- capture_runtime_client/private/schemas/start-runtime-model-installation-v2.schema.json +21 -0
- capture_runtime_client/private/schemas/time-locator.schema.json +27 -0
- capture_runtime_client/py.typed +1 -0
- capture_runtime_client/transport.py +158 -0
- capture_runtime_client-0.4.0.dist-info/METADATA +18 -0
- capture_runtime_client-0.4.0.dist-info/RECORD +48 -0
- capture_runtime_client-0.4.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,627 @@
|
|
|
1
|
+
# Generated by packages/capture-runtime/scripts/generate_contracts.py. Do not edit.
|
|
2
|
+
|
|
3
|
+
"""Generated host-side Pydantic models for the Capture Runtime v2 API."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from enum import StrEnum
|
|
9
|
+
from typing import Annotated, Any, Final, Literal, Self
|
|
10
|
+
|
|
11
|
+
from pydantic import (
|
|
12
|
+
BaseModel,
|
|
13
|
+
ConfigDict,
|
|
14
|
+
Field,
|
|
15
|
+
StringConstraints,
|
|
16
|
+
field_validator,
|
|
17
|
+
model_validator,
|
|
18
|
+
)
|
|
19
|
+
from pydantic.alias_generators import to_camel
|
|
20
|
+
|
|
21
|
+
API_VERSION: Final = "2.0"
|
|
22
|
+
RUNTIME_VERSION: Final = "0.4.0"
|
|
23
|
+
CAPTURE_DOCUMENT_SCHEMA_VERSION: Final = "2"
|
|
24
|
+
|
|
25
|
+
NonEmptyString = Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]
|
|
26
|
+
CaptureText = Annotated[
|
|
27
|
+
str, StringConstraints(strip_whitespace=True, min_length=1, max_length=2_000_000)
|
|
28
|
+
]
|
|
29
|
+
ProjectedText = Annotated[
|
|
30
|
+
str, StringConstraints(strip_whitespace=True, min_length=1, max_length=8_000_000)
|
|
31
|
+
]
|
|
32
|
+
WarningText = Annotated[str, StringConstraints(strip_whitespace=True, max_length=500)]
|
|
33
|
+
Sha256Hex = Annotated[str, StringConstraints(pattern=r"^[0-9a-f]{64}$")]
|
|
34
|
+
EngineDigest = Annotated[str, StringConstraints(pattern=r"^sha256:[0-9a-f]{64}$")]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class StrictModel(BaseModel):
|
|
38
|
+
"""Reject unexpected wire fields and expose camelCase JSON aliases."""
|
|
39
|
+
|
|
40
|
+
model_config = ConfigDict(
|
|
41
|
+
alias_generator=to_camel,
|
|
42
|
+
extra="forbid",
|
|
43
|
+
populate_by_name=True,
|
|
44
|
+
str_strip_whitespace=True,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _require_aware(value: datetime) -> datetime:
|
|
49
|
+
if value.tzinfo is None or value.utcoffset() is None:
|
|
50
|
+
raise ValueError("timestamp must include a timezone")
|
|
51
|
+
return value
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class CaptureSourceKind(StrEnum):
|
|
55
|
+
PDF = "pdf"
|
|
56
|
+
IMAGE = "image"
|
|
57
|
+
AUDIO = "audio"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class StructuringMode(StrEnum):
|
|
61
|
+
RUNTIME = "runtime"
|
|
62
|
+
HOST = "host"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class RuntimeInstallationStatus(StrEnum):
|
|
66
|
+
QUEUED = "queued"
|
|
67
|
+
RUNNING = "running"
|
|
68
|
+
COMPLETED = "completed"
|
|
69
|
+
FAILED = "failed"
|
|
70
|
+
CANCELLED = "cancelled"
|
|
71
|
+
MANUAL_ACTION_REQUIRED = "manual_action_required"
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class RuntimeModelOptionStatus(StrEnum):
|
|
75
|
+
NOT_INSTALLED = "not-installed"
|
|
76
|
+
INSTALLED = "installed"
|
|
77
|
+
ACTIVE = "active"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class RuntimeRequirementStatus(StrEnum):
|
|
81
|
+
READY = "ready"
|
|
82
|
+
MISSING = "missing"
|
|
83
|
+
INSTALLABLE = "installable"
|
|
84
|
+
MANUAL_ACTION_REQUIRED = "manual_action_required"
|
|
85
|
+
UNAVAILABLE = "unavailable"
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
CaptureRequirementId = Literal[
|
|
89
|
+
"windowsml-ocr",
|
|
90
|
+
"whisper-primary",
|
|
91
|
+
"ollama-runtime",
|
|
92
|
+
"capture-ollama-model",
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class PageLocator(StrictModel):
|
|
97
|
+
kind: Literal["page"] = "page"
|
|
98
|
+
page: int = Field(ge=1)
|
|
99
|
+
bounding_box: tuple[float, float, float, float] | None = None
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class TimeLocator(StrictModel):
|
|
103
|
+
kind: Literal["time"] = "time"
|
|
104
|
+
start_ms: int = Field(ge=0)
|
|
105
|
+
end_ms: int = Field(gt=0)
|
|
106
|
+
|
|
107
|
+
@model_validator(mode="after")
|
|
108
|
+
def validate_interval(self) -> Self:
|
|
109
|
+
if self.end_ms <= self.start_ms:
|
|
110
|
+
raise ValueError("endMs must be greater than startMs")
|
|
111
|
+
return self
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
CaptureLocator = Annotated[PageLocator | TimeLocator, Field(discriminator="kind")]
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class CaptureSource(StrictModel):
|
|
118
|
+
sha256: Sha256Hex
|
|
119
|
+
file_name: Annotated[
|
|
120
|
+
str, StringConstraints(strip_whitespace=True, min_length=1, max_length=255)
|
|
121
|
+
]
|
|
122
|
+
media_type: NonEmptyString
|
|
123
|
+
bytes: int = Field(ge=1)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class CaptureEngine(StrictModel):
|
|
127
|
+
engine: NonEmptyString
|
|
128
|
+
model: NonEmptyString
|
|
129
|
+
digest: EngineDigest
|
|
130
|
+
device: NonEmptyString | None = None
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class RawCaptureSegment(StrictModel):
|
|
134
|
+
segment_id: NonEmptyString
|
|
135
|
+
order: int = Field(ge=0)
|
|
136
|
+
locator: CaptureLocator
|
|
137
|
+
text: CaptureText
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def project_source_text(segments: list[RawCaptureSegment]) -> str:
|
|
141
|
+
return "\n".join(segment.text for segment in segments)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class RawCapture(StrictModel):
|
|
145
|
+
schema_version: Literal["2"] = CAPTURE_DOCUMENT_SCHEMA_VERSION
|
|
146
|
+
diagnostic_only: Literal[True] = True
|
|
147
|
+
source: CaptureSource
|
|
148
|
+
segments: list[RawCaptureSegment] = Field(min_length=1, max_length=10_000)
|
|
149
|
+
source_text: ProjectedText
|
|
150
|
+
extraction_engine: CaptureEngine
|
|
151
|
+
warnings: list[WarningText] = Field(default_factory=list, max_length=1_000)
|
|
152
|
+
created_at: datetime
|
|
153
|
+
|
|
154
|
+
_aware_created_at = field_validator("created_at")(_require_aware)
|
|
155
|
+
|
|
156
|
+
@model_validator(mode="after")
|
|
157
|
+
def validate_projection(self) -> Self:
|
|
158
|
+
expected_orders = list(range(len(self.segments)))
|
|
159
|
+
if [segment.order for segment in self.segments] != expected_orders:
|
|
160
|
+
raise ValueError("raw segment order must be contiguous and match list order")
|
|
161
|
+
if self.source_text != project_source_text(self.segments):
|
|
162
|
+
raise ValueError("sourceText must be the exact raw segment projection")
|
|
163
|
+
identifiers = [segment.segment_id for segment in self.segments]
|
|
164
|
+
if len(identifiers) != len(set(identifiers)):
|
|
165
|
+
raise ValueError("raw segmentId values must be unique")
|
|
166
|
+
return self
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class CaptureBlock(StrictModel):
|
|
170
|
+
block_id: NonEmptyString
|
|
171
|
+
order: int = Field(ge=0)
|
|
172
|
+
type: Literal["heading", "paragraph", "list-item", "table", "quote", "transcript"]
|
|
173
|
+
source_segment_id: NonEmptyString
|
|
174
|
+
locator: CaptureLocator
|
|
175
|
+
source_text: CaptureText
|
|
176
|
+
target_text: CaptureText
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class CaptureDocument(StrictModel):
|
|
180
|
+
schema_version: Literal["2"] = CAPTURE_DOCUMENT_SCHEMA_VERSION
|
|
181
|
+
source: CaptureSource
|
|
182
|
+
raw_segments: list[RawCaptureSegment] = Field(min_length=1, max_length=10_000)
|
|
183
|
+
blocks: list[CaptureBlock] = Field(min_length=1, max_length=10_000)
|
|
184
|
+
source_text: ProjectedText
|
|
185
|
+
target_text: ProjectedText
|
|
186
|
+
extraction_engine: CaptureEngine
|
|
187
|
+
structuring_engine: CaptureEngine
|
|
188
|
+
warnings: list[WarningText] = Field(default_factory=list, max_length=1_000)
|
|
189
|
+
created_at: datetime
|
|
190
|
+
completed_at: datetime
|
|
191
|
+
|
|
192
|
+
_aware_created_at = field_validator("created_at")(_require_aware)
|
|
193
|
+
_aware_completed_at = field_validator("completed_at")(_require_aware)
|
|
194
|
+
|
|
195
|
+
@model_validator(mode="after")
|
|
196
|
+
def validate_document(self) -> Self:
|
|
197
|
+
if self.completed_at < self.created_at:
|
|
198
|
+
raise ValueError("completedAt must not precede createdAt")
|
|
199
|
+
if [segment.order for segment in self.raw_segments] != list(range(len(self.raw_segments))):
|
|
200
|
+
raise ValueError("raw segment order must be contiguous and match list order")
|
|
201
|
+
if [block.order for block in self.blocks] != list(range(len(self.blocks))):
|
|
202
|
+
raise ValueError("block order must be contiguous and match list order")
|
|
203
|
+
segment_ids = [segment.segment_id for segment in self.raw_segments]
|
|
204
|
+
if len(segment_ids) != len(set(segment_ids)):
|
|
205
|
+
raise ValueError("raw segmentId values must be unique")
|
|
206
|
+
block_ids = [block.block_id for block in self.blocks]
|
|
207
|
+
if len(block_ids) != len(set(block_ids)):
|
|
208
|
+
raise ValueError("blockId values must be unique")
|
|
209
|
+
segments_by_id = {segment.segment_id: segment for segment in self.raw_segments}
|
|
210
|
+
if len(self.blocks) != len(self.raw_segments):
|
|
211
|
+
raise ValueError("blocks must cover every raw segment exactly once")
|
|
212
|
+
for index, block in enumerate(self.blocks):
|
|
213
|
+
expected_segment = self.raw_segments[index]
|
|
214
|
+
segment = segments_by_id.get(block.source_segment_id)
|
|
215
|
+
if segment is None:
|
|
216
|
+
raise ValueError("every block must reference a raw source segment")
|
|
217
|
+
if block.source_segment_id != expected_segment.segment_id:
|
|
218
|
+
raise ValueError("block sequence must follow raw segment order")
|
|
219
|
+
if block.locator != segment.locator:
|
|
220
|
+
raise ValueError("block locator must equal its raw source segment locator")
|
|
221
|
+
if block.source_text != segment.text:
|
|
222
|
+
raise ValueError("block sourceText must equal its raw source segment text")
|
|
223
|
+
if self.source_text != project_source_text(self.raw_segments):
|
|
224
|
+
raise ValueError("sourceText must be the exact raw segment projection")
|
|
225
|
+
expected_target = "\n".join(block.target_text for block in self.blocks)
|
|
226
|
+
if self.target_text != expected_target:
|
|
227
|
+
raise ValueError("targetText must be the exact block target projection")
|
|
228
|
+
return self
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class RuntimeArtifactDescriptorV2(StrictModel):
|
|
232
|
+
artifact_url: NonEmptyString
|
|
233
|
+
artifact_file_name: NonEmptyString
|
|
234
|
+
bytes: int = Field(ge=1, le=536_870_912)
|
|
235
|
+
sha256: Sha256Hex
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
class RuntimeRequirementV2(StrictModel):
|
|
239
|
+
requirement_id: CaptureRequirementId
|
|
240
|
+
kind: NonEmptyString
|
|
241
|
+
display_name: NonEmptyString
|
|
242
|
+
status: RuntimeRequirementStatus
|
|
243
|
+
required_for: list[str]
|
|
244
|
+
install_strategy: NonEmptyString
|
|
245
|
+
detail: str | None = None
|
|
246
|
+
artifact: RuntimeArtifactDescriptorV2 | None = None
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class RuntimeRequirementsV2(StrictModel):
|
|
250
|
+
items: list[RuntimeRequirementV2]
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class StartRuntimeInstallationV2(StrictModel):
|
|
254
|
+
requirement_id: CaptureRequirementId
|
|
255
|
+
consent: Literal[True]
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
class RuntimeModelOptionV2(StrictModel):
|
|
259
|
+
option_id: NonEmptyString
|
|
260
|
+
display_name: NonEmptyString
|
|
261
|
+
model_reference: NonEmptyString
|
|
262
|
+
expected_digest: Sha256Hex | None = None
|
|
263
|
+
expected_bytes: int | None = Field(default=None, ge=1)
|
|
264
|
+
profile_id: NonEmptyString
|
|
265
|
+
profile_spec_sha256: Sha256Hex
|
|
266
|
+
status: RuntimeModelOptionStatus
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class RuntimeModelOptionsV2(StrictModel):
|
|
270
|
+
catalog_sha256: Sha256Hex
|
|
271
|
+
items: list[RuntimeModelOptionV2]
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
class StartRuntimeModelInstallationV2(StrictModel):
|
|
275
|
+
option_id: NonEmptyString
|
|
276
|
+
consent: Literal[True]
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
class RuntimeModelInstallationV2(StrictModel):
|
|
280
|
+
installation_id: str
|
|
281
|
+
option_id: NonEmptyString
|
|
282
|
+
status: RuntimeInstallationStatus
|
|
283
|
+
progress: float = Field(ge=0, le=1)
|
|
284
|
+
error: CaptureFailureV2 | None = None
|
|
285
|
+
created_at: datetime
|
|
286
|
+
updated_at: datetime
|
|
287
|
+
completed_at: datetime | None = None
|
|
288
|
+
|
|
289
|
+
_aware_times = field_validator("created_at", "updated_at", "completed_at")(
|
|
290
|
+
lambda value: None if value is None else _require_aware(value)
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
class RuntimeModelInstallationsV2(StrictModel):
|
|
295
|
+
items: list[RuntimeModelInstallationV2]
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
class RuntimeInstallationV2(StrictModel):
|
|
299
|
+
installation_id: str
|
|
300
|
+
requirement_id: CaptureRequirementId
|
|
301
|
+
status: RuntimeInstallationStatus
|
|
302
|
+
progress: float = Field(ge=0, le=1)
|
|
303
|
+
error: CaptureFailureV2 | None = None
|
|
304
|
+
created_at: datetime
|
|
305
|
+
updated_at: datetime
|
|
306
|
+
completed_at: datetime | None = None
|
|
307
|
+
|
|
308
|
+
_aware_times = field_validator("created_at", "updated_at", "completed_at")(
|
|
309
|
+
lambda value: None if value is None else _require_aware(value)
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
class RuntimeInstallationsV2(StrictModel):
|
|
314
|
+
items: list[RuntimeInstallationV2]
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
class StreamingIngestionMode(StrEnum):
|
|
318
|
+
FILE = "file"
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
class StreamingIngestionStatus(StrEnum):
|
|
322
|
+
OPEN = "open"
|
|
323
|
+
FINALIZING = "finalizing"
|
|
324
|
+
READY = "ready"
|
|
325
|
+
CANCELLED = "cancelled"
|
|
326
|
+
FAILED = "failed"
|
|
327
|
+
EXPIRED = "expired"
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
class StreamingCaptureStatus(StrEnum):
|
|
331
|
+
CREATED = "created"
|
|
332
|
+
WAITING_INPUT = "waiting_input"
|
|
333
|
+
EXTRACTING = "extracting"
|
|
334
|
+
AWAITING_STRUCTURING = "awaiting_structuring"
|
|
335
|
+
STRUCTURING = "structuring"
|
|
336
|
+
COMPLETED = "completed"
|
|
337
|
+
FAILED = "failed"
|
|
338
|
+
CANCELLED = "cancelled"
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
class StreamingEventType(StrEnum):
|
|
342
|
+
ACCEPTED = "accepted"
|
|
343
|
+
INPUT_CHECKPOINT = "input_checkpoint"
|
|
344
|
+
HEARTBEAT = "heartbeat"
|
|
345
|
+
SEGMENT = "segment"
|
|
346
|
+
CHECKPOINT = "checkpoint"
|
|
347
|
+
RESYNC_REQUIRED = "resync_required"
|
|
348
|
+
COMPLETED = "completed"
|
|
349
|
+
FAILED = "failed"
|
|
350
|
+
CANCELLED = "cancelled"
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
class OpenIngestionV2(StrictModel):
|
|
354
|
+
protocol_version: Literal["2"] = "2"
|
|
355
|
+
kind: CaptureSourceKind = CaptureSourceKind.AUDIO
|
|
356
|
+
mode: StreamingIngestionMode = StreamingIngestionMode.FILE
|
|
357
|
+
client_request_id: NonEmptyString
|
|
358
|
+
file_name: Annotated[
|
|
359
|
+
str, StringConstraints(strip_whitespace=True, min_length=1, max_length=255)
|
|
360
|
+
]
|
|
361
|
+
media_type: NonEmptyString
|
|
362
|
+
total_bytes: int = Field(gt=0)
|
|
363
|
+
source_sha256: Sha256Hex | None = None
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
class IngestionV2(StrictModel):
|
|
367
|
+
protocol_version: Literal["2"] = "2"
|
|
368
|
+
kind: CaptureSourceKind = CaptureSourceKind.AUDIO
|
|
369
|
+
ingestion_id: NonEmptyString
|
|
370
|
+
status: StreamingIngestionStatus
|
|
371
|
+
file_name: Annotated[
|
|
372
|
+
str, StringConstraints(strip_whitespace=True, min_length=1, max_length=255)
|
|
373
|
+
]
|
|
374
|
+
media_type: NonEmptyString
|
|
375
|
+
total_bytes: int = Field(gt=0)
|
|
376
|
+
received_bytes: int = Field(ge=0)
|
|
377
|
+
contiguous_bytes: int = Field(ge=0)
|
|
378
|
+
next_chunk_index: int = Field(ge=0)
|
|
379
|
+
next_offset: int = Field(ge=0)
|
|
380
|
+
source_sha256: Sha256Hex | None = None
|
|
381
|
+
finalized_sha256: Sha256Hex | None = None
|
|
382
|
+
expires_at: datetime
|
|
383
|
+
|
|
384
|
+
_aware_expires_at = field_validator("expires_at")(_require_aware)
|
|
385
|
+
|
|
386
|
+
@model_validator(mode="after")
|
|
387
|
+
def validate_progress(self) -> Self:
|
|
388
|
+
if self.received_bytes > self.total_bytes:
|
|
389
|
+
raise ValueError("receivedBytes must not exceed totalBytes")
|
|
390
|
+
if self.contiguous_bytes > self.received_bytes:
|
|
391
|
+
raise ValueError("contiguousBytes must not exceed receivedBytes")
|
|
392
|
+
if self.next_offset != self.contiguous_bytes:
|
|
393
|
+
raise ValueError("nextOffset must equal contiguousBytes")
|
|
394
|
+
if self.status is StreamingIngestionStatus.READY:
|
|
395
|
+
if self.received_bytes != self.total_bytes or self.finalized_sha256 is None:
|
|
396
|
+
raise ValueError("ready ingestion must be complete and checksummed")
|
|
397
|
+
return self
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
class StartCaptureV2(StrictModel):
|
|
401
|
+
protocol_version: Literal["2"] = "2"
|
|
402
|
+
client_request_id: NonEmptyString
|
|
403
|
+
ingestion_id: NonEmptyString
|
|
404
|
+
structuring_mode: StructuringMode
|
|
405
|
+
target_language: str | None = None
|
|
406
|
+
start_policy: Literal["eager"] = "eager"
|
|
407
|
+
|
|
408
|
+
@field_validator("target_language")
|
|
409
|
+
@classmethod
|
|
410
|
+
def validate_target_language(cls, value: str | None) -> str | None:
|
|
411
|
+
if value is not None and not 1 <= len(value) <= 64:
|
|
412
|
+
raise ValueError("targetLanguage must be 1 to 64 characters")
|
|
413
|
+
return value
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
class FinalizeIngestionV2(StrictModel):
|
|
417
|
+
protocol_version: Literal["2"] = "2"
|
|
418
|
+
total_bytes: int = Field(gt=0)
|
|
419
|
+
sha256: Sha256Hex
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
class CaptureFailureV2(StrictModel):
|
|
423
|
+
code: Annotated[str, StringConstraints(pattern=r"^[a-z][a-z0-9_]{1,63}$")]
|
|
424
|
+
message: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1, max_length=500)]
|
|
425
|
+
stage: NonEmptyString | None = None
|
|
426
|
+
retryable: bool = False
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
class ReportStructuringFailureV2(StrictModel):
|
|
430
|
+
protocol_version: Literal["2"] = "2"
|
|
431
|
+
code: Annotated[str, StringConstraints(pattern=r"^[a-z][a-z0-9_]{1,63}$")]
|
|
432
|
+
message: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1, max_length=500)]
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
class CaptureOperationV2(StrictModel):
|
|
436
|
+
protocol_version: Literal["2"] = "2"
|
|
437
|
+
capture_id: NonEmptyString
|
|
438
|
+
ingestion_id: NonEmptyString
|
|
439
|
+
kind: CaptureSourceKind = CaptureSourceKind.AUDIO
|
|
440
|
+
status: StreamingCaptureStatus
|
|
441
|
+
progress: float | None = Field(default=None, ge=0, le=1)
|
|
442
|
+
partial_revision: int = Field(ge=0)
|
|
443
|
+
last_event_sequence: int = Field(ge=0)
|
|
444
|
+
source: CaptureSource | None = None
|
|
445
|
+
error: CaptureFailureV2 | None = None
|
|
446
|
+
created_at: datetime
|
|
447
|
+
updated_at: datetime
|
|
448
|
+
completed_at: datetime | None = None
|
|
449
|
+
|
|
450
|
+
_aware_times = field_validator("created_at", "updated_at", "completed_at")(
|
|
451
|
+
lambda value: None if value is None else _require_aware(value)
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
@model_validator(mode="after")
|
|
455
|
+
def validate_state(self) -> Self:
|
|
456
|
+
terminal = {
|
|
457
|
+
StreamingCaptureStatus.COMPLETED,
|
|
458
|
+
StreamingCaptureStatus.FAILED,
|
|
459
|
+
StreamingCaptureStatus.CANCELLED,
|
|
460
|
+
}
|
|
461
|
+
if (self.status in terminal) != (self.completed_at is not None):
|
|
462
|
+
raise ValueError("terminal streaming captures must have completedAt")
|
|
463
|
+
return self
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
class CaptureStreamingResult(StrictModel):
|
|
467
|
+
operation: CaptureOperationV2
|
|
468
|
+
raw: RawCapture
|
|
469
|
+
result: CaptureDocument
|
|
470
|
+
|
|
471
|
+
@model_validator(mode="after")
|
|
472
|
+
def validate_source_identity(self) -> Self:
|
|
473
|
+
if self.raw.source != self.result.source:
|
|
474
|
+
raise ValueError("raw and structured result source identity must match")
|
|
475
|
+
if self.operation.source is not None and self.operation.source != self.raw.source:
|
|
476
|
+
raise ValueError("operation and result source identity must match")
|
|
477
|
+
return self
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
class PartialCaptureV2(StrictModel):
|
|
481
|
+
protocol_version: Literal["2"] = "2"
|
|
482
|
+
capture_id: NonEmptyString
|
|
483
|
+
source: CaptureSource
|
|
484
|
+
revision: int = Field(ge=0)
|
|
485
|
+
covered_until_ms: int = Field(ge=0)
|
|
486
|
+
segments: list[RawCaptureSegment] = Field(default_factory=list, max_length=10_000)
|
|
487
|
+
source_text: Annotated[str, StringConstraints(max_length=8_000_000)] = ""
|
|
488
|
+
extraction_engine: CaptureEngine | None = None
|
|
489
|
+
updated_at: datetime
|
|
490
|
+
|
|
491
|
+
_aware_updated_at = field_validator("updated_at")(_require_aware)
|
|
492
|
+
|
|
493
|
+
@model_validator(mode="after")
|
|
494
|
+
def validate_projection(self) -> Self:
|
|
495
|
+
if [segment.order for segment in self.segments] != list(range(len(self.segments))):
|
|
496
|
+
raise ValueError("partial segment order must be contiguous")
|
|
497
|
+
expected_text = project_source_text(self.segments) if self.segments else ""
|
|
498
|
+
if self.source_text != expected_text:
|
|
499
|
+
raise ValueError("sourceText must be the exact partial segment projection")
|
|
500
|
+
return self
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
class CaptureEventV2(StrictModel):
|
|
504
|
+
protocol_version: Literal["2"] = "2"
|
|
505
|
+
event_id: NonEmptyString
|
|
506
|
+
sequence: int = Field(ge=0)
|
|
507
|
+
capture_id: NonEmptyString
|
|
508
|
+
kind: CaptureSourceKind = CaptureSourceKind.AUDIO
|
|
509
|
+
event_type: StreamingEventType
|
|
510
|
+
stage: NonEmptyString
|
|
511
|
+
progress: float | None = Field(default=None, ge=0, le=1)
|
|
512
|
+
partial_revision: int | None = Field(default=None, ge=0)
|
|
513
|
+
covered_until_ms: int | None = Field(default=None, ge=0)
|
|
514
|
+
segments: list[RawCaptureSegment] = Field(default_factory=list, max_length=1_000)
|
|
515
|
+
error: CaptureFailureV2 | None = None
|
|
516
|
+
created_at: datetime
|
|
517
|
+
|
|
518
|
+
_aware_created_at = field_validator("created_at")(_require_aware)
|
|
519
|
+
|
|
520
|
+
@model_validator(mode="after")
|
|
521
|
+
def validate_event_payload(self) -> Self:
|
|
522
|
+
if self.event_type is StreamingEventType.SEGMENT and not self.segments:
|
|
523
|
+
raise ValueError("segment events must contain at least one segment")
|
|
524
|
+
if self.event_type is StreamingEventType.FAILED and self.error is None:
|
|
525
|
+
raise ValueError("failed events must contain an error")
|
|
526
|
+
if self.event_type is not StreamingEventType.FAILED and self.error is not None:
|
|
527
|
+
raise ValueError("only failed events may contain an error")
|
|
528
|
+
return self
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
class RuntimeStreamingCapabilitiesV2(StrictModel):
|
|
532
|
+
protocol_version: Literal["2"] = "2"
|
|
533
|
+
capture_kinds: list[CaptureSourceKind] = Field(
|
|
534
|
+
default_factory=lambda: [
|
|
535
|
+
CaptureSourceKind.PDF,
|
|
536
|
+
CaptureSourceKind.IMAGE,
|
|
537
|
+
CaptureSourceKind.AUDIO,
|
|
538
|
+
],
|
|
539
|
+
min_length=1,
|
|
540
|
+
)
|
|
541
|
+
supports_progressive_audio: bool = True
|
|
542
|
+
max_chunk_bytes: int = Field(gt=0, le=4 * 1024 * 1024)
|
|
543
|
+
checkpoint_interval_ms: int = Field(gt=0)
|
|
544
|
+
heartbeat_interval_ms: int = Field(gt=0)
|
|
545
|
+
stall_timeout_ms: int = Field(gt=0)
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
class RuntimeReady(StrictModel):
|
|
549
|
+
"""General v2 readiness payload shared by runtime clients."""
|
|
550
|
+
|
|
551
|
+
ready: bool
|
|
552
|
+
service: Literal["capture-runtime"] = "capture-runtime"
|
|
553
|
+
api_version: Literal["2.0"] = API_VERSION
|
|
554
|
+
runtime_version: Literal["0.4.0"] = RUNTIME_VERSION
|
|
555
|
+
capture_document_schema_version: Literal["2"] = CAPTURE_DOCUMENT_SCHEMA_VERSION
|
|
556
|
+
capture_document_schema_sha256: Sha256Hex | None = None
|
|
557
|
+
schema_sha256: Sha256Hex | None = None
|
|
558
|
+
contract_set_version: Literal["2"] = "2"
|
|
559
|
+
capabilities: dict[str, Any] = Field(default_factory=dict)
|
|
560
|
+
message: str | None = None
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
class ErrorBodyV2(StrictModel):
|
|
564
|
+
code: NonEmptyString
|
|
565
|
+
message: NonEmptyString
|
|
566
|
+
details: dict[str, Any] | None = None
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
class ErrorEnvelopeV2(StrictModel):
|
|
570
|
+
error: ErrorBodyV2
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
# Generated public names. Do not edit.
|
|
574
|
+
__all__ = [
|
|
575
|
+
'StrictModel',
|
|
576
|
+
'NonEmptyString',
|
|
577
|
+
'CaptureText',
|
|
578
|
+
'ProjectedText',
|
|
579
|
+
'WarningText',
|
|
580
|
+
'Sha256Hex',
|
|
581
|
+
'EngineDigest',
|
|
582
|
+
'CaptureLocator',
|
|
583
|
+
'CaptureRequirementId',
|
|
584
|
+
'project_source_text',
|
|
585
|
+
'PageLocator',
|
|
586
|
+
'TimeLocator',
|
|
587
|
+
'CaptureSource',
|
|
588
|
+
'CaptureEngine',
|
|
589
|
+
'RawCaptureSegment',
|
|
590
|
+
'RawCapture',
|
|
591
|
+
'CaptureBlock',
|
|
592
|
+
'CaptureDocument',
|
|
593
|
+
'RuntimeArtifactDescriptorV2',
|
|
594
|
+
'RuntimeRequirementV2',
|
|
595
|
+
'RuntimeRequirementsV2',
|
|
596
|
+
'StartRuntimeInstallationV2',
|
|
597
|
+
'RuntimeModelOptionV2',
|
|
598
|
+
'RuntimeModelOptionsV2',
|
|
599
|
+
'StartRuntimeModelInstallationV2',
|
|
600
|
+
'RuntimeModelInstallationV2',
|
|
601
|
+
'RuntimeModelInstallationsV2',
|
|
602
|
+
'RuntimeInstallationV2',
|
|
603
|
+
'RuntimeInstallationsV2',
|
|
604
|
+
'OpenIngestionV2',
|
|
605
|
+
'IngestionV2',
|
|
606
|
+
'StartCaptureV2',
|
|
607
|
+
'FinalizeIngestionV2',
|
|
608
|
+
'CaptureFailureV2',
|
|
609
|
+
'ReportStructuringFailureV2',
|
|
610
|
+
'CaptureOperationV2',
|
|
611
|
+
'CaptureStreamingResult',
|
|
612
|
+
'PartialCaptureV2',
|
|
613
|
+
'CaptureEventV2',
|
|
614
|
+
'RuntimeStreamingCapabilitiesV2',
|
|
615
|
+
'RuntimeReady',
|
|
616
|
+
'ErrorBodyV2',
|
|
617
|
+
'ErrorEnvelopeV2',
|
|
618
|
+
'CaptureSourceKind',
|
|
619
|
+
'StructuringMode',
|
|
620
|
+
'RuntimeInstallationStatus',
|
|
621
|
+
'RuntimeModelOptionStatus',
|
|
622
|
+
'RuntimeRequirementStatus',
|
|
623
|
+
'StreamingIngestionMode',
|
|
624
|
+
'StreamingIngestionStatus',
|
|
625
|
+
'StreamingCaptureStatus',
|
|
626
|
+
'StreamingEventType',
|
|
627
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Private generated schemas used by strict SDK validation."""
|