retab 0.0.42__py3-none-any.whl → 0.0.43__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.
Files changed (53) hide show
  1. retab/__init__.py +2 -1
  2. retab/client.py +16 -45
  3. retab/resources/consensus/client.py +1 -1
  4. retab/resources/consensus/responses.py +1 -1
  5. retab/resources/documents/client.py +94 -68
  6. retab/resources/documents/extractions.py +55 -46
  7. retab/resources/evaluations/client.py +32 -19
  8. retab/resources/evaluations/documents.py +12 -11
  9. retab/resources/evaluations/iterations.py +48 -30
  10. retab/resources/jsonlUtils.py +3 -4
  11. retab/resources/processors/automations/endpoints.py +49 -39
  12. retab/resources/processors/automations/links.py +52 -43
  13. retab/resources/processors/automations/mailboxes.py +74 -59
  14. retab/resources/processors/automations/outlook.py +104 -82
  15. retab/resources/processors/client.py +35 -30
  16. retab/resources/usage.py +2 -0
  17. retab/types/ai_models.py +1 -1
  18. retab/types/deprecated_evals.py +195 -0
  19. retab/types/evaluations/__init__.py +5 -2
  20. retab/types/evaluations/iterations.py +9 -43
  21. retab/types/evaluations/model.py +20 -22
  22. retab/types/extractions.py +1 -0
  23. retab/types/logs.py +5 -6
  24. retab/types/mime.py +1 -10
  25. retab/types/schemas/enhance.py +22 -5
  26. retab/types/schemas/evaluate.py +1 -1
  27. retab/types/schemas/object.py +26 -0
  28. retab/types/standards.py +2 -2
  29. retab/utils/__init__.py +3 -0
  30. retab/utils/ai_models.py +127 -12
  31. retab/utils/hashing.py +24 -0
  32. retab/utils/json_schema.py +1 -26
  33. retab/utils/mime.py +0 -17
  34. {retab-0.0.42.dist-info → retab-0.0.43.dist-info}/METADATA +3 -5
  35. {retab-0.0.42.dist-info → retab-0.0.43.dist-info}/RECORD +37 -51
  36. retab/_utils/__init__.py +0 -0
  37. retab/_utils/_model_cards/anthropic.yaml +0 -59
  38. retab/_utils/_model_cards/auto.yaml +0 -43
  39. retab/_utils/_model_cards/gemini.yaml +0 -117
  40. retab/_utils/_model_cards/openai.yaml +0 -301
  41. retab/_utils/_model_cards/xai.yaml +0 -28
  42. retab/_utils/ai_models.py +0 -138
  43. retab/_utils/benchmarking.py +0 -484
  44. retab/_utils/chat.py +0 -327
  45. retab/_utils/display.py +0 -440
  46. retab/_utils/json_schema.py +0 -2156
  47. retab/_utils/mime.py +0 -165
  48. retab/_utils/responses.py +0 -169
  49. retab/_utils/stream_context_managers.py +0 -52
  50. retab/_utils/usage/__init__.py +0 -0
  51. retab/_utils/usage/usage.py +0 -301
  52. {retab-0.0.42.dist-info → retab-0.0.43.dist-info}/WHEEL +0 -0
  53. {retab-0.0.42.dist-info → retab-0.0.43.dist-info}/top_level.txt +0 -0
retab/__init__.py CHANGED
@@ -1,4 +1,5 @@
1
1
  from .client import AsyncRetab, Retab
2
2
  from .types.schemas.object import Schema
3
+ from . import utils
3
4
 
4
- __all__ = ["Retab", "AsyncRetab", "Schema"]
5
+ __all__ = ["Retab", "AsyncRetab", "Schema", "utils"]
retab/client.py CHANGED
@@ -7,10 +7,9 @@ import backoff
7
7
  import backoff.types
8
8
  import httpx
9
9
  import truststore
10
- from pydantic_core import PydanticUndefined
11
10
 
12
- from .resources import consensus, documents, evals, files, finetuning, models, processors, schemas, secrets, usage, evaluations
13
- from .types.standards import PreparedRequest
11
+ from .resources import consensus, documents, files, finetuning, models, processors, schemas, secrets, usage, evaluations
12
+ from .types.standards import PreparedRequest, FieldUnset
14
13
 
15
14
 
16
15
  class MaxRetriesExceeded(Exception):
@@ -43,20 +42,15 @@ class BaseRetab:
43
42
  ValueError: If no API key is provided through arguments or environment variables
44
43
  """
45
44
 
46
- # claude_api_key (str, optional): Claude API key. Will look for CLAUDE_API_KEY env variable if not provided
47
- # xai_api_key (str, optional): XAI API key. Will look for XAI_API_KEY env variable if not provided
48
- # gemini_api_key (str, optional): Gemini API key. Will look for GEMINI_API_KEY env variable if not provided
49
-
50
45
  def __init__(
51
46
  self,
52
47
  api_key: Optional[str] = None,
53
48
  base_url: Optional[str] = None,
54
49
  timeout: float = 240.0,
55
50
  max_retries: int = 3,
56
- openai_api_key: Optional[str] = PydanticUndefined, # type: ignore[assignment]
57
- gemini_api_key: Optional[str] = PydanticUndefined, # type: ignore[assignment]
58
- # claude_api_key: Optional[str] = PydanticUndefined, # type: ignore[assignment]
59
- xai_api_key: Optional[str] = PydanticUndefined, # type: ignore[assignment]
51
+ openai_api_key: Optional[str] = FieldUnset,
52
+ gemini_api_key: Optional[str] = FieldUnset,
53
+ xai_api_key: Optional[str] = FieldUnset,
60
54
  ) -> None:
61
55
  if api_key is None:
62
56
  api_key = os.environ.get("RETAB_API_KEY")
@@ -80,30 +74,21 @@ class BaseRetab:
80
74
  "Content-Type": "application/json",
81
75
  }
82
76
 
83
- # Only check environment variables if the value is PydanticUndefined
84
- if openai_api_key is PydanticUndefined:
77
+ # Only check environment variables if the value is FieldUnset
78
+ if openai_api_key is FieldUnset:
85
79
  openai_api_key = os.environ.get("OPENAI_API_KEY")
86
80
 
87
- # if claude_api_key is PydanticUndefined:
88
- # claude_api_key = os.environ.get("CLAUDE_API_KEY")
89
-
90
- # if xai_api_key is PydanticUndefined:
91
- # xai_api_key = os.environ.get("XAI_API_KEY")
92
-
93
- if gemini_api_key is PydanticUndefined:
81
+ if gemini_api_key is FieldUnset:
94
82
  gemini_api_key = os.environ.get("GEMINI_API_KEY")
95
83
 
96
- # Only add headers if the values are actual strings (not None or PydanticUndefined)
97
- if openai_api_key and openai_api_key is not PydanticUndefined:
84
+ # Only add headers if the values are actual strings (not None or FieldUnset)
85
+ if openai_api_key and openai_api_key is not FieldUnset:
98
86
  self.headers["OpenAI-Api-Key"] = openai_api_key
99
87
 
100
- # if claude_api_key and claude_api_key is not PydanticUndefined:
101
- # self.headers["Anthropic-Api-Key"] = claude_api_key
102
-
103
- if xai_api_key and xai_api_key is not PydanticUndefined:
88
+ if xai_api_key and xai_api_key is not FieldUnset:
104
89
  self.headers["XAI-Api-Key"] = xai_api_key
105
90
 
106
- if gemini_api_key and gemini_api_key is not PydanticUndefined:
91
+ if gemini_api_key and gemini_api_key is not FieldUnset:
107
92
  self.headers["Gemini-Api-Key"] = gemini_api_key
108
93
 
109
94
  def _prepare_url(self, endpoint: str) -> str:
@@ -158,8 +143,6 @@ class Retab(BaseRetab):
158
143
  timeout (float): Request timeout in seconds. Defaults to 240.0
159
144
  max_retries (int): Maximum number of retries for failed requests. Defaults to 3
160
145
  openai_api_key (str, optional): OpenAI API key. Will look for OPENAI_API_KEY env variable if not provided
161
- claude_api_key (str, optional): Claude API key. Will look for CLAUDE_API_KEY env variable if not provided
162
- xai_api_key (str, optional): XAI API key. Will look for XAI_API_KEY env variable if not provided
163
146
  gemini_api_key (str, optional): Gemini API key. Will look for GEMINI_API_KEY env variable if not provided
164
147
 
165
148
  Attributes:
@@ -179,10 +162,8 @@ class Retab(BaseRetab):
179
162
  base_url: Optional[str] = None,
180
163
  timeout: float = 240.0,
181
164
  max_retries: int = 3,
182
- openai_api_key: Optional[str] = PydanticUndefined, # type: ignore[assignment]
183
- gemini_api_key: Optional[str] = PydanticUndefined, # type: ignore[assignment]
184
- # claude_api_key: Optional[str] = PydanticUndefined, # type: ignore[assignment]
185
- # xai_api_key: Optional[str] = PydanticUndefined, # type: ignore[assignment]
165
+ openai_api_key: Optional[str] = FieldUnset,
166
+ gemini_api_key: Optional[str] = FieldUnset,
186
167
  ) -> None:
187
168
  super().__init__(
188
169
  api_key=api_key,
@@ -191,16 +172,12 @@ class Retab(BaseRetab):
191
172
  max_retries=max_retries,
192
173
  openai_api_key=openai_api_key,
193
174
  gemini_api_key=gemini_api_key,
194
- # claude_api_key=claude_api_key,
195
- # xai_api_key=xai_api_key,
196
175
  )
197
176
 
198
177
  self.client = httpx.Client(timeout=self.timeout)
199
- self.evals = evals.Evals(client=self)
200
178
  self.evaluations = evaluations.Evaluations(client=self)
201
179
  self.files = files.Files(client=self)
202
180
  self.fine_tuning = finetuning.FineTuning(client=self)
203
- # self.prompt_optimization = prompt_optimization.PromptOptimization(client=self)
204
181
  self.documents = documents.Documents(client=self)
205
182
  self.models = models.Models(client=self)
206
183
  self.schemas = schemas.Schemas(client=self)
@@ -447,10 +424,8 @@ class AsyncRetab(BaseRetab):
447
424
  base_url: Optional[str] = None,
448
425
  timeout: float = 240.0,
449
426
  max_retries: int = 3,
450
- openai_api_key: Optional[str] = PydanticUndefined, # type: ignore[assignment]
451
- gemini_api_key: Optional[str] = PydanticUndefined, # type: ignore[assignment]
452
- # claude_api_key: Optional[str] = PydanticUndefined, # type: ignore[assignment]
453
- # xai_api_key: Optional[str] = PydanticUndefined, # type: ignore[assignment]
427
+ openai_api_key: Optional[str] = FieldUnset,
428
+ gemini_api_key: Optional[str] = FieldUnset,
454
429
  ) -> None:
455
430
  super().__init__(
456
431
  api_key=api_key,
@@ -459,17 +434,13 @@ class AsyncRetab(BaseRetab):
459
434
  max_retries=max_retries,
460
435
  openai_api_key=openai_api_key,
461
436
  gemini_api_key=gemini_api_key,
462
- # claude_api_key=claude_api_key,
463
- # xai_api_key=xai_api_key,
464
437
  )
465
438
 
466
439
  self.client = httpx.AsyncClient(timeout=self.timeout)
467
440
 
468
- self.evals = evals.AsyncEvals(client=self)
469
441
  self.evaluations = evaluations.AsyncEvaluations(client=self)
470
442
  self.files = files.AsyncFiles(client=self)
471
443
  self.fine_tuning = finetuning.AsyncFineTuning(client=self)
472
- # self.prompt_optimization = prompt_optimization.AsyncPromptOptimization(client=self)
473
444
  self.documents = documents.AsyncDocuments(client=self)
474
445
  self.models = models.AsyncModels(client=self)
475
446
  self.schemas = schemas.AsyncSchemas(client=self)
@@ -21,7 +21,7 @@ class BaseConsensusMixin:
21
21
  mode=mode,
22
22
  )
23
23
 
24
- return PreparedRequest(method="POST", url="/v1/consensus/reconcile", data=request.model_dump(), idempotency_key=idempotency_key)
24
+ return PreparedRequest(method="POST", url="/v1/consensus/reconcile", data=request.model_dump(mode="json", exclude_unset=True), idempotency_key=idempotency_key)
25
25
 
26
26
 
27
27
  class Consensus(SyncAPIResource, BaseConsensusMixin):
@@ -55,7 +55,7 @@ class BaseResponsesMixin:
55
55
  instructions=instructions,
56
56
  )
57
57
 
58
- return PreparedRequest(method="POST", url="/v1/responses", data=request.model_dump(), idempotency_key=idempotency_key)
58
+ return PreparedRequest(method="POST", url="/v1/responses", data=request.model_dump(mode="json", exclude_unset=True), idempotency_key=idempotency_key)
59
59
 
60
60
  def prepare_parse(
61
61
  self,
@@ -4,7 +4,6 @@ from typing import Any, Literal
4
4
 
5
5
  import PIL.Image
6
6
  from pydantic import HttpUrl
7
- from pydantic_core import PydanticUndefined
8
7
  from openai.types.chat.chat_completion_reasoning_effort import ChatCompletionReasoningEffort
9
8
 
10
9
  from ..._resource import AsyncAPIResource, SyncAPIResource
@@ -19,8 +18,7 @@ from ...types.mime import MIMEData
19
18
  from ...types.modalities import Modality
20
19
  from ...types.ai_models import LLMModel
21
20
  from ...types.schemas.object import Schema
22
- from ...types.standards import PreparedRequest
23
- from .extractions import AsyncExtractions, Extractions
21
+ from ...types.standards import PreparedRequest, FieldUnset
24
22
 
25
23
 
26
24
  def maybe_parse_to_pydantic(schema: Schema, response: RetabParsedChatCompletion, allow_partial: bool = False) -> RetabParsedChatCompletion:
@@ -40,40 +38,50 @@ class BaseDocumentsMixin:
40
38
  self,
41
39
  document: Path | str | IOBase | MIMEData | PIL.Image.Image | HttpUrl,
42
40
  modality: Modality = "native",
43
- image_resolution_dpi: int = PydanticUndefined, # type: ignore[assignment]
44
- browser_canvas: BrowserCanvas = PydanticUndefined, # type: ignore[assignment]
41
+ image_resolution_dpi: int = FieldUnset,
42
+ browser_canvas: BrowserCanvas = FieldUnset,
45
43
  idempotency_key: str | None = None,
46
44
  ) -> PreparedRequest:
47
45
  mime_document = prepare_mime_document(document)
48
46
 
49
- loading_request = DocumentCreateMessageRequest(
50
- document=mime_document,
51
- modality=modality,
52
- image_resolution_dpi=image_resolution_dpi,
53
- browser_canvas=browser_canvas,
47
+ loading_request_dict = {
48
+ "document": mime_document,
49
+ "modality": modality,
50
+ }
51
+ if image_resolution_dpi is not FieldUnset:
52
+ loading_request_dict["image_resolution_dpi"] = image_resolution_dpi
53
+ if browser_canvas is not FieldUnset:
54
+ loading_request_dict["browser_canvas"] = browser_canvas
55
+
56
+ loading_request = DocumentCreateMessageRequest(**loading_request_dict)
57
+ return PreparedRequest(
58
+ method="POST", url="/v1/documents/create_messages", data=loading_request.model_dump(mode="json", exclude_unset=True), idempotency_key=idempotency_key
54
59
  )
55
- return PreparedRequest(method="POST", url="/v1/documents/create_messages", data=loading_request.model_dump(), idempotency_key=idempotency_key)
56
60
 
57
61
  def _prepare_create_inputs(
58
62
  self,
59
63
  document: Path | str | IOBase | MIMEData | PIL.Image.Image | HttpUrl,
60
64
  json_schema: dict[str, Any] | Path | str,
61
65
  modality: Modality = "native",
62
- image_resolution_dpi: int = PydanticUndefined, # type: ignore[assignment],
63
- browser_canvas: BrowserCanvas = PydanticUndefined, # type: ignore[assignment],
66
+ image_resolution_dpi: int = FieldUnset,
67
+ browser_canvas: BrowserCanvas = FieldUnset,
64
68
  idempotency_key: str | None = None,
65
69
  ) -> PreparedRequest:
66
70
  mime_document = prepare_mime_document(document)
67
71
  loaded_schema = load_json_schema(json_schema)
68
72
 
69
- loading_request = DocumentCreateInputRequest(
70
- document=mime_document,
71
- modality=modality,
72
- json_schema=loaded_schema,
73
- image_resolution_dpi=image_resolution_dpi,
74
- browser_canvas=browser_canvas,
75
- )
76
- return PreparedRequest(method="POST", url="/v1/documents/create_inputs", data=loading_request.model_dump(), idempotency_key=idempotency_key)
73
+ loading_request_dict = {
74
+ "document": mime_document,
75
+ "modality": modality,
76
+ "json_schema": loaded_schema,
77
+ }
78
+ if image_resolution_dpi is not FieldUnset:
79
+ loading_request_dict["image_resolution_dpi"] = image_resolution_dpi
80
+ if browser_canvas is not FieldUnset:
81
+ loading_request_dict["browser_canvas"] = browser_canvas
82
+
83
+ loading_request = DocumentCreateInputRequest(**loading_request_dict)
84
+ return PreparedRequest(method="POST", url="/v1/documents/create_inputs", data=loading_request.model_dump(mode="json", exclude_unset=True), idempotency_key=idempotency_key)
77
85
 
78
86
  def _prepare_correct_image_orientation(self, document: Path | str | IOBase | MIMEData | PIL.Image.Image) -> PreparedRequest:
79
87
  mime_document = prepare_mime_document(document)
@@ -105,7 +113,7 @@ class BaseDocumentsMixin:
105
113
  image_resolution_dpi=image_resolution_dpi,
106
114
  browser_canvas=browser_canvas,
107
115
  )
108
- return PreparedRequest(method="POST", url="/v1/documents/parse", data=parse_request.model_dump(), idempotency_key=idempotency_key)
116
+ return PreparedRequest(method="POST", url="/v1/documents/parse", data=parse_request.model_dump(mode="json", exclude_unset=True), idempotency_key=idempotency_key)
109
117
 
110
118
 
111
119
  class Documents(SyncAPIResource, BaseDocumentsMixin):
@@ -145,8 +153,8 @@ class Documents(SyncAPIResource, BaseDocumentsMixin):
145
153
  self,
146
154
  document: Path | str | IOBase | MIMEData | PIL.Image.Image | HttpUrl,
147
155
  modality: Modality = "native",
148
- image_resolution_dpi: int = PydanticUndefined, # type: ignore[assignment]
149
- browser_canvas: BrowserCanvas = PydanticUndefined, # type: ignore[assignment]
156
+ image_resolution_dpi: int = FieldUnset,
157
+ browser_canvas: BrowserCanvas = FieldUnset,
150
158
  idempotency_key: str | None = None,
151
159
  ) -> DocumentMessage:
152
160
  """
@@ -175,8 +183,8 @@ class Documents(SyncAPIResource, BaseDocumentsMixin):
175
183
  document: Path | str | IOBase | MIMEData | PIL.Image.Image | HttpUrl,
176
184
  json_schema: dict[str, Any] | Path | str,
177
185
  modality: Modality = "native",
178
- image_resolution_dpi: int = PydanticUndefined, # type: ignore[assignment]
179
- browser_canvas: BrowserCanvas = PydanticUndefined, # type: ignore[assignment]
186
+ image_resolution_dpi: int = FieldUnset,
187
+ browser_canvas: BrowserCanvas = FieldUnset,
180
188
  idempotency_key: str | None = None,
181
189
  ) -> DocumentMessage:
182
190
  """
@@ -212,12 +220,12 @@ class Documents(SyncAPIResource, BaseDocumentsMixin):
212
220
  model: str,
213
221
  document: Path | str | IOBase | HttpUrl | None = None,
214
222
  documents: list[Path | str | IOBase | HttpUrl] | None = None,
215
- image_resolution_dpi: int = PydanticUndefined, # type: ignore[assignment]
216
- browser_canvas: BrowserCanvas = PydanticUndefined, # type: ignore[assignment]
217
- temperature: float = PydanticUndefined, # type: ignore[assignment]
218
- modality: Modality = PydanticUndefined, # type: ignore[assignment]
219
- reasoning_effort: ChatCompletionReasoningEffort = PydanticUndefined, # type: ignore[assignment]
220
- n_consensus: int = PydanticUndefined, # type: ignore[assignment]
223
+ image_resolution_dpi: int = FieldUnset,
224
+ browser_canvas: BrowserCanvas = FieldUnset,
225
+ temperature: float = FieldUnset,
226
+ modality: Modality = FieldUnset,
227
+ reasoning_effort: ChatCompletionReasoningEffort = FieldUnset,
228
+ n_consensus: int = FieldUnset,
221
229
  idempotency_key: str | None = None,
222
230
  store: bool = False,
223
231
  ) -> RetabParsedChatCompletion:
@@ -264,20 +272,29 @@ class Documents(SyncAPIResource, BaseDocumentsMixin):
264
272
  else:
265
273
  raise ValueError("Must provide either 'document' or 'documents' parameter.")
266
274
 
275
+ # Build request dictionary with only provided fields
276
+ request_dict = {
277
+ "json_schema": json_schema,
278
+ "documents": processed_documents,
279
+ "model": model,
280
+ "stream": False,
281
+ "store": store,
282
+ }
283
+ if temperature is not FieldUnset:
284
+ request_dict["temperature"] = temperature
285
+ if modality is not FieldUnset:
286
+ request_dict["modality"] = modality
287
+ if reasoning_effort is not FieldUnset:
288
+ request_dict["reasoning_effort"] = reasoning_effort
289
+ if n_consensus is not FieldUnset:
290
+ request_dict["n_consensus"] = n_consensus
291
+ if image_resolution_dpi is not FieldUnset:
292
+ request_dict["image_resolution_dpi"] = image_resolution_dpi
293
+ if browser_canvas is not FieldUnset:
294
+ request_dict["browser_canvas"] = browser_canvas
295
+
267
296
  # Validate DocumentAPIRequest data (raises exception if invalid)
268
- request = DocumentExtractRequest(
269
- json_schema=json_schema,
270
- documents=processed_documents,
271
- model=model,
272
- temperature=temperature,
273
- stream=False,
274
- modality=modality,
275
- store=store,
276
- reasoning_effort=reasoning_effort,
277
- n_consensus=n_consensus,
278
- image_resolution_dpi=image_resolution_dpi,
279
- browser_canvas=browser_canvas,
280
- )
297
+ request = DocumentExtractRequest(**request_dict)
281
298
 
282
299
  prepared_request = PreparedRequest(
283
300
  method="POST", url="/v1/documents/extract", data=request.model_dump(mode="json", exclude_unset=True, exclude_defaults=True), idempotency_key=idempotency_key
@@ -340,8 +357,8 @@ class AsyncDocuments(AsyncAPIResource, BaseDocumentsMixin):
340
357
  self,
341
358
  document: Path | str | IOBase | MIMEData | PIL.Image.Image,
342
359
  modality: Modality = "native",
343
- image_resolution_dpi: int = PydanticUndefined, # type: ignore[assignment]
344
- browser_canvas: BrowserCanvas = PydanticUndefined, # type: ignore[assignment]
360
+ image_resolution_dpi: int = FieldUnset,
361
+ browser_canvas: BrowserCanvas = FieldUnset,
345
362
  idempotency_key: str | None = None,
346
363
  ) -> DocumentMessage:
347
364
  """
@@ -372,8 +389,8 @@ class AsyncDocuments(AsyncAPIResource, BaseDocumentsMixin):
372
389
  document: Path | str | IOBase | MIMEData | PIL.Image.Image | HttpUrl,
373
390
  json_schema: dict[str, Any] | Path | str,
374
391
  modality: Modality = "native",
375
- image_resolution_dpi: int = PydanticUndefined, # type: ignore[assignment]
376
- browser_canvas: BrowserCanvas = PydanticUndefined, # type: ignore[assignment]
392
+ image_resolution_dpi: int = FieldUnset,
393
+ browser_canvas: BrowserCanvas = FieldUnset,
377
394
  idempotency_key: str | None = None,
378
395
  ) -> DocumentMessage:
379
396
  """
@@ -434,12 +451,12 @@ class AsyncDocuments(AsyncAPIResource, BaseDocumentsMixin):
434
451
  model: str,
435
452
  document: Path | str | IOBase | HttpUrl | None = None,
436
453
  documents: list[Path | str | IOBase | HttpUrl] | None = None,
437
- image_resolution_dpi: int = PydanticUndefined, # type: ignore[assignment]
438
- browser_canvas: BrowserCanvas = PydanticUndefined, # type: ignore[assignment]
439
- temperature: float = PydanticUndefined, # type: ignore[assignment]
440
- modality: Modality = PydanticUndefined, # type: ignore[assignment]
441
- reasoning_effort: ChatCompletionReasoningEffort = PydanticUndefined, # type: ignore[assignment]
442
- n_consensus: int = PydanticUndefined, # type: ignore[assignment]
454
+ image_resolution_dpi: int = FieldUnset,
455
+ browser_canvas: BrowserCanvas = FieldUnset,
456
+ temperature: float = FieldUnset,
457
+ modality: Modality = FieldUnset,
458
+ reasoning_effort: ChatCompletionReasoningEffort = FieldUnset,
459
+ n_consensus: int = FieldUnset,
443
460
  idempotency_key: str | None = None,
444
461
  store: bool = False,
445
462
  ) -> RetabParsedChatCompletion:
@@ -486,20 +503,29 @@ class AsyncDocuments(AsyncAPIResource, BaseDocumentsMixin):
486
503
  else:
487
504
  raise ValueError("Must provide either 'document' or 'documents' parameter.")
488
505
 
506
+ # Build request dictionary with only provided fields
507
+ request_dict = {
508
+ "json_schema": json_schema,
509
+ "documents": processed_documents,
510
+ "model": model,
511
+ "stream": False,
512
+ "store": store,
513
+ }
514
+ if temperature is not FieldUnset:
515
+ request_dict["temperature"] = temperature
516
+ if modality is not FieldUnset:
517
+ request_dict["modality"] = modality
518
+ if reasoning_effort is not FieldUnset:
519
+ request_dict["reasoning_effort"] = reasoning_effort
520
+ if n_consensus is not FieldUnset:
521
+ request_dict["n_consensus"] = n_consensus
522
+ if image_resolution_dpi is not FieldUnset:
523
+ request_dict["image_resolution_dpi"] = image_resolution_dpi
524
+ if browser_canvas is not FieldUnset:
525
+ request_dict["browser_canvas"] = browser_canvas
526
+
489
527
  # Validate DocumentAPIRequest data (raises exception if invalid)
490
- request = DocumentExtractRequest(
491
- json_schema=json_schema,
492
- documents=processed_documents,
493
- model=model,
494
- temperature=temperature,
495
- stream=False,
496
- modality=modality,
497
- store=store,
498
- reasoning_effort=reasoning_effort,
499
- n_consensus=n_consensus,
500
- image_resolution_dpi=image_resolution_dpi,
501
- browser_canvas=browser_canvas,
502
- )
528
+ request = DocumentExtractRequest(**request_dict)
503
529
 
504
530
  prepared_request = PreparedRequest(
505
531
  method="POST", url="/v1/documents/extract", data=request.model_dump(mode="json", exclude_unset=True, exclude_defaults=True), idempotency_key=idempotency_key
@@ -10,7 +10,6 @@ from openai.types.chat.chat_completion_reasoning_effort import ChatCompletionRea
10
10
  from openai.types.chat.parsed_chat_completion import ParsedChatCompletionMessage
11
11
  from openai.types.responses.response import Response
12
12
  from openai.types.responses.response_input_param import ResponseInputItemParam
13
- from pydantic_core import PydanticUndefined
14
13
  from pydantic import HttpUrl
15
14
 
16
15
  from ..._resource import AsyncAPIResource, SyncAPIResource
@@ -23,7 +22,7 @@ from ...types.documents.extractions import DocumentExtractRequest, LogExtraction
23
22
  from ...types.browser_canvas import BrowserCanvas
24
23
  from ...types.modalities import Modality
25
24
  from ...types.schemas.object import Schema
26
- from ...types.standards import PreparedRequest
25
+ from ...types.standards import PreparedRequest, FieldUnset
27
26
 
28
27
 
29
28
  def maybe_parse_to_pydantic(schema: Schema, response: RetabParsedChatCompletion, allow_partial: bool = False) -> RetabParsedChatCompletion:
@@ -44,14 +43,14 @@ class BaseExtractionsMixin:
44
43
  json_schema: dict[str, Any] | Path | str,
45
44
  document: Path | str | IOBase | HttpUrl | None = None,
46
45
  documents: list[Path | str | IOBase | HttpUrl] | None = None,
47
- image_resolution_dpi: int = PydanticUndefined, # type: ignore[assignment]
48
- browser_canvas: BrowserCanvas = PydanticUndefined, # type: ignore[assignment]
49
- model: str = PydanticUndefined, # type: ignore[assignment]
50
- temperature: float = PydanticUndefined, # type: ignore[assignment]
51
- modality: Modality = PydanticUndefined, # type: ignore[assignment]
52
- reasoning_effort: ChatCompletionReasoningEffort = PydanticUndefined, # type: ignore[assignment]
46
+ image_resolution_dpi: int = FieldUnset,
47
+ browser_canvas: BrowserCanvas = FieldUnset,
48
+ model: str = FieldUnset,
49
+ temperature: float = FieldUnset,
50
+ modality: Modality = FieldUnset,
51
+ reasoning_effort: ChatCompletionReasoningEffort = FieldUnset,
53
52
  stream: bool = False,
54
- n_consensus: int = PydanticUndefined, # type: ignore[assignment]
53
+ n_consensus: int = FieldUnset,
55
54
  store: bool = False,
56
55
  idempotency_key: str | None = None,
57
56
  ) -> PreparedRequest:
@@ -71,20 +70,30 @@ class BaseExtractionsMixin:
71
70
  else:
72
71
  raise ValueError("Must provide either 'document' or 'documents' parameter.")
73
72
 
73
+ # Build request dictionary with only provided fields
74
+ request_dict = {
75
+ 'json_schema': json_schema,
76
+ 'documents': processed_documents,
77
+ 'stream': stream,
78
+ 'store': store,
79
+ }
80
+ if model is not FieldUnset:
81
+ request_dict['model'] = model
82
+ if temperature is not FieldUnset:
83
+ request_dict['temperature'] = temperature
84
+ if modality is not FieldUnset:
85
+ request_dict['modality'] = modality
86
+ if reasoning_effort is not FieldUnset:
87
+ request_dict['reasoning_effort'] = reasoning_effort
88
+ if n_consensus is not FieldUnset:
89
+ request_dict['n_consensus'] = n_consensus
90
+ if image_resolution_dpi is not FieldUnset:
91
+ request_dict['image_resolution_dpi'] = image_resolution_dpi
92
+ if browser_canvas is not FieldUnset:
93
+ request_dict['browser_canvas'] = browser_canvas
94
+
74
95
  # Validate DocumentAPIRequest data (raises exception if invalid)
75
- request = DocumentExtractRequest(
76
- json_schema=json_schema,
77
- documents=processed_documents,
78
- model=model,
79
- temperature=temperature,
80
- stream=stream,
81
- modality=modality,
82
- store=store,
83
- reasoning_effort=reasoning_effort,
84
- n_consensus=n_consensus,
85
- image_resolution_dpi=image_resolution_dpi,
86
- browser_canvas=browser_canvas,
87
- )
96
+ request = DocumentExtractRequest(**request_dict)
88
97
 
89
98
  return PreparedRequest(
90
99
  method="POST", url="/v1/documents/extractions", data=request.model_dump(mode="json", exclude_unset=True, exclude_defaults=True), idempotency_key=idempotency_key
@@ -144,12 +153,12 @@ class Extractions(SyncAPIResource, BaseExtractionsMixin):
144
153
  model: str,
145
154
  document: Path | str | IOBase | HttpUrl | None = None,
146
155
  documents: list[Path | str | IOBase | HttpUrl] | None = None,
147
- image_resolution_dpi: int = PydanticUndefined, # type: ignore[assignment]
148
- browser_canvas: BrowserCanvas = PydanticUndefined, # type: ignore[assignment]
149
- temperature: float = PydanticUndefined, # type: ignore[assignment]
150
- modality: Modality = PydanticUndefined, # type: ignore[assignment]
151
- reasoning_effort: ChatCompletionReasoningEffort = PydanticUndefined, # type: ignore[assignment]
152
- n_consensus: int = PydanticUndefined, # type: ignore[assignment]
156
+ image_resolution_dpi: int = FieldUnset,
157
+ browser_canvas: BrowserCanvas = FieldUnset,
158
+ temperature: float = FieldUnset,
159
+ modality: Modality = FieldUnset,
160
+ reasoning_effort: ChatCompletionReasoningEffort = FieldUnset,
161
+ n_consensus: int = FieldUnset,
153
162
  idempotency_key: str | None = None,
154
163
  store: bool = False,
155
164
  ) -> RetabParsedChatCompletion:
@@ -204,12 +213,12 @@ class Extractions(SyncAPIResource, BaseExtractionsMixin):
204
213
  model: str,
205
214
  document: Path | str | IOBase | HttpUrl | None = None,
206
215
  documents: list[Path | str | IOBase | HttpUrl] | None = None,
207
- image_resolution_dpi: int = PydanticUndefined, # type: ignore[assignment]
208
- browser_canvas: BrowserCanvas = PydanticUndefined, # type: ignore[assignment]
209
- temperature: float = PydanticUndefined, # type: ignore[assignment]
210
- modality: Modality = PydanticUndefined, # type: ignore[assignment]
211
- reasoning_effort: ChatCompletionReasoningEffort = PydanticUndefined, # type: ignore[assignment]
212
- n_consensus: int = PydanticUndefined, # type: ignore[assignment]
216
+ image_resolution_dpi: int = FieldUnset,
217
+ browser_canvas: BrowserCanvas = FieldUnset,
218
+ temperature: float = FieldUnset,
219
+ modality: Modality = FieldUnset,
220
+ reasoning_effort: ChatCompletionReasoningEffort = FieldUnset,
221
+ n_consensus: int = FieldUnset,
213
222
  idempotency_key: str | None = None,
214
223
  store: bool = False,
215
224
  ) -> Generator[RetabParsedChatCompletion, None, None]:
@@ -345,12 +354,12 @@ class AsyncExtractions(AsyncAPIResource, BaseExtractionsMixin):
345
354
  model: str,
346
355
  document: Path | str | IOBase | HttpUrl | None = None,
347
356
  documents: list[Path | str | IOBase | HttpUrl] | None = None,
348
- image_resolution_dpi: int = PydanticUndefined, # type: ignore[assignment]
349
- browser_canvas: BrowserCanvas = PydanticUndefined, # type: ignore[assignment]
350
- temperature: float = PydanticUndefined, # type: ignore[assignment]
351
- modality: Modality = PydanticUndefined, # type: ignore[assignment]
352
- reasoning_effort: ChatCompletionReasoningEffort = PydanticUndefined, # type: ignore[assignment]
353
- n_consensus: int = PydanticUndefined, # type: ignore[assignment]
357
+ image_resolution_dpi: int = FieldUnset,
358
+ browser_canvas: BrowserCanvas = FieldUnset,
359
+ temperature: float = FieldUnset,
360
+ modality: Modality = FieldUnset,
361
+ reasoning_effort: ChatCompletionReasoningEffort = FieldUnset,
362
+ n_consensus: int = FieldUnset,
354
363
  idempotency_key: str | None = None,
355
364
  store: bool = False,
356
365
  ) -> RetabParsedChatCompletion:
@@ -401,12 +410,12 @@ class AsyncExtractions(AsyncAPIResource, BaseExtractionsMixin):
401
410
  model: str,
402
411
  document: Path | str | IOBase | HttpUrl | None = None,
403
412
  documents: list[Path | str | IOBase | HttpUrl] | None = None,
404
- image_resolution_dpi: int = PydanticUndefined, # type: ignore[assignment]
405
- browser_canvas: BrowserCanvas = PydanticUndefined, # type: ignore[assignment]
406
- temperature: float = PydanticUndefined, # type: ignore[assignment]
407
- modality: Modality = PydanticUndefined, # type: ignore[assignment]
408
- reasoning_effort: ChatCompletionReasoningEffort = PydanticUndefined, # type: ignore[assignment]
409
- n_consensus: int = PydanticUndefined, # type: ignore[assignment]
413
+ image_resolution_dpi: int = FieldUnset,
414
+ browser_canvas: BrowserCanvas = FieldUnset,
415
+ temperature: float = FieldUnset,
416
+ modality: Modality = FieldUnset,
417
+ reasoning_effort: ChatCompletionReasoningEffort = FieldUnset,
418
+ n_consensus: int = FieldUnset,
410
419
  idempotency_key: str | None = None,
411
420
  store: bool = False,
412
421
  ) -> AsyncGenerator[RetabParsedChatCompletion, None]: