retab 0.0.41__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 (60) hide show
  1. retab/__init__.py +2 -1
  2. retab/client.py +21 -50
  3. retab/resources/consensus/client.py +1 -1
  4. retab/resources/consensus/completions_stream.py +2 -2
  5. retab/resources/consensus/responses.py +1 -1
  6. retab/resources/documents/client.py +103 -76
  7. retab/resources/documents/extractions.py +55 -46
  8. retab/resources/evaluations/client.py +32 -19
  9. retab/resources/evaluations/documents.py +12 -11
  10. retab/resources/evaluations/iterations.py +48 -30
  11. retab/resources/jsonlUtils.py +3 -4
  12. retab/resources/processors/automations/endpoints.py +57 -43
  13. retab/resources/processors/automations/links.py +54 -45
  14. retab/resources/processors/automations/logs.py +2 -2
  15. retab/resources/processors/automations/mailboxes.py +116 -90
  16. retab/resources/processors/automations/outlook.py +126 -86
  17. retab/resources/processors/automations/tests.py +7 -1
  18. retab/resources/processors/client.py +37 -32
  19. retab/resources/usage.py +2 -0
  20. retab/types/ai_models.py +1 -1
  21. retab/types/automations/mailboxes.py +1 -1
  22. retab/types/deprecated_evals.py +195 -0
  23. retab/types/documents/extractions.py +2 -2
  24. retab/types/documents/parse.py +3 -1
  25. retab/types/evaluations/__init__.py +5 -2
  26. retab/types/evaluations/iterations.py +9 -43
  27. retab/types/evaluations/model.py +20 -22
  28. retab/types/extractions.py +35 -9
  29. retab/types/logs.py +5 -6
  30. retab/types/mime.py +1 -10
  31. retab/types/schemas/enhance.py +22 -5
  32. retab/types/schemas/evaluate.py +1 -1
  33. retab/types/schemas/object.py +26 -0
  34. retab/types/standards.py +2 -2
  35. retab/utils/__init__.py +3 -0
  36. retab/utils/ai_models.py +127 -12
  37. retab/utils/hashing.py +24 -0
  38. retab/utils/json_schema.py +1 -26
  39. retab/utils/mime.py +0 -17
  40. retab-0.0.43.dist-info/METADATA +117 -0
  41. {retab-0.0.41.dist-info → retab-0.0.43.dist-info}/RECORD +43 -57
  42. retab/_utils/__init__.py +0 -0
  43. retab/_utils/_model_cards/anthropic.yaml +0 -59
  44. retab/_utils/_model_cards/auto.yaml +0 -43
  45. retab/_utils/_model_cards/gemini.yaml +0 -117
  46. retab/_utils/_model_cards/openai.yaml +0 -301
  47. retab/_utils/_model_cards/xai.yaml +0 -28
  48. retab/_utils/ai_models.py +0 -138
  49. retab/_utils/benchmarking.py +0 -484
  50. retab/_utils/chat.py +0 -327
  51. retab/_utils/display.py +0 -440
  52. retab/_utils/json_schema.py +0 -2156
  53. retab/_utils/mime.py +0 -165
  54. retab/_utils/responses.py +0 -169
  55. retab/_utils/stream_context_managers.py +0 -52
  56. retab/_utils/usage/__init__.py +0 -0
  57. retab/_utils/usage/usage.py +0 -301
  58. retab-0.0.41.dist-info/METADATA +0 -418
  59. {retab-0.0.41.dist-info → retab-0.0.43.dist-info}/WHEEL +0 -0
  60. {retab-0.0.41.dist-info → retab-0.0.43.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,15 @@
1
1
  from typing import Any, Literal, List
2
2
 
3
- from pydantic_core import PydanticUndefined
3
+ from ....types.standards import FieldUnset
4
4
 
5
5
  from ...._resource import AsyncAPIResource, SyncAPIResource
6
- from ....types.automations.outlook import FetchParams, ListOutlooks, MatchParams, Outlook, UpdateOutlookRequest
6
+ from ....types.automations.outlook import (
7
+ FetchParams,
8
+ ListOutlooks,
9
+ MatchParams,
10
+ Outlook,
11
+ UpdateOutlookRequest,
12
+ )
7
13
  from ....types.standards import PreparedRequest
8
14
 
9
15
 
@@ -15,33 +21,49 @@ class OutlooksMixin:
15
21
  name: str,
16
22
  processor_id: str,
17
23
  webhook_url: str,
18
- default_language: str = PydanticUndefined, # type: ignore[assignment]
19
- webhook_headers: dict[str, str] = PydanticUndefined, # type: ignore[assignment]
20
- need_validation: bool = PydanticUndefined, # type: ignore[assignment]
21
- authorized_domains: list[str] = PydanticUndefined, # type: ignore[assignment]
22
- authorized_emails: list[str] = PydanticUndefined, # type: ignore[assignment]
23
- layout_schema: dict[str, Any] = PydanticUndefined, # type: ignore[assignment]
24
- match_params: list[MatchParams] = PydanticUndefined, # type: ignore[assignment]
25
- fetch_params: list[FetchParams] = PydanticUndefined, # type: ignore[assignment]
24
+ default_language: str = FieldUnset,
25
+ webhook_headers: dict[str, str] = FieldUnset,
26
+ need_validation: bool = FieldUnset,
27
+ authorized_domains: list[str] = FieldUnset,
28
+ authorized_emails: list[str] = FieldUnset,
29
+ layout_schema: dict[str, Any] = FieldUnset,
30
+ match_params: list[MatchParams] = FieldUnset,
31
+ fetch_params: list[FetchParams] = FieldUnset,
26
32
  ) -> PreparedRequest:
33
+ # Build outlook dictionary with only provided fields
34
+ outlook_dict: dict[str, Any] = {
35
+ 'processor_id': processor_id,
36
+ 'name': name,
37
+ 'webhook_url': webhook_url,
38
+ }
39
+ if default_language is not FieldUnset:
40
+ outlook_dict['default_language'] = default_language
41
+ if webhook_headers is not FieldUnset:
42
+ outlook_dict['webhook_headers'] = webhook_headers
43
+ if need_validation is not FieldUnset:
44
+ outlook_dict['need_validation'] = need_validation
45
+ if authorized_domains is not FieldUnset:
46
+ outlook_dict['authorized_domains'] = authorized_domains
47
+ if authorized_emails is not FieldUnset:
48
+ outlook_dict['authorized_emails'] = authorized_emails
49
+ if layout_schema is not FieldUnset:
50
+ outlook_dict['layout_schema'] = layout_schema
51
+ if match_params is not FieldUnset:
52
+ outlook_dict['match_params'] = match_params
53
+ if fetch_params is not FieldUnset:
54
+ outlook_dict['fetch_params'] = fetch_params
55
+
27
56
  # Validate the data
28
- outlook_data = Outlook(
29
- processor_id=processor_id,
30
- name=name,
31
- default_language=default_language,
32
- webhook_url=webhook_url,
33
- webhook_headers=webhook_headers,
34
- need_validation=need_validation,
35
- authorized_domains=authorized_domains,
36
- authorized_emails=authorized_emails,
37
- layout_schema=layout_schema,
38
- match_params=match_params,
39
- fetch_params=fetch_params,
57
+ outlook_data = Outlook(**outlook_dict)
58
+ return PreparedRequest(
59
+ method="POST",
60
+ url=self.outlooks_base_url,
61
+ data=outlook_data.model_dump(mode="json", exclude_unset=True),
40
62
  )
41
- return PreparedRequest(method="POST", url=self.outlooks_base_url, data=outlook_data.model_dump(mode="json"))
42
63
 
43
64
  def prepare_list(
44
65
  self,
66
+ processor_id: str,
45
67
  before: str | None = None,
46
68
  after: str | None = None,
47
69
  limit: int = 10,
@@ -50,6 +72,7 @@ class OutlooksMixin:
50
72
  webhook_url: str | None = None,
51
73
  ) -> PreparedRequest:
52
74
  params = {
75
+ "processor_id": processor_id,
53
76
  "before": before,
54
77
  "after": after,
55
78
  "limit": limit,
@@ -68,32 +91,47 @@ class OutlooksMixin:
68
91
  def prepare_update(
69
92
  self,
70
93
  outlook_id: str,
71
- name: str = PydanticUndefined, # type: ignore[assignment]
72
- default_language: str = PydanticUndefined, # type: ignore[assignment]
73
- webhook_url: str = PydanticUndefined, # type: ignore[assignment]
74
- webhook_headers: dict[str, str] = PydanticUndefined, # type: ignore[assignment]
75
- need_validation: bool = PydanticUndefined, # type: ignore[assignment]
76
- authorized_domains: list[str] = PydanticUndefined, # type: ignore[assignment]
77
- authorized_emails: list[str] = PydanticUndefined, # type: ignore[assignment]
78
- match_params: list[MatchParams] = PydanticUndefined, # type: ignore[assignment]
79
- fetch_params: list[FetchParams] = PydanticUndefined, # type: ignore[assignment]
80
- layout_schema: dict[str, Any] = PydanticUndefined, # type: ignore[assignment]
94
+ name: str = FieldUnset,
95
+ default_language: str = FieldUnset,
96
+ webhook_url: str = FieldUnset,
97
+ webhook_headers: dict[str, str] = FieldUnset,
98
+ need_validation: bool = FieldUnset,
99
+ authorized_domains: list[str] = FieldUnset,
100
+ authorized_emails: list[str] = FieldUnset,
101
+ match_params: list[MatchParams] = FieldUnset,
102
+ fetch_params: list[FetchParams] = FieldUnset,
103
+ layout_schema: dict[str, Any] = FieldUnset,
81
104
  ) -> PreparedRequest:
82
- update_outlook_request = UpdateOutlookRequest(
83
- name=name,
84
- default_language=default_language,
85
- webhook_url=webhook_url,
86
- webhook_headers=webhook_headers,
87
- need_validation=need_validation,
88
- authorized_domains=authorized_domains,
89
- authorized_emails=authorized_emails,
90
- layout_schema=layout_schema,
91
- match_params=match_params,
92
- fetch_params=fetch_params,
105
+ update_dict: dict[str, Any] = {}
106
+ if name is not FieldUnset:
107
+ update_dict['name'] = name
108
+ if default_language is not FieldUnset:
109
+ update_dict['default_language'] = default_language
110
+ if webhook_url is not FieldUnset:
111
+ update_dict['webhook_url'] = webhook_url
112
+ if webhook_headers is not FieldUnset:
113
+ update_dict['webhook_headers'] = webhook_headers
114
+ if need_validation is not FieldUnset:
115
+ update_dict['need_validation'] = need_validation
116
+ if authorized_domains is not FieldUnset:
117
+ update_dict['authorized_domains'] = authorized_domains
118
+ if authorized_emails is not FieldUnset:
119
+ update_dict['authorized_emails'] = authorized_emails
120
+ if layout_schema is not FieldUnset:
121
+ update_dict['layout_schema'] = layout_schema
122
+ if match_params is not FieldUnset:
123
+ update_dict['match_params'] = match_params
124
+ if fetch_params is not FieldUnset:
125
+ update_dict['fetch_params'] = fetch_params
126
+
127
+ update_outlook_request = UpdateOutlookRequest(**update_dict)
128
+
129
+ return PreparedRequest(
130
+ method="PUT",
131
+ url=f"{self.outlooks_base_url}/{outlook_id}",
132
+ data=update_outlook_request.model_dump(mode="json", exclude_unset=True),
93
133
  )
94
134
 
95
- return PreparedRequest(method="PUT", url=f"{self.outlooks_base_url}/{outlook_id}", data=update_outlook_request.model_dump(mode="json"))
96
-
97
135
  def prepare_delete(self, outlook_id: str) -> PreparedRequest:
98
136
  return PreparedRequest(method="DELETE", url=f"{self.outlooks_base_url}/{outlook_id}")
99
137
 
@@ -109,14 +147,14 @@ class Outlooks(SyncAPIResource, OutlooksMixin):
109
147
  name: str,
110
148
  processor_id: str,
111
149
  webhook_url: str,
112
- default_language: str = PydanticUndefined, # type: ignore[assignment]
113
- webhook_headers: dict[str, str] = PydanticUndefined, # type: ignore[assignment]
114
- need_validation: bool = PydanticUndefined, # type: ignore[assignment]
115
- authorized_domains: list[str] = PydanticUndefined, # type: ignore[assignment]
116
- authorized_emails: list[str] = PydanticUndefined, # type: ignore[assignment]
117
- layout_schema: dict[str, Any] = PydanticUndefined, # type: ignore[assignment]
118
- match_params: list[MatchParams] = PydanticUndefined, # type: ignore[assignment]
119
- fetch_params: list[FetchParams] = PydanticUndefined, # type: ignore[assignment]
150
+ default_language: str = FieldUnset,
151
+ webhook_headers: dict[str, str] = FieldUnset,
152
+ need_validation: bool = FieldUnset,
153
+ authorized_domains: list[str] = FieldUnset,
154
+ authorized_emails: list[str] = FieldUnset,
155
+ layout_schema: dict[str, Any] = FieldUnset,
156
+ match_params: list[MatchParams] = FieldUnset,
157
+ fetch_params: list[FetchParams] = FieldUnset,
120
158
  ) -> Outlook:
121
159
  """Create a new outlook automation configuration.
122
160
 
@@ -149,12 +187,13 @@ class Outlooks(SyncAPIResource, OutlooksMixin):
149
187
  )
150
188
  response = self._client._prepared_request(request)
151
189
 
152
- print(f"Outlook plugin created. Url: https://www.retab.dev/dashboard/processors/automations/{response['id']}")
190
+ print(f"Outlook plugin created. Url: https://www.retab.com/dashboard/processors/automations/{response['id']}")
153
191
 
154
192
  return Outlook.model_validate(response)
155
193
 
156
194
  def list(
157
195
  self,
196
+ processor_id: str,
158
197
  before: str | None = None,
159
198
  after: str | None = None,
160
199
  limit: int = 10,
@@ -174,7 +213,7 @@ class Outlooks(SyncAPIResource, OutlooksMixin):
174
213
  Returns:
175
214
  List[Outlook]: List of outlook plugin configurations
176
215
  """
177
- request = self.prepare_list(before, after, limit, order, name, webhook_url)
216
+ request = self.prepare_list(processor_id, before, after, limit, order, name, webhook_url)
178
217
  response = self._client._prepared_request(request)
179
218
  return ListOutlooks.model_validate(response)
180
219
 
@@ -194,16 +233,16 @@ class Outlooks(SyncAPIResource, OutlooksMixin):
194
233
  def update(
195
234
  self,
196
235
  outlook_id: str,
197
- name: str = PydanticUndefined, # type: ignore[assignment]
198
- default_language: str = PydanticUndefined, # type: ignore[assignment]
199
- webhook_url: str = PydanticUndefined, # type: ignore[assignment]
200
- webhook_headers: dict[str, str] = PydanticUndefined, # type: ignore[assignment]
201
- need_validation: bool = PydanticUndefined, # type: ignore[assignment]
202
- authorized_domains: List[str] = PydanticUndefined, # type: ignore[assignment]
203
- authorized_emails: List[str] = PydanticUndefined, # type: ignore[assignment]
204
- layout_schema: dict[str, Any] = PydanticUndefined, # type: ignore[assignment]
205
- match_params: List[MatchParams] = PydanticUndefined, # type: ignore[assignment]
206
- fetch_params: List[FetchParams] = PydanticUndefined, # type: ignore[assignment]
236
+ name: str = FieldUnset,
237
+ default_language: str = FieldUnset,
238
+ webhook_url: str = FieldUnset,
239
+ webhook_headers: dict[str, str] = FieldUnset,
240
+ need_validation: bool = FieldUnset,
241
+ authorized_domains: List[str] = FieldUnset,
242
+ authorized_emails: List[str] = FieldUnset,
243
+ layout_schema: dict[str, Any] = FieldUnset,
244
+ match_params: List[MatchParams] = FieldUnset,
245
+ fetch_params: List[FetchParams] = FieldUnset,
207
246
  ) -> Outlook:
208
247
  """Update an outlook automation configuration.
209
248
 
@@ -257,14 +296,14 @@ class AsyncOutlooks(AsyncAPIResource, OutlooksMixin):
257
296
  name: str,
258
297
  processor_id: str,
259
298
  webhook_url: str,
260
- default_language: str = PydanticUndefined, # type: ignore[assignment]
261
- webhook_headers: dict[str, str] = PydanticUndefined, # type: ignore[assignment]
262
- need_validation: bool = PydanticUndefined, # type: ignore[assignment]
263
- authorized_domains: list[str] = PydanticUndefined, # type: ignore[assignment]
264
- authorized_emails: list[str] = PydanticUndefined, # type: ignore[assignment]
265
- layout_schema: dict[str, Any] = PydanticUndefined, # type: ignore[assignment]
266
- match_params: list[MatchParams] = PydanticUndefined, # type: ignore[assignment]
267
- fetch_params: list[FetchParams] = PydanticUndefined, # type: ignore[assignment]
299
+ default_language: str = FieldUnset,
300
+ webhook_headers: dict[str, str] = FieldUnset,
301
+ need_validation: bool = FieldUnset,
302
+ authorized_domains: list[str] = FieldUnset,
303
+ authorized_emails: list[str] = FieldUnset,
304
+ layout_schema: dict[str, Any] = FieldUnset,
305
+ match_params: list[MatchParams] = FieldUnset,
306
+ fetch_params: list[FetchParams] = FieldUnset,
268
307
  ) -> Outlook:
269
308
  request = self.prepare_create(
270
309
  name=name,
@@ -280,11 +319,12 @@ class AsyncOutlooks(AsyncAPIResource, OutlooksMixin):
280
319
  fetch_params=fetch_params,
281
320
  )
282
321
  response = await self._client._prepared_request(request)
283
- print(f"Outlook plugin created. Url: https://www.retab.dev/dashboard/processors/automations/{response['id']}")
322
+ print(f"Outlook plugin created. Url: https://www.retab.com/dashboard/processors/automations/{response['id']}")
284
323
  return Outlook.model_validate(response)
285
324
 
286
325
  async def list(
287
326
  self,
327
+ processor_id: str,
288
328
  before: str | None = None,
289
329
  after: str | None = None,
290
330
  limit: int = 10,
@@ -292,7 +332,7 @@ class AsyncOutlooks(AsyncAPIResource, OutlooksMixin):
292
332
  name: str | None = None,
293
333
  webhook_url: str | None = None,
294
334
  ) -> ListOutlooks:
295
- request = self.prepare_list(before, after, limit, order, name, webhook_url)
335
+ request = self.prepare_list(processor_id, before, after, limit, order, name, webhook_url)
296
336
  response = await self._client._prepared_request(request)
297
337
  return ListOutlooks.model_validate(response)
298
338
 
@@ -304,16 +344,16 @@ class AsyncOutlooks(AsyncAPIResource, OutlooksMixin):
304
344
  async def update(
305
345
  self,
306
346
  outlook_id: str,
307
- name: str = PydanticUndefined, # type: ignore[assignment]
308
- default_language: str = PydanticUndefined, # type: ignore[assignment]
309
- webhook_url: str = PydanticUndefined, # type: ignore[assignment]
310
- webhook_headers: dict[str, str] = PydanticUndefined, # type: ignore[assignment]
311
- need_validation: bool = PydanticUndefined, # type: ignore[assignment]
312
- authorized_domains: List[str] = PydanticUndefined, # type: ignore[assignment]
313
- authorized_emails: List[str] = PydanticUndefined, # type: ignore[assignment]
314
- layout_schema: dict[str, Any] = PydanticUndefined, # type: ignore[assignment]
315
- match_params: List[MatchParams] = PydanticUndefined, # type: ignore[assignment]
316
- fetch_params: List[FetchParams] = PydanticUndefined, # type: ignore[assignment]
347
+ name: str = FieldUnset,
348
+ default_language: str = FieldUnset,
349
+ webhook_url: str = FieldUnset,
350
+ webhook_headers: dict[str, str] = FieldUnset,
351
+ need_validation: bool = FieldUnset,
352
+ authorized_domains: List[str] = FieldUnset,
353
+ authorized_emails: List[str] = FieldUnset,
354
+ layout_schema: dict[str, Any] = FieldUnset,
355
+ match_params: List[MatchParams] = FieldUnset,
356
+ fetch_params: List[FetchParams] = FieldUnset,
317
357
  ) -> Outlook:
318
358
  request = self.prepare_update(
319
359
  outlook_id=outlook_id,
@@ -1,4 +1,5 @@
1
1
  import json
2
+ import base64
2
3
  from io import IOBase
3
4
  from pathlib import Path
4
5
 
@@ -15,7 +16,12 @@ from ....types.standards import PreparedRequest
15
16
  class TestsMixin:
16
17
  def prepare_upload(self, automation_id: str, document: Path | str | IOBase | HttpUrl | Image | MIMEData) -> PreparedRequest:
17
18
  mime_document = prepare_mime_document(document)
18
- return PreparedRequest(method="POST", url=f"/v1/processors/automations/tests/upload/{automation_id}", data={"document": mime_document.model_dump(mode="json")})
19
+
20
+ # Convert MIME document to file upload format (similar to processors client)
21
+ files = {"file": (mime_document.filename, base64.b64decode(mime_document.content), mime_document.mime_type)}
22
+
23
+ # Send as multipart form data with file upload
24
+ return PreparedRequest(method="POST", url=f"/v1/processors/automations/tests/upload/{automation_id}", files=files)
19
25
 
20
26
  def prepare_webhook(self, automation_id: str) -> PreparedRequest:
21
27
  return PreparedRequest(method="POST", url=f"/v1/processors/automations/tests/webhook/{automation_id}", data=None)
@@ -6,8 +6,6 @@ from typing import Any, List, Literal
6
6
  import PIL.Image
7
7
  from openai.types.chat.chat_completion_reasoning_effort import ChatCompletionReasoningEffort
8
8
  from pydantic import BaseModel, HttpUrl
9
- from pydantic_core import PydanticUndefined
10
-
11
9
  from ..._resource import AsyncAPIResource, SyncAPIResource
12
10
  from ...utils.ai_models import assert_valid_model_extraction
13
11
  from ...utils.json_schema import load_json_schema
@@ -17,7 +15,7 @@ from ...types.documents.extractions import RetabParsedChatCompletion
17
15
  from ...types.logs import ProcessorConfig, UpdateProcessorRequest
18
16
  from ...types.modalities import Modality
19
17
  from ...types.pagination import ListMetadata
20
- from ...types.standards import PreparedRequest
18
+ from ...types.standards import PreparedRequest, FieldUnset
21
19
  from .automations.client import AsyncAutomations, Automations
22
20
 
23
21
 
@@ -35,30 +33,37 @@ class ProcessorsMixin:
35
33
  json_schema: dict[str, Any] | Path | str,
36
34
  modality: Modality = "native",
37
35
  model: str = "gpt-4o-mini",
38
- temperature: float = PydanticUndefined, # type: ignore[assignment]
39
- reasoning_effort: ChatCompletionReasoningEffort = PydanticUndefined, # type: ignore[assignment]
40
- image_resolution_dpi: int = PydanticUndefined, # type: ignore[assignment]
41
- browser_canvas: BrowserCanvas = PydanticUndefined, # type: ignore[assignment]
42
- n_consensus: int = PydanticUndefined, # type: ignore[assignment]
36
+ temperature: float = FieldUnset,
37
+ reasoning_effort: ChatCompletionReasoningEffort = FieldUnset,
38
+ image_resolution_dpi: int = FieldUnset,
39
+ browser_canvas: BrowserCanvas = FieldUnset,
40
+ n_consensus: int = FieldUnset,
43
41
  ) -> PreparedRequest:
44
42
  assert_valid_model_extraction(model)
45
43
 
46
44
  # Load the JSON schema from file path, string, or dict
47
45
  loaded_schema = load_json_schema(json_schema)
48
46
 
49
- processor_config = ProcessorConfig(
50
- name=name,
51
- json_schema=loaded_schema,
52
- modality=modality,
53
- model=model,
54
- temperature=temperature,
55
- reasoning_effort=reasoning_effort,
56
- image_resolution_dpi=image_resolution_dpi,
57
- browser_canvas=browser_canvas,
58
- n_consensus=n_consensus,
59
- )
47
+ config_dict = {
48
+ 'name': name,
49
+ 'json_schema': loaded_schema,
50
+ 'modality': modality,
51
+ 'model': model,
52
+ }
53
+ if temperature is not FieldUnset:
54
+ config_dict['temperature'] = temperature
55
+ if reasoning_effort is not FieldUnset:
56
+ config_dict['reasoning_effort'] = reasoning_effort
57
+ if image_resolution_dpi is not FieldUnset:
58
+ config_dict['image_resolution_dpi'] = image_resolution_dpi
59
+ if browser_canvas is not FieldUnset:
60
+ config_dict['browser_canvas'] = browser_canvas
61
+ if n_consensus is not FieldUnset:
62
+ config_dict['n_consensus'] = n_consensus
63
+
64
+ processor_config = ProcessorConfig(**config_dict)
60
65
 
61
- return PreparedRequest(method="POST", url="/v1/processors", data=processor_config.model_dump(mode="json"))
66
+ return PreparedRequest(method="POST", url="/v1/processors", data=processor_config.model_dump(mode="json", exclude_unset=True))
62
67
 
63
68
  def prepare_list(
64
69
  self,
@@ -215,11 +220,11 @@ class Processors(SyncAPIResource, ProcessorsMixin):
215
220
  json_schema: dict[str, Any] | Path | str,
216
221
  modality: Modality = "native",
217
222
  model: str = "gpt-4o-mini",
218
- temperature: float = PydanticUndefined, # type: ignore[assignment]
219
- reasoning_effort: ChatCompletionReasoningEffort = PydanticUndefined, # type: ignore[assignment]
220
- image_resolution_dpi: int = PydanticUndefined, # type: ignore[assignment]
221
- browser_canvas: BrowserCanvas = PydanticUndefined, # type: ignore[assignment]
222
- n_consensus: int = PydanticUndefined, # type: ignore[assignment]
223
+ temperature: float = FieldUnset,
224
+ reasoning_effort: ChatCompletionReasoningEffort = FieldUnset,
225
+ image_resolution_dpi: int = FieldUnset,
226
+ browser_canvas: BrowserCanvas = FieldUnset,
227
+ n_consensus: int = FieldUnset,
223
228
  ) -> ProcessorConfig:
224
229
  """Create a new processor configuration.
225
230
 
@@ -248,7 +253,7 @@ class Processors(SyncAPIResource, ProcessorsMixin):
248
253
  n_consensus=n_consensus,
249
254
  )
250
255
  response = self._client._prepared_request(request)
251
- print(f"Processor ID: {response['id']}. Processor available at https://www.retab.dev/dashboard/processors/{response['id']}")
256
+ print(f"Processor ID: {response['id']}. Processor available at https://www.retab.com/dashboard/processors/{response['id']}")
252
257
  return ProcessorConfig.model_validate(response)
253
258
 
254
259
  def list(
@@ -390,11 +395,11 @@ class AsyncProcessors(AsyncAPIResource, ProcessorsMixin):
390
395
  json_schema: dict[str, Any] | Path | str,
391
396
  modality: Modality = "native",
392
397
  model: str = "gpt-4o-mini",
393
- temperature: float = PydanticUndefined, # type: ignore[assignment]
394
- reasoning_effort: ChatCompletionReasoningEffort = PydanticUndefined, # type: ignore[assignment]
395
- image_resolution_dpi: int = PydanticUndefined, # type: ignore[assignment]
396
- browser_canvas: BrowserCanvas = PydanticUndefined, # type: ignore[assignment]
397
- n_consensus: int = PydanticUndefined, # type: ignore[assignment]
398
+ temperature: float = FieldUnset,
399
+ reasoning_effort: ChatCompletionReasoningEffort = FieldUnset,
400
+ image_resolution_dpi: int = FieldUnset,
401
+ browser_canvas: BrowserCanvas = FieldUnset,
402
+ n_consensus: int = FieldUnset,
398
403
  ) -> ProcessorConfig:
399
404
  request = self.prepare_create(
400
405
  name=name,
@@ -408,7 +413,7 @@ class AsyncProcessors(AsyncAPIResource, ProcessorsMixin):
408
413
  n_consensus=n_consensus,
409
414
  )
410
415
  response = await self._client._prepared_request(request)
411
- print(f"Processor ID: {response['id']}. Processor available at https://www.retab.dev/dashboard/processors/{response['id']}")
416
+ print(f"Processor ID: {response['id']}. Processor available at https://www.retab.com/dashboard/processors/{response['id']}")
412
417
 
413
418
  return ProcessorConfig.model_validate(response)
414
419
 
retab/resources/usage.py CHANGED
@@ -84,6 +84,7 @@ class Usage(SyncAPIResource, UsageMixin):
84
84
  def monthly_credits_usage(self) -> MonthlyUsageResponse:
85
85
  """
86
86
  Get monthly credits usage information.
87
+ Credits are calculated dynamically based on MIME type and consumption.
87
88
 
88
89
  Returns:
89
90
  dict: Monthly usage data including credits consumed and limits
@@ -198,6 +199,7 @@ class AsyncUsage(AsyncAPIResource, UsageMixin):
198
199
  async def monthly_credits_usage(self) -> MonthlyUsageResponse:
199
200
  """
200
201
  Get monthly credits usage information.
202
+ Credits are calculated dynamically based on MIME type and consumption.
201
203
 
202
204
  Returns:
203
205
  dict: Monthly usage data including credits consumed and limits
retab/types/ai_models.py CHANGED
@@ -79,7 +79,7 @@ class FinetunedModel(BaseModel):
79
79
 
80
80
  # Monthly Usage
81
81
  class MonthlyUsageResponseContent(BaseModel):
82
- request_count: int
82
+ credits_count: float # Changed to float to support decimal credits
83
83
 
84
84
 
85
85
  MonthlyUsageResponse = MonthlyUsageResponseContent
@@ -17,7 +17,7 @@ class Mailbox(AutomationConfig):
17
17
  def object(self) -> str:
18
18
  return "automation.mailbox"
19
19
 
20
- EMAIL_PATTERN: ClassVar[str] = f".*@{os.getenv('EMAIL_DOMAIN', 'mailbox.retab.dev')}$"
20
+ EMAIL_PATTERN: ClassVar[str] = f".*@{os.getenv('EMAIL_DOMAIN', 'mailbox.retab.com')}$"
21
21
  id: str = Field(default_factory=lambda: "mb_" + nanoid.generate(), description="Unique identifier for the mailbox")
22
22
 
23
23
  # Email Specific config