|
2 | 2 |
|
3 | 3 | from __future__ import annotations |
4 | 4 |
|
5 | | -from typing import List, Union, Iterable, Optional |
| 5 | +import functools |
| 6 | +from typing import Any, List, Union, Iterable, Optional |
6 | 7 |
|
7 | 8 | import httpx |
8 | 9 |
|
9 | | -from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given |
| 10 | +from ...lib import polling |
| 11 | +from ..._types import Body, FileTypes, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given |
10 | 12 | from ..._utils import maybe_transform, async_maybe_transform |
11 | 13 | from ..._compat import cached_property |
12 | 14 | from ..._resource import SyncAPIResource, AsyncAPIResource |
@@ -340,6 +342,112 @@ def search( |
340 | 342 | cast_to=FileSearchResponse, |
341 | 343 | ) |
342 | 344 |
|
| 345 | + def poll( |
| 346 | + self, |
| 347 | + file_id: str, |
| 348 | + *, |
| 349 | + store_identifier: str, |
| 350 | + poll_interval_ms: int | NotGiven = not_given, |
| 351 | + poll_timeout_ms: float | NotGiven = not_given, |
| 352 | + **kwargs: Any, |
| 353 | + ) -> StoreFile: |
| 354 | + """ |
| 355 | + Poll for a file's status until it reaches a terminal state. |
| 356 | + Args: |
| 357 | + file_id: The ID of the file to poll |
| 358 | + store_identifier: The ID of the store |
| 359 | + poll_interval_ms: The interval between polls in milliseconds |
| 360 | + poll_timeout_ms: The maximum time to poll for in milliseconds |
| 361 | + Returns: |
| 362 | + The file object once it reaches a terminal state |
| 363 | + """ |
| 364 | + polling_interval_ms = poll_interval_ms or 500 |
| 365 | + polling_timeout_ms = poll_timeout_ms or None |
| 366 | + return polling.poll( |
| 367 | + fn=functools.partial(self.retrieve, file_id, store_identifier=store_identifier, **kwargs), |
| 368 | + condition=lambda res: res.status == "completed" or res.status == "failed" or res.status == "cancelled", |
| 369 | + interval_seconds=polling_interval_ms / 1000, |
| 370 | + timeout_seconds=polling_timeout_ms / 1000 if polling_timeout_ms else None, |
| 371 | + ) |
| 372 | + |
| 373 | + def create_and_poll( |
| 374 | + self, |
| 375 | + file_id: str, |
| 376 | + *, |
| 377 | + store_identifier: str, |
| 378 | + metadata: Optional[object] | NotGiven = not_given, |
| 379 | + experimental: file_create_params.Experimental | Omit = omit, |
| 380 | + poll_interval_ms: int | NotGiven = not_given, |
| 381 | + poll_timeout_ms: float | NotGiven = not_given, |
| 382 | + **kwargs: Any, |
| 383 | + ) -> StoreFile: |
| 384 | + """ |
| 385 | + Attach a file to the given store and wait for it to be processed. |
| 386 | + Args: |
| 387 | + file_id: The ID of the file to poll |
| 388 | + store_identifier: The ID of the store |
| 389 | + metadata: The metadata to attach to the file |
| 390 | + poll_interval_ms: The interval between polls in milliseconds |
| 391 | + poll_timeout_ms: The maximum time to poll for in milliseconds |
| 392 | + Returns: |
| 393 | + The file object once it reaches a terminal state |
| 394 | + """ |
| 395 | + self.create( |
| 396 | + store_identifier=store_identifier, file_id=file_id, metadata=metadata, experimental=experimental, **kwargs |
| 397 | + ) |
| 398 | + return self.poll( |
| 399 | + file_id, |
| 400 | + store_identifier=store_identifier, |
| 401 | + poll_interval_ms=poll_interval_ms, |
| 402 | + poll_timeout_ms=poll_timeout_ms, |
| 403 | + **kwargs, |
| 404 | + ) |
| 405 | + |
| 406 | + def upload( |
| 407 | + self, |
| 408 | + *, |
| 409 | + store_identifier: str, |
| 410 | + file: FileTypes, |
| 411 | + metadata: Optional[object] | Omit = omit, |
| 412 | + experimental: file_create_params.Experimental | Omit = omit, |
| 413 | + **kwargs: Any, |
| 414 | + ) -> StoreFile: |
| 415 | + """Upload a file to the `files` API and then attach it to the given store. |
| 416 | + Note the file will be asynchronously processed (you can use the alternative |
| 417 | + polling helper method to wait for processing to complete). |
| 418 | + """ |
| 419 | + file_obj = self._client.files.create(file=file, **kwargs) |
| 420 | + return self.create( |
| 421 | + store_identifier=store_identifier, |
| 422 | + file_id=file_obj.id, |
| 423 | + metadata=metadata, |
| 424 | + experimental=experimental, |
| 425 | + **kwargs, |
| 426 | + ) |
| 427 | + |
| 428 | + def upload_and_poll( |
| 429 | + self, |
| 430 | + *, |
| 431 | + store_identifier: str, |
| 432 | + file: FileTypes, |
| 433 | + metadata: Optional[object] | NotGiven = not_given, |
| 434 | + experimental: file_create_params.Experimental | Omit = omit, |
| 435 | + poll_interval_ms: int | NotGiven = not_given, |
| 436 | + poll_timeout_ms: float | NotGiven = not_given, |
| 437 | + **kwargs: Any, |
| 438 | + ) -> StoreFile: |
| 439 | + """Add a file to a store and poll until processing is complete.""" |
| 440 | + file_obj = self._client.files.create(file=file, **kwargs) |
| 441 | + return self.create_and_poll( |
| 442 | + store_identifier=store_identifier, |
| 443 | + file_id=file_obj.id, |
| 444 | + metadata=metadata, |
| 445 | + experimental=experimental, |
| 446 | + poll_interval_ms=poll_interval_ms, |
| 447 | + poll_timeout_ms=poll_timeout_ms, |
| 448 | + **kwargs, |
| 449 | + ) |
| 450 | + |
343 | 451 |
|
344 | 452 | class AsyncFilesResource(AsyncAPIResource): |
345 | 453 | @cached_property |
@@ -656,6 +764,116 @@ async def search( |
656 | 764 | cast_to=FileSearchResponse, |
657 | 765 | ) |
658 | 766 |
|
| 767 | + async def poll( |
| 768 | + self, |
| 769 | + file_id: str, |
| 770 | + *, |
| 771 | + store_identifier: str, |
| 772 | + poll_interval_ms: int | NotGiven = not_given, |
| 773 | + poll_timeout_ms: float | NotGiven = not_given, |
| 774 | + **kwargs: Any, |
| 775 | + ) -> StoreFile: |
| 776 | + """ |
| 777 | + Poll for a file's status until it reaches a terminal state. |
| 778 | + Args: |
| 779 | + file_id: The ID of the file to poll |
| 780 | + store_identifier: The ID of the store |
| 781 | + poll_interval_ms: The interval between polls in milliseconds |
| 782 | + poll_timeout_ms: The maximum time to poll for in milliseconds |
| 783 | + Returns: |
| 784 | + The file object once it reaches a terminal state |
| 785 | + """ |
| 786 | + polling_interval_ms = poll_interval_ms or 500 |
| 787 | + polling_timeout_ms = poll_timeout_ms or None |
| 788 | + return await polling.poll_async( |
| 789 | + fn=functools.partial(self.retrieve, file_id, store_identifier=store_identifier, **kwargs), |
| 790 | + condition=lambda res: res.status == "completed" or res.status == "failed" or res.status == "cancelled", |
| 791 | + interval_seconds=polling_interval_ms / 1000, |
| 792 | + timeout_seconds=polling_timeout_ms / 1000 if polling_timeout_ms else None, |
| 793 | + ) |
| 794 | + |
| 795 | + async def create_and_poll( |
| 796 | + self, |
| 797 | + file_id: str, |
| 798 | + *, |
| 799 | + store_identifier: str, |
| 800 | + metadata: Optional[object] | NotGiven = not_given, |
| 801 | + experimental: file_create_params.Experimental | Omit = omit, |
| 802 | + poll_interval_ms: int | NotGiven = not_given, |
| 803 | + poll_timeout_ms: float | NotGiven = not_given, |
| 804 | + **kwargs: Any, |
| 805 | + ) -> StoreFile: |
| 806 | + """ |
| 807 | + Attach a file to the given vector store and wait for it to be processed. |
| 808 | + Args: |
| 809 | + file_id: The ID of the file to poll |
| 810 | + store_identifier: The ID of the store |
| 811 | + metadata: The metadata to attach to the file |
| 812 | + poll_interval_ms: The interval between polls in milliseconds |
| 813 | + poll_timeout_ms: The maximum time to poll for in milliseconds |
| 814 | + Returns: |
| 815 | + The file object once it reaches a terminal state |
| 816 | + """ |
| 817 | + await self.create( |
| 818 | + store_identifier=store_identifier, |
| 819 | + file_id=file_id, |
| 820 | + metadata=metadata, |
| 821 | + experimental=experimental, |
| 822 | + **kwargs, |
| 823 | + ) |
| 824 | + return await self.poll( |
| 825 | + file_id, |
| 826 | + store_identifier=store_identifier, |
| 827 | + poll_interval_ms=poll_interval_ms, |
| 828 | + poll_timeout_ms=poll_timeout_ms, |
| 829 | + **kwargs, |
| 830 | + ) |
| 831 | + |
| 832 | + async def upload( |
| 833 | + self, |
| 834 | + *, |
| 835 | + store_identifier: str, |
| 836 | + file: FileTypes, |
| 837 | + metadata: Optional[object] | NotGiven = not_given, |
| 838 | + experimental: file_create_params.Experimental | Omit = omit, |
| 839 | + **kwargs: Any, |
| 840 | + ) -> StoreFile: |
| 841 | + """Upload a file to the `files` API and then attach it to the given vector store. |
| 842 | + Note the file will be asynchronously processed (you can use the alternative |
| 843 | + polling helper method to wait for processing to complete). |
| 844 | + """ |
| 845 | + file_obj = await self._client.files.create(file=file, **kwargs) |
| 846 | + return await self.create( |
| 847 | + store_identifier=store_identifier, |
| 848 | + file_id=file_obj.id, |
| 849 | + metadata=metadata, |
| 850 | + experimental=experimental, |
| 851 | + **kwargs, |
| 852 | + ) |
| 853 | + |
| 854 | + async def upload_and_poll( |
| 855 | + self, |
| 856 | + *, |
| 857 | + store_identifier: str, |
| 858 | + file: FileTypes, |
| 859 | + metadata: Optional[object] | NotGiven = not_given, |
| 860 | + experimental: file_create_params.Experimental | Omit = omit, |
| 861 | + poll_interval_ms: int | NotGiven = not_given, |
| 862 | + poll_timeout_ms: float | NotGiven = not_given, |
| 863 | + **kwargs: Any, |
| 864 | + ) -> StoreFile: |
| 865 | + """Add a file to a store and poll until processing is complete.""" |
| 866 | + file_obj = await self._client.files.create(file=file, **kwargs) |
| 867 | + return await self.create_and_poll( |
| 868 | + store_identifier=store_identifier, |
| 869 | + file_id=file_obj.id, |
| 870 | + metadata=metadata, |
| 871 | + experimental=experimental, |
| 872 | + poll_interval_ms=poll_interval_ms, |
| 873 | + poll_timeout_ms=poll_timeout_ms, |
| 874 | + **kwargs, |
| 875 | + ) |
| 876 | + |
659 | 877 |
|
660 | 878 | class FilesResourceWithRawResponse: |
661 | 879 | def __init__(self, files: FilesResource) -> None: |
|
0 commit comments