From 84988e1eeaa6d25b265bfb77863ed6a4ce271201 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 11:44:51 +0000 Subject: [PATCH 1/5] chore(test): do not count install time for mock server timeout --- scripts/mock | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/scripts/mock b/scripts/mock index 0b28f6e..bcf3b39 100755 --- a/scripts/mock +++ b/scripts/mock @@ -21,11 +21,22 @@ echo "==> Starting mock server with URL ${URL}" # Run prism mock on the given spec if [ "$1" == "--daemon" ]; then + # Pre-install the package so the download doesn't eat into the startup timeout + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism --version + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & - # Wait for server to come online + # Wait for server to come online (max 30s) echo -n "Waiting for server" + attempts=0 while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do + attempts=$((attempts + 1)) + if [ "$attempts" -ge 300 ]; then + echo + echo "Timed out waiting for Prism server to start" + cat .prism.log + exit 1 + fi echo -n "." sleep 0.1 done From 18b15733d52e1ddb60d1f9a847e4fd7a712b4701 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 15:50:19 +0000 Subject: [PATCH 2/5] feat(api): add avatar, voice, document, and realtime session endpoints --- .stats.yml | 8 +- README.md | 71 ++ api.md | 71 ++ src/runwayml/_client.py | 148 +++- src/runwayml/pagination.py | 52 ++ src/runwayml/resources/__init__.py | 15 +- src/runwayml/resources/avatars.py | 682 ++++++++++++++++++ src/runwayml/resources/documents.py | 462 ++++++++++++ src/runwayml/resources/realtime_sessions.py | 365 ++++++++++ src/runwayml/resources/voices.py | 580 +++++++++++++++ src/runwayml/types/__init__.py | 22 + src/runwayml/types/avatar_create_params.py | 107 +++ src/runwayml/types/avatar_create_response.py | 368 ++++++++++ src/runwayml/types/avatar_list_params.py | 15 + src/runwayml/types/avatar_list_response.py | 368 ++++++++++ .../types/avatar_retrieve_response.py | 368 ++++++++++ src/runwayml/types/avatar_update_params.py | 111 +++ src/runwayml/types/avatar_update_response.py | 368 ++++++++++ src/runwayml/types/document_create_params.py | 15 + .../types/document_create_response.py | 45 ++ src/runwayml/types/document_list_params.py | 15 + src/runwayml/types/document_list_response.py | 42 ++ .../types/document_retrieve_response.py | 45 ++ .../organization_retrieve_usage_response.py | 4 + .../types/realtime_session_create_params.py | 57 ++ .../types/realtime_session_create_response.py | 10 + .../realtime_session_retrieve_response.py | 116 +++ src/runwayml/types/voice_create_params.py | 36 + src/runwayml/types/voice_create_response.py | 10 + src/runwayml/types/voice_list_params.py | 15 + src/runwayml/types/voice_list_response.py | 81 +++ src/runwayml/types/voice_preview_params.py | 18 + src/runwayml/types/voice_preview_response.py | 15 + src/runwayml/types/voice_retrieve_response.py | 81 +++ tests/api_resources/test_avatars.py | 500 +++++++++++++ tests/api_resources/test_documents.py | 327 +++++++++ tests/api_resources/test_realtime_sessions.py | 289 ++++++++ tests/api_resources/test_voices.py | 446 ++++++++++++ 38 files changed, 6337 insertions(+), 11 deletions(-) create mode 100644 src/runwayml/pagination.py create mode 100644 src/runwayml/resources/avatars.py create mode 100644 src/runwayml/resources/documents.py create mode 100644 src/runwayml/resources/realtime_sessions.py create mode 100644 src/runwayml/resources/voices.py create mode 100644 src/runwayml/types/avatar_create_params.py create mode 100644 src/runwayml/types/avatar_create_response.py create mode 100644 src/runwayml/types/avatar_list_params.py create mode 100644 src/runwayml/types/avatar_list_response.py create mode 100644 src/runwayml/types/avatar_retrieve_response.py create mode 100644 src/runwayml/types/avatar_update_params.py create mode 100644 src/runwayml/types/avatar_update_response.py create mode 100644 src/runwayml/types/document_create_params.py create mode 100644 src/runwayml/types/document_create_response.py create mode 100644 src/runwayml/types/document_list_params.py create mode 100644 src/runwayml/types/document_list_response.py create mode 100644 src/runwayml/types/document_retrieve_response.py create mode 100644 src/runwayml/types/realtime_session_create_params.py create mode 100644 src/runwayml/types/realtime_session_create_response.py create mode 100644 src/runwayml/types/realtime_session_retrieve_response.py create mode 100644 src/runwayml/types/voice_create_params.py create mode 100644 src/runwayml/types/voice_create_response.py create mode 100644 src/runwayml/types/voice_list_params.py create mode 100644 src/runwayml/types/voice_list_response.py create mode 100644 src/runwayml/types/voice_preview_params.py create mode 100644 src/runwayml/types/voice_preview_response.py create mode 100644 src/runwayml/types/voice_retrieve_response.py create mode 100644 tests/api_resources/test_avatars.py create mode 100644 tests/api_resources/test_documents.py create mode 100644 tests/api_resources/test_realtime_sessions.py create mode 100644 tests/api_resources/test_voices.py diff --git a/.stats.yml b/.stats.yml index 720cb80..e306cf4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 14 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runwayml%2Frunwayml-b3276a8508268090b14e297f5cb18448da7a763653c6d38c23f0eea0984d8008.yml -openapi_spec_hash: 95ae975f17217c8d144c4ba80846beca -config_hash: 803d5c0aa94eea0a7981b91728218d3f +configured_endpoints: 31 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runwayml%2Frunwayml-4ddc8e3d83c8601fc378c702bbcb5af2976b481db513bd389a5f57645a20cd04.yml +openapi_spec_hash: 5795c6af9e9404765bda670e781fe500 +config_hash: 3c88fcd4dd6f3a7d7f6e94b57b430243 diff --git a/README.md b/README.md index 10b9971..00f3a2a 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,77 @@ Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typ Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`. +## Pagination + +List methods in the RunwayML API are paginated. + +This library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually: + +```python +from runwayml import RunwayML + +client = RunwayML() + +all_avatars = [] +# Automatically fetches more pages as needed. +for avatar in client.avatars.list( + limit=1, +): + # Do something with avatar here + all_avatars.append(avatar) +print(all_avatars) +``` + +Or, asynchronously: + +```python +import asyncio +from runwayml import AsyncRunwayML + +client = AsyncRunwayML() + + +async def main() -> None: + all_avatars = [] + # Iterate through items across all pages, issuing requests as needed. + async for avatar in client.avatars.list( + limit=1, + ): + all_avatars.append(avatar) + print(all_avatars) + + +asyncio.run(main()) +``` + +Alternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages: + +```python +first_page = await client.avatars.list( + limit=1, +) +if first_page.has_next_page(): + print(f"will fetch next page using these details: {first_page.next_page_info()}") + next_page = await first_page.get_next_page() + print(f"number of items we just fetched: {len(next_page.data)}") + +# Remove `await` for non-async usage. +``` + +Or just work directly with the returned data: + +```python +first_page = await client.avatars.list( + limit=1, +) + +print(f"next page cursor: {first_page.next_cursor}") # => "next page cursor: ..." +for avatar in first_page.data: + print(avatar) + +# Remove `await` for non-async usage. +``` + ## Nested params Nested parameters are dictionaries, typed using `TypedDict`, for example: diff --git a/api.md b/api.md index 72145fe..6661946 100644 --- a/api.md +++ b/api.md @@ -143,3 +143,74 @@ Methods: - client.organization.retrieve() -> OrganizationRetrieveResponse - client.organization.retrieve_usage(\*\*params) -> OrganizationRetrieveUsageResponse + +# Avatars + +Types: + +```python +from runwayml.types import ( + AvatarCreateResponse, + AvatarRetrieveResponse, + AvatarUpdateResponse, + AvatarListResponse, +) +``` + +Methods: + +- client.avatars.create(\*\*params) -> AvatarCreateResponse +- client.avatars.retrieve(id) -> AvatarRetrieveResponse +- client.avatars.update(id, \*\*params) -> AvatarUpdateResponse +- client.avatars.list(\*\*params) -> SyncCursorPage[AvatarListResponse] +- client.avatars.delete(id) -> None + +# Documents + +Types: + +```python +from runwayml.types import DocumentCreateResponse, DocumentRetrieveResponse, DocumentListResponse +``` + +Methods: + +- client.documents.create(\*\*params) -> DocumentCreateResponse +- client.documents.retrieve(id) -> DocumentRetrieveResponse +- client.documents.list(\*\*params) -> SyncCursorPage[DocumentListResponse] +- client.documents.delete(id) -> None + +# RealtimeSessions + +Types: + +```python +from runwayml.types import RealtimeSessionCreateResponse, RealtimeSessionRetrieveResponse +``` + +Methods: + +- client.realtime_sessions.create(\*\*params) -> RealtimeSessionCreateResponse +- client.realtime_sessions.retrieve(id) -> RealtimeSessionRetrieveResponse +- client.realtime_sessions.delete(id) -> None + +# Voices + +Types: + +```python +from runwayml.types import ( + VoiceCreateResponse, + VoiceRetrieveResponse, + VoiceListResponse, + VoicePreviewResponse, +) +``` + +Methods: + +- client.voices.create(\*\*params) -> VoiceCreateResponse +- client.voices.retrieve(id) -> VoiceRetrieveResponse +- client.voices.list(\*\*params) -> SyncCursorPage[VoiceListResponse] +- client.voices.delete(id) -> None +- client.voices.preview(\*\*params) -> VoicePreviewResponse diff --git a/src/runwayml/_client.py b/src/runwayml/_client.py index 047882b..4dabd86 100644 --- a/src/runwayml/_client.py +++ b/src/runwayml/_client.py @@ -44,10 +44,11 @@ video_to_video, voice_isolation, speech_to_speech, + realtime_sessions, character_performance, ) from .resources.tasks import TasksResource, AsyncTasksResource - from .resources.uploads import UploadsResource, AsyncUploadsResource + from .resources.organization import OrganizationResource, AsyncOrganizationResource from .resources.sound_effect import SoundEffectResource, AsyncSoundEffectResource from .resources.text_to_image import TextToImageResource, AsyncTextToImageResource @@ -58,6 +59,7 @@ from .resources.video_to_video import VideoToVideoResource, AsyncVideoToVideoResource from .resources.voice_isolation import VoiceIsolationResource, AsyncVoiceIsolationResource from .resources.speech_to_speech import SpeechToSpeechResource, AsyncSpeechToSpeechResource + from .resources.realtime_sessions import RealtimeSessionsResource, AsyncRealtimeSessionsResource from .resources.character_performance import CharacterPerformanceResource, AsyncCharacterPerformanceResource __all__ = [ @@ -222,6 +224,30 @@ def organization(self) -> OrganizationResource: return OrganizationResource(self) + @cached_property + def avatars(self) -> AvatarsResource: + from .resources.avatars import AvatarsResource + + return AvatarsResource(self) + + @cached_property + def documents(self) -> DocumentsResource: + from .resources.documents import DocumentsResource + + return DocumentsResource(self) + + @cached_property + def realtime_sessions(self) -> RealtimeSessionsResource: + from .resources.realtime_sessions import RealtimeSessionsResource + + return RealtimeSessionsResource(self) + + @cached_property + def voices(self) -> VoicesResource: + from .resources.voices import VoicesResource + + return VoicesResource(self) + @cached_property def with_raw_response(self) -> RunwayMLWithRawResponse: return RunwayMLWithRawResponse(self) @@ -488,6 +514,30 @@ def organization(self) -> AsyncOrganizationResource: return AsyncOrganizationResource(self) + @cached_property + def avatars(self) -> AsyncAvatarsResource: + from .resources.avatars import AsyncAvatarsResource + + return AsyncAvatarsResource(self) + + @cached_property + def documents(self) -> AsyncDocumentsResource: + from .resources.documents import AsyncDocumentsResource + + return AsyncDocumentsResource(self) + + @cached_property + def realtime_sessions(self) -> AsyncRealtimeSessionsResource: + from .resources.realtime_sessions import AsyncRealtimeSessionsResource + + return AsyncRealtimeSessionsResource(self) + + @cached_property + def voices(self) -> AsyncVoicesResource: + from .resources.voices import AsyncVoicesResource + + return AsyncVoicesResource(self) + @cached_property def with_raw_response(self) -> AsyncRunwayMLWithRawResponse: return AsyncRunwayMLWithRawResponse(self) @@ -699,6 +749,30 @@ def organization(self) -> organization.OrganizationResourceWithRawResponse: return OrganizationResourceWithRawResponse(self._client.organization) + @cached_property + def avatars(self) -> avatars.AvatarsResourceWithRawResponse: + from .resources.avatars import AvatarsResourceWithRawResponse + + return AvatarsResourceWithRawResponse(self._client.avatars) + + @cached_property + def documents(self) -> documents.DocumentsResourceWithRawResponse: + from .resources.documents import DocumentsResourceWithRawResponse + + return DocumentsResourceWithRawResponse(self._client.documents) + + @cached_property + def realtime_sessions(self) -> realtime_sessions.RealtimeSessionsResourceWithRawResponse: + from .resources.realtime_sessions import RealtimeSessionsResourceWithRawResponse + + return RealtimeSessionsResourceWithRawResponse(self._client.realtime_sessions) + + @cached_property + def voices(self) -> voices.VoicesResourceWithRawResponse: + from .resources.voices import VoicesResourceWithRawResponse + + return VoicesResourceWithRawResponse(self._client.voices) + class AsyncRunwayMLWithRawResponse: _client: AsyncRunwayML @@ -795,6 +869,30 @@ def organization(self) -> organization.AsyncOrganizationResourceWithRawResponse: return AsyncOrganizationResourceWithRawResponse(self._client.organization) + @cached_property + def avatars(self) -> avatars.AsyncAvatarsResourceWithRawResponse: + from .resources.avatars import AsyncAvatarsResourceWithRawResponse + + return AsyncAvatarsResourceWithRawResponse(self._client.avatars) + + @cached_property + def documents(self) -> documents.AsyncDocumentsResourceWithRawResponse: + from .resources.documents import AsyncDocumentsResourceWithRawResponse + + return AsyncDocumentsResourceWithRawResponse(self._client.documents) + + @cached_property + def realtime_sessions(self) -> realtime_sessions.AsyncRealtimeSessionsResourceWithRawResponse: + from .resources.realtime_sessions import AsyncRealtimeSessionsResourceWithRawResponse + + return AsyncRealtimeSessionsResourceWithRawResponse(self._client.realtime_sessions) + + @cached_property + def voices(self) -> voices.AsyncVoicesResourceWithRawResponse: + from .resources.voices import AsyncVoicesResourceWithRawResponse + + return AsyncVoicesResourceWithRawResponse(self._client.voices) + class RunwayMLWithStreamedResponse: _client: RunwayML @@ -891,6 +989,30 @@ def organization(self) -> organization.OrganizationResourceWithStreamingResponse return OrganizationResourceWithStreamingResponse(self._client.organization) + @cached_property + def avatars(self) -> avatars.AvatarsResourceWithStreamingResponse: + from .resources.avatars import AvatarsResourceWithStreamingResponse + + return AvatarsResourceWithStreamingResponse(self._client.avatars) + + @cached_property + def documents(self) -> documents.DocumentsResourceWithStreamingResponse: + from .resources.documents import DocumentsResourceWithStreamingResponse + + return DocumentsResourceWithStreamingResponse(self._client.documents) + + @cached_property + def realtime_sessions(self) -> realtime_sessions.RealtimeSessionsResourceWithStreamingResponse: + from .resources.realtime_sessions import RealtimeSessionsResourceWithStreamingResponse + + return RealtimeSessionsResourceWithStreamingResponse(self._client.realtime_sessions) + + @cached_property + def voices(self) -> voices.VoicesResourceWithStreamingResponse: + from .resources.voices import VoicesResourceWithStreamingResponse + + return VoicesResourceWithStreamingResponse(self._client.voices) + class AsyncRunwayMLWithStreamedResponse: _client: AsyncRunwayML @@ -987,6 +1109,30 @@ def organization(self) -> organization.AsyncOrganizationResourceWithStreamingRes return AsyncOrganizationResourceWithStreamingResponse(self._client.organization) + @cached_property + def avatars(self) -> avatars.AsyncAvatarsResourceWithStreamingResponse: + from .resources.avatars import AsyncAvatarsResourceWithStreamingResponse + + return AsyncAvatarsResourceWithStreamingResponse(self._client.avatars) + + @cached_property + def documents(self) -> documents.AsyncDocumentsResourceWithStreamingResponse: + from .resources.documents import AsyncDocumentsResourceWithStreamingResponse + + return AsyncDocumentsResourceWithStreamingResponse(self._client.documents) + + @cached_property + def realtime_sessions(self) -> realtime_sessions.AsyncRealtimeSessionsResourceWithStreamingResponse: + from .resources.realtime_sessions import AsyncRealtimeSessionsResourceWithStreamingResponse + + return AsyncRealtimeSessionsResourceWithStreamingResponse(self._client.realtime_sessions) + + @cached_property + def voices(self) -> voices.AsyncVoicesResourceWithStreamingResponse: + from .resources.voices import AsyncVoicesResourceWithStreamingResponse + + return AsyncVoicesResourceWithStreamingResponse(self._client.voices) + Client = RunwayML diff --git a/src/runwayml/pagination.py b/src/runwayml/pagination.py new file mode 100644 index 0000000..a61c6ad --- /dev/null +++ b/src/runwayml/pagination.py @@ -0,0 +1,52 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Generic, TypeVar, Optional +from typing_extensions import override + +from pydantic import Field as FieldInfo + +from ._base_client import BasePage, PageInfo, BaseSyncPage, BaseAsyncPage + +__all__ = ["SyncCursorPage", "AsyncCursorPage"] + +_T = TypeVar("_T") + + +class SyncCursorPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + data: List[_T] + next_cursor: Optional[str] = FieldInfo(alias="nextCursor", default=None) + + @override + def _get_page_items(self) -> List[_T]: + data = self.data + if not data: + return [] + return data + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_cursor = self.next_cursor + if not next_cursor: + return None + + return PageInfo(params={"cursor": next_cursor}) + + +class AsyncCursorPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + data: List[_T] + next_cursor: Optional[str] = FieldInfo(alias="nextCursor", default=None) + + @override + def _get_page_items(self) -> List[_T]: + data = self.data + if not data: + return [] + return data + + @override + def next_page_info(self) -> Optional[PageInfo]: + next_cursor = self.next_cursor + if not next_cursor: + return None + + return PageInfo(params={"cursor": next_cursor}) diff --git a/src/runwayml/resources/__init__.py b/src/runwayml/resources/__init__.py index 1b6f367..4f29840 100644 --- a/src/runwayml/resources/__init__.py +++ b/src/runwayml/resources/__init__.py @@ -96,6 +96,14 @@ SpeechToSpeechResourceWithStreamingResponse, AsyncSpeechToSpeechResourceWithStreamingResponse, ) +from .realtime_sessions import ( + RealtimeSessionsResource, + AsyncRealtimeSessionsResource, + RealtimeSessionsResourceWithRawResponse, + AsyncRealtimeSessionsResourceWithRawResponse, + RealtimeSessionsResourceWithStreamingResponse, + AsyncRealtimeSessionsResourceWithStreamingResponse, +) from .character_performance import ( CharacterPerformanceResource, AsyncCharacterPerformanceResource, @@ -178,10 +186,5 @@ "AsyncOrganizationResourceWithRawResponse", "OrganizationResourceWithStreamingResponse", "AsyncOrganizationResourceWithStreamingResponse", - "UploadsResource", - "AsyncUploadsResource", - "UploadsResourceWithRawResponse", - "AsyncUploadsResourceWithRawResponse", - "UploadsResourceWithStreamingResponse", - "AsyncUploadsResourceWithStreamingResponse", + ] diff --git a/src/runwayml/resources/avatars.py b/src/runwayml/resources/avatars.py new file mode 100644 index 0000000..4556c2c --- /dev/null +++ b/src/runwayml/resources/avatars.py @@ -0,0 +1,682 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Any, Optional, cast +from typing_extensions import Literal + +import httpx + +from ..types import avatar_list_params, avatar_create_params, avatar_update_params +from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given +from .._utils import maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..pagination import SyncCursorPage, AsyncCursorPage +from .._base_client import AsyncPaginator, make_request_options +from ..types.avatar_list_response import AvatarListResponse +from ..types.avatar_create_response import AvatarCreateResponse +from ..types.avatar_update_response import AvatarUpdateResponse +from ..types.avatar_retrieve_response import AvatarRetrieveResponse + +__all__ = ["AvatarsResource", "AsyncAvatarsResource"] + + +class AvatarsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> AvatarsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/runwayml/sdk-python#accessing-raw-response-data-eg-headers + """ + return AvatarsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AvatarsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/runwayml/sdk-python#with_streaming_response + """ + return AvatarsResourceWithStreamingResponse(self) + + def create( + self, + *, + name: str, + personality: str, + reference_image: str, + voice: avatar_create_params.Voice, + document_ids: SequenceNotStr[str] | Omit = omit, + image_processing: Literal["optimize", "none"] | Omit = omit, + start_script: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AvatarCreateResponse: + """ + Create a new avatar with a reference image and voice. + + Args: + name: The character name for the avatar. + + personality: System prompt defining how the avatar should behave in conversations. + + reference_image: A HTTPS URL. + + voice: The voice configuration for the avatar. + + document_ids: Optional list of knowledge document IDs to attach to this avatar. Documents + provide additional context during conversations. + + image_processing: Controls image preprocessing. `optimize` improves the image for better avatar + results. `none` uses the image as-is; quality not guaranteed. + + start_script: Optional opening message that the avatar will say when a session starts. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return cast( + AvatarCreateResponse, + self._post( + "/v1/avatars", + body=maybe_transform( + { + "name": name, + "personality": personality, + "reference_image": reference_image, + "voice": voice, + "document_ids": document_ids, + "image_processing": image_processing, + "start_script": start_script, + }, + avatar_create_params.AvatarCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast( + Any, AvatarCreateResponse + ), # Union types cannot be passed in as arguments in the type system + ), + ) + + def retrieve( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AvatarRetrieveResponse: + """ + Get details of a specific avatar. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return cast( + AvatarRetrieveResponse, + self._get( + f"/v1/avatars/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast( + Any, AvatarRetrieveResponse + ), # Union types cannot be passed in as arguments in the type system + ), + ) + + def update( + self, + id: str, + *, + document_ids: SequenceNotStr[str] | Omit = omit, + image_processing: Literal["optimize", "none"] | Omit = omit, + name: str | Omit = omit, + personality: str | Omit = omit, + reference_image: str | Omit = omit, + start_script: Optional[str] | Omit = omit, + voice: avatar_update_params.Voice | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AvatarUpdateResponse: + """Update an existing avatar. + + At least one field must be provided. + + Args: + document_ids: List of knowledge document IDs to attach to this avatar. Replaces all current + attachments. Documents provide additional context during conversations. + + image_processing: Controls image preprocessing. `optimize` improves the image for better avatar + results. `none` uses the image as-is; quality not guaranteed. + + name: The character name for the avatar. + + personality: System prompt defining how the avatar should behave in conversations. + + reference_image: A HTTPS URL. + + start_script: Optional opening message that the avatar will say when a session starts. Set to + null to clear. + + voice: The voice configuration for the avatar. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return cast( + AvatarUpdateResponse, + self._patch( + f"/v1/avatars/{id}", + body=maybe_transform( + { + "document_ids": document_ids, + "image_processing": image_processing, + "name": name, + "personality": personality, + "reference_image": reference_image, + "start_script": start_script, + "voice": voice, + }, + avatar_update_params.AvatarUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast( + Any, AvatarUpdateResponse + ), # Union types cannot be passed in as arguments in the type system + ), + ) + + def list( + self, + *, + limit: int, + cursor: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncCursorPage[AvatarListResponse]: + """ + List avatars for the authenticated user with cursor-based pagination. + + Args: + limit: The maximum number of items to return per page. + + cursor: Cursor from a previous response for fetching the next page of results. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/v1/avatars", + page=SyncCursorPage[AvatarListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "cursor": cursor, + }, + avatar_list_params.AvatarListParams, + ), + ), + model=cast(Any, AvatarListResponse), # Union types cannot be passed in as arguments in the type system + ) + + def delete( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete an avatar. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/v1/avatars/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncAvatarsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncAvatarsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/runwayml/sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncAvatarsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAvatarsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/runwayml/sdk-python#with_streaming_response + """ + return AsyncAvatarsResourceWithStreamingResponse(self) + + async def create( + self, + *, + name: str, + personality: str, + reference_image: str, + voice: avatar_create_params.Voice, + document_ids: SequenceNotStr[str] | Omit = omit, + image_processing: Literal["optimize", "none"] | Omit = omit, + start_script: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AvatarCreateResponse: + """ + Create a new avatar with a reference image and voice. + + Args: + name: The character name for the avatar. + + personality: System prompt defining how the avatar should behave in conversations. + + reference_image: A HTTPS URL. + + voice: The voice configuration for the avatar. + + document_ids: Optional list of knowledge document IDs to attach to this avatar. Documents + provide additional context during conversations. + + image_processing: Controls image preprocessing. `optimize` improves the image for better avatar + results. `none` uses the image as-is; quality not guaranteed. + + start_script: Optional opening message that the avatar will say when a session starts. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return cast( + AvatarCreateResponse, + await self._post( + "/v1/avatars", + body=await async_maybe_transform( + { + "name": name, + "personality": personality, + "reference_image": reference_image, + "voice": voice, + "document_ids": document_ids, + "image_processing": image_processing, + "start_script": start_script, + }, + avatar_create_params.AvatarCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast( + Any, AvatarCreateResponse + ), # Union types cannot be passed in as arguments in the type system + ), + ) + + async def retrieve( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AvatarRetrieveResponse: + """ + Get details of a specific avatar. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return cast( + AvatarRetrieveResponse, + await self._get( + f"/v1/avatars/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast( + Any, AvatarRetrieveResponse + ), # Union types cannot be passed in as arguments in the type system + ), + ) + + async def update( + self, + id: str, + *, + document_ids: SequenceNotStr[str] | Omit = omit, + image_processing: Literal["optimize", "none"] | Omit = omit, + name: str | Omit = omit, + personality: str | Omit = omit, + reference_image: str | Omit = omit, + start_script: Optional[str] | Omit = omit, + voice: avatar_update_params.Voice | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AvatarUpdateResponse: + """Update an existing avatar. + + At least one field must be provided. + + Args: + document_ids: List of knowledge document IDs to attach to this avatar. Replaces all current + attachments. Documents provide additional context during conversations. + + image_processing: Controls image preprocessing. `optimize` improves the image for better avatar + results. `none` uses the image as-is; quality not guaranteed. + + name: The character name for the avatar. + + personality: System prompt defining how the avatar should behave in conversations. + + reference_image: A HTTPS URL. + + start_script: Optional opening message that the avatar will say when a session starts. Set to + null to clear. + + voice: The voice configuration for the avatar. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return cast( + AvatarUpdateResponse, + await self._patch( + f"/v1/avatars/{id}", + body=await async_maybe_transform( + { + "document_ids": document_ids, + "image_processing": image_processing, + "name": name, + "personality": personality, + "reference_image": reference_image, + "start_script": start_script, + "voice": voice, + }, + avatar_update_params.AvatarUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast( + Any, AvatarUpdateResponse + ), # Union types cannot be passed in as arguments in the type system + ), + ) + + def list( + self, + *, + limit: int, + cursor: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[AvatarListResponse, AsyncCursorPage[AvatarListResponse]]: + """ + List avatars for the authenticated user with cursor-based pagination. + + Args: + limit: The maximum number of items to return per page. + + cursor: Cursor from a previous response for fetching the next page of results. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/v1/avatars", + page=AsyncCursorPage[AvatarListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "cursor": cursor, + }, + avatar_list_params.AvatarListParams, + ), + ), + model=cast(Any, AvatarListResponse), # Union types cannot be passed in as arguments in the type system + ) + + async def delete( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete an avatar. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/v1/avatars/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AvatarsResourceWithRawResponse: + def __init__(self, avatars: AvatarsResource) -> None: + self._avatars = avatars + + self.create = to_raw_response_wrapper( + avatars.create, + ) + self.retrieve = to_raw_response_wrapper( + avatars.retrieve, + ) + self.update = to_raw_response_wrapper( + avatars.update, + ) + self.list = to_raw_response_wrapper( + avatars.list, + ) + self.delete = to_raw_response_wrapper( + avatars.delete, + ) + + +class AsyncAvatarsResourceWithRawResponse: + def __init__(self, avatars: AsyncAvatarsResource) -> None: + self._avatars = avatars + + self.create = async_to_raw_response_wrapper( + avatars.create, + ) + self.retrieve = async_to_raw_response_wrapper( + avatars.retrieve, + ) + self.update = async_to_raw_response_wrapper( + avatars.update, + ) + self.list = async_to_raw_response_wrapper( + avatars.list, + ) + self.delete = async_to_raw_response_wrapper( + avatars.delete, + ) + + +class AvatarsResourceWithStreamingResponse: + def __init__(self, avatars: AvatarsResource) -> None: + self._avatars = avatars + + self.create = to_streamed_response_wrapper( + avatars.create, + ) + self.retrieve = to_streamed_response_wrapper( + avatars.retrieve, + ) + self.update = to_streamed_response_wrapper( + avatars.update, + ) + self.list = to_streamed_response_wrapper( + avatars.list, + ) + self.delete = to_streamed_response_wrapper( + avatars.delete, + ) + + +class AsyncAvatarsResourceWithStreamingResponse: + def __init__(self, avatars: AsyncAvatarsResource) -> None: + self._avatars = avatars + + self.create = async_to_streamed_response_wrapper( + avatars.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + avatars.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + avatars.update, + ) + self.list = async_to_streamed_response_wrapper( + avatars.list, + ) + self.delete = async_to_streamed_response_wrapper( + avatars.delete, + ) diff --git a/src/runwayml/resources/documents.py b/src/runwayml/resources/documents.py new file mode 100644 index 0000000..8e5ba60 --- /dev/null +++ b/src/runwayml/resources/documents.py @@ -0,0 +1,462 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..types import document_list_params, document_create_params +from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from .._utils import maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..pagination import SyncCursorPage, AsyncCursorPage +from .._base_client import AsyncPaginator, make_request_options +from ..types.document_list_response import DocumentListResponse +from ..types.document_create_response import DocumentCreateResponse +from ..types.document_retrieve_response import DocumentRetrieveResponse + +__all__ = ["DocumentsResource", "AsyncDocumentsResource"] + + +class DocumentsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> DocumentsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/runwayml/sdk-python#accessing-raw-response-data-eg-headers + """ + return DocumentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DocumentsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/runwayml/sdk-python#with_streaming_response + """ + return DocumentsResourceWithStreamingResponse(self) + + def create( + self, + *, + content: str, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DocumentCreateResponse: + """Create a new knowledge document. + + Documents can be attached to avatars to provide + additional context during conversations. + + Args: + content: The markdown or plain text content of the document. + + name: A descriptive name for the document. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/v1/documents", + body=maybe_transform( + { + "content": content, + "name": name, + }, + document_create_params.DocumentCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DocumentCreateResponse, + ) + + def retrieve( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DocumentRetrieveResponse: + """ + Get details of a specific knowledge document. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + f"/v1/documents/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DocumentRetrieveResponse, + ) + + def list( + self, + *, + limit: int, + cursor: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncCursorPage[DocumentListResponse]: + """ + List knowledge documents for the authenticated user with cursor-based + pagination. + + Args: + limit: The maximum number of items to return per page. + + cursor: Cursor from a previous response for fetching the next page of results. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/v1/documents", + page=SyncCursorPage[DocumentListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "cursor": cursor, + }, + document_list_params.DocumentListParams, + ), + ), + model=DocumentListResponse, + ) + + def delete( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Delete a knowledge document. + + This also removes it from all avatars it was + attached to. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/v1/documents/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncDocumentsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncDocumentsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/runwayml/sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncDocumentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDocumentsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/runwayml/sdk-python#with_streaming_response + """ + return AsyncDocumentsResourceWithStreamingResponse(self) + + async def create( + self, + *, + content: str, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DocumentCreateResponse: + """Create a new knowledge document. + + Documents can be attached to avatars to provide + additional context during conversations. + + Args: + content: The markdown or plain text content of the document. + + name: A descriptive name for the document. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/v1/documents", + body=await async_maybe_transform( + { + "content": content, + "name": name, + }, + document_create_params.DocumentCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DocumentCreateResponse, + ) + + async def retrieve( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DocumentRetrieveResponse: + """ + Get details of a specific knowledge document. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + f"/v1/documents/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DocumentRetrieveResponse, + ) + + def list( + self, + *, + limit: int, + cursor: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[DocumentListResponse, AsyncCursorPage[DocumentListResponse]]: + """ + List knowledge documents for the authenticated user with cursor-based + pagination. + + Args: + limit: The maximum number of items to return per page. + + cursor: Cursor from a previous response for fetching the next page of results. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/v1/documents", + page=AsyncCursorPage[DocumentListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "cursor": cursor, + }, + document_list_params.DocumentListParams, + ), + ), + model=DocumentListResponse, + ) + + async def delete( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Delete a knowledge document. + + This also removes it from all avatars it was + attached to. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/v1/documents/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class DocumentsResourceWithRawResponse: + def __init__(self, documents: DocumentsResource) -> None: + self._documents = documents + + self.create = to_raw_response_wrapper( + documents.create, + ) + self.retrieve = to_raw_response_wrapper( + documents.retrieve, + ) + self.list = to_raw_response_wrapper( + documents.list, + ) + self.delete = to_raw_response_wrapper( + documents.delete, + ) + + +class AsyncDocumentsResourceWithRawResponse: + def __init__(self, documents: AsyncDocumentsResource) -> None: + self._documents = documents + + self.create = async_to_raw_response_wrapper( + documents.create, + ) + self.retrieve = async_to_raw_response_wrapper( + documents.retrieve, + ) + self.list = async_to_raw_response_wrapper( + documents.list, + ) + self.delete = async_to_raw_response_wrapper( + documents.delete, + ) + + +class DocumentsResourceWithStreamingResponse: + def __init__(self, documents: DocumentsResource) -> None: + self._documents = documents + + self.create = to_streamed_response_wrapper( + documents.create, + ) + self.retrieve = to_streamed_response_wrapper( + documents.retrieve, + ) + self.list = to_streamed_response_wrapper( + documents.list, + ) + self.delete = to_streamed_response_wrapper( + documents.delete, + ) + + +class AsyncDocumentsResourceWithStreamingResponse: + def __init__(self, documents: AsyncDocumentsResource) -> None: + self._documents = documents + + self.create = async_to_streamed_response_wrapper( + documents.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + documents.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + documents.list, + ) + self.delete = async_to_streamed_response_wrapper( + documents.delete, + ) diff --git a/src/runwayml/resources/realtime_sessions.py b/src/runwayml/resources/realtime_sessions.py new file mode 100644 index 0000000..fc5281a --- /dev/null +++ b/src/runwayml/resources/realtime_sessions.py @@ -0,0 +1,365 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Any, cast +from typing_extensions import Literal + +import httpx + +from ..types import realtime_session_create_params +from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from .._utils import maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.realtime_session_create_response import RealtimeSessionCreateResponse +from ..types.realtime_session_retrieve_response import RealtimeSessionRetrieveResponse + +__all__ = ["RealtimeSessionsResource", "AsyncRealtimeSessionsResource"] + + +class RealtimeSessionsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RealtimeSessionsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/runwayml/sdk-python#accessing-raw-response-data-eg-headers + """ + return RealtimeSessionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RealtimeSessionsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/runwayml/sdk-python#with_streaming_response + """ + return RealtimeSessionsResourceWithStreamingResponse(self) + + def create( + self, + *, + avatar: realtime_session_create_params.Avatar, + model: Literal["gwm1_avatars"], + max_duration: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RealtimeSessionCreateResponse: + """ + Create a new realtime session with the specified model configuration. + + Args: + avatar: The avatar configuration for the session. + + model: The realtime session model type. + + max_duration: Maximum session duration in seconds. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/v1/realtime_sessions", + body=maybe_transform( + { + "avatar": avatar, + "model": model, + "max_duration": max_duration, + }, + realtime_session_create_params.RealtimeSessionCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RealtimeSessionCreateResponse, + ) + + def retrieve( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RealtimeSessionRetrieveResponse: + """ + Get the status of a realtime session. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return cast( + RealtimeSessionRetrieveResponse, + self._get( + f"/v1/realtime_sessions/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast( + Any, RealtimeSessionRetrieveResponse + ), # Union types cannot be passed in as arguments in the type system + ), + ) + + def delete( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Cancel an active realtime session. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/v1/realtime_sessions/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncRealtimeSessionsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRealtimeSessionsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/runwayml/sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncRealtimeSessionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRealtimeSessionsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/runwayml/sdk-python#with_streaming_response + """ + return AsyncRealtimeSessionsResourceWithStreamingResponse(self) + + async def create( + self, + *, + avatar: realtime_session_create_params.Avatar, + model: Literal["gwm1_avatars"], + max_duration: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RealtimeSessionCreateResponse: + """ + Create a new realtime session with the specified model configuration. + + Args: + avatar: The avatar configuration for the session. + + model: The realtime session model type. + + max_duration: Maximum session duration in seconds. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/v1/realtime_sessions", + body=await async_maybe_transform( + { + "avatar": avatar, + "model": model, + "max_duration": max_duration, + }, + realtime_session_create_params.RealtimeSessionCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RealtimeSessionCreateResponse, + ) + + async def retrieve( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RealtimeSessionRetrieveResponse: + """ + Get the status of a realtime session. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return cast( + RealtimeSessionRetrieveResponse, + await self._get( + f"/v1/realtime_sessions/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast( + Any, RealtimeSessionRetrieveResponse + ), # Union types cannot be passed in as arguments in the type system + ), + ) + + async def delete( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Cancel an active realtime session. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/v1/realtime_sessions/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class RealtimeSessionsResourceWithRawResponse: + def __init__(self, realtime_sessions: RealtimeSessionsResource) -> None: + self._realtime_sessions = realtime_sessions + + self.create = to_raw_response_wrapper( + realtime_sessions.create, + ) + self.retrieve = to_raw_response_wrapper( + realtime_sessions.retrieve, + ) + self.delete = to_raw_response_wrapper( + realtime_sessions.delete, + ) + + +class AsyncRealtimeSessionsResourceWithRawResponse: + def __init__(self, realtime_sessions: AsyncRealtimeSessionsResource) -> None: + self._realtime_sessions = realtime_sessions + + self.create = async_to_raw_response_wrapper( + realtime_sessions.create, + ) + self.retrieve = async_to_raw_response_wrapper( + realtime_sessions.retrieve, + ) + self.delete = async_to_raw_response_wrapper( + realtime_sessions.delete, + ) + + +class RealtimeSessionsResourceWithStreamingResponse: + def __init__(self, realtime_sessions: RealtimeSessionsResource) -> None: + self._realtime_sessions = realtime_sessions + + self.create = to_streamed_response_wrapper( + realtime_sessions.create, + ) + self.retrieve = to_streamed_response_wrapper( + realtime_sessions.retrieve, + ) + self.delete = to_streamed_response_wrapper( + realtime_sessions.delete, + ) + + +class AsyncRealtimeSessionsResourceWithStreamingResponse: + def __init__(self, realtime_sessions: AsyncRealtimeSessionsResource) -> None: + self._realtime_sessions = realtime_sessions + + self.create = async_to_streamed_response_wrapper( + realtime_sessions.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + realtime_sessions.retrieve, + ) + self.delete = async_to_streamed_response_wrapper( + realtime_sessions.delete, + ) diff --git a/src/runwayml/resources/voices.py b/src/runwayml/resources/voices.py new file mode 100644 index 0000000..3636ad9 --- /dev/null +++ b/src/runwayml/resources/voices.py @@ -0,0 +1,580 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Any, Optional, cast +from typing_extensions import Literal + +import httpx + +from ..types import voice_list_params, voice_create_params, voice_preview_params +from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from .._utils import maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..pagination import SyncCursorPage, AsyncCursorPage +from .._base_client import AsyncPaginator, make_request_options +from ..types.voice_list_response import VoiceListResponse +from ..types.voice_create_response import VoiceCreateResponse +from ..types.voice_preview_response import VoicePreviewResponse +from ..types.voice_retrieve_response import VoiceRetrieveResponse + +__all__ = ["VoicesResource", "AsyncVoicesResource"] + + +class VoicesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> VoicesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/runwayml/sdk-python#accessing-raw-response-data-eg-headers + """ + return VoicesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> VoicesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/runwayml/sdk-python#with_streaming_response + """ + return VoicesResourceWithStreamingResponse(self) + + def create( + self, + *, + from_: voice_create_params.From, + name: str, + description: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VoiceCreateResponse: + """ + Create a custom voice from a text description. + + Args: + from_: The source configuration for creating the voice. + + name: A name for the voice. + + description: An optional description of the voice. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/v1/voices", + body=maybe_transform( + { + "from_": from_, + "name": name, + "description": description, + }, + voice_create_params.VoiceCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VoiceCreateResponse, + ) + + def retrieve( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VoiceRetrieveResponse: + """ + Get details about a specific custom voice. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return cast( + VoiceRetrieveResponse, + self._get( + f"/v1/voices/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast( + Any, VoiceRetrieveResponse + ), # Union types cannot be passed in as arguments in the type system + ), + ) + + def list( + self, + *, + limit: int, + cursor: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncCursorPage[VoiceListResponse]: + """ + List custom voices for the authenticated organization with cursor-based + pagination. + + Args: + limit: The maximum number of items to return per page. + + cursor: Cursor from a previous response for fetching the next page of results. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/v1/voices", + page=SyncCursorPage[VoiceListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "cursor": cursor, + }, + voice_list_params.VoiceListParams, + ), + ), + model=cast(Any, VoiceListResponse), # Union types cannot be passed in as arguments in the type system + ) + + def delete( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a custom voice. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/v1/voices/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def preview( + self, + *, + model: Literal["eleven_multilingual_ttv_v2", "eleven_ttv_v3"], + prompt: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VoicePreviewResponse: + """Generate a short audio preview of a voice from a text description. + + Use this to + audition a voice before creating it. + + Args: + model: The voice design model to use. + + prompt: A text description of the desired voice characteristics. Must be at least 20 + characters. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/v1/voices/preview", + body=maybe_transform( + { + "model": model, + "prompt": prompt, + }, + voice_preview_params.VoicePreviewParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VoicePreviewResponse, + ) + + +class AsyncVoicesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncVoicesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/runwayml/sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncVoicesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncVoicesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/runwayml/sdk-python#with_streaming_response + """ + return AsyncVoicesResourceWithStreamingResponse(self) + + async def create( + self, + *, + from_: voice_create_params.From, + name: str, + description: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VoiceCreateResponse: + """ + Create a custom voice from a text description. + + Args: + from_: The source configuration for creating the voice. + + name: A name for the voice. + + description: An optional description of the voice. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/v1/voices", + body=await async_maybe_transform( + { + "from_": from_, + "name": name, + "description": description, + }, + voice_create_params.VoiceCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VoiceCreateResponse, + ) + + async def retrieve( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VoiceRetrieveResponse: + """ + Get details about a specific custom voice. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return cast( + VoiceRetrieveResponse, + await self._get( + f"/v1/voices/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast( + Any, VoiceRetrieveResponse + ), # Union types cannot be passed in as arguments in the type system + ), + ) + + def list( + self, + *, + limit: int, + cursor: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[VoiceListResponse, AsyncCursorPage[VoiceListResponse]]: + """ + List custom voices for the authenticated organization with cursor-based + pagination. + + Args: + limit: The maximum number of items to return per page. + + cursor: Cursor from a previous response for fetching the next page of results. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/v1/voices", + page=AsyncCursorPage[VoiceListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "cursor": cursor, + }, + voice_list_params.VoiceListParams, + ), + ), + model=cast(Any, VoiceListResponse), # Union types cannot be passed in as arguments in the type system + ) + + async def delete( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a custom voice. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/v1/voices/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def preview( + self, + *, + model: Literal["eleven_multilingual_ttv_v2", "eleven_ttv_v3"], + prompt: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VoicePreviewResponse: + """Generate a short audio preview of a voice from a text description. + + Use this to + audition a voice before creating it. + + Args: + model: The voice design model to use. + + prompt: A text description of the desired voice characteristics. Must be at least 20 + characters. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/v1/voices/preview", + body=await async_maybe_transform( + { + "model": model, + "prompt": prompt, + }, + voice_preview_params.VoicePreviewParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VoicePreviewResponse, + ) + + +class VoicesResourceWithRawResponse: + def __init__(self, voices: VoicesResource) -> None: + self._voices = voices + + self.create = to_raw_response_wrapper( + voices.create, + ) + self.retrieve = to_raw_response_wrapper( + voices.retrieve, + ) + self.list = to_raw_response_wrapper( + voices.list, + ) + self.delete = to_raw_response_wrapper( + voices.delete, + ) + self.preview = to_raw_response_wrapper( + voices.preview, + ) + + +class AsyncVoicesResourceWithRawResponse: + def __init__(self, voices: AsyncVoicesResource) -> None: + self._voices = voices + + self.create = async_to_raw_response_wrapper( + voices.create, + ) + self.retrieve = async_to_raw_response_wrapper( + voices.retrieve, + ) + self.list = async_to_raw_response_wrapper( + voices.list, + ) + self.delete = async_to_raw_response_wrapper( + voices.delete, + ) + self.preview = async_to_raw_response_wrapper( + voices.preview, + ) + + +class VoicesResourceWithStreamingResponse: + def __init__(self, voices: VoicesResource) -> None: + self._voices = voices + + self.create = to_streamed_response_wrapper( + voices.create, + ) + self.retrieve = to_streamed_response_wrapper( + voices.retrieve, + ) + self.list = to_streamed_response_wrapper( + voices.list, + ) + self.delete = to_streamed_response_wrapper( + voices.delete, + ) + self.preview = to_streamed_response_wrapper( + voices.preview, + ) + + +class AsyncVoicesResourceWithStreamingResponse: + def __init__(self, voices: AsyncVoicesResource) -> None: + self._voices = voices + + self.create = async_to_streamed_response_wrapper( + voices.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + voices.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + voices.list, + ) + self.delete = async_to_streamed_response_wrapper( + voices.delete, + ) + self.preview = async_to_streamed_response_wrapper( + voices.preview, + ) diff --git a/src/runwayml/types/__init__.py b/src/runwayml/types/__init__.py index 7dd42d4..1d7a4d9 100644 --- a/src/runwayml/types/__init__.py +++ b/src/runwayml/types/__init__.py @@ -2,7 +2,26 @@ from __future__ import annotations +from .voice_list_params import VoiceListParams as VoiceListParams +from .avatar_list_params import AvatarListParams as AvatarListParams +from .voice_create_params import VoiceCreateParams as VoiceCreateParams +from .voice_list_response import VoiceListResponse as VoiceListResponse +from .avatar_create_params import AvatarCreateParams as AvatarCreateParams +from .avatar_list_response import AvatarListResponse as AvatarListResponse +from .avatar_update_params import AvatarUpdateParams as AvatarUpdateParams +from .document_list_params import DocumentListParams as DocumentListParams +from .voice_preview_params import VoicePreviewParams as VoicePreviewParams +from .voice_create_response import VoiceCreateResponse as VoiceCreateResponse +from .avatar_create_response import AvatarCreateResponse as AvatarCreateResponse +from .avatar_update_response import AvatarUpdateResponse as AvatarUpdateResponse +from .document_create_params import DocumentCreateParams as DocumentCreateParams +from .document_list_response import DocumentListResponse as DocumentListResponse from .task_retrieve_response import TaskRetrieveResponse as TaskRetrieveResponse +from .voice_preview_response import VoicePreviewResponse as VoicePreviewResponse +from .voice_retrieve_response import VoiceRetrieveResponse as VoiceRetrieveResponse +from .avatar_retrieve_response import AvatarRetrieveResponse as AvatarRetrieveResponse +from .document_create_response import DocumentCreateResponse as DocumentCreateResponse +from .document_retrieve_response import DocumentRetrieveResponse as DocumentRetrieveResponse from .sound_effect_create_params import SoundEffectCreateParams as SoundEffectCreateParams from .text_to_image_create_params import TextToImageCreateParams as TextToImageCreateParams from .text_to_video_create_params import TextToVideoCreateParams as TextToVideoCreateParams @@ -17,12 +36,15 @@ from .voice_isolation_create_params import VoiceIsolationCreateParams as VoiceIsolationCreateParams from .image_to_video_create_response import ImageToVideoCreateResponse as ImageToVideoCreateResponse from .organization_retrieve_response import OrganizationRetrieveResponse as OrganizationRetrieveResponse +from .realtime_session_create_params import RealtimeSessionCreateParams as RealtimeSessionCreateParams from .speech_to_speech_create_params import SpeechToSpeechCreateParams as SpeechToSpeechCreateParams from .text_to_speech_create_response import TextToSpeechCreateResponse as TextToSpeechCreateResponse from .video_to_video_create_response import VideoToVideoCreateResponse as VideoToVideoCreateResponse from .voice_isolation_create_response import VoiceIsolationCreateResponse as VoiceIsolationCreateResponse +from .realtime_session_create_response import RealtimeSessionCreateResponse as RealtimeSessionCreateResponse from .speech_to_speech_create_response import SpeechToSpeechCreateResponse as SpeechToSpeechCreateResponse from .organization_retrieve_usage_params import OrganizationRetrieveUsageParams as OrganizationRetrieveUsageParams +from .realtime_session_retrieve_response import RealtimeSessionRetrieveResponse as RealtimeSessionRetrieveResponse from .character_performance_create_params import CharacterPerformanceCreateParams as CharacterPerformanceCreateParams from .organization_retrieve_usage_response import OrganizationRetrieveUsageResponse as OrganizationRetrieveUsageResponse from .character_performance_create_response import ( diff --git a/src/runwayml/types/avatar_create_params.py b/src/runwayml/types/avatar_create_params.py new file mode 100644 index 0000000..2574c91 --- /dev/null +++ b/src/runwayml/types/avatar_create_params.py @@ -0,0 +1,107 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict + +from .._types import SequenceNotStr +from .._utils import PropertyInfo + +__all__ = ["AvatarCreateParams", "Voice", "VoiceRunwayLivePreset", "VoiceCustom"] + + +class AvatarCreateParams(TypedDict, total=False): + name: Required[str] + """The character name for the avatar.""" + + personality: Required[str] + """System prompt defining how the avatar should behave in conversations.""" + + reference_image: Required[Annotated[str, PropertyInfo(alias="referenceImage")]] + """A HTTPS URL.""" + + voice: Required[Voice] + """The voice configuration for the avatar.""" + + document_ids: Annotated[SequenceNotStr[str], PropertyInfo(alias="documentIds")] + """Optional list of knowledge document IDs to attach to this avatar. + + Documents provide additional context during conversations. + """ + + image_processing: Annotated[Literal["optimize", "none"], PropertyInfo(alias="imageProcessing")] + """Controls image preprocessing. + + `optimize` improves the image for better avatar results. `none` uses the image + as-is; quality not guaranteed. + """ + + start_script: Annotated[str, PropertyInfo(alias="startScript")] + """Optional opening message that the avatar will say when a session starts.""" + + +class VoiceRunwayLivePreset(TypedDict, total=False): + """A preset voice from the Runway API.""" + + preset_id: Required[ + Annotated[ + Literal[ + "victoria", + "vincent", + "clara", + "drew", + "skye", + "max", + "morgan", + "felix", + "mia", + "marcus", + "summer", + "ruby", + "aurora", + "jasper", + "leo", + "adrian", + "nina", + "emma", + "blake", + "david", + "maya", + "nathan", + "sam", + "georgia", + "petra", + "adam", + "zach", + "violet", + "roman", + "luna", + ], + PropertyInfo(alias="presetId"), + ] + ] + """The ID of a preset voice. + + Available voices: `victoria` (Victoria), `vincent` (Vincent), `clara` (Clara), + `drew` (Drew), `skye` (Skye), `max` (Max), `morgan` (Morgan), `felix` (Felix), + `mia` (Mia), `marcus` (Marcus), `summer` (Summer), `ruby` (Ruby), `aurora` + (Aurora), `jasper` (Jasper), `leo` (Leo), `adrian` (Adrian), `nina` (Nina), + `emma` (Emma), `blake` (Blake), `david` (David), `maya` (Maya), `nathan` + (Nathan), `sam` (Sam), `georgia` (Georgia), `petra` (Petra), `adam` (Adam), + `zach` (Zach), `violet` (Violet), `roman` (Roman), `luna` (Luna). + """ + + type: Required[Literal["runway-live-preset"]] + + +class VoiceCustom(TypedDict, total=False): + """A custom voice created via the Voices API.""" + + id: Required[str] + """The ID of a custom voice created via the Voices API.""" + + type: Required[Literal["custom"]] + + +Voice: TypeAlias = Union[VoiceRunwayLivePreset, VoiceCustom] diff --git a/src/runwayml/types/avatar_create_response.py b/src/runwayml/types/avatar_create_response.py new file mode 100644 index 0000000..8b5f990 --- /dev/null +++ b/src/runwayml/types/avatar_create_response.py @@ -0,0 +1,368 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from .._utils import PropertyInfo +from .._models import BaseModel + +__all__ = [ + "AvatarCreateResponse", + "Processing", + "ProcessingVoice", + "ProcessingVoiceRunwayLivePreset", + "ProcessingVoiceCustom", + "Ready", + "ReadyVoice", + "ReadyVoiceRunwayLivePreset", + "ReadyVoiceCustom", + "Failed", + "FailedVoice", + "FailedVoiceRunwayLivePreset", + "FailedVoiceCustom", +] + + +class ProcessingVoiceRunwayLivePreset(BaseModel): + """A preset voice from the Runway API.""" + + description: str + """A brief description of the voice characteristics.""" + + name: str + """The display name of the voice.""" + + preset_id: Literal[ + "victoria", + "vincent", + "clara", + "drew", + "skye", + "max", + "morgan", + "felix", + "mia", + "marcus", + "summer", + "ruby", + "aurora", + "jasper", + "leo", + "adrian", + "nina", + "emma", + "blake", + "david", + "maya", + "nathan", + "sam", + "georgia", + "petra", + "adam", + "zach", + "violet", + "roman", + "luna", + ] = FieldInfo(alias="presetId") + """The preset voice identifier.""" + + type: Literal["runway-live-preset"] + + +class ProcessingVoiceCustom(BaseModel): + """A custom voice created via the Voices API.""" + + id: str + """The unique identifier of the custom voice.""" + + deleted: bool + """Whether the voice has been deleted. + + When true, name and description are omitted. + """ + + type: Literal["custom"] + + description: Optional[str] = None + """A brief description of the voice characteristics.""" + + name: Optional[str] = None + """The display name of the voice.""" + + +ProcessingVoice: TypeAlias = Annotated[ + Union[ProcessingVoiceRunwayLivePreset, ProcessingVoiceCustom], PropertyInfo(discriminator="type") +] + + +class Processing(BaseModel): + """An avatar that is still being processed.""" + + id: str + """The unique identifier of the avatar.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the avatar was created.""" + + document_ids: List[str] = FieldInfo(alias="documentIds") + """IDs of knowledge documents attached to this avatar.""" + + name: str + """The character name for the avatar.""" + + personality: str + """System prompt defining how the avatar should behave in conversations.""" + + processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None) + """A URI pointing to a low-resolution preview of the processed reference image.""" + + reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None) + """A URI pointing to a low-resolution preview of the avatar's reference image.""" + + start_script: Optional[str] = FieldInfo(alias="startScript", default=None) + """ + Opening message that the avatar will say when a session starts, or null if not + set. + """ + + status: Literal["PROCESSING"] + + updated_at: datetime = FieldInfo(alias="updatedAt") + """When the avatar was last updated.""" + + voice: ProcessingVoice + """The voice configured for this avatar.""" + + +class ReadyVoiceRunwayLivePreset(BaseModel): + """A preset voice from the Runway API.""" + + description: str + """A brief description of the voice characteristics.""" + + name: str + """The display name of the voice.""" + + preset_id: Literal[ + "victoria", + "vincent", + "clara", + "drew", + "skye", + "max", + "morgan", + "felix", + "mia", + "marcus", + "summer", + "ruby", + "aurora", + "jasper", + "leo", + "adrian", + "nina", + "emma", + "blake", + "david", + "maya", + "nathan", + "sam", + "georgia", + "petra", + "adam", + "zach", + "violet", + "roman", + "luna", + ] = FieldInfo(alias="presetId") + """The preset voice identifier.""" + + type: Literal["runway-live-preset"] + + +class ReadyVoiceCustom(BaseModel): + """A custom voice created via the Voices API.""" + + id: str + """The unique identifier of the custom voice.""" + + deleted: bool + """Whether the voice has been deleted. + + When true, name and description are omitted. + """ + + type: Literal["custom"] + + description: Optional[str] = None + """A brief description of the voice characteristics.""" + + name: Optional[str] = None + """The display name of the voice.""" + + +ReadyVoice: TypeAlias = Annotated[ + Union[ReadyVoiceRunwayLivePreset, ReadyVoiceCustom], PropertyInfo(discriminator="type") +] + + +class Ready(BaseModel): + """An avatar that is ready for use in sessions.""" + + id: str + """The unique identifier of the avatar.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the avatar was created.""" + + document_ids: List[str] = FieldInfo(alias="documentIds") + """IDs of knowledge documents attached to this avatar.""" + + name: str + """The character name for the avatar.""" + + personality: str + """System prompt defining how the avatar should behave in conversations.""" + + processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None) + """A URI pointing to a low-resolution preview of the processed reference image.""" + + reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None) + """A URI pointing to a low-resolution preview of the avatar's reference image.""" + + start_script: Optional[str] = FieldInfo(alias="startScript", default=None) + """ + Opening message that the avatar will say when a session starts, or null if not + set. + """ + + status: Literal["READY"] + + updated_at: datetime = FieldInfo(alias="updatedAt") + """When the avatar was last updated.""" + + voice: ReadyVoice + """The voice configured for this avatar.""" + + +class FailedVoiceRunwayLivePreset(BaseModel): + """A preset voice from the Runway API.""" + + description: str + """A brief description of the voice characteristics.""" + + name: str + """The display name of the voice.""" + + preset_id: Literal[ + "victoria", + "vincent", + "clara", + "drew", + "skye", + "max", + "morgan", + "felix", + "mia", + "marcus", + "summer", + "ruby", + "aurora", + "jasper", + "leo", + "adrian", + "nina", + "emma", + "blake", + "david", + "maya", + "nathan", + "sam", + "georgia", + "petra", + "adam", + "zach", + "violet", + "roman", + "luna", + ] = FieldInfo(alias="presetId") + """The preset voice identifier.""" + + type: Literal["runway-live-preset"] + + +class FailedVoiceCustom(BaseModel): + """A custom voice created via the Voices API.""" + + id: str + """The unique identifier of the custom voice.""" + + deleted: bool + """Whether the voice has been deleted. + + When true, name and description are omitted. + """ + + type: Literal["custom"] + + description: Optional[str] = None + """A brief description of the voice characteristics.""" + + name: Optional[str] = None + """The display name of the voice.""" + + +FailedVoice: TypeAlias = Annotated[ + Union[FailedVoiceRunwayLivePreset, FailedVoiceCustom], PropertyInfo(discriminator="type") +] + + +class Failed(BaseModel): + """An avatar that failed to finish processing.""" + + id: str + """The unique identifier of the avatar.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the avatar was created.""" + + document_ids: List[str] = FieldInfo(alias="documentIds") + """IDs of knowledge documents attached to this avatar.""" + + failure_reason: str = FieldInfo(alias="failureReason") + """A human-readable error message. + + This value is not stable and should not be matched against programmatically. + """ + + name: str + """The character name for the avatar.""" + + personality: str + """System prompt defining how the avatar should behave in conversations.""" + + processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None) + """A URI pointing to a low-resolution preview of the processed reference image.""" + + reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None) + """A URI pointing to a low-resolution preview of the avatar's reference image.""" + + start_script: Optional[str] = FieldInfo(alias="startScript", default=None) + """ + Opening message that the avatar will say when a session starts, or null if not + set. + """ + + status: Literal["FAILED"] + + updated_at: datetime = FieldInfo(alias="updatedAt") + """When the avatar was last updated.""" + + voice: FailedVoice + """The voice configured for this avatar.""" + + +AvatarCreateResponse: TypeAlias = Annotated[Union[Processing, Ready, Failed], PropertyInfo(discriminator="status")] diff --git a/src/runwayml/types/avatar_list_params.py b/src/runwayml/types/avatar_list_params.py new file mode 100644 index 0000000..051c552 --- /dev/null +++ b/src/runwayml/types/avatar_list_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["AvatarListParams"] + + +class AvatarListParams(TypedDict, total=False): + limit: Required[int] + """The maximum number of items to return per page.""" + + cursor: str + """Cursor from a previous response for fetching the next page of results.""" diff --git a/src/runwayml/types/avatar_list_response.py b/src/runwayml/types/avatar_list_response.py new file mode 100644 index 0000000..fd2e650 --- /dev/null +++ b/src/runwayml/types/avatar_list_response.py @@ -0,0 +1,368 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from .._utils import PropertyInfo +from .._models import BaseModel + +__all__ = [ + "AvatarListResponse", + "Processing", + "ProcessingVoice", + "ProcessingVoiceRunwayLivePreset", + "ProcessingVoiceCustom", + "Ready", + "ReadyVoice", + "ReadyVoiceRunwayLivePreset", + "ReadyVoiceCustom", + "Failed", + "FailedVoice", + "FailedVoiceRunwayLivePreset", + "FailedVoiceCustom", +] + + +class ProcessingVoiceRunwayLivePreset(BaseModel): + """A preset voice from the Runway API.""" + + description: str + """A brief description of the voice characteristics.""" + + name: str + """The display name of the voice.""" + + preset_id: Literal[ + "victoria", + "vincent", + "clara", + "drew", + "skye", + "max", + "morgan", + "felix", + "mia", + "marcus", + "summer", + "ruby", + "aurora", + "jasper", + "leo", + "adrian", + "nina", + "emma", + "blake", + "david", + "maya", + "nathan", + "sam", + "georgia", + "petra", + "adam", + "zach", + "violet", + "roman", + "luna", + ] = FieldInfo(alias="presetId") + """The preset voice identifier.""" + + type: Literal["runway-live-preset"] + + +class ProcessingVoiceCustom(BaseModel): + """A custom voice created via the Voices API.""" + + id: str + """The unique identifier of the custom voice.""" + + deleted: bool + """Whether the voice has been deleted. + + When true, name and description are omitted. + """ + + type: Literal["custom"] + + description: Optional[str] = None + """A brief description of the voice characteristics.""" + + name: Optional[str] = None + """The display name of the voice.""" + + +ProcessingVoice: TypeAlias = Annotated[ + Union[ProcessingVoiceRunwayLivePreset, ProcessingVoiceCustom], PropertyInfo(discriminator="type") +] + + +class Processing(BaseModel): + """An avatar that is still being processed.""" + + id: str + """The unique identifier of the avatar.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the avatar was created.""" + + document_ids: List[str] = FieldInfo(alias="documentIds") + """IDs of knowledge documents attached to this avatar.""" + + name: str + """The character name for the avatar.""" + + personality: str + """System prompt defining how the avatar should behave in conversations.""" + + processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None) + """A URI pointing to a low-resolution preview of the processed reference image.""" + + reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None) + """A URI pointing to a low-resolution preview of the avatar's reference image.""" + + start_script: Optional[str] = FieldInfo(alias="startScript", default=None) + """ + Opening message that the avatar will say when a session starts, or null if not + set. + """ + + status: Literal["PROCESSING"] + + updated_at: datetime = FieldInfo(alias="updatedAt") + """When the avatar was last updated.""" + + voice: ProcessingVoice + """The voice configured for this avatar.""" + + +class ReadyVoiceRunwayLivePreset(BaseModel): + """A preset voice from the Runway API.""" + + description: str + """A brief description of the voice characteristics.""" + + name: str + """The display name of the voice.""" + + preset_id: Literal[ + "victoria", + "vincent", + "clara", + "drew", + "skye", + "max", + "morgan", + "felix", + "mia", + "marcus", + "summer", + "ruby", + "aurora", + "jasper", + "leo", + "adrian", + "nina", + "emma", + "blake", + "david", + "maya", + "nathan", + "sam", + "georgia", + "petra", + "adam", + "zach", + "violet", + "roman", + "luna", + ] = FieldInfo(alias="presetId") + """The preset voice identifier.""" + + type: Literal["runway-live-preset"] + + +class ReadyVoiceCustom(BaseModel): + """A custom voice created via the Voices API.""" + + id: str + """The unique identifier of the custom voice.""" + + deleted: bool + """Whether the voice has been deleted. + + When true, name and description are omitted. + """ + + type: Literal["custom"] + + description: Optional[str] = None + """A brief description of the voice characteristics.""" + + name: Optional[str] = None + """The display name of the voice.""" + + +ReadyVoice: TypeAlias = Annotated[ + Union[ReadyVoiceRunwayLivePreset, ReadyVoiceCustom], PropertyInfo(discriminator="type") +] + + +class Ready(BaseModel): + """An avatar that is ready for use in sessions.""" + + id: str + """The unique identifier of the avatar.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the avatar was created.""" + + document_ids: List[str] = FieldInfo(alias="documentIds") + """IDs of knowledge documents attached to this avatar.""" + + name: str + """The character name for the avatar.""" + + personality: str + """System prompt defining how the avatar should behave in conversations.""" + + processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None) + """A URI pointing to a low-resolution preview of the processed reference image.""" + + reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None) + """A URI pointing to a low-resolution preview of the avatar's reference image.""" + + start_script: Optional[str] = FieldInfo(alias="startScript", default=None) + """ + Opening message that the avatar will say when a session starts, or null if not + set. + """ + + status: Literal["READY"] + + updated_at: datetime = FieldInfo(alias="updatedAt") + """When the avatar was last updated.""" + + voice: ReadyVoice + """The voice configured for this avatar.""" + + +class FailedVoiceRunwayLivePreset(BaseModel): + """A preset voice from the Runway API.""" + + description: str + """A brief description of the voice characteristics.""" + + name: str + """The display name of the voice.""" + + preset_id: Literal[ + "victoria", + "vincent", + "clara", + "drew", + "skye", + "max", + "morgan", + "felix", + "mia", + "marcus", + "summer", + "ruby", + "aurora", + "jasper", + "leo", + "adrian", + "nina", + "emma", + "blake", + "david", + "maya", + "nathan", + "sam", + "georgia", + "petra", + "adam", + "zach", + "violet", + "roman", + "luna", + ] = FieldInfo(alias="presetId") + """The preset voice identifier.""" + + type: Literal["runway-live-preset"] + + +class FailedVoiceCustom(BaseModel): + """A custom voice created via the Voices API.""" + + id: str + """The unique identifier of the custom voice.""" + + deleted: bool + """Whether the voice has been deleted. + + When true, name and description are omitted. + """ + + type: Literal["custom"] + + description: Optional[str] = None + """A brief description of the voice characteristics.""" + + name: Optional[str] = None + """The display name of the voice.""" + + +FailedVoice: TypeAlias = Annotated[ + Union[FailedVoiceRunwayLivePreset, FailedVoiceCustom], PropertyInfo(discriminator="type") +] + + +class Failed(BaseModel): + """An avatar that failed to finish processing.""" + + id: str + """The unique identifier of the avatar.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the avatar was created.""" + + document_ids: List[str] = FieldInfo(alias="documentIds") + """IDs of knowledge documents attached to this avatar.""" + + failure_reason: str = FieldInfo(alias="failureReason") + """A human-readable error message. + + This value is not stable and should not be matched against programmatically. + """ + + name: str + """The character name for the avatar.""" + + personality: str + """System prompt defining how the avatar should behave in conversations.""" + + processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None) + """A URI pointing to a low-resolution preview of the processed reference image.""" + + reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None) + """A URI pointing to a low-resolution preview of the avatar's reference image.""" + + start_script: Optional[str] = FieldInfo(alias="startScript", default=None) + """ + Opening message that the avatar will say when a session starts, or null if not + set. + """ + + status: Literal["FAILED"] + + updated_at: datetime = FieldInfo(alias="updatedAt") + """When the avatar was last updated.""" + + voice: FailedVoice + """The voice configured for this avatar.""" + + +AvatarListResponse: TypeAlias = Annotated[Union[Processing, Ready, Failed], PropertyInfo(discriminator="status")] diff --git a/src/runwayml/types/avatar_retrieve_response.py b/src/runwayml/types/avatar_retrieve_response.py new file mode 100644 index 0000000..0f37a12 --- /dev/null +++ b/src/runwayml/types/avatar_retrieve_response.py @@ -0,0 +1,368 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from .._utils import PropertyInfo +from .._models import BaseModel + +__all__ = [ + "AvatarRetrieveResponse", + "Processing", + "ProcessingVoice", + "ProcessingVoiceRunwayLivePreset", + "ProcessingVoiceCustom", + "Ready", + "ReadyVoice", + "ReadyVoiceRunwayLivePreset", + "ReadyVoiceCustom", + "Failed", + "FailedVoice", + "FailedVoiceRunwayLivePreset", + "FailedVoiceCustom", +] + + +class ProcessingVoiceRunwayLivePreset(BaseModel): + """A preset voice from the Runway API.""" + + description: str + """A brief description of the voice characteristics.""" + + name: str + """The display name of the voice.""" + + preset_id: Literal[ + "victoria", + "vincent", + "clara", + "drew", + "skye", + "max", + "morgan", + "felix", + "mia", + "marcus", + "summer", + "ruby", + "aurora", + "jasper", + "leo", + "adrian", + "nina", + "emma", + "blake", + "david", + "maya", + "nathan", + "sam", + "georgia", + "petra", + "adam", + "zach", + "violet", + "roman", + "luna", + ] = FieldInfo(alias="presetId") + """The preset voice identifier.""" + + type: Literal["runway-live-preset"] + + +class ProcessingVoiceCustom(BaseModel): + """A custom voice created via the Voices API.""" + + id: str + """The unique identifier of the custom voice.""" + + deleted: bool + """Whether the voice has been deleted. + + When true, name and description are omitted. + """ + + type: Literal["custom"] + + description: Optional[str] = None + """A brief description of the voice characteristics.""" + + name: Optional[str] = None + """The display name of the voice.""" + + +ProcessingVoice: TypeAlias = Annotated[ + Union[ProcessingVoiceRunwayLivePreset, ProcessingVoiceCustom], PropertyInfo(discriminator="type") +] + + +class Processing(BaseModel): + """An avatar that is still being processed.""" + + id: str + """The unique identifier of the avatar.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the avatar was created.""" + + document_ids: List[str] = FieldInfo(alias="documentIds") + """IDs of knowledge documents attached to this avatar.""" + + name: str + """The character name for the avatar.""" + + personality: str + """System prompt defining how the avatar should behave in conversations.""" + + processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None) + """A URI pointing to a low-resolution preview of the processed reference image.""" + + reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None) + """A URI pointing to a low-resolution preview of the avatar's reference image.""" + + start_script: Optional[str] = FieldInfo(alias="startScript", default=None) + """ + Opening message that the avatar will say when a session starts, or null if not + set. + """ + + status: Literal["PROCESSING"] + + updated_at: datetime = FieldInfo(alias="updatedAt") + """When the avatar was last updated.""" + + voice: ProcessingVoice + """The voice configured for this avatar.""" + + +class ReadyVoiceRunwayLivePreset(BaseModel): + """A preset voice from the Runway API.""" + + description: str + """A brief description of the voice characteristics.""" + + name: str + """The display name of the voice.""" + + preset_id: Literal[ + "victoria", + "vincent", + "clara", + "drew", + "skye", + "max", + "morgan", + "felix", + "mia", + "marcus", + "summer", + "ruby", + "aurora", + "jasper", + "leo", + "adrian", + "nina", + "emma", + "blake", + "david", + "maya", + "nathan", + "sam", + "georgia", + "petra", + "adam", + "zach", + "violet", + "roman", + "luna", + ] = FieldInfo(alias="presetId") + """The preset voice identifier.""" + + type: Literal["runway-live-preset"] + + +class ReadyVoiceCustom(BaseModel): + """A custom voice created via the Voices API.""" + + id: str + """The unique identifier of the custom voice.""" + + deleted: bool + """Whether the voice has been deleted. + + When true, name and description are omitted. + """ + + type: Literal["custom"] + + description: Optional[str] = None + """A brief description of the voice characteristics.""" + + name: Optional[str] = None + """The display name of the voice.""" + + +ReadyVoice: TypeAlias = Annotated[ + Union[ReadyVoiceRunwayLivePreset, ReadyVoiceCustom], PropertyInfo(discriminator="type") +] + + +class Ready(BaseModel): + """An avatar that is ready for use in sessions.""" + + id: str + """The unique identifier of the avatar.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the avatar was created.""" + + document_ids: List[str] = FieldInfo(alias="documentIds") + """IDs of knowledge documents attached to this avatar.""" + + name: str + """The character name for the avatar.""" + + personality: str + """System prompt defining how the avatar should behave in conversations.""" + + processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None) + """A URI pointing to a low-resolution preview of the processed reference image.""" + + reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None) + """A URI pointing to a low-resolution preview of the avatar's reference image.""" + + start_script: Optional[str] = FieldInfo(alias="startScript", default=None) + """ + Opening message that the avatar will say when a session starts, or null if not + set. + """ + + status: Literal["READY"] + + updated_at: datetime = FieldInfo(alias="updatedAt") + """When the avatar was last updated.""" + + voice: ReadyVoice + """The voice configured for this avatar.""" + + +class FailedVoiceRunwayLivePreset(BaseModel): + """A preset voice from the Runway API.""" + + description: str + """A brief description of the voice characteristics.""" + + name: str + """The display name of the voice.""" + + preset_id: Literal[ + "victoria", + "vincent", + "clara", + "drew", + "skye", + "max", + "morgan", + "felix", + "mia", + "marcus", + "summer", + "ruby", + "aurora", + "jasper", + "leo", + "adrian", + "nina", + "emma", + "blake", + "david", + "maya", + "nathan", + "sam", + "georgia", + "petra", + "adam", + "zach", + "violet", + "roman", + "luna", + ] = FieldInfo(alias="presetId") + """The preset voice identifier.""" + + type: Literal["runway-live-preset"] + + +class FailedVoiceCustom(BaseModel): + """A custom voice created via the Voices API.""" + + id: str + """The unique identifier of the custom voice.""" + + deleted: bool + """Whether the voice has been deleted. + + When true, name and description are omitted. + """ + + type: Literal["custom"] + + description: Optional[str] = None + """A brief description of the voice characteristics.""" + + name: Optional[str] = None + """The display name of the voice.""" + + +FailedVoice: TypeAlias = Annotated[ + Union[FailedVoiceRunwayLivePreset, FailedVoiceCustom], PropertyInfo(discriminator="type") +] + + +class Failed(BaseModel): + """An avatar that failed to finish processing.""" + + id: str + """The unique identifier of the avatar.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the avatar was created.""" + + document_ids: List[str] = FieldInfo(alias="documentIds") + """IDs of knowledge documents attached to this avatar.""" + + failure_reason: str = FieldInfo(alias="failureReason") + """A human-readable error message. + + This value is not stable and should not be matched against programmatically. + """ + + name: str + """The character name for the avatar.""" + + personality: str + """System prompt defining how the avatar should behave in conversations.""" + + processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None) + """A URI pointing to a low-resolution preview of the processed reference image.""" + + reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None) + """A URI pointing to a low-resolution preview of the avatar's reference image.""" + + start_script: Optional[str] = FieldInfo(alias="startScript", default=None) + """ + Opening message that the avatar will say when a session starts, or null if not + set. + """ + + status: Literal["FAILED"] + + updated_at: datetime = FieldInfo(alias="updatedAt") + """When the avatar was last updated.""" + + voice: FailedVoice + """The voice configured for this avatar.""" + + +AvatarRetrieveResponse: TypeAlias = Annotated[Union[Processing, Ready, Failed], PropertyInfo(discriminator="status")] diff --git a/src/runwayml/types/avatar_update_params.py b/src/runwayml/types/avatar_update_params.py new file mode 100644 index 0000000..eb3fe85 --- /dev/null +++ b/src/runwayml/types/avatar_update_params.py @@ -0,0 +1,111 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Optional +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict + +from .._types import SequenceNotStr +from .._utils import PropertyInfo + +__all__ = ["AvatarUpdateParams", "Voice", "VoiceRunwayLivePreset", "VoiceCustom"] + + +class AvatarUpdateParams(TypedDict, total=False): + document_ids: Annotated[SequenceNotStr[str], PropertyInfo(alias="documentIds")] + """List of knowledge document IDs to attach to this avatar. + + Replaces all current attachments. Documents provide additional context during + conversations. + """ + + image_processing: Annotated[Literal["optimize", "none"], PropertyInfo(alias="imageProcessing")] + """Controls image preprocessing. + + `optimize` improves the image for better avatar results. `none` uses the image + as-is; quality not guaranteed. + """ + + name: str + """The character name for the avatar.""" + + personality: str + """System prompt defining how the avatar should behave in conversations.""" + + reference_image: Annotated[str, PropertyInfo(alias="referenceImage")] + """A HTTPS URL.""" + + start_script: Annotated[Optional[str], PropertyInfo(alias="startScript")] + """Optional opening message that the avatar will say when a session starts. + + Set to null to clear. + """ + + voice: Voice + """The voice configuration for the avatar.""" + + +class VoiceRunwayLivePreset(TypedDict, total=False): + """A preset voice from the Runway API.""" + + preset_id: Required[ + Annotated[ + Literal[ + "victoria", + "vincent", + "clara", + "drew", + "skye", + "max", + "morgan", + "felix", + "mia", + "marcus", + "summer", + "ruby", + "aurora", + "jasper", + "leo", + "adrian", + "nina", + "emma", + "blake", + "david", + "maya", + "nathan", + "sam", + "georgia", + "petra", + "adam", + "zach", + "violet", + "roman", + "luna", + ], + PropertyInfo(alias="presetId"), + ] + ] + """The ID of a preset voice. + + Available voices: `victoria` (Victoria), `vincent` (Vincent), `clara` (Clara), + `drew` (Drew), `skye` (Skye), `max` (Max), `morgan` (Morgan), `felix` (Felix), + `mia` (Mia), `marcus` (Marcus), `summer` (Summer), `ruby` (Ruby), `aurora` + (Aurora), `jasper` (Jasper), `leo` (Leo), `adrian` (Adrian), `nina` (Nina), + `emma` (Emma), `blake` (Blake), `david` (David), `maya` (Maya), `nathan` + (Nathan), `sam` (Sam), `georgia` (Georgia), `petra` (Petra), `adam` (Adam), + `zach` (Zach), `violet` (Violet), `roman` (Roman), `luna` (Luna). + """ + + type: Required[Literal["runway-live-preset"]] + + +class VoiceCustom(TypedDict, total=False): + """A custom voice created via the Voices API.""" + + id: Required[str] + """The ID of a custom voice created via the Voices API.""" + + type: Required[Literal["custom"]] + + +Voice: TypeAlias = Union[VoiceRunwayLivePreset, VoiceCustom] diff --git a/src/runwayml/types/avatar_update_response.py b/src/runwayml/types/avatar_update_response.py new file mode 100644 index 0000000..6b9b0c6 --- /dev/null +++ b/src/runwayml/types/avatar_update_response.py @@ -0,0 +1,368 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from .._utils import PropertyInfo +from .._models import BaseModel + +__all__ = [ + "AvatarUpdateResponse", + "Processing", + "ProcessingVoice", + "ProcessingVoiceRunwayLivePreset", + "ProcessingVoiceCustom", + "Ready", + "ReadyVoice", + "ReadyVoiceRunwayLivePreset", + "ReadyVoiceCustom", + "Failed", + "FailedVoice", + "FailedVoiceRunwayLivePreset", + "FailedVoiceCustom", +] + + +class ProcessingVoiceRunwayLivePreset(BaseModel): + """A preset voice from the Runway API.""" + + description: str + """A brief description of the voice characteristics.""" + + name: str + """The display name of the voice.""" + + preset_id: Literal[ + "victoria", + "vincent", + "clara", + "drew", + "skye", + "max", + "morgan", + "felix", + "mia", + "marcus", + "summer", + "ruby", + "aurora", + "jasper", + "leo", + "adrian", + "nina", + "emma", + "blake", + "david", + "maya", + "nathan", + "sam", + "georgia", + "petra", + "adam", + "zach", + "violet", + "roman", + "luna", + ] = FieldInfo(alias="presetId") + """The preset voice identifier.""" + + type: Literal["runway-live-preset"] + + +class ProcessingVoiceCustom(BaseModel): + """A custom voice created via the Voices API.""" + + id: str + """The unique identifier of the custom voice.""" + + deleted: bool + """Whether the voice has been deleted. + + When true, name and description are omitted. + """ + + type: Literal["custom"] + + description: Optional[str] = None + """A brief description of the voice characteristics.""" + + name: Optional[str] = None + """The display name of the voice.""" + + +ProcessingVoice: TypeAlias = Annotated[ + Union[ProcessingVoiceRunwayLivePreset, ProcessingVoiceCustom], PropertyInfo(discriminator="type") +] + + +class Processing(BaseModel): + """An avatar that is still being processed.""" + + id: str + """The unique identifier of the avatar.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the avatar was created.""" + + document_ids: List[str] = FieldInfo(alias="documentIds") + """IDs of knowledge documents attached to this avatar.""" + + name: str + """The character name for the avatar.""" + + personality: str + """System prompt defining how the avatar should behave in conversations.""" + + processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None) + """A URI pointing to a low-resolution preview of the processed reference image.""" + + reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None) + """A URI pointing to a low-resolution preview of the avatar's reference image.""" + + start_script: Optional[str] = FieldInfo(alias="startScript", default=None) + """ + Opening message that the avatar will say when a session starts, or null if not + set. + """ + + status: Literal["PROCESSING"] + + updated_at: datetime = FieldInfo(alias="updatedAt") + """When the avatar was last updated.""" + + voice: ProcessingVoice + """The voice configured for this avatar.""" + + +class ReadyVoiceRunwayLivePreset(BaseModel): + """A preset voice from the Runway API.""" + + description: str + """A brief description of the voice characteristics.""" + + name: str + """The display name of the voice.""" + + preset_id: Literal[ + "victoria", + "vincent", + "clara", + "drew", + "skye", + "max", + "morgan", + "felix", + "mia", + "marcus", + "summer", + "ruby", + "aurora", + "jasper", + "leo", + "adrian", + "nina", + "emma", + "blake", + "david", + "maya", + "nathan", + "sam", + "georgia", + "petra", + "adam", + "zach", + "violet", + "roman", + "luna", + ] = FieldInfo(alias="presetId") + """The preset voice identifier.""" + + type: Literal["runway-live-preset"] + + +class ReadyVoiceCustom(BaseModel): + """A custom voice created via the Voices API.""" + + id: str + """The unique identifier of the custom voice.""" + + deleted: bool + """Whether the voice has been deleted. + + When true, name and description are omitted. + """ + + type: Literal["custom"] + + description: Optional[str] = None + """A brief description of the voice characteristics.""" + + name: Optional[str] = None + """The display name of the voice.""" + + +ReadyVoice: TypeAlias = Annotated[ + Union[ReadyVoiceRunwayLivePreset, ReadyVoiceCustom], PropertyInfo(discriminator="type") +] + + +class Ready(BaseModel): + """An avatar that is ready for use in sessions.""" + + id: str + """The unique identifier of the avatar.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the avatar was created.""" + + document_ids: List[str] = FieldInfo(alias="documentIds") + """IDs of knowledge documents attached to this avatar.""" + + name: str + """The character name for the avatar.""" + + personality: str + """System prompt defining how the avatar should behave in conversations.""" + + processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None) + """A URI pointing to a low-resolution preview of the processed reference image.""" + + reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None) + """A URI pointing to a low-resolution preview of the avatar's reference image.""" + + start_script: Optional[str] = FieldInfo(alias="startScript", default=None) + """ + Opening message that the avatar will say when a session starts, or null if not + set. + """ + + status: Literal["READY"] + + updated_at: datetime = FieldInfo(alias="updatedAt") + """When the avatar was last updated.""" + + voice: ReadyVoice + """The voice configured for this avatar.""" + + +class FailedVoiceRunwayLivePreset(BaseModel): + """A preset voice from the Runway API.""" + + description: str + """A brief description of the voice characteristics.""" + + name: str + """The display name of the voice.""" + + preset_id: Literal[ + "victoria", + "vincent", + "clara", + "drew", + "skye", + "max", + "morgan", + "felix", + "mia", + "marcus", + "summer", + "ruby", + "aurora", + "jasper", + "leo", + "adrian", + "nina", + "emma", + "blake", + "david", + "maya", + "nathan", + "sam", + "georgia", + "petra", + "adam", + "zach", + "violet", + "roman", + "luna", + ] = FieldInfo(alias="presetId") + """The preset voice identifier.""" + + type: Literal["runway-live-preset"] + + +class FailedVoiceCustom(BaseModel): + """A custom voice created via the Voices API.""" + + id: str + """The unique identifier of the custom voice.""" + + deleted: bool + """Whether the voice has been deleted. + + When true, name and description are omitted. + """ + + type: Literal["custom"] + + description: Optional[str] = None + """A brief description of the voice characteristics.""" + + name: Optional[str] = None + """The display name of the voice.""" + + +FailedVoice: TypeAlias = Annotated[ + Union[FailedVoiceRunwayLivePreset, FailedVoiceCustom], PropertyInfo(discriminator="type") +] + + +class Failed(BaseModel): + """An avatar that failed to finish processing.""" + + id: str + """The unique identifier of the avatar.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the avatar was created.""" + + document_ids: List[str] = FieldInfo(alias="documentIds") + """IDs of knowledge documents attached to this avatar.""" + + failure_reason: str = FieldInfo(alias="failureReason") + """A human-readable error message. + + This value is not stable and should not be matched against programmatically. + """ + + name: str + """The character name for the avatar.""" + + personality: str + """System prompt defining how the avatar should behave in conversations.""" + + processed_image_uri: Optional[str] = FieldInfo(alias="processedImageUri", default=None) + """A URI pointing to a low-resolution preview of the processed reference image.""" + + reference_image_uri: Optional[str] = FieldInfo(alias="referenceImageUri", default=None) + """A URI pointing to a low-resolution preview of the avatar's reference image.""" + + start_script: Optional[str] = FieldInfo(alias="startScript", default=None) + """ + Opening message that the avatar will say when a session starts, or null if not + set. + """ + + status: Literal["FAILED"] + + updated_at: datetime = FieldInfo(alias="updatedAt") + """When the avatar was last updated.""" + + voice: FailedVoice + """The voice configured for this avatar.""" + + +AvatarUpdateResponse: TypeAlias = Annotated[Union[Processing, Ready, Failed], PropertyInfo(discriminator="status")] diff --git a/src/runwayml/types/document_create_params.py b/src/runwayml/types/document_create_params.py new file mode 100644 index 0000000..1ea559f --- /dev/null +++ b/src/runwayml/types/document_create_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["DocumentCreateParams"] + + +class DocumentCreateParams(TypedDict, total=False): + content: Required[str] + """The markdown or plain text content of the document.""" + + name: Required[str] + """A descriptive name for the document.""" diff --git a/src/runwayml/types/document_create_response.py b/src/runwayml/types/document_create_response.py new file mode 100644 index 0000000..9277124 --- /dev/null +++ b/src/runwayml/types/document_create_response.py @@ -0,0 +1,45 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["DocumentCreateResponse", "UsedBy"] + + +class UsedBy(BaseModel): + id: str + """The avatar ID.""" + + image_url: Optional[str] = FieldInfo(alias="imageUrl", default=None) + """URL to the avatar image, or null if not yet processed.""" + + name: str + """The avatar name.""" + + +class DocumentCreateResponse(BaseModel): + id: str + """The unique identifier of the document.""" + + content: str + """The full content of the document.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the document was created.""" + + name: str + """The name of the document.""" + + type: Literal["text", "file"] + """The type of document.""" + + updated_at: datetime = FieldInfo(alias="updatedAt") + """When the document was last updated.""" + + used_by: List[UsedBy] = FieldInfo(alias="usedBy") + """Avatars that use this document. Always empty for newly created documents.""" diff --git a/src/runwayml/types/document_list_params.py b/src/runwayml/types/document_list_params.py new file mode 100644 index 0000000..97e5b63 --- /dev/null +++ b/src/runwayml/types/document_list_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["DocumentListParams"] + + +class DocumentListParams(TypedDict, total=False): + limit: Required[int] + """The maximum number of items to return per page.""" + + cursor: str + """Cursor from a previous response for fetching the next page of results.""" diff --git a/src/runwayml/types/document_list_response.py b/src/runwayml/types/document_list_response.py new file mode 100644 index 0000000..d9d65fe --- /dev/null +++ b/src/runwayml/types/document_list_response.py @@ -0,0 +1,42 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["DocumentListResponse", "UsedBy"] + + +class UsedBy(BaseModel): + id: str + """The avatar ID.""" + + image_url: Optional[str] = FieldInfo(alias="imageUrl", default=None) + """URL to the avatar image, or null if not yet processed.""" + + name: str + """The avatar name.""" + + +class DocumentListResponse(BaseModel): + id: str + """The unique identifier of the document.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the document was created.""" + + name: str + """The name of the document.""" + + type: Literal["text", "file"] + """The type of document.""" + + updated_at: datetime = FieldInfo(alias="updatedAt") + """When the document was last updated.""" + + used_by: List[UsedBy] = FieldInfo(alias="usedBy") + """Avatars that use this document.""" diff --git a/src/runwayml/types/document_retrieve_response.py b/src/runwayml/types/document_retrieve_response.py new file mode 100644 index 0000000..de805ec --- /dev/null +++ b/src/runwayml/types/document_retrieve_response.py @@ -0,0 +1,45 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["DocumentRetrieveResponse", "UsedBy"] + + +class UsedBy(BaseModel): + id: str + """The avatar ID.""" + + image_url: Optional[str] = FieldInfo(alias="imageUrl", default=None) + """URL to the avatar image, or null if not yet processed.""" + + name: str + """The avatar name.""" + + +class DocumentRetrieveResponse(BaseModel): + id: str + """The unique identifier of the document.""" + + content: str + """The full content of the document.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the document was created.""" + + name: str + """The name of the document.""" + + type: Literal["text", "file"] + """The type of document.""" + + updated_at: datetime = FieldInfo(alias="updatedAt") + """When the document was last updated.""" + + used_by: List[UsedBy] = FieldInfo(alias="usedBy") + """Avatars that use this document.""" diff --git a/src/runwayml/types/organization_retrieve_usage_response.py b/src/runwayml/types/organization_retrieve_usage_response.py index faefaf2..99326c9 100644 --- a/src/runwayml/types/organization_retrieve_usage_response.py +++ b/src/runwayml/types/organization_retrieve_usage_response.py @@ -32,6 +32,8 @@ class ResultUsedCredit(BaseModel): "eleven_voice_isolation", "eleven_voice_dubbing", "eleven_multilingual_sts_v2", + "gwm1_avatars", + "voice_processing", ] """The model that credits were spent on.""" @@ -66,6 +68,8 @@ class OrganizationRetrieveUsageResponse(BaseModel): "eleven_voice_isolation", "eleven_voice_dubbing", "eleven_multilingual_sts_v2", + "gwm1_avatars", + "voice_processing", ] ] """The list of models with usage during the queried time range.""" diff --git a/src/runwayml/types/realtime_session_create_params.py b/src/runwayml/types/realtime_session_create_params.py new file mode 100644 index 0000000..3cedd9b --- /dev/null +++ b/src/runwayml/types/realtime_session_create_params.py @@ -0,0 +1,57 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["RealtimeSessionCreateParams", "Avatar", "AvatarRunwayPreset", "AvatarCustom"] + + +class RealtimeSessionCreateParams(TypedDict, total=False): + avatar: Required[Avatar] + """The avatar configuration for the session.""" + + model: Required[Literal["gwm1_avatars"]] + """The realtime session model type.""" + + max_duration: Annotated[int, PropertyInfo(alias="maxDuration")] + """Maximum session duration in seconds.""" + + +class AvatarRunwayPreset(TypedDict, total=False): + """A preset avatar from Runway.""" + + preset_id: Required[ + Annotated[ + Literal[ + "game-character", + "music-superstar", + "game-character-man", + "cat-character", + "influencer", + "tennis-coach", + "human-resource", + "fashion-designer", + "cooking-teacher", + ], + PropertyInfo(alias="presetId"), + ] + ] + """ID of a preset avatar.""" + + type: Required[Literal["runway-preset"]] + + +class AvatarCustom(TypedDict, total=False): + """A user-created avatar.""" + + avatar_id: Required[Annotated[str, PropertyInfo(alias="avatarId")]] + """ID of a user-created avatar.""" + + type: Required[Literal["custom"]] + + +Avatar: TypeAlias = Union[AvatarRunwayPreset, AvatarCustom] diff --git a/src/runwayml/types/realtime_session_create_response.py b/src/runwayml/types/realtime_session_create_response.py new file mode 100644 index 0000000..434f3ba --- /dev/null +++ b/src/runwayml/types/realtime_session_create_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel + +__all__ = ["RealtimeSessionCreateResponse"] + + +class RealtimeSessionCreateResponse(BaseModel): + id: str + """The ID of the created realtime session.""" diff --git a/src/runwayml/types/realtime_session_retrieve_response.py b/src/runwayml/types/realtime_session_retrieve_response.py new file mode 100644 index 0000000..2956214 --- /dev/null +++ b/src/runwayml/types/realtime_session_retrieve_response.py @@ -0,0 +1,116 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from .._utils import PropertyInfo +from .._models import BaseModel + +__all__ = ["RealtimeSessionRetrieveResponse", "NotReady", "Ready", "Running", "Completed", "Failed", "Cancelled"] + + +class NotReady(BaseModel): + """A session that is being provisioned.""" + + id: str + """The realtime session ID.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the session was created.""" + + status: Literal["NOT_READY"] + + queued: Optional[bool] = None + """When true, the session is waiting in a queue for available capacity. + + When false or absent, the session is actively being provisioned. + """ + + +class Ready(BaseModel): + """A session that is ready to connect.""" + + id: str + """The realtime session ID.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the session was created.""" + + expires_at: datetime = FieldInfo(alias="expiresAt") + """When the session credentials expire.""" + + session_key: str = FieldInfo(alias="sessionKey") + """Session key for authenticating the /consume endpoint. Use as Bearer token.""" + + status: Literal["READY"] + + +class Running(BaseModel): + """A session with an active WebRTC connection.""" + + id: str + """The realtime session ID.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the session was created.""" + + status: Literal["RUNNING"] + + +class Completed(BaseModel): + """A session that ended normally.""" + + id: str + """The realtime session ID.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the session was created.""" + + duration: int + """The session duration in seconds.""" + + status: Literal["COMPLETED"] + + +class Failed(BaseModel): + """A session that encountered an error.""" + + id: str + """The realtime session ID.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the session was created.""" + + failure: str + """A human-readable error message. + + This value is not stable and should not be matched against programmatically. + """ + + failure_code: str = FieldInfo(alias="failureCode") + """A stable, machine-readable error code. + + See https://docs.dev.runwayml.com/errors/task-failures/ for more information. + """ + + status: Literal["FAILED"] + + +class Cancelled(BaseModel): + """A session that was explicitly cancelled.""" + + id: str + """The realtime session ID.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the session was created.""" + + status: Literal["CANCELLED"] + + +RealtimeSessionRetrieveResponse: TypeAlias = Annotated[ + Union[NotReady, Ready, Running, Completed, Failed, Cancelled], PropertyInfo(discriminator="status") +] diff --git a/src/runwayml/types/voice_create_params.py b/src/runwayml/types/voice_create_params.py new file mode 100644 index 0000000..c008f45 --- /dev/null +++ b/src/runwayml/types/voice_create_params.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["VoiceCreateParams", "From"] + + +class VoiceCreateParams(TypedDict, total=False): + from_: Required[Annotated[From, PropertyInfo(alias="from")]] + """The source configuration for creating the voice.""" + + name: Required[str] + """A name for the voice.""" + + description: Optional[str] + """An optional description of the voice.""" + + +class From(TypedDict, total=False): + """The source configuration for creating the voice.""" + + model: Required[Literal["eleven_multilingual_ttv_v2", "eleven_ttv_v3"]] + """The voice design model to use.""" + + prompt: Required[str] + """A text description of the desired voice characteristics. + + Must be at least 20 characters. + """ + + type: Required[Literal["text"]] diff --git a/src/runwayml/types/voice_create_response.py b/src/runwayml/types/voice_create_response.py new file mode 100644 index 0000000..1bab78e --- /dev/null +++ b/src/runwayml/types/voice_create_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel + +__all__ = ["VoiceCreateResponse"] + + +class VoiceCreateResponse(BaseModel): + id: str + """The ID of the voice that was created.""" diff --git a/src/runwayml/types/voice_list_params.py b/src/runwayml/types/voice_list_params.py new file mode 100644 index 0000000..306876f --- /dev/null +++ b/src/runwayml/types/voice_list_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["VoiceListParams"] + + +class VoiceListParams(TypedDict, total=False): + limit: Required[int] + """The maximum number of items to return per page.""" + + cursor: str + """Cursor from a previous response for fetching the next page of results.""" diff --git a/src/runwayml/types/voice_list_response.py b/src/runwayml/types/voice_list_response.py new file mode 100644 index 0000000..19d691c --- /dev/null +++ b/src/runwayml/types/voice_list_response.py @@ -0,0 +1,81 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from .._utils import PropertyInfo +from .._models import BaseModel + +__all__ = ["VoiceListResponse", "Processing", "Ready", "Failed"] + + +class Processing(BaseModel): + """A voice that is still being processed.""" + + id: str + """The unique identifier of the voice.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the voice was created.""" + + description: Optional[str] = None + """A description of the voice, or null if not set.""" + + name: str + """The name of the voice.""" + + status: Literal["PROCESSING"] + + +class Ready(BaseModel): + """A voice that is ready for use.""" + + id: str + """The unique identifier of the voice.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the voice was created.""" + + description: Optional[str] = None + """A description of the voice, or null if not set.""" + + name: str + """The name of the voice.""" + + preview_url: Optional[str] = FieldInfo(alias="previewUrl", default=None) + """ + A signed URL to an MP3 audio sample of the voice, or null if no sample is + available. + """ + + status: Literal["READY"] + + +class Failed(BaseModel): + """A voice that failed to finish processing.""" + + id: str + """The unique identifier of the voice.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the voice was created.""" + + description: Optional[str] = None + """A description of the voice, or null if not set.""" + + failure_reason: str = FieldInfo(alias="failureReason") + """A human-readable error message. + + This value is not stable and should not be matched against programmatically. + """ + + name: str + """The name of the voice.""" + + status: Literal["FAILED"] + + +VoiceListResponse: TypeAlias = Annotated[Union[Processing, Ready, Failed], PropertyInfo(discriminator="status")] diff --git a/src/runwayml/types/voice_preview_params.py b/src/runwayml/types/voice_preview_params.py new file mode 100644 index 0000000..f603c8a --- /dev/null +++ b/src/runwayml/types/voice_preview_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["VoicePreviewParams"] + + +class VoicePreviewParams(TypedDict, total=False): + model: Required[Literal["eleven_multilingual_ttv_v2", "eleven_ttv_v3"]] + """The voice design model to use.""" + + prompt: Required[str] + """A text description of the desired voice characteristics. + + Must be at least 20 characters. + """ diff --git a/src/runwayml/types/voice_preview_response.py b/src/runwayml/types/voice_preview_response.py new file mode 100644 index 0000000..716a051 --- /dev/null +++ b/src/runwayml/types/voice_preview_response.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["VoicePreviewResponse"] + + +class VoicePreviewResponse(BaseModel): + duration_secs: float = FieldInfo(alias="durationSecs") + """Duration of the audio preview in seconds.""" + + url: str + """A presigned URL to the audio preview. The URL expires after 24 hours.""" diff --git a/src/runwayml/types/voice_retrieve_response.py b/src/runwayml/types/voice_retrieve_response.py new file mode 100644 index 0000000..5aa18e6 --- /dev/null +++ b/src/runwayml/types/voice_retrieve_response.py @@ -0,0 +1,81 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from .._utils import PropertyInfo +from .._models import BaseModel + +__all__ = ["VoiceRetrieveResponse", "Processing", "Ready", "Failed"] + + +class Processing(BaseModel): + """A voice that is still being processed.""" + + id: str + """The unique identifier of the voice.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the voice was created.""" + + description: Optional[str] = None + """A description of the voice, or null if not set.""" + + name: str + """The name of the voice.""" + + status: Literal["PROCESSING"] + + +class Ready(BaseModel): + """A voice that is ready for use.""" + + id: str + """The unique identifier of the voice.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the voice was created.""" + + description: Optional[str] = None + """A description of the voice, or null if not set.""" + + name: str + """The name of the voice.""" + + preview_url: Optional[str] = FieldInfo(alias="previewUrl", default=None) + """ + A signed URL to an MP3 audio sample of the voice, or null if no sample is + available. + """ + + status: Literal["READY"] + + +class Failed(BaseModel): + """A voice that failed to finish processing.""" + + id: str + """The unique identifier of the voice.""" + + created_at: datetime = FieldInfo(alias="createdAt") + """When the voice was created.""" + + description: Optional[str] = None + """A description of the voice, or null if not set.""" + + failure_reason: str = FieldInfo(alias="failureReason") + """A human-readable error message. + + This value is not stable and should not be matched against programmatically. + """ + + name: str + """The name of the voice.""" + + status: Literal["FAILED"] + + +VoiceRetrieveResponse: TypeAlias = Annotated[Union[Processing, Ready, Failed], PropertyInfo(discriminator="status")] diff --git a/tests/api_resources/test_avatars.py b/tests/api_resources/test_avatars.py new file mode 100644 index 0000000..3ba4a33 --- /dev/null +++ b/tests/api_resources/test_avatars.py @@ -0,0 +1,500 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from runwayml import RunwayML, AsyncRunwayML +from tests.utils import assert_matches_type +from runwayml.types import ( + AvatarListResponse, + AvatarCreateResponse, + AvatarUpdateResponse, + AvatarRetrieveResponse, +) +from runwayml.pagination import SyncCursorPage, AsyncCursorPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAvatars: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: RunwayML) -> None: + avatar = client.avatars.create( + name="x", + personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.", + reference_image="https://example.com/reference.jpg", + voice={ + "preset_id": "adrian", + "type": "runway-live-preset", + }, + ) + assert_matches_type(AvatarCreateResponse, avatar, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: RunwayML) -> None: + avatar = client.avatars.create( + name="x", + personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.", + reference_image="https://example.com/reference.jpg", + voice={ + "preset_id": "adrian", + "type": "runway-live-preset", + }, + document_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + image_processing="optimize", + start_script="Hello! How can I help you today?", + ) + assert_matches_type(AvatarCreateResponse, avatar, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: RunwayML) -> None: + response = client.avatars.with_raw_response.create( + name="x", + personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.", + reference_image="https://example.com/reference.jpg", + voice={ + "preset_id": "adrian", + "type": "runway-live-preset", + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + avatar = response.parse() + assert_matches_type(AvatarCreateResponse, avatar, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: RunwayML) -> None: + with client.avatars.with_streaming_response.create( + name="x", + personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.", + reference_image="https://example.com/reference.jpg", + voice={ + "preset_id": "adrian", + "type": "runway-live-preset", + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + avatar = response.parse() + assert_matches_type(AvatarCreateResponse, avatar, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: RunwayML) -> None: + avatar = client.avatars.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(AvatarRetrieveResponse, avatar, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: RunwayML) -> None: + response = client.avatars.with_raw_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + avatar = response.parse() + assert_matches_type(AvatarRetrieveResponse, avatar, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: RunwayML) -> None: + with client.avatars.with_streaming_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + avatar = response.parse() + assert_matches_type(AvatarRetrieveResponse, avatar, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: RunwayML) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.avatars.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_update(self, client: RunwayML) -> None: + avatar = client.avatars.update( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(AvatarUpdateResponse, avatar, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: RunwayML) -> None: + avatar = client.avatars.update( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + document_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + image_processing="optimize", + name="x", + personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.", + reference_image="https://example.com/reference.jpg", + start_script="Hello! How can I help you today?", + voice={ + "preset_id": "adrian", + "type": "runway-live-preset", + }, + ) + assert_matches_type(AvatarUpdateResponse, avatar, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: RunwayML) -> None: + response = client.avatars.with_raw_response.update( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + avatar = response.parse() + assert_matches_type(AvatarUpdateResponse, avatar, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: RunwayML) -> None: + with client.avatars.with_streaming_response.update( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + avatar = response.parse() + assert_matches_type(AvatarUpdateResponse, avatar, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: RunwayML) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.avatars.with_raw_response.update( + id="", + ) + + @parametrize + def test_method_list(self, client: RunwayML) -> None: + avatar = client.avatars.list( + limit=1, + ) + assert_matches_type(SyncCursorPage[AvatarListResponse], avatar, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: RunwayML) -> None: + avatar = client.avatars.list( + limit=1, + cursor="x", + ) + assert_matches_type(SyncCursorPage[AvatarListResponse], avatar, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: RunwayML) -> None: + response = client.avatars.with_raw_response.list( + limit=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + avatar = response.parse() + assert_matches_type(SyncCursorPage[AvatarListResponse], avatar, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: RunwayML) -> None: + with client.avatars.with_streaming_response.list( + limit=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + avatar = response.parse() + assert_matches_type(SyncCursorPage[AvatarListResponse], avatar, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: RunwayML) -> None: + avatar = client.avatars.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert avatar is None + + @parametrize + def test_raw_response_delete(self, client: RunwayML) -> None: + response = client.avatars.with_raw_response.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + avatar = response.parse() + assert avatar is None + + @parametrize + def test_streaming_response_delete(self, client: RunwayML) -> None: + with client.avatars.with_streaming_response.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + avatar = response.parse() + assert avatar is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: RunwayML) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.avatars.with_raw_response.delete( + "", + ) + + +class TestAsyncAvatars: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncRunwayML) -> None: + avatar = await async_client.avatars.create( + name="x", + personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.", + reference_image="https://example.com/reference.jpg", + voice={ + "preset_id": "adrian", + "type": "runway-live-preset", + }, + ) + assert_matches_type(AvatarCreateResponse, avatar, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncRunwayML) -> None: + avatar = await async_client.avatars.create( + name="x", + personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.", + reference_image="https://example.com/reference.jpg", + voice={ + "preset_id": "adrian", + "type": "runway-live-preset", + }, + document_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + image_processing="optimize", + start_script="Hello! How can I help you today?", + ) + assert_matches_type(AvatarCreateResponse, avatar, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncRunwayML) -> None: + response = await async_client.avatars.with_raw_response.create( + name="x", + personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.", + reference_image="https://example.com/reference.jpg", + voice={ + "preset_id": "adrian", + "type": "runway-live-preset", + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + avatar = await response.parse() + assert_matches_type(AvatarCreateResponse, avatar, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncRunwayML) -> None: + async with async_client.avatars.with_streaming_response.create( + name="x", + personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.", + reference_image="https://example.com/reference.jpg", + voice={ + "preset_id": "adrian", + "type": "runway-live-preset", + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + avatar = await response.parse() + assert_matches_type(AvatarCreateResponse, avatar, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncRunwayML) -> None: + avatar = await async_client.avatars.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(AvatarRetrieveResponse, avatar, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncRunwayML) -> None: + response = await async_client.avatars.with_raw_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + avatar = await response.parse() + assert_matches_type(AvatarRetrieveResponse, avatar, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncRunwayML) -> None: + async with async_client.avatars.with_streaming_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + avatar = await response.parse() + assert_matches_type(AvatarRetrieveResponse, avatar, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncRunwayML) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.avatars.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_update(self, async_client: AsyncRunwayML) -> None: + avatar = await async_client.avatars.update( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(AvatarUpdateResponse, avatar, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncRunwayML) -> None: + avatar = await async_client.avatars.update( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + document_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + image_processing="optimize", + name="x", + personality="You are a helpful support agent assisting users with their account questions. Be friendly, patient, and provide clear step-by-step guidance.", + reference_image="https://example.com/reference.jpg", + start_script="Hello! How can I help you today?", + voice={ + "preset_id": "adrian", + "type": "runway-live-preset", + }, + ) + assert_matches_type(AvatarUpdateResponse, avatar, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncRunwayML) -> None: + response = await async_client.avatars.with_raw_response.update( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + avatar = await response.parse() + assert_matches_type(AvatarUpdateResponse, avatar, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncRunwayML) -> None: + async with async_client.avatars.with_streaming_response.update( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + avatar = await response.parse() + assert_matches_type(AvatarUpdateResponse, avatar, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncRunwayML) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.avatars.with_raw_response.update( + id="", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncRunwayML) -> None: + avatar = await async_client.avatars.list( + limit=1, + ) + assert_matches_type(AsyncCursorPage[AvatarListResponse], avatar, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncRunwayML) -> None: + avatar = await async_client.avatars.list( + limit=1, + cursor="x", + ) + assert_matches_type(AsyncCursorPage[AvatarListResponse], avatar, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncRunwayML) -> None: + response = await async_client.avatars.with_raw_response.list( + limit=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + avatar = await response.parse() + assert_matches_type(AsyncCursorPage[AvatarListResponse], avatar, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncRunwayML) -> None: + async with async_client.avatars.with_streaming_response.list( + limit=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + avatar = await response.parse() + assert_matches_type(AsyncCursorPage[AvatarListResponse], avatar, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncRunwayML) -> None: + avatar = await async_client.avatars.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert avatar is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncRunwayML) -> None: + response = await async_client.avatars.with_raw_response.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + avatar = await response.parse() + assert avatar is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncRunwayML) -> None: + async with async_client.avatars.with_streaming_response.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + avatar = await response.parse() + assert avatar is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncRunwayML) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.avatars.with_raw_response.delete( + "", + ) diff --git a/tests/api_resources/test_documents.py b/tests/api_resources/test_documents.py new file mode 100644 index 0000000..fb21e0e --- /dev/null +++ b/tests/api_resources/test_documents.py @@ -0,0 +1,327 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from runwayml import RunwayML, AsyncRunwayML +from tests.utils import assert_matches_type +from runwayml.types import ( + DocumentListResponse, + DocumentCreateResponse, + DocumentRetrieveResponse, +) +from runwayml.pagination import SyncCursorPage, AsyncCursorPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestDocuments: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: RunwayML) -> None: + document = client.documents.create( + content="# Product FAQ\n\n## What is your return policy?\n\nWe offer a 30-day return policy...", + name="Product FAQ", + ) + assert_matches_type(DocumentCreateResponse, document, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: RunwayML) -> None: + response = client.documents.with_raw_response.create( + content="# Product FAQ\n\n## What is your return policy?\n\nWe offer a 30-day return policy...", + name="Product FAQ", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + document = response.parse() + assert_matches_type(DocumentCreateResponse, document, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: RunwayML) -> None: + with client.documents.with_streaming_response.create( + content="# Product FAQ\n\n## What is your return policy?\n\nWe offer a 30-day return policy...", + name="Product FAQ", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + document = response.parse() + assert_matches_type(DocumentCreateResponse, document, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: RunwayML) -> None: + document = client.documents.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(DocumentRetrieveResponse, document, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: RunwayML) -> None: + response = client.documents.with_raw_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + document = response.parse() + assert_matches_type(DocumentRetrieveResponse, document, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: RunwayML) -> None: + with client.documents.with_streaming_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + document = response.parse() + assert_matches_type(DocumentRetrieveResponse, document, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: RunwayML) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.documents.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_list(self, client: RunwayML) -> None: + document = client.documents.list( + limit=1, + ) + assert_matches_type(SyncCursorPage[DocumentListResponse], document, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: RunwayML) -> None: + document = client.documents.list( + limit=1, + cursor="x", + ) + assert_matches_type(SyncCursorPage[DocumentListResponse], document, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: RunwayML) -> None: + response = client.documents.with_raw_response.list( + limit=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + document = response.parse() + assert_matches_type(SyncCursorPage[DocumentListResponse], document, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: RunwayML) -> None: + with client.documents.with_streaming_response.list( + limit=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + document = response.parse() + assert_matches_type(SyncCursorPage[DocumentListResponse], document, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: RunwayML) -> None: + document = client.documents.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert document is None + + @parametrize + def test_raw_response_delete(self, client: RunwayML) -> None: + response = client.documents.with_raw_response.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + document = response.parse() + assert document is None + + @parametrize + def test_streaming_response_delete(self, client: RunwayML) -> None: + with client.documents.with_streaming_response.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + document = response.parse() + assert document is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: RunwayML) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.documents.with_raw_response.delete( + "", + ) + + +class TestAsyncDocuments: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncRunwayML) -> None: + document = await async_client.documents.create( + content="# Product FAQ\n\n## What is your return policy?\n\nWe offer a 30-day return policy...", + name="Product FAQ", + ) + assert_matches_type(DocumentCreateResponse, document, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncRunwayML) -> None: + response = await async_client.documents.with_raw_response.create( + content="# Product FAQ\n\n## What is your return policy?\n\nWe offer a 30-day return policy...", + name="Product FAQ", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + document = await response.parse() + assert_matches_type(DocumentCreateResponse, document, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncRunwayML) -> None: + async with async_client.documents.with_streaming_response.create( + content="# Product FAQ\n\n## What is your return policy?\n\nWe offer a 30-day return policy...", + name="Product FAQ", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + document = await response.parse() + assert_matches_type(DocumentCreateResponse, document, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncRunwayML) -> None: + document = await async_client.documents.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(DocumentRetrieveResponse, document, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncRunwayML) -> None: + response = await async_client.documents.with_raw_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + document = await response.parse() + assert_matches_type(DocumentRetrieveResponse, document, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncRunwayML) -> None: + async with async_client.documents.with_streaming_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + document = await response.parse() + assert_matches_type(DocumentRetrieveResponse, document, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncRunwayML) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.documents.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncRunwayML) -> None: + document = await async_client.documents.list( + limit=1, + ) + assert_matches_type(AsyncCursorPage[DocumentListResponse], document, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncRunwayML) -> None: + document = await async_client.documents.list( + limit=1, + cursor="x", + ) + assert_matches_type(AsyncCursorPage[DocumentListResponse], document, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncRunwayML) -> None: + response = await async_client.documents.with_raw_response.list( + limit=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + document = await response.parse() + assert_matches_type(AsyncCursorPage[DocumentListResponse], document, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncRunwayML) -> None: + async with async_client.documents.with_streaming_response.list( + limit=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + document = await response.parse() + assert_matches_type(AsyncCursorPage[DocumentListResponse], document, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncRunwayML) -> None: + document = await async_client.documents.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert document is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncRunwayML) -> None: + response = await async_client.documents.with_raw_response.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + document = await response.parse() + assert document is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncRunwayML) -> None: + async with async_client.documents.with_streaming_response.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + document = await response.parse() + assert document is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncRunwayML) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.documents.with_raw_response.delete( + "", + ) diff --git a/tests/api_resources/test_realtime_sessions.py b/tests/api_resources/test_realtime_sessions.py new file mode 100644 index 0000000..2392ca8 --- /dev/null +++ b/tests/api_resources/test_realtime_sessions.py @@ -0,0 +1,289 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from runwayml import RunwayML, AsyncRunwayML +from tests.utils import assert_matches_type +from runwayml.types import ( + RealtimeSessionCreateResponse, + RealtimeSessionRetrieveResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRealtimeSessions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: RunwayML) -> None: + realtime_session = client.realtime_sessions.create( + avatar={ + "preset_id": "game-character", + "type": "runway-preset", + }, + model="gwm1_avatars", + ) + assert_matches_type(RealtimeSessionCreateResponse, realtime_session, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: RunwayML) -> None: + realtime_session = client.realtime_sessions.create( + avatar={ + "preset_id": "game-character", + "type": "runway-preset", + }, + model="gwm1_avatars", + max_duration=10, + ) + assert_matches_type(RealtimeSessionCreateResponse, realtime_session, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: RunwayML) -> None: + response = client.realtime_sessions.with_raw_response.create( + avatar={ + "preset_id": "game-character", + "type": "runway-preset", + }, + model="gwm1_avatars", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + realtime_session = response.parse() + assert_matches_type(RealtimeSessionCreateResponse, realtime_session, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: RunwayML) -> None: + with client.realtime_sessions.with_streaming_response.create( + avatar={ + "preset_id": "game-character", + "type": "runway-preset", + }, + model="gwm1_avatars", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + realtime_session = response.parse() + assert_matches_type(RealtimeSessionCreateResponse, realtime_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: RunwayML) -> None: + realtime_session = client.realtime_sessions.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(RealtimeSessionRetrieveResponse, realtime_session, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: RunwayML) -> None: + response = client.realtime_sessions.with_raw_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + realtime_session = response.parse() + assert_matches_type(RealtimeSessionRetrieveResponse, realtime_session, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: RunwayML) -> None: + with client.realtime_sessions.with_streaming_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + realtime_session = response.parse() + assert_matches_type(RealtimeSessionRetrieveResponse, realtime_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: RunwayML) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.realtime_sessions.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_delete(self, client: RunwayML) -> None: + realtime_session = client.realtime_sessions.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert realtime_session is None + + @parametrize + def test_raw_response_delete(self, client: RunwayML) -> None: + response = client.realtime_sessions.with_raw_response.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + realtime_session = response.parse() + assert realtime_session is None + + @parametrize + def test_streaming_response_delete(self, client: RunwayML) -> None: + with client.realtime_sessions.with_streaming_response.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + realtime_session = response.parse() + assert realtime_session is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: RunwayML) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.realtime_sessions.with_raw_response.delete( + "", + ) + + +class TestAsyncRealtimeSessions: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncRunwayML) -> None: + realtime_session = await async_client.realtime_sessions.create( + avatar={ + "preset_id": "game-character", + "type": "runway-preset", + }, + model="gwm1_avatars", + ) + assert_matches_type(RealtimeSessionCreateResponse, realtime_session, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncRunwayML) -> None: + realtime_session = await async_client.realtime_sessions.create( + avatar={ + "preset_id": "game-character", + "type": "runway-preset", + }, + model="gwm1_avatars", + max_duration=10, + ) + assert_matches_type(RealtimeSessionCreateResponse, realtime_session, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncRunwayML) -> None: + response = await async_client.realtime_sessions.with_raw_response.create( + avatar={ + "preset_id": "game-character", + "type": "runway-preset", + }, + model="gwm1_avatars", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + realtime_session = await response.parse() + assert_matches_type(RealtimeSessionCreateResponse, realtime_session, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncRunwayML) -> None: + async with async_client.realtime_sessions.with_streaming_response.create( + avatar={ + "preset_id": "game-character", + "type": "runway-preset", + }, + model="gwm1_avatars", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + realtime_session = await response.parse() + assert_matches_type(RealtimeSessionCreateResponse, realtime_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncRunwayML) -> None: + realtime_session = await async_client.realtime_sessions.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(RealtimeSessionRetrieveResponse, realtime_session, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncRunwayML) -> None: + response = await async_client.realtime_sessions.with_raw_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + realtime_session = await response.parse() + assert_matches_type(RealtimeSessionRetrieveResponse, realtime_session, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncRunwayML) -> None: + async with async_client.realtime_sessions.with_streaming_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + realtime_session = await response.parse() + assert_matches_type(RealtimeSessionRetrieveResponse, realtime_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncRunwayML) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.realtime_sessions.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncRunwayML) -> None: + realtime_session = await async_client.realtime_sessions.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert realtime_session is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncRunwayML) -> None: + response = await async_client.realtime_sessions.with_raw_response.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + realtime_session = await response.parse() + assert realtime_session is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncRunwayML) -> None: + async with async_client.realtime_sessions.with_streaming_response.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + realtime_session = await response.parse() + assert realtime_session is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncRunwayML) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.realtime_sessions.with_raw_response.delete( + "", + ) diff --git a/tests/api_resources/test_voices.py b/tests/api_resources/test_voices.py new file mode 100644 index 0000000..548a5aa --- /dev/null +++ b/tests/api_resources/test_voices.py @@ -0,0 +1,446 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from runwayml import RunwayML, AsyncRunwayML +from tests.utils import assert_matches_type +from runwayml.types import ( + VoiceListResponse, + VoiceCreateResponse, + VoicePreviewResponse, + VoiceRetrieveResponse, +) +from runwayml.pagination import SyncCursorPage, AsyncCursorPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestVoices: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: RunwayML) -> None: + voice = client.voices.create( + from_={ + "model": "eleven_multilingual_ttv_v2", + "prompt": "xxxxxxxxxxxxxxxxxxxx", + "type": "text", + }, + name="x", + ) + assert_matches_type(VoiceCreateResponse, voice, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: RunwayML) -> None: + voice = client.voices.create( + from_={ + "model": "eleven_multilingual_ttv_v2", + "prompt": "xxxxxxxxxxxxxxxxxxxx", + "type": "text", + }, + name="x", + description="x", + ) + assert_matches_type(VoiceCreateResponse, voice, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: RunwayML) -> None: + response = client.voices.with_raw_response.create( + from_={ + "model": "eleven_multilingual_ttv_v2", + "prompt": "xxxxxxxxxxxxxxxxxxxx", + "type": "text", + }, + name="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + voice = response.parse() + assert_matches_type(VoiceCreateResponse, voice, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: RunwayML) -> None: + with client.voices.with_streaming_response.create( + from_={ + "model": "eleven_multilingual_ttv_v2", + "prompt": "xxxxxxxxxxxxxxxxxxxx", + "type": "text", + }, + name="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + voice = response.parse() + assert_matches_type(VoiceCreateResponse, voice, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: RunwayML) -> None: + voice = client.voices.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(VoiceRetrieveResponse, voice, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: RunwayML) -> None: + response = client.voices.with_raw_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + voice = response.parse() + assert_matches_type(VoiceRetrieveResponse, voice, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: RunwayML) -> None: + with client.voices.with_streaming_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + voice = response.parse() + assert_matches_type(VoiceRetrieveResponse, voice, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: RunwayML) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.voices.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_list(self, client: RunwayML) -> None: + voice = client.voices.list( + limit=1, + ) + assert_matches_type(SyncCursorPage[VoiceListResponse], voice, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: RunwayML) -> None: + voice = client.voices.list( + limit=1, + cursor="x", + ) + assert_matches_type(SyncCursorPage[VoiceListResponse], voice, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: RunwayML) -> None: + response = client.voices.with_raw_response.list( + limit=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + voice = response.parse() + assert_matches_type(SyncCursorPage[VoiceListResponse], voice, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: RunwayML) -> None: + with client.voices.with_streaming_response.list( + limit=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + voice = response.parse() + assert_matches_type(SyncCursorPage[VoiceListResponse], voice, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: RunwayML) -> None: + voice = client.voices.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert voice is None + + @parametrize + def test_raw_response_delete(self, client: RunwayML) -> None: + response = client.voices.with_raw_response.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + voice = response.parse() + assert voice is None + + @parametrize + def test_streaming_response_delete(self, client: RunwayML) -> None: + with client.voices.with_streaming_response.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + voice = response.parse() + assert voice is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: RunwayML) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.voices.with_raw_response.delete( + "", + ) + + @parametrize + def test_method_preview(self, client: RunwayML) -> None: + voice = client.voices.preview( + model="eleven_multilingual_ttv_v2", + prompt="xxxxxxxxxxxxxxxxxxxx", + ) + assert_matches_type(VoicePreviewResponse, voice, path=["response"]) + + @parametrize + def test_raw_response_preview(self, client: RunwayML) -> None: + response = client.voices.with_raw_response.preview( + model="eleven_multilingual_ttv_v2", + prompt="xxxxxxxxxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + voice = response.parse() + assert_matches_type(VoicePreviewResponse, voice, path=["response"]) + + @parametrize + def test_streaming_response_preview(self, client: RunwayML) -> None: + with client.voices.with_streaming_response.preview( + model="eleven_multilingual_ttv_v2", + prompt="xxxxxxxxxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + voice = response.parse() + assert_matches_type(VoicePreviewResponse, voice, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncVoices: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncRunwayML) -> None: + voice = await async_client.voices.create( + from_={ + "model": "eleven_multilingual_ttv_v2", + "prompt": "xxxxxxxxxxxxxxxxxxxx", + "type": "text", + }, + name="x", + ) + assert_matches_type(VoiceCreateResponse, voice, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncRunwayML) -> None: + voice = await async_client.voices.create( + from_={ + "model": "eleven_multilingual_ttv_v2", + "prompt": "xxxxxxxxxxxxxxxxxxxx", + "type": "text", + }, + name="x", + description="x", + ) + assert_matches_type(VoiceCreateResponse, voice, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncRunwayML) -> None: + response = await async_client.voices.with_raw_response.create( + from_={ + "model": "eleven_multilingual_ttv_v2", + "prompt": "xxxxxxxxxxxxxxxxxxxx", + "type": "text", + }, + name="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + voice = await response.parse() + assert_matches_type(VoiceCreateResponse, voice, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncRunwayML) -> None: + async with async_client.voices.with_streaming_response.create( + from_={ + "model": "eleven_multilingual_ttv_v2", + "prompt": "xxxxxxxxxxxxxxxxxxxx", + "type": "text", + }, + name="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + voice = await response.parse() + assert_matches_type(VoiceCreateResponse, voice, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncRunwayML) -> None: + voice = await async_client.voices.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(VoiceRetrieveResponse, voice, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncRunwayML) -> None: + response = await async_client.voices.with_raw_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + voice = await response.parse() + assert_matches_type(VoiceRetrieveResponse, voice, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncRunwayML) -> None: + async with async_client.voices.with_streaming_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + voice = await response.parse() + assert_matches_type(VoiceRetrieveResponse, voice, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncRunwayML) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.voices.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncRunwayML) -> None: + voice = await async_client.voices.list( + limit=1, + ) + assert_matches_type(AsyncCursorPage[VoiceListResponse], voice, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncRunwayML) -> None: + voice = await async_client.voices.list( + limit=1, + cursor="x", + ) + assert_matches_type(AsyncCursorPage[VoiceListResponse], voice, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncRunwayML) -> None: + response = await async_client.voices.with_raw_response.list( + limit=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + voice = await response.parse() + assert_matches_type(AsyncCursorPage[VoiceListResponse], voice, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncRunwayML) -> None: + async with async_client.voices.with_streaming_response.list( + limit=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + voice = await response.parse() + assert_matches_type(AsyncCursorPage[VoiceListResponse], voice, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncRunwayML) -> None: + voice = await async_client.voices.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert voice is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncRunwayML) -> None: + response = await async_client.voices.with_raw_response.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + voice = await response.parse() + assert voice is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncRunwayML) -> None: + async with async_client.voices.with_streaming_response.delete( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + voice = await response.parse() + assert voice is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncRunwayML) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.voices.with_raw_response.delete( + "", + ) + + @parametrize + async def test_method_preview(self, async_client: AsyncRunwayML) -> None: + voice = await async_client.voices.preview( + model="eleven_multilingual_ttv_v2", + prompt="xxxxxxxxxxxxxxxxxxxx", + ) + assert_matches_type(VoicePreviewResponse, voice, path=["response"]) + + @parametrize + async def test_raw_response_preview(self, async_client: AsyncRunwayML) -> None: + response = await async_client.voices.with_raw_response.preview( + model="eleven_multilingual_ttv_v2", + prompt="xxxxxxxxxxxxxxxxxxxx", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + voice = await response.parse() + assert_matches_type(VoicePreviewResponse, voice, path=["response"]) + + @parametrize + async def test_streaming_response_preview(self, async_client: AsyncRunwayML) -> None: + async with async_client.voices.with_streaming_response.preview( + model="eleven_multilingual_ttv_v2", + prompt="xxxxxxxxxxxxxxxxxxxx", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + voice = await response.parse() + assert_matches_type(VoicePreviewResponse, voice, path=["response"]) + + assert cast(Any, response.is_closed) is True From bc7a4f5f54e8472ba2ef5780c89b7c3336caa8b6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 15:51:19 +0000 Subject: [PATCH 3/5] release: 4.7.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/runwayml/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 85ea8cd..1eec10e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "4.6.3" + ".": "4.7.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f5833e..f371af4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 4.7.0 (2026-03-06) + +Full Changelog: [v4.6.3...v4.7.0](https://github.com/runwayml/sdk-python/compare/v4.6.3...v4.7.0) + +### Features + +* **api:** add avatar, voice, document, and realtime session endpoints ([18b1573](https://github.com/runwayml/sdk-python/commit/18b15733d52e1ddb60d1f9a847e4fd7a712b4701)) + + +### Chores + +* **test:** do not count install time for mock server timeout ([84988e1](https://github.com/runwayml/sdk-python/commit/84988e1eeaa6d25b265bfb77863ed6a4ce271201)) + ## 4.6.3 (2026-02-27) Full Changelog: [v4.6.2...v4.6.3](https://github.com/runwayml/sdk-python/compare/v4.6.2...v4.6.3) diff --git a/pyproject.toml b/pyproject.toml index 020798f..8f44411 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "runwayml" -version = "4.6.3" +version = "4.7.0" description = "The official Python library for the runwayml API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/runwayml/_version.py b/src/runwayml/_version.py index 0a54027..86051f8 100644 --- a/src/runwayml/_version.py +++ b/src/runwayml/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "runwayml" -__version__ = "4.6.3" # x-release-please-version +__version__ = "4.7.0" # x-release-please-version From ba29ab077034e27cc1b8520e658409012bbe30db Mon Sep 17 00:00:00 2001 From: Daniil Date: Fri, 6 Mar 2026 17:33:55 +0100 Subject: [PATCH 4/5] fix lint --- src/runwayml/_client.py | 1 - src/runwayml/resources/__init__.py | 13 ++++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/runwayml/_client.py b/src/runwayml/_client.py index 4dabd86..d52a25f 100644 --- a/src/runwayml/_client.py +++ b/src/runwayml/_client.py @@ -48,7 +48,6 @@ character_performance, ) from .resources.tasks import TasksResource, AsyncTasksResource - from .resources.organization import OrganizationResource, AsyncOrganizationResource from .resources.sound_effect import SoundEffectResource, AsyncSoundEffectResource from .resources.text_to_image import TextToImageResource, AsyncTextToImageResource diff --git a/src/runwayml/resources/__init__.py b/src/runwayml/resources/__init__.py index 4f29840..cd9219d 100644 --- a/src/runwayml/resources/__init__.py +++ b/src/runwayml/resources/__init__.py @@ -186,5 +186,16 @@ "AsyncOrganizationResourceWithRawResponse", "OrganizationResourceWithStreamingResponse", "AsyncOrganizationResourceWithStreamingResponse", - + "UploadsResource", + "AsyncUploadsResource", + "UploadsResourceWithRawResponse", + "AsyncUploadsResourceWithRawResponse", + "UploadsResourceWithStreamingResponse", + "AsyncUploadsResourceWithStreamingResponse", + "RealtimeSessionsResource", + "AsyncRealtimeSessionsResource", + "RealtimeSessionsResourceWithRawResponse", + "AsyncRealtimeSessionsResourceWithRawResponse", + "RealtimeSessionsResourceWithStreamingResponse", + "AsyncRealtimeSessionsResourceWithStreamingResponse", ] From 774eea19a4c5e55d9e5949538dd48120461dc98a Mon Sep 17 00:00:00 2001 From: Daniil Date: Fri, 6 Mar 2026 17:43:16 +0100 Subject: [PATCH 5/5] fix lint --- src/runwayml/_client.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/runwayml/_client.py b/src/runwayml/_client.py index d52a25f..4bee591 100644 --- a/src/runwayml/_client.py +++ b/src/runwayml/_client.py @@ -33,7 +33,10 @@ if TYPE_CHECKING: from .resources import ( tasks, + voices, + avatars, uploads, + documents, organization, sound_effect, text_to_image, @@ -48,6 +51,10 @@ character_performance, ) from .resources.tasks import TasksResource, AsyncTasksResource + from .resources.voices import VoicesResource, AsyncVoicesResource + from .resources.avatars import AvatarsResource, AsyncAvatarsResource + from .resources.uploads import UploadsResource, AsyncUploadsResource + from .resources.documents import DocumentsResource, AsyncDocumentsResource from .resources.organization import OrganizationResource, AsyncOrganizationResource from .resources.sound_effect import SoundEffectResource, AsyncSoundEffectResource from .resources.text_to_image import TextToImageResource, AsyncTextToImageResource