retab 0.0.36__py3-none-any.whl → 0.0.37__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 (119) hide show
  1. {uiform → retab}/_utils/ai_models.py +2 -2
  2. {uiform → retab}/_utils/benchmarking.py +15 -16
  3. {uiform → retab}/_utils/chat.py +9 -14
  4. {uiform → retab}/_utils/display.py +0 -3
  5. {uiform → retab}/_utils/json_schema.py +9 -14
  6. {uiform → retab}/_utils/mime.py +11 -14
  7. {uiform → retab}/_utils/responses.py +9 -3
  8. {uiform → retab}/_utils/stream_context_managers.py +1 -1
  9. {uiform → retab}/_utils/usage/usage.py +28 -28
  10. {uiform → retab}/client.py +32 -31
  11. {uiform → retab}/resources/consensus/client.py +17 -36
  12. {uiform → retab}/resources/consensus/completions.py +24 -47
  13. {uiform → retab}/resources/consensus/completions_stream.py +26 -38
  14. {uiform → retab}/resources/consensus/responses.py +31 -80
  15. {uiform → retab}/resources/consensus/responses_stream.py +31 -79
  16. {uiform → retab}/resources/documents/client.py +59 -45
  17. {uiform → retab}/resources/documents/extractions.py +181 -90
  18. {uiform → retab}/resources/evals.py +56 -43
  19. retab/resources/evaluations/__init__.py +3 -0
  20. retab/resources/evaluations/client.py +301 -0
  21. retab/resources/evaluations/documents.py +233 -0
  22. retab/resources/evaluations/iterations.py +452 -0
  23. {uiform → retab}/resources/files.py +2 -2
  24. {uiform → retab}/resources/jsonlUtils.py +220 -216
  25. retab/resources/models.py +73 -0
  26. retab/resources/processors/automations/client.py +244 -0
  27. {uiform → retab}/resources/processors/automations/endpoints.py +77 -118
  28. retab/resources/processors/automations/links.py +294 -0
  29. {uiform → retab}/resources/processors/automations/logs.py +30 -19
  30. {uiform → retab}/resources/processors/automations/mailboxes.py +136 -174
  31. retab/resources/processors/automations/outlook.py +337 -0
  32. {uiform → retab}/resources/processors/automations/tests.py +22 -25
  33. {uiform → retab}/resources/processors/client.py +179 -164
  34. {uiform → retab}/resources/schemas.py +78 -66
  35. {uiform → retab}/resources/secrets/external_api_keys.py +1 -5
  36. retab/resources/secrets/webhook.py +64 -0
  37. {uiform → retab}/resources/usage.py +39 -2
  38. {uiform → retab}/types/ai_models.py +13 -13
  39. {uiform → retab}/types/automations/cron.py +19 -12
  40. {uiform → retab}/types/automations/endpoints.py +7 -4
  41. {uiform → retab}/types/automations/links.py +7 -3
  42. {uiform → retab}/types/automations/mailboxes.py +9 -9
  43. {uiform → retab}/types/automations/outlook.py +15 -11
  44. retab/types/browser_canvas.py +3 -0
  45. {uiform → retab}/types/chat.py +2 -2
  46. {uiform → retab}/types/completions.py +9 -12
  47. retab/types/consensus.py +19 -0
  48. {uiform → retab}/types/db/annotations.py +3 -3
  49. {uiform → retab}/types/db/files.py +8 -6
  50. {uiform → retab}/types/documents/create_messages.py +18 -20
  51. {uiform → retab}/types/documents/extractions.py +69 -24
  52. {uiform → retab}/types/evals.py +5 -5
  53. retab/types/evaluations/__init__.py +31 -0
  54. retab/types/evaluations/documents.py +30 -0
  55. retab/types/evaluations/iterations.py +112 -0
  56. retab/types/evaluations/model.py +73 -0
  57. retab/types/events.py +79 -0
  58. {uiform → retab}/types/extractions.py +33 -10
  59. retab/types/inference_settings.py +15 -0
  60. retab/types/jobs/base.py +54 -0
  61. retab/types/jobs/batch_annotation.py +12 -0
  62. {uiform → retab}/types/jobs/evaluation.py +1 -2
  63. {uiform → retab}/types/logs.py +37 -34
  64. retab/types/metrics.py +32 -0
  65. {uiform → retab}/types/mime.py +22 -20
  66. {uiform → retab}/types/modalities.py +10 -10
  67. retab/types/predictions.py +19 -0
  68. {uiform → retab}/types/schemas/enhance.py +4 -2
  69. {uiform → retab}/types/schemas/evaluate.py +7 -4
  70. {uiform → retab}/types/schemas/generate.py +6 -3
  71. {uiform → retab}/types/schemas/layout.py +1 -1
  72. {uiform → retab}/types/schemas/object.py +13 -14
  73. {uiform → retab}/types/schemas/templates.py +1 -3
  74. {uiform → retab}/types/secrets/external_api_keys.py +0 -1
  75. {uiform → retab}/types/standards.py +18 -1
  76. {retab-0.0.36.dist-info → retab-0.0.37.dist-info}/METADATA +7 -6
  77. retab-0.0.37.dist-info/RECORD +107 -0
  78. retab-0.0.37.dist-info/top_level.txt +1 -0
  79. retab-0.0.36.dist-info/RECORD +0 -96
  80. retab-0.0.36.dist-info/top_level.txt +0 -1
  81. uiform/_utils/benchmarking copy.py +0 -588
  82. uiform/resources/models.py +0 -45
  83. uiform/resources/processors/automations/client.py +0 -78
  84. uiform/resources/processors/automations/links.py +0 -356
  85. uiform/resources/processors/automations/outlook.py +0 -444
  86. uiform/resources/secrets/webhook.py +0 -62
  87. uiform/types/consensus.py +0 -10
  88. uiform/types/events.py +0 -76
  89. uiform/types/jobs/base.py +0 -150
  90. uiform/types/jobs/batch_annotation.py +0 -22
  91. {uiform → retab}/__init__.py +0 -0
  92. {uiform → retab}/_resource.py +0 -0
  93. {uiform → retab}/_utils/__init__.py +0 -0
  94. {uiform → retab}/_utils/usage/__init__.py +0 -0
  95. {uiform → retab}/py.typed +0 -0
  96. {uiform → retab}/resources/__init__.py +0 -0
  97. {uiform → retab}/resources/consensus/__init__.py +0 -0
  98. {uiform → retab}/resources/documents/__init__.py +0 -0
  99. {uiform → retab}/resources/finetuning.py +0 -0
  100. {uiform → retab}/resources/openai_example.py +0 -0
  101. {uiform → retab}/resources/processors/__init__.py +0 -0
  102. {uiform → retab}/resources/processors/automations/__init__.py +0 -0
  103. {uiform → retab}/resources/prompt_optimization.py +0 -0
  104. {uiform → retab}/resources/secrets/__init__.py +0 -0
  105. {uiform → retab}/resources/secrets/client.py +0 -0
  106. {uiform → retab}/types/__init__.py +0 -0
  107. {uiform → retab}/types/automations/__init__.py +0 -0
  108. {uiform → retab}/types/automations/webhooks.py +0 -0
  109. {uiform → retab}/types/db/__init__.py +0 -0
  110. {uiform → retab}/types/documents/__init__.py +0 -0
  111. {uiform → retab}/types/documents/correct_orientation.py +0 -0
  112. {uiform → retab}/types/jobs/__init__.py +0 -0
  113. {uiform → retab}/types/jobs/finetune.py +0 -0
  114. {uiform → retab}/types/jobs/prompt_optimization.py +0 -0
  115. {uiform → retab}/types/jobs/webcrawl.py +0 -0
  116. {uiform → retab}/types/pagination.py +0 -0
  117. {uiform → retab}/types/schemas/__init__.py +0 -0
  118. {uiform → retab}/types/secrets/__init__.py +0 -0
  119. {retab-0.0.36.dist-info → retab-0.0.37.dist-info}/WHEEL +0 -0
@@ -1,16 +1,16 @@
1
1
  import json
2
2
  import os
3
3
  from types import TracebackType
4
- from typing import Any, AsyncIterator, BinaryIO, Iterator, List, Optional
4
+ from typing import Any, AsyncIterator, Iterator, Optional
5
5
 
6
6
  import backoff
7
7
  import backoff.types
8
8
  import httpx
9
+ import truststore
9
10
  from pydantic_core import PydanticUndefined
10
11
 
11
- from .resources import processors, consensus, documents, evals, files, finetuning, models, schemas, secrets, usage
12
+ from .resources import consensus, documents, evals, files, finetuning, models, processors, schemas, secrets, usage, evaluations
12
13
  from .types.standards import PreparedRequest
13
- import truststore
14
14
 
15
15
 
16
16
  class MaxRetriesExceeded(Exception):
@@ -70,7 +70,6 @@ class BaseUiForm:
70
70
  if base_url is None:
71
71
  base_url = os.environ.get("UIFORM_API_BASE_URL", "https://api.uiform.com")
72
72
 
73
-
74
73
  truststore.inject_into_ssl()
75
74
  self.api_key = api_key
76
75
  self.base_url = base_url.rstrip("/")
@@ -84,26 +83,26 @@ class BaseUiForm:
84
83
  # Only check environment variables if the value is PydanticUndefined
85
84
  if openai_api_key is PydanticUndefined:
86
85
  openai_api_key = os.environ.get("OPENAI_API_KEY")
87
-
86
+
88
87
  # if claude_api_key is PydanticUndefined:
89
88
  # claude_api_key = os.environ.get("CLAUDE_API_KEY")
90
-
89
+
91
90
  # if xai_api_key is PydanticUndefined:
92
91
  # xai_api_key = os.environ.get("XAI_API_KEY")
93
-
92
+
94
93
  if gemini_api_key is PydanticUndefined:
95
94
  gemini_api_key = os.environ.get("GEMINI_API_KEY")
96
95
 
97
96
  # Only add headers if the values are actual strings (not None or PydanticUndefined)
98
97
  if openai_api_key and openai_api_key is not PydanticUndefined:
99
98
  self.headers["OpenAI-Api-Key"] = openai_api_key
100
-
99
+
101
100
  # if claude_api_key and claude_api_key is not PydanticUndefined:
102
101
  # self.headers["Anthropic-Api-Key"] = claude_api_key
103
-
102
+
104
103
  if xai_api_key and xai_api_key is not PydanticUndefined:
105
104
  self.headers["XAI-Api-Key"] = xai_api_key
106
-
105
+
107
106
  if gemini_api_key and gemini_api_key is not PydanticUndefined:
108
107
  self.headers["Gemini-Api-Key"] = gemini_api_key
109
108
 
@@ -126,12 +125,12 @@ class BaseUiForm:
126
125
 
127
126
  def _parse_response(self, response: httpx.Response) -> Any:
128
127
  """Parse response based on content-type.
129
-
128
+
130
129
  Returns:
131
130
  Any: Parsed JSON object for JSON responses, raw text string for text responses
132
131
  """
133
132
  content_type = response.headers.get("content-type", "")
134
-
133
+
135
134
  # Check if it's a JSON response
136
135
  if "application/json" in content_type or "application/stream+json" in content_type:
137
136
  return response.json()
@@ -198,6 +197,7 @@ class UiForm(BaseUiForm):
198
197
 
199
198
  self.client = httpx.Client(timeout=self.timeout)
200
199
  self.evals = evals.Evals(client=self)
200
+ self.evaluations = evaluations.Evaluations(client=self)
201
201
  self.files = files.Files(client=self)
202
202
  self.fine_tuning = finetuning.FineTuning(client=self)
203
203
  # self.prompt_optimization = prompt_optimization.PromptOptimization(client=self)
@@ -247,7 +247,7 @@ class UiForm(BaseUiForm):
247
247
  "params": params,
248
248
  "headers": self._get_headers(idempotency_key),
249
249
  }
250
-
250
+
251
251
  # Handle different content types
252
252
  if files or form_data:
253
253
  # For multipart/form-data requests
@@ -262,7 +262,7 @@ class UiForm(BaseUiForm):
262
262
  elif data:
263
263
  # For JSON requests
264
264
  request_kwargs["json"] = data
265
-
265
+
266
266
  response = self.client.request(**request_kwargs)
267
267
  self._validate_response(response)
268
268
  return self._parse_response(response)
@@ -314,7 +314,7 @@ class UiForm(BaseUiForm):
314
314
  "params": params,
315
315
  "headers": self._get_headers(idempotency_key),
316
316
  }
317
-
317
+
318
318
  # Handle different content types
319
319
  if files or form_data:
320
320
  # For multipart/form-data requests
@@ -329,10 +329,10 @@ class UiForm(BaseUiForm):
329
329
  elif data:
330
330
  # For JSON requests
331
331
  stream_kwargs["json"] = data
332
-
332
+
333
333
  with self.client.stream(**stream_kwargs) as response_ctx_manager:
334
334
  self._validate_response(response_ctx_manager)
335
-
335
+
336
336
  content_type = response_ctx_manager.headers.get("content-type", "")
337
337
  is_json_stream = "application/json" in content_type or "application/stream+json" in content_type
338
338
  is_text_stream = "text/plain" in content_type or ("text/" in content_type and not is_json_stream)
@@ -340,7 +340,7 @@ class UiForm(BaseUiForm):
340
340
  for chunk in response_ctx_manager.iter_lines():
341
341
  if not chunk:
342
342
  continue
343
-
343
+
344
344
  if is_json_stream:
345
345
  try:
346
346
  yield json.loads(chunk)
@@ -375,7 +375,7 @@ class UiForm(BaseUiForm):
375
375
  form_data=request.form_data,
376
376
  files=request.files,
377
377
  idempotency_key=request.idempotency_key,
378
- raise_for_status=request.raise_for_status
378
+ raise_for_status=request.raise_for_status,
379
379
  )
380
380
 
381
381
  def _prepared_request_stream(self, request: PreparedRequest) -> Iterator[Any]:
@@ -387,7 +387,7 @@ class UiForm(BaseUiForm):
387
387
  form_data=request.form_data,
388
388
  files=request.files,
389
389
  idempotency_key=request.idempotency_key,
390
- raise_for_status=request.raise_for_status
390
+ raise_for_status=request.raise_for_status,
391
391
  ):
392
392
  yield item
393
393
 
@@ -466,6 +466,7 @@ class AsyncUiForm(BaseUiForm):
466
466
  self.client = httpx.AsyncClient(timeout=self.timeout)
467
467
 
468
468
  self.evals = evals.AsyncEvals(client=self)
469
+ self.evaluations = evaluations.AsyncEvaluations(client=self)
469
470
  self.files = files.AsyncFiles(client=self)
470
471
  self.fine_tuning = finetuning.AsyncFineTuning(client=self)
471
472
  # self.prompt_optimization = prompt_optimization.AsyncPromptOptimization(client=self)
@@ -479,12 +480,12 @@ class AsyncUiForm(BaseUiForm):
479
480
 
480
481
  def _parse_response(self, response: httpx.Response) -> Any:
481
482
  """Parse response based on content-type.
482
-
483
+
483
484
  Returns:
484
485
  Any: Parsed JSON object for JSON responses, raw text string for text responses
485
486
  """
486
487
  content_type = response.headers.get("content-type", "")
487
-
488
+
488
489
  # Check if it's a JSON response
489
490
  if "application/json" in content_type or "application/stream+json" in content_type:
490
491
  return response.json()
@@ -536,7 +537,7 @@ class AsyncUiForm(BaseUiForm):
536
537
  "params": params,
537
538
  "headers": self._get_headers(idempotency_key),
538
539
  }
539
-
540
+
540
541
  # Handle different content types
541
542
  if files or form_data:
542
543
  # For multipart/form-data requests
@@ -551,7 +552,7 @@ class AsyncUiForm(BaseUiForm):
551
552
  elif data:
552
553
  # For JSON requests
553
554
  request_kwargs["json"] = data
554
-
555
+
555
556
  response = await self.client.request(**request_kwargs)
556
557
  self._validate_response(response)
557
558
  return self._parse_response(response)
@@ -602,7 +603,7 @@ class AsyncUiForm(BaseUiForm):
602
603
  "params": params,
603
604
  "headers": self._get_headers(idempotency_key),
604
605
  }
605
-
606
+
606
607
  # Handle different content types
607
608
  if files or form_data:
608
609
  # For multipart/form-data requests
@@ -617,18 +618,18 @@ class AsyncUiForm(BaseUiForm):
617
618
  elif data:
618
619
  # For JSON requests
619
620
  stream_kwargs["json"] = data
620
-
621
+
621
622
  async with self.client.stream(**stream_kwargs) as response_ctx_manager:
622
623
  self._validate_response(response_ctx_manager)
623
-
624
+
624
625
  content_type = response_ctx_manager.headers.get("content-type", "")
625
626
  is_json_stream = "application/json" in content_type or "application/stream+json" in content_type
626
627
  is_text_stream = "text/plain" in content_type or ("text/" in content_type and not is_json_stream)
627
-
628
+
628
629
  async for chunk in response_ctx_manager.aiter_lines():
629
630
  if not chunk:
630
631
  continue
631
-
632
+
632
633
  if is_json_stream:
633
634
  try:
634
635
  yield json.loads(chunk)
@@ -662,7 +663,7 @@ class AsyncUiForm(BaseUiForm):
662
663
  form_data=request.form_data,
663
664
  files=request.files,
664
665
  idempotency_key=request.idempotency_key,
665
- raise_for_status=request.raise_for_status
666
+ raise_for_status=request.raise_for_status,
666
667
  )
667
668
 
668
669
  async def _prepared_request_stream(self, request: PreparedRequest) -> AsyncIterator[Any]:
@@ -674,7 +675,7 @@ class AsyncUiForm(BaseUiForm):
674
675
  form_data=request.form_data,
675
676
  files=request.files,
676
677
  idempotency_key=request.idempotency_key,
677
- raise_for_status=request.raise_for_status
678
+ raise_for_status=request.raise_for_status,
678
679
  ):
679
680
  yield item
680
681
 
@@ -1,15 +1,13 @@
1
1
  from typing import Any, Dict, List, Literal, Optional
2
2
 
3
- from pydantic import BaseModel, Field
4
-
5
3
  from ..._resource import AsyncAPIResource, SyncAPIResource
4
+ from ...types.consensus import ReconciliationResponse, ReconciliationRequest
6
5
  from ...types.standards import PreparedRequest
7
6
  from .completions import AsyncCompletions, Completions
8
7
  from .responses import AsyncResponses, Responses
9
- from ...types.consensus import ReconciliationResponse
10
8
 
11
- class BaseConsensusMixin:
12
9
 
10
+ class BaseConsensusMixin:
13
11
  def _prepare_reconcile(
14
12
  self,
15
13
  list_dicts: List[Dict[str, Any]],
@@ -17,21 +15,15 @@ class BaseConsensusMixin:
17
15
  mode: Literal["direct", "aligned"] = "direct",
18
16
  idempotency_key: str | None = None,
19
17
  ) -> PreparedRequest:
20
- data = {
21
- "list_dicts": list_dicts,
22
- "mode": mode,
23
- }
24
-
25
- if reference_schema is not None:
26
- data["reference_schema"] = reference_schema
27
-
28
- return PreparedRequest(
29
- method="POST",
30
- url="/v1/consensus/reconcile",
31
- data=data,
32
- idempotency_key=idempotency_key
18
+ request = ReconciliationRequest(
19
+ list_dicts=list_dicts,
20
+ reference_schema=reference_schema,
21
+ mode=mode,
33
22
  )
34
23
 
24
+ return PreparedRequest(method="POST", url="/v1/consensus/reconcile", data=request.model_dump(), idempotency_key=idempotency_key)
25
+
26
+
35
27
  class Consensus(SyncAPIResource, BaseConsensusMixin):
36
28
  """Consensus API wrapper for synchronous operations"""
37
29
 
@@ -49,25 +41,20 @@ class Consensus(SyncAPIResource, BaseConsensusMixin):
49
41
  ) -> ReconciliationResponse:
50
42
  """
51
43
  Reconcile multiple dictionaries to produce a single unified consensus dictionary.
52
-
44
+
53
45
  Args:
54
46
  list_dicts: List of dictionaries to reconcile
55
47
  reference_schema: Optional schema to validate dictionaries against
56
48
  mode: Mode for consensus computation ("direct" or "aligned")
57
49
  idempotency_key: Optional idempotency key for the request
58
-
50
+
59
51
  Returns:
60
52
  Dict containing the consensus dictionary and consensus likelihoods
61
-
53
+
62
54
  Raises:
63
55
  UiformAPIError: If the API request fails
64
56
  """
65
- request = self._prepare_reconcile(
66
- list_dicts,
67
- reference_schema,
68
- mode,
69
- idempotency_key
70
- )
57
+ request = self._prepare_reconcile(list_dicts, reference_schema, mode, idempotency_key)
71
58
  response = self._client._prepared_request(request)
72
59
  return ReconciliationResponse.model_validate(response)
73
60
 
@@ -80,7 +67,6 @@ class AsyncConsensus(AsyncAPIResource, BaseConsensusMixin):
80
67
  self.completions = AsyncCompletions(client=client)
81
68
  self.responses = AsyncResponses(client=client)
82
69
 
83
-
84
70
  async def reconcile(
85
71
  self,
86
72
  list_dicts: List[Dict[str, Any]],
@@ -90,25 +76,20 @@ class AsyncConsensus(AsyncAPIResource, BaseConsensusMixin):
90
76
  ) -> ReconciliationResponse:
91
77
  """
92
78
  Reconcile multiple dictionaries to produce a single unified consensus dictionary asynchronously.
93
-
79
+
94
80
  Args:
95
81
  list_dicts: List of dictionaries to reconcile
96
82
  reference_schema: Optional schema to validate dictionaries against
97
83
  mode: Mode for consensus computation ("direct" or "aligned")
98
84
  idempotency_key: Optional idempotency key for the request
99
-
85
+
100
86
  Returns:
101
87
  Dict containing the consensus dictionary and consensus likelihoods
102
-
88
+
103
89
  Raises:
104
90
  UiformAPIError: If the API request fails
105
91
  """
106
- request = self._prepare_reconcile(
107
- list_dicts,
108
- reference_schema,
109
- mode,
110
- idempotency_key
111
- )
92
+ request = self._prepare_reconcile(list_dicts, reference_schema, mode, idempotency_key)
112
93
  response = await self._client._prepared_request(request)
113
94
 
114
95
  return ReconciliationResponse.model_validate(response)
@@ -1,28 +1,19 @@
1
- import json
2
- from pathlib import Path
3
- from typing import Any, AsyncGenerator, Generator
4
-
5
1
  from openai.types.chat.chat_completion_reasoning_effort import ChatCompletionReasoningEffort
6
- from openai.types.chat.parsed_chat_completion import ParsedChatCompletionMessage
7
2
  from openai.types.shared_params.response_format_json_schema import ResponseFormatJSONSchema
8
- #from openai.lib._parsing import ResponseFormatT
9
- from pydantic import BaseModel as ResponseFormatT
10
3
 
4
+ # from openai.lib._parsing import ResponseFormatT
5
+ from pydantic import BaseModel as ResponseFormatT
11
6
 
12
7
  from ..._resource import AsyncAPIResource, SyncAPIResource
13
8
  from ..._utils.ai_models import assert_valid_model_extraction
14
- from ..._utils.json_schema import load_json_schema, unflatten_dict
15
- from ..._utils.stream_context_managers import as_async_context_manager, as_context_manager
16
9
  from ...types.chat import ChatCompletionUiformMessage
17
10
  from ...types.completions import UiChatCompletionsRequest
18
- from ...types.documents.extractions import UiParsedChatCompletion, UiParsedChatCompletionChunk, UiParsedChoice
19
- from ...types.standards import PreparedRequest
11
+ from ...types.documents.extractions import UiParsedChatCompletion
20
12
  from ...types.schemas.object import Schema
21
-
13
+ from ...types.standards import PreparedRequest
22
14
 
23
15
 
24
16
  class BaseCompletionsMixin:
25
-
26
17
  def prepare_parse(
27
18
  self,
28
19
  response_format: type[ResponseFormatT],
@@ -40,9 +31,10 @@ class BaseCompletionsMixin:
40
31
 
41
32
  schema_obj = Schema(json_schema=json_schema)
42
33
 
43
- data = {
44
- "messages": messages,
45
- "response_format": {
34
+ request = UiChatCompletionsRequest(
35
+ model=model,
36
+ messages=messages,
37
+ response_format={
46
38
  "type": "json_schema",
47
39
  "json_schema": {
48
40
  "name": schema_obj.id,
@@ -50,18 +42,12 @@ class BaseCompletionsMixin:
50
42
  "strict": True,
51
43
  },
52
44
  },
53
- "model": model,
54
- "temperature": temperature,
55
- "stream": stream,
56
- "reasoning_effort": reasoning_effort,
57
- "n_consensus": n_consensus,
58
- }
59
-
60
- # Validate DocumentAPIRequest data (raises exception if invalid)
61
- ui_chat_completions_request = UiChatCompletionsRequest.model_validate(data)
62
-
63
- return PreparedRequest(method="POST", url="/v1/completions", data=ui_chat_completions_request.model_dump(), idempotency_key=idempotency_key)
64
-
45
+ temperature=temperature,
46
+ stream=stream,
47
+ reasoning_effort=reasoning_effort,
48
+ n_consensus=n_consensus,
49
+ )
50
+ return PreparedRequest(method="POST", url="/v1/completions", data=request.model_dump(), idempotency_key=idempotency_key)
65
51
 
66
52
  def prepare_create(
67
53
  self,
@@ -74,16 +60,16 @@ class BaseCompletionsMixin:
74
60
  n_consensus: int,
75
61
  idempotency_key: str | None = None,
76
62
  ) -> PreparedRequest:
77
-
78
63
  json_schema = response_format["json_schema"].get("schema")
79
64
 
80
65
  assert isinstance(json_schema, dict), f"json_schema must be a dictionary, got {type(json_schema)}"
81
66
 
82
67
  schema_obj = Schema(json_schema=json_schema)
83
68
 
84
- data = {
85
- "messages": messages,
86
- "response_format": {
69
+ request = UiChatCompletionsRequest(
70
+ model=model,
71
+ messages=messages,
72
+ response_format={
87
73
  "type": "json_schema",
88
74
  "json_schema": {
89
75
  "name": schema_obj.id,
@@ -91,17 +77,12 @@ class BaseCompletionsMixin:
91
77
  "strict": True,
92
78
  },
93
79
  },
94
- "model": model,
95
- "temperature": temperature,
96
- "stream": stream,
97
- "reasoning_effort": reasoning_effort,
98
- "n_consensus": n_consensus,
99
- }
100
-
101
- # Validate DocumentAPIRequest data (raises exception if invalid)
102
- ui_chat_completions_request = UiChatCompletionsRequest.model_validate(data)
103
-
104
- return PreparedRequest(method="POST", url="/v1/completions", data=ui_chat_completions_request.model_dump(), idempotency_key=idempotency_key)
80
+ temperature=temperature,
81
+ stream=stream,
82
+ reasoning_effort=reasoning_effort,
83
+ n_consensus=n_consensus,
84
+ )
85
+ return PreparedRequest(method="POST", url="/v1/completions", data=request.model_dump(), idempotency_key=idempotency_key)
105
86
 
106
87
 
107
88
  class Completions(SyncAPIResource, BaseCompletionsMixin):
@@ -137,7 +118,6 @@ class Completions(SyncAPIResource, BaseCompletionsMixin):
137
118
 
138
119
  return UiParsedChatCompletion.model_validate(response)
139
120
 
140
-
141
121
  def parse(
142
122
  self,
143
123
  response_format: type[ResponseFormatT],
@@ -210,9 +190,6 @@ class AsyncCompletions(AsyncAPIResource, BaseCompletionsMixin):
210
190
  response = await self._client._prepared_request(request)
211
191
  return UiParsedChatCompletion.model_validate(response)
212
192
 
213
-
214
-
215
-
216
193
  async def parse(
217
194
  self,
218
195
  response_format: type[ResponseFormatT],
@@ -1,28 +1,25 @@
1
1
  import json
2
- from pathlib import Path
3
- from typing import Any, AsyncGenerator, Generator
2
+ from typing import AsyncGenerator, Generator
4
3
 
5
4
  from openai.types.chat.chat_completion_reasoning_effort import ChatCompletionReasoningEffort
6
5
  from openai.types.chat.parsed_chat_completion import ParsedChatCompletionMessage
7
6
  from openai.types.shared_params.response_format_json_schema import ResponseFormatJSONSchema
8
- #from openai.lib._parsing import ResponseFormatT
9
- from pydantic import BaseModel as ResponseFormatT
10
7
 
8
+ # from openai.lib._parsing import ResponseFormatT
9
+ from pydantic import BaseModel as ResponseFormatT
11
10
 
12
11
  from ..._resource import AsyncAPIResource, SyncAPIResource
13
12
  from ..._utils.ai_models import assert_valid_model_extraction
14
- from ..._utils.json_schema import load_json_schema, unflatten_dict
13
+ from ..._utils.json_schema import unflatten_dict
15
14
  from ..._utils.stream_context_managers import as_async_context_manager, as_context_manager
16
15
  from ...types.chat import ChatCompletionUiformMessage
17
16
  from ...types.completions import UiChatCompletionsRequest
18
17
  from ...types.documents.extractions import UiParsedChatCompletion, UiParsedChatCompletionChunk, UiParsedChoice
19
- from ...types.standards import PreparedRequest
20
18
  from ...types.schemas.object import Schema
21
-
19
+ from ...types.standards import PreparedRequest
22
20
 
23
21
 
24
22
  class BaseCompletionsMixin:
25
-
26
23
  def prepare_parse(
27
24
  self,
28
25
  response_format: type[ResponseFormatT],
@@ -37,12 +34,11 @@ class BaseCompletionsMixin:
37
34
  assert_valid_model_extraction(model)
38
35
 
39
36
  json_schema = response_format.model_json_schema()
40
-
41
37
  schema_obj = Schema(json_schema=json_schema)
42
38
 
43
- data = {
44
- "messages": messages,
45
- "response_format": {
39
+ request = UiChatCompletionsRequest(
40
+ messages=messages,
41
+ response_format={
46
42
  "type": "json_schema",
47
43
  "json_schema": {
48
44
  "name": schema_obj.id,
@@ -50,18 +46,14 @@ class BaseCompletionsMixin:
50
46
  "strict": True,
51
47
  },
52
48
  },
53
- "model": model,
54
- "temperature": temperature,
55
- "stream": stream,
56
- "reasoning_effort": reasoning_effort,
57
- "n_consensus": n_consensus,
58
- }
59
-
60
- # Validate DocumentAPIRequest data (raises exception if invalid)
61
- ui_chat_completions_request = UiChatCompletionsRequest.model_validate(data)
62
-
63
- return PreparedRequest(method="POST", url="/v1/completions", data=ui_chat_completions_request.model_dump(), idempotency_key=idempotency_key)
49
+ model=model,
50
+ temperature=temperature,
51
+ stream=stream,
52
+ reasoning_effort=reasoning_effort,
53
+ n_consensus=n_consensus,
54
+ )
64
55
 
56
+ return PreparedRequest(method="POST", url="/v1/completions", data=request.model_dump(), idempotency_key=idempotency_key)
65
57
 
66
58
  def prepare_create(
67
59
  self,
@@ -74,16 +66,17 @@ class BaseCompletionsMixin:
74
66
  n_consensus: int,
75
67
  idempotency_key: str | None = None,
76
68
  ) -> PreparedRequest:
77
-
78
69
  json_schema = response_format["json_schema"].get("schema")
79
70
 
80
71
  assert isinstance(json_schema, dict), f"json_schema must be a dictionary, got {type(json_schema)}"
81
72
 
82
73
  schema_obj = Schema(json_schema=json_schema)
83
74
 
84
- data = {
85
- "messages": messages,
86
- "response_format": {
75
+ # Validate DocumentAPIRequest data (raises exception if invalid)
76
+ request = UiChatCompletionsRequest(
77
+ model=model,
78
+ messages=messages,
79
+ response_format={
87
80
  "type": "json_schema",
88
81
  "json_schema": {
89
82
  "name": schema_obj.id,
@@ -91,17 +84,13 @@ class BaseCompletionsMixin:
91
84
  "strict": True,
92
85
  },
93
86
  },
94
- "model": model,
95
- "temperature": temperature,
96
- "stream": stream,
97
- "reasoning_effort": reasoning_effort,
98
- "n_consensus": n_consensus,
99
- }
100
-
101
- # Validate DocumentAPIRequest data (raises exception if invalid)
102
- ui_chat_completions_request = UiChatCompletionsRequest.model_validate(data)
87
+ temperature=temperature,
88
+ stream=stream,
89
+ reasoning_effort=reasoning_effort,
90
+ n_consensus=n_consensus,
91
+ )
103
92
 
104
- return PreparedRequest(method="POST", url="/v1/completions", data=ui_chat_completions_request.model_dump(), idempotency_key=idempotency_key)
93
+ return PreparedRequest(method="POST", url="/v1/completions", data=request.model_dump(), idempotency_key=idempotency_key)
105
94
 
106
95
 
107
96
  class Completions(SyncAPIResource, BaseCompletionsMixin):
@@ -193,7 +182,6 @@ class Completions(SyncAPIResource, BaseCompletionsMixin):
193
182
  class AsyncCompletions(AsyncAPIResource, BaseCompletionsMixin):
194
183
  """Multi-provider Completions API wrapper for asynchronous usage."""
195
184
 
196
-
197
185
  @as_async_context_manager
198
186
  async def stream(
199
187
  self,