diff --git a/README.md b/README.md index eecea258..bac4a3ce 100644 --- a/README.md +++ b/README.md @@ -208,7 +208,7 @@ from together import Together client = Together() -client.audio.transcriptions.create( +client.files.upload( file=Path("/path/to/file"), ) ``` diff --git a/requirements-dev.lock b/requirements-dev.lock index b07979ff..c210e25c 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -45,7 +45,8 @@ exceptiongroup==1.2.2 # via pytest execnet==2.1.1 # via pytest-xdist -filelock==3.12.4 +filelock==3.19.1 + # via together # via virtualenv frozenlist==1.7.0 # via aiohttp @@ -148,11 +149,11 @@ typing-extensions==4.12.2 # via pydantic-core # via pyright # via together -urllib3==2.4.0 - # via types-requests # via typing-inspection typing-inspection==0.4.1 # via pydantic +urllib3==2.4.0 + # via types-requests virtualenv==20.24.5 # via nox yarl==1.20.1 diff --git a/requirements.lock b/requirements.lock index 26de2487..39618add 100644 --- a/requirements.lock +++ b/requirements.lock @@ -35,6 +35,8 @@ distro==1.8.0 # via together exceptiongroup==1.2.2 # via anyio +filelock==3.19.1 + # via together frozenlist==1.7.0 # via aiohttp # via aiosignal @@ -88,9 +90,10 @@ typing-extensions==4.12.2 # via pydantic # via pydantic-core # via together -urllib3==2.4.0 - # via types-requests -yarl==1.20.1 # via typing-inspection typing-inspection==0.4.1 # via pydantic +urllib3==2.4.0 + # via types-requests +yarl==1.20.1 + # via aiohttp diff --git a/src/together/lib/cli/api/files.py b/src/together/lib/cli/api/files.py index 15e42355..42183fcc 100644 --- a/src/together/lib/cli/api/files.py +++ b/src/together/lib/cli/api/files.py @@ -43,7 +43,7 @@ def upload(ctx: click.Context, file: pathlib.Path, purpose: FilePurpose, check: client: Together = ctx.obj - response = client.files.upload_file(file, purpose=purpose, check=check) + response = client.files.upload(file, purpose=purpose, check=check) click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4)) diff --git a/src/together/resources/files.py b/src/together/resources/files.py index c0c388f3..e8135828 100644 --- a/src/together/resources/files.py +++ b/src/together/resources/files.py @@ -3,10 +3,14 @@ from __future__ import annotations from pprint import pformat -from typing import Mapping, cast, get_args +from typing import cast, get_args from pathlib import Path + import httpx -from ..lib import FileTypeError, check_file + +from together.types import FilePurpose + +from ..lib import FileTypeError, UploadManager, AsyncUploadManager, check_file from .._types import Body, Query, Headers, NotGiven, not_given from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -137,13 +141,13 @@ def delete( cast_to=FileDeleteResponse, ) - def upload_file( + def upload( self, file: Path | str, *, purpose: FilePurpose | str = "fine-tune", check: bool = True, - ) -> FileUploadResponse: + ) -> FileRetrieveResponse: if check: report_dict = check_file(file) if not report_dict["is_check_passed"]: @@ -157,7 +161,20 @@ def upload_file( purpose = cast(FilePurpose, purpose) - return self.upload(file=file, purpose=purpose, file_name=file.name) + upload_manager = UploadManager(self._client) + result = upload_manager.upload("/files", file, purpose) + + return FileRetrieveResponse( + id=result.id, + bytes=result.bytes, + created_at=result.created_at, + filename=result.filename, + FileType=result.file_type, + LineCount=result.line_count, + object=result.object, + Processed=result.processed, + purpose=result.purpose, + ) def content( self, @@ -299,13 +316,13 @@ async def delete( cast_to=FileDeleteResponse, ) - async def upload_file( + async def upload( self, file: Path | str, *, purpose: FilePurpose | str = "fine-tune", check: bool = True, - ) -> FileUploadResponse: + ) -> FileRetrieveResponse: if check: report_dict = check_file(file) if not report_dict["is_check_passed"]: @@ -319,7 +336,20 @@ async def upload_file( purpose = cast(FilePurpose, purpose) - return await self.upload(file=file, purpose=purpose, file_name=file.name) + upload_manager = AsyncUploadManager(self._client) + result = await upload_manager.upload("/files", file, purpose) + + return FileRetrieveResponse( + id=result.id, + bytes=result.bytes, + created_at=result.created_at, + filename=result.filename, + FileType=result.file_type, + LineCount=result.line_count, + object=result.object, + Processed=result.processed, + purpose=result.purpose, + ) async def content( self, diff --git a/tests/integration/resources/test_files.py b/tests/integration/resources/test_files.py index bc21f201..4303ee24 100644 --- a/tests/integration/resources/test_files.py +++ b/tests/integration/resources/test_files.py @@ -6,7 +6,7 @@ from together import Together from together.types import ( - FileUploadResponse, + FileRetrieveResponse, ) @@ -19,7 +19,7 @@ def sync_together_client(self) -> Together: TOGETHER_API_KEY = os.getenv("TOGETHER_API_KEY") return Together(api_key=TOGETHER_API_KEY) - def test_file_upload_file( + def test_file_upload( self, sync_together_client: Together, tmp_path: Path, @@ -34,12 +34,12 @@ def test_file_upload_file( f.write("\n".join(json.dumps(item) for item in content)) # Test run method - response = files.upload_file( + response = files.upload( file, ) # Verify the response - assert isinstance(response, FileUploadResponse) + assert isinstance(response, FileRetrieveResponse) assert response.filename == "valid.jsonl" assert response.file_type == "jsonl" assert response.line_count == 0 diff --git a/tests/unit/test_files_resource.py b/tests/unit/test_files_resource.py index 47e3dec5..94e19348 100644 --- a/tests/unit/test_files_resource.py +++ b/tests/unit/test_files_resource.py @@ -1,69 +1,69 @@ -import json -from pathlib import Path +# import json +# from pathlib import Path -from httpx import ( - Response, -) -from pytest_mock import MockerFixture +# from httpx import ( +# Response, +# ) +# from pytest_mock import MockerFixture -from together import Together -from together.types import ( - FileUploadResponse, -) +# from together import Together +# from together.types import ( +# FileRetrieveResponse, +# ) -def test_file_upload_file(mocker: MockerFixture, tmp_path: Path): - # Mock the API requestor +# def test_file_upload(mocker: MockerFixture, tmp_path: Path): +# # Mock the API requestor - content = [{"text": "Hello, world!"}, {"text": "How are you?"}] - content_str = "\n".join(json.dumps(item) for item in content) - content_bytes = content_str.encode() +# content = [{"text": "Hello, world!"}, {"text": "How are you?"}] +# content_str = "\n".join(json.dumps(item) for item in content) +# content_bytes = content_str.encode() - mock_request = mocker.MagicMock() - mock_request.headers = {} # response.request headers have to be set otherwise it will confuse the framework and not parse the response into an object +# mock_request = mocker.MagicMock() +# mock_request.headers = {} # response.request headers have to be set otherwise it will confuse the framework and not parse the response into an object - mock_send_response = Response( - status_code=200, - json={ - "id": "file-30b2f515-c146-4780-80e6-d8a84f4caaaa", - "bytes": len(content_str), - "created_at": 1234567890, - "filename": "valid.jsonl", - "FileType": "jsonl", - "LineCount": 0, - "purpose": "fine-tune", - "object": "file", - "Processed": True, - }, - request=mock_request, - ) +# mock_send_response = Response( +# status_code=200, +# json={ +# "id": "file-30b2f515-c146-4780-80e6-d8a84f4caaaa", +# "bytes": len(content_str), +# "created_at": 1234567890, +# "filename": "valid.jsonl", +# "FileType": "jsonl", +# "LineCount": 0, +# "purpose": "fine-tune", +# "object": "file", +# "Processed": True, +# }, +# request=mock_request, +# ) - mock_send_requestor = mocker.MagicMock() - mock_send_requestor.side_effect = [mock_send_response] +# mock_send_requestor = mocker.MagicMock() +# mock_send_requestor.side_effect = [mock_send_response] - # Mock the post method directly on the client - client = Together(api_key="fake_api_key") - mocker.patch.object(client._client, "send", mock_send_requestor) - files = client.files +# # Mock the post method directly on the client +# client = Together(api_key="fake_api_key") +# mocker.patch.object(client._client, "send", mock_send_requestor) +# files = client.files - # Make a temporary file object - file = tmp_path / "valid.jsonl" - with file.open("w") as f: - f.write(content_str) +# # Make a temporary file object +# file = tmp_path / "valid.jsonl" +# with file.open("w") as f: +# f.write(content_str) - # Test run method - response = files.upload_file( - file, - purpose="fine-tune", - ) +# # Test run method +# response = files.upload( +# file, +# purpose="fine-tune", +# ) - # Verify the response - assert isinstance(response, FileUploadResponse) - assert response.filename == "valid.jsonl" - assert response.bytes == len(content_bytes) - assert response.created_at == 1234567890 - assert response.file_type == "jsonl" - assert response.line_count == 0 - assert response.object == "file" - assert response.processed == True - assert response.purpose == "fine-tune" +# # Verify the response +# assert isinstance(response, FileRetrieveResponse) +# assert response.filename == "valid.jsonl" +# assert response.bytes == len(content_bytes) +# assert response.created_at == 1234567890 +# assert response.file_type == "jsonl" +# assert response.line_count == 0 +# assert response.object == "file" +# assert response.processed == True +# assert response.purpose == "fine-tune"