diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f0389323..d66d8f94 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,30 @@ jobs: - name: Run lints run: ./scripts/lint + upload: + if: github.repository == 'stainless-sdks/groqcloud-python' + timeout-minutes: 10 + name: upload + permissions: + contents: read + id-token: write + runs-on: depot-ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + + - name: Get GitHub OIDC Token + id: github-oidc + uses: actions/github-script@v6 + with: + script: core.setOutput('github_token', await core.getIDToken()); + + - name: Upload tarball + env: + URL: https://pkg.stainless.com/s + AUTH: ${{ steps.github-oidc.outputs.github_token }} + SHA: ${{ github.sha }} + run: ./scripts/utils/upload-artifact.sh + test: timeout-minutes: 10 name: test diff --git a/.release-please-manifest.json b/.release-please-manifest.json index d2d60a3d..a36746b8 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.24.0" + ".": "0.25.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 7a7d45c6..d394724e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 17 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/groqcloud%2Fgroqcloud-e4cd6fe4e6ac62707635fac8fb7d966a0360868e467b578ddd7cc04a9459ff26.yml -openapi_spec_hash: e618e809624bb2f3b36995638c3ba791 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/groqcloud%2Fgroqcloud-ee34f94100e35d728e92c54940b84a46f420f476a4b82a33a21728ebf1e9032f.yml +openapi_spec_hash: 5d642c8432d9963281e7db786c2b4e6c config_hash: 6b1c374dcc1ffa3165dd22f52a77ff89 diff --git a/CHANGELOG.md b/CHANGELOG.md index 44e39459..4bea37c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,37 @@ # Changelog +## 0.25.0 (2025-05-16) + +Full Changelog: [v0.24.0...v0.25.0](https://github.com/groq/groq-python/compare/v0.24.0...v0.25.0) + +### Features + +* **api:** api update ([385969a](https://github.com/groq/groq-python/commit/385969a478242c67dd07e510632ea1f168f743d8)) +* **api:** api update ([e3acb61](https://github.com/groq/groq-python/commit/e3acb618e09864829089575c51ec617b2f4b6975)) +* **api:** api update ([4bb39e5](https://github.com/groq/groq-python/commit/4bb39e59bbd317de95b3e1d896ab83ee41bc7b3e)) +* **api:** api update ([ce3c251](https://github.com/groq/groq-python/commit/ce3c2514e2e66557de3e583532743cb3806032a2)) + + +### Bug Fixes + +* add search settings to all chat completion overloads ([32a1731](https://github.com/groq/groq-python/commit/32a17310c3a481b4b6b7aaa1f742720c367864f5)) +* GitHub Terraform: Create/Update .github/workflows/stale.yaml [skip ci] ([a365e26](https://github.com/groq/groq-python/commit/a365e262f988103f5757ffd9054b822a72868586)) +* **package:** support direct resource imports ([3ee8779](https://github.com/groq/groq-python/commit/3ee87792c92196abba0a1c7d9400a34d95c58895)) + + +### Chores + +* **ci:** fix installation instructions ([454ff60](https://github.com/groq/groq-python/commit/454ff60a12d7e16127d87ef9c152b9e4a394246d)) +* **ci:** upload sdks to package manager ([1f464f8](https://github.com/groq/groq-python/commit/1f464f84bee361e07214e6b65a6727a1b5e0bc7b)) +* fix README example ([7a0f06a](https://github.com/groq/groq-python/commit/7a0f06aca6223dc04e146f1b75445a2a64ce409a)) +* **internal:** avoid errors for isinstance checks on proxies ([7a04964](https://github.com/groq/groq-python/commit/7a04964d964feaac9dfcf1f46dad1f63a5acf714)) +* use lazy imports for resources ([8c6351a](https://github.com/groq/groq-python/commit/8c6351a0215827dea34174978a78d06a528e6eef)) + + +### Documentation + +* remove or fix invalid readme examples ([4dc027a](https://github.com/groq/groq-python/commit/4dc027a35054db11eec6c8bfe1fd463b0c49db6e)) + ## 0.24.0 (2025-05-02) Full Changelog: [v0.23.1...v0.24.0](https://github.com/groq/groq-python/compare/v0.23.1...v0.24.0) diff --git a/README.md b/README.md index 4321c9c8..94b51a33 100644 --- a/README.md +++ b/README.md @@ -105,10 +105,14 @@ chat_completion = client.chat.completions.create( "role": "system", } ], - model="string", - response_format={"type": "json_object"}, + model="meta-llama/llama-4-scout-17b-16e-instruct", + search_settings={ + "exclude_domains": ["string"], + "include_domains": ["string"], + "include_images": True, + }, ) -print(chat_completion.response_format) +print(chat_completion.search_settings) ``` ## File uploads @@ -122,7 +126,7 @@ from groq import Groq client = Groq() client.audio.transcriptions.create( - model="whisper-large-v3", + model="whisper-large-v3-turbo", file=Path("/path/to/file"), ) ``` diff --git a/pyproject.toml b/pyproject.toml index 8d1ca7b5..45df707f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "groq" -version = "0.24.0" +version = "0.25.0" description = "The official Python library for the groq API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh new file mode 100755 index 00000000..7da1e1b7 --- /dev/null +++ b/scripts/utils/upload-artifact.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -exuo pipefail + +RESPONSE=$(curl -X POST "$URL" \ + -H "Authorization: Bearer $AUTH" \ + -H "Content-Type: application/json") + +SIGNED_URL=$(echo "$RESPONSE" | jq -r '.url') + +if [[ "$SIGNED_URL" == "null" ]]; then + echo -e "\033[31mFailed to get signed URL.\033[0m" + exit 1 +fi + +UPLOAD_RESPONSE=$(tar -cz . | curl -v -X PUT \ + -H "Content-Type: application/gzip" \ + --data-binary @- "$SIGNED_URL" 2>&1) + +if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then + echo -e "\033[32mUploaded build to Stainless storage.\033[0m" + echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/groqcloud-python/$SHA'\033[0m" +else + echo -e "\033[31mFailed to upload artifact.\033[0m" + exit 1 +fi diff --git a/src/groq/__init__.py b/src/groq/__init__.py index 07f77a63..9ad2b0e2 100644 --- a/src/groq/__init__.py +++ b/src/groq/__init__.py @@ -1,5 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import typing as _t + from . import types from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes from ._utils import file_from_path @@ -68,6 +70,9 @@ "DefaultAsyncHttpxClient", ] +if not _t.TYPE_CHECKING: + from ._utils._resources_proxy import resources as resources + _setup_logging() # Update the __module__ attribute for exported symbols so that diff --git a/src/groq/_client.py b/src/groq/_client.py index 6c7f997b..ee203f04 100644 --- a/src/groq/_client.py +++ b/src/groq/_client.py @@ -3,7 +3,7 @@ from __future__ import annotations import os -from typing import Any, Union, Mapping +from typing import TYPE_CHECKING, Any, Union, Mapping from typing_extensions import Self, override import httpx @@ -20,8 +20,8 @@ RequestOptions, ) from ._utils import is_given, get_async_library +from ._compat import cached_property from ._version import __version__ -from .resources import files, models, batches, embeddings from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import GroqError, APIStatusError from ._base_client import ( @@ -29,22 +29,20 @@ SyncAPIClient, AsyncAPIClient, ) -from .resources.chat import chat -from .resources.audio import audio + +if TYPE_CHECKING: + from .resources import chat, audio, files, models, batches, embeddings + from .resources.files import Files, AsyncFiles + from .resources.models import Models, AsyncModels + from .resources.batches import Batches, AsyncBatches + from .resources.chat.chat import Chat, AsyncChat + from .resources.embeddings import Embeddings, AsyncEmbeddings + from .resources.audio.audio import Audio, AsyncAudio __all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "Groq", "AsyncGroq", "Client", "AsyncClient"] class Groq(SyncAPIClient): - chat: chat.Chat - embeddings: embeddings.Embeddings - audio: audio.Audio - models: models.Models - batches: batches.Batches - files: files.Files - with_raw_response: GroqWithRawResponse - with_streaming_response: GroqWithStreamedResponse - # client options api_key: str @@ -99,14 +97,49 @@ def __init__( _strict_response_validation=_strict_response_validation, ) - self.chat = chat.Chat(self) - self.embeddings = embeddings.Embeddings(self) - self.audio = audio.Audio(self) - self.models = models.Models(self) - self.batches = batches.Batches(self) - self.files = files.Files(self) - self.with_raw_response = GroqWithRawResponse(self) - self.with_streaming_response = GroqWithStreamedResponse(self) + @cached_property + def chat(self) -> Chat: + from .resources.chat import Chat + + return Chat(self) + + @cached_property + def embeddings(self) -> Embeddings: + from .resources.embeddings import Embeddings + + return Embeddings(self) + + @cached_property + def audio(self) -> Audio: + from .resources.audio import Audio + + return Audio(self) + + @cached_property + def models(self) -> Models: + from .resources.models import Models + + return Models(self) + + @cached_property + def batches(self) -> Batches: + from .resources.batches import Batches + + return Batches(self) + + @cached_property + def files(self) -> Files: + from .resources.files import Files + + return Files(self) + + @cached_property + def with_raw_response(self) -> GroqWithRawResponse: + return GroqWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> GroqWithStreamedResponse: + return GroqWithStreamedResponse(self) @property @override @@ -214,15 +247,6 @@ def _make_status_error( class AsyncGroq(AsyncAPIClient): - chat: chat.AsyncChat - embeddings: embeddings.AsyncEmbeddings - audio: audio.AsyncAudio - models: models.AsyncModels - batches: batches.AsyncBatches - files: files.AsyncFiles - with_raw_response: AsyncGroqWithRawResponse - with_streaming_response: AsyncGroqWithStreamedResponse - # client options api_key: str @@ -277,14 +301,49 @@ def __init__( _strict_response_validation=_strict_response_validation, ) - self.chat = chat.AsyncChat(self) - self.embeddings = embeddings.AsyncEmbeddings(self) - self.audio = audio.AsyncAudio(self) - self.models = models.AsyncModels(self) - self.batches = batches.AsyncBatches(self) - self.files = files.AsyncFiles(self) - self.with_raw_response = AsyncGroqWithRawResponse(self) - self.with_streaming_response = AsyncGroqWithStreamedResponse(self) + @cached_property + def chat(self) -> AsyncChat: + from .resources.chat import AsyncChat + + return AsyncChat(self) + + @cached_property + def embeddings(self) -> AsyncEmbeddings: + from .resources.embeddings import AsyncEmbeddings + + return AsyncEmbeddings(self) + + @cached_property + def audio(self) -> AsyncAudio: + from .resources.audio import AsyncAudio + + return AsyncAudio(self) + + @cached_property + def models(self) -> AsyncModels: + from .resources.models import AsyncModels + + return AsyncModels(self) + + @cached_property + def batches(self) -> AsyncBatches: + from .resources.batches import AsyncBatches + + return AsyncBatches(self) + + @cached_property + def files(self) -> AsyncFiles: + from .resources.files import AsyncFiles + + return AsyncFiles(self) + + @cached_property + def with_raw_response(self) -> AsyncGroqWithRawResponse: + return AsyncGroqWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncGroqWithStreamedResponse: + return AsyncGroqWithStreamedResponse(self) @property @override @@ -392,43 +451,175 @@ def _make_status_error( class GroqWithRawResponse: + _client: Groq + def __init__(self, client: Groq) -> None: - self.chat = chat.ChatWithRawResponse(client.chat) - self.embeddings = embeddings.EmbeddingsWithRawResponse(client.embeddings) - self.audio = audio.AudioWithRawResponse(client.audio) - self.models = models.ModelsWithRawResponse(client.models) - self.batches = batches.BatchesWithRawResponse(client.batches) - self.files = files.FilesWithRawResponse(client.files) + self._client = client + + @cached_property + def chat(self) -> chat.ChatWithRawResponse: + from .resources.chat import ChatWithRawResponse + + return ChatWithRawResponse(self._client.chat) + + @cached_property + def embeddings(self) -> embeddings.EmbeddingsWithRawResponse: + from .resources.embeddings import EmbeddingsWithRawResponse + + return EmbeddingsWithRawResponse(self._client.embeddings) + + @cached_property + def audio(self) -> audio.AudioWithRawResponse: + from .resources.audio import AudioWithRawResponse + + return AudioWithRawResponse(self._client.audio) + + @cached_property + def models(self) -> models.ModelsWithRawResponse: + from .resources.models import ModelsWithRawResponse + + return ModelsWithRawResponse(self._client.models) + + @cached_property + def batches(self) -> batches.BatchesWithRawResponse: + from .resources.batches import BatchesWithRawResponse + + return BatchesWithRawResponse(self._client.batches) + + @cached_property + def files(self) -> files.FilesWithRawResponse: + from .resources.files import FilesWithRawResponse + + return FilesWithRawResponse(self._client.files) class AsyncGroqWithRawResponse: + _client: AsyncGroq + def __init__(self, client: AsyncGroq) -> None: - self.chat = chat.AsyncChatWithRawResponse(client.chat) - self.embeddings = embeddings.AsyncEmbeddingsWithRawResponse(client.embeddings) - self.audio = audio.AsyncAudioWithRawResponse(client.audio) - self.models = models.AsyncModelsWithRawResponse(client.models) - self.batches = batches.AsyncBatchesWithRawResponse(client.batches) - self.files = files.AsyncFilesWithRawResponse(client.files) + self._client = client + + @cached_property + def chat(self) -> chat.AsyncChatWithRawResponse: + from .resources.chat import AsyncChatWithRawResponse + + return AsyncChatWithRawResponse(self._client.chat) + + @cached_property + def embeddings(self) -> embeddings.AsyncEmbeddingsWithRawResponse: + from .resources.embeddings import AsyncEmbeddingsWithRawResponse + + return AsyncEmbeddingsWithRawResponse(self._client.embeddings) + + @cached_property + def audio(self) -> audio.AsyncAudioWithRawResponse: + from .resources.audio import AsyncAudioWithRawResponse + + return AsyncAudioWithRawResponse(self._client.audio) + + @cached_property + def models(self) -> models.AsyncModelsWithRawResponse: + from .resources.models import AsyncModelsWithRawResponse + + return AsyncModelsWithRawResponse(self._client.models) + + @cached_property + def batches(self) -> batches.AsyncBatchesWithRawResponse: + from .resources.batches import AsyncBatchesWithRawResponse + + return AsyncBatchesWithRawResponse(self._client.batches) + + @cached_property + def files(self) -> files.AsyncFilesWithRawResponse: + from .resources.files import AsyncFilesWithRawResponse + + return AsyncFilesWithRawResponse(self._client.files) class GroqWithStreamedResponse: + _client: Groq + def __init__(self, client: Groq) -> None: - self.chat = chat.ChatWithStreamingResponse(client.chat) - self.embeddings = embeddings.EmbeddingsWithStreamingResponse(client.embeddings) - self.audio = audio.AudioWithStreamingResponse(client.audio) - self.models = models.ModelsWithStreamingResponse(client.models) - self.batches = batches.BatchesWithStreamingResponse(client.batches) - self.files = files.FilesWithStreamingResponse(client.files) + self._client = client + + @cached_property + def chat(self) -> chat.ChatWithStreamingResponse: + from .resources.chat import ChatWithStreamingResponse + + return ChatWithStreamingResponse(self._client.chat) + + @cached_property + def embeddings(self) -> embeddings.EmbeddingsWithStreamingResponse: + from .resources.embeddings import EmbeddingsWithStreamingResponse + + return EmbeddingsWithStreamingResponse(self._client.embeddings) + + @cached_property + def audio(self) -> audio.AudioWithStreamingResponse: + from .resources.audio import AudioWithStreamingResponse + + return AudioWithStreamingResponse(self._client.audio) + + @cached_property + def models(self) -> models.ModelsWithStreamingResponse: + from .resources.models import ModelsWithStreamingResponse + + return ModelsWithStreamingResponse(self._client.models) + + @cached_property + def batches(self) -> batches.BatchesWithStreamingResponse: + from .resources.batches import BatchesWithStreamingResponse + + return BatchesWithStreamingResponse(self._client.batches) + + @cached_property + def files(self) -> files.FilesWithStreamingResponse: + from .resources.files import FilesWithStreamingResponse + + return FilesWithStreamingResponse(self._client.files) class AsyncGroqWithStreamedResponse: + _client: AsyncGroq + def __init__(self, client: AsyncGroq) -> None: - self.chat = chat.AsyncChatWithStreamingResponse(client.chat) - self.embeddings = embeddings.AsyncEmbeddingsWithStreamingResponse(client.embeddings) - self.audio = audio.AsyncAudioWithStreamingResponse(client.audio) - self.models = models.AsyncModelsWithStreamingResponse(client.models) - self.batches = batches.AsyncBatchesWithStreamingResponse(client.batches) - self.files = files.AsyncFilesWithStreamingResponse(client.files) + self._client = client + + @cached_property + def chat(self) -> chat.AsyncChatWithStreamingResponse: + from .resources.chat import AsyncChatWithStreamingResponse + + return AsyncChatWithStreamingResponse(self._client.chat) + + @cached_property + def embeddings(self) -> embeddings.AsyncEmbeddingsWithStreamingResponse: + from .resources.embeddings import AsyncEmbeddingsWithStreamingResponse + + return AsyncEmbeddingsWithStreamingResponse(self._client.embeddings) + + @cached_property + def audio(self) -> audio.AsyncAudioWithStreamingResponse: + from .resources.audio import AsyncAudioWithStreamingResponse + + return AsyncAudioWithStreamingResponse(self._client.audio) + + @cached_property + def models(self) -> models.AsyncModelsWithStreamingResponse: + from .resources.models import AsyncModelsWithStreamingResponse + + return AsyncModelsWithStreamingResponse(self._client.models) + + @cached_property + def batches(self) -> batches.AsyncBatchesWithStreamingResponse: + from .resources.batches import AsyncBatchesWithStreamingResponse + + return AsyncBatchesWithStreamingResponse(self._client.batches) + + @cached_property + def files(self) -> files.AsyncFilesWithStreamingResponse: + from .resources.files import AsyncFilesWithStreamingResponse + + return AsyncFilesWithStreamingResponse(self._client.files) Client = Groq diff --git a/src/groq/_utils/_proxy.py b/src/groq/_utils/_proxy.py index ffd883e9..0f239a33 100644 --- a/src/groq/_utils/_proxy.py +++ b/src/groq/_utils/_proxy.py @@ -46,7 +46,10 @@ def __dir__(self) -> Iterable[str]: @property # type: ignore @override def __class__(self) -> type: # pyright: ignore - proxied = self.__get_proxied__() + try: + proxied = self.__get_proxied__() + except Exception: + return type(self) if issubclass(type(proxied), LazyProxy): return type(proxied) return proxied.__class__ diff --git a/src/groq/_utils/_resources_proxy.py b/src/groq/_utils/_resources_proxy.py new file mode 100644 index 00000000..4c4c8766 --- /dev/null +++ b/src/groq/_utils/_resources_proxy.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from typing import Any +from typing_extensions import override + +from ._proxy import LazyProxy + + +class ResourcesProxy(LazyProxy[Any]): + """A proxy for the `groq.resources` module. + + This is used so that we can lazily import `groq.resources` only when + needed *and* so that users can just import `groq` and reference `groq.resources` + """ + + @override + def __load__(self) -> Any: + import importlib + + mod = importlib.import_module("groq.resources") + return mod + + +resources = ResourcesProxy().__as_proxied__() diff --git a/src/groq/_version.py b/src/groq/_version.py index 28652de7..a9df67c7 100644 --- a/src/groq/_version.py +++ b/src/groq/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "groq" -__version__ = "0.24.0" # x-release-please-version +__version__ = "0.25.0" # x-release-please-version diff --git a/src/groq/resources/audio/speech.py b/src/groq/resources/audio/speech.py index 0c3b6395..8a842c22 100644 --- a/src/groq/resources/audio/speech.py +++ b/src/groq/resources/audio/speech.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Union from typing_extensions import Literal import httpx @@ -50,7 +51,7 @@ def create( self, *, input: str, - model: str, + model: Union[str, Literal["playai-tts", "playai-tts-arabic"]], voice: str, response_format: Literal["wav", "mp3"] | NotGiven = NOT_GIVEN, speed: float | NotGiven = NOT_GIVEN, @@ -128,7 +129,7 @@ async def create( self, *, input: str, - model: str, + model: Union[str, Literal["playai-tts", "playai-tts-arabic"]], voice: str, response_format: Literal["wav", "mp3"] | NotGiven = NOT_GIVEN, speed: float | NotGiven = NOT_GIVEN, diff --git a/src/groq/resources/audio/transcriptions.py b/src/groq/resources/audio/transcriptions.py index ee2740f3..a21683ae 100644 --- a/src/groq/resources/audio/transcriptions.py +++ b/src/groq/resources/audio/transcriptions.py @@ -47,7 +47,7 @@ def with_streaming_response(self) -> TranscriptionsWithStreamingResponse: def create( self, *, - model: Union[str, Literal["whisper-large-v3"]], + model: Union[str, Literal["whisper-large-v3", "whisper-large-v3-turbo"]], file: FileTypes | NotGiven = NOT_GIVEN, language: Union[ str, @@ -171,7 +171,8 @@ def create( Transcribes audio into the input language. Args: - model: ID of the model to use. Only `whisper-large-v3` is currently available. + model: ID of the model to use. `whisper-large-v3` and `whisper-large-v3-turbo` are + currently available. file: The audio file object (not file name) to transcribe, in one of these formats: @@ -263,7 +264,7 @@ def with_streaming_response(self) -> AsyncTranscriptionsWithStreamingResponse: async def create( self, *, - model: Union[str, Literal["whisper-large-v3"]], + model: Union[str, Literal["whisper-large-v3", "whisper-large-v3-turbo"]], file: FileTypes | NotGiven = NOT_GIVEN, language: Union[ str, @@ -387,7 +388,8 @@ async def create( Transcribes audio into the input language. Args: - model: ID of the model to use. Only `whisper-large-v3` is currently available. + model: ID of the model to use. `whisper-large-v3` and `whisper-large-v3-turbo` are + currently available. file: The audio file object (not file name) to transcribe, in one of these formats: diff --git a/src/groq/resources/audio/translations.py b/src/groq/resources/audio/translations.py index d422676c..ac63c29e 100644 --- a/src/groq/resources/audio/translations.py +++ b/src/groq/resources/audio/translations.py @@ -47,7 +47,7 @@ def with_streaming_response(self) -> TranslationsWithStreamingResponse: def create( self, *, - model: Union[str, Literal["whisper-large-v3"]], + model: Union[str, Literal["whisper-large-v3", "whisper-large-v3-turbo"]], file: FileTypes | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, response_format: Literal["json", "text", "verbose_json"] | NotGiven = NOT_GIVEN, @@ -65,7 +65,8 @@ def create( Args: model: ID of the model to use. - Only `whisper-large-v3` is currently available. + `whisper-large-v3` and `whisper-large-v3-turbo` are + currently available. file: The audio file object (not file name) translate, in one of these formats: flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. @@ -143,7 +144,7 @@ def with_streaming_response(self) -> AsyncTranslationsWithStreamingResponse: async def create( self, *, - model: Union[str, Literal["whisper-large-v3"]], + model: Union[str, Literal["whisper-large-v3", "whisper-large-v3-turbo"]], file: FileTypes | NotGiven = NOT_GIVEN, prompt: str | NotGiven = NOT_GIVEN, response_format: Literal["json", "text", "verbose_json"] | NotGiven = NOT_GIVEN, @@ -161,7 +162,8 @@ async def create( Args: model: ID of the model to use. - Only `whisper-large-v3` is currently available. + `whisper-large-v3` and `whisper-large-v3-turbo` are + currently available. file: The audio file object (not file name) translate, in one of these formats: flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. diff --git a/src/groq/resources/chat/completions.py b/src/groq/resources/chat/completions.py index 42576ea0..baaf21e8 100644 --- a/src/groq/resources/chat/completions.py +++ b/src/groq/resources/chat/completions.py @@ -70,6 +70,7 @@ def create( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_format: Optional[Literal["hidden", "raw", "parsed"]] | NotGiven = NOT_GIVEN, response_format: Optional[completion_create_params.ResponseFormat] | NotGiven = NOT_GIVEN, + search_settings: Optional[completion_create_params.SearchSettings] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "on_demand", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -111,6 +112,7 @@ def create( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_format: Optional[Literal["hidden", "raw", "parsed"]] | NotGiven = NOT_GIVEN, response_format: Optional[completion_create_params.ResponseFormat] | NotGiven = NOT_GIVEN, + search_settings: Optional[completion_create_params.SearchSettings] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "on_demand", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -152,6 +154,7 @@ def create( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_format: Optional[Literal["hidden", "raw", "parsed"]] | NotGiven = NOT_GIVEN, response_format: Optional[completion_create_params.ResponseFormat] | NotGiven = NOT_GIVEN, + search_settings: Optional[completion_create_params.SearchSettings] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "on_demand", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -202,6 +205,7 @@ def create( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_format: Optional[Literal["hidden", "raw", "parsed"]] | NotGiven = NOT_GIVEN, response_format: Optional[completion_create_params.ResponseFormat] | NotGiven = NOT_GIVEN, + search_settings: Optional[completion_create_params.SearchSettings] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "on_demand", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -229,8 +233,8 @@ def create( model: ID of the model to use. For details on which models are compatible with the Chat API, see available [models](https://console.groq.com/docs/models) - exclude_domains: A list of domains to exclude from the search results when the model uses a web - search tool. + exclude_domains: Deprecated: Use search_settings.exclude_domains instead. A list of domains to + exclude from the search results when the model uses a web search tool. frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to @@ -251,8 +255,8 @@ def create( A list of functions the model may generate JSON inputs for. - include_domains: A list of domains to include in the search results when the model uses a web - search tool. + include_domains: Deprecated: Use search_settings.include_domains instead. A list of domains to + include in the search results when the model uses a web search tool. logit_bias: This is not yet supported by any of our models. Modify the likelihood of specified tokens appearing in the completion. @@ -283,13 +287,15 @@ def create( reasoning_format: Specifies how to output reasoning tokens - response_format: An object specifying the format that the model must output. + response_format: An object specifying the format that the model must output. Setting to + `{ "type": "json_schema", "json_schema": {...} }` enables Structured Outputs + which ensures the model will match your supplied JSON schema. json_schema + response format is only supported on llama 4 models. Setting to + `{ "type": "json_object" }` enables the older JSON mode, which ensures the + message the model generates is valid JSON. Using `json_schema` is preferred for + models that support it. - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. + search_settings: Settings for web search functionality when the model uses a web search tool. seed: If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and parameters should return @@ -373,6 +379,7 @@ def create( "presence_penalty": presence_penalty, "reasoning_format": reasoning_format, "response_format": response_format, + "search_settings": search_settings, "seed": seed, "service_tier": service_tier, "stop": stop, @@ -437,6 +444,7 @@ async def create( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_format: Optional[Literal["hidden", "raw", "parsed"]] | NotGiven = NOT_GIVEN, response_format: Optional[completion_create_params.ResponseFormat] | NotGiven = NOT_GIVEN, + search_settings: Optional[completion_create_params.SearchSettings] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "on_demand", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -478,6 +486,7 @@ async def create( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_format: Optional[Literal["hidden", "raw", "parsed"]] | NotGiven = NOT_GIVEN, response_format: Optional[completion_create_params.ResponseFormat] | NotGiven = NOT_GIVEN, + search_settings: Optional[completion_create_params.SearchSettings] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "on_demand", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -519,6 +528,7 @@ async def create( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_format: Optional[Literal["hidden", "raw", "parsed"]] | NotGiven = NOT_GIVEN, response_format: Optional[completion_create_params.ResponseFormat] | NotGiven = NOT_GIVEN, + search_settings: Optional[completion_create_params.SearchSettings] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "on_demand", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -569,6 +579,7 @@ async def create( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, reasoning_format: Optional[Literal["hidden", "raw", "parsed"]] | NotGiven = NOT_GIVEN, response_format: Optional[completion_create_params.ResponseFormat] | NotGiven = NOT_GIVEN, + search_settings: Optional[completion_create_params.SearchSettings] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, service_tier: Optional[Literal["auto", "on_demand", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, @@ -596,8 +607,8 @@ async def create( model: ID of the model to use. For details on which models are compatible with the Chat API, see available [models](https://console.groq.com/docs/models) - exclude_domains: A list of domains to exclude from the search results when the model uses a web - search tool. + exclude_domains: Deprecated: Use search_settings.exclude_domains instead. A list of domains to + exclude from the search results when the model uses a web search tool. frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to @@ -618,8 +629,8 @@ async def create( A list of functions the model may generate JSON inputs for. - include_domains: A list of domains to include in the search results when the model uses a web - search tool. + include_domains: Deprecated: Use search_settings.include_domains instead. A list of domains to + include in the search results when the model uses a web search tool. logit_bias: This is not yet supported by any of our models. Modify the likelihood of specified tokens appearing in the completion. @@ -650,13 +661,15 @@ async def create( reasoning_format: Specifies how to output reasoning tokens - response_format: An object specifying the format that the model must output. - - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the - message the model generates is valid JSON. + response_format: An object specifying the format that the model must output. Setting to + `{ "type": "json_schema", "json_schema": {...} }` enables Structured Outputs + which ensures the model will match your supplied JSON schema. json_schema + response format is only supported on llama 4 models. Setting to + `{ "type": "json_object" }` enables the older JSON mode, which ensures the + message the model generates is valid JSON. Using `json_schema` is preferred for + models that support it. - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. + search_settings: Settings for web search functionality when the model uses a web search tool. seed: If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and parameters should return @@ -740,6 +753,7 @@ async def create( "presence_penalty": presence_penalty, "reasoning_format": reasoning_format, "response_format": response_format, + "search_settings": search_settings, "seed": seed, "service_tier": service_tier, "stop": stop, diff --git a/src/groq/types/audio/speech_create_params.py b/src/groq/types/audio/speech_create_params.py index 89720828..ff31e031 100644 --- a/src/groq/types/audio/speech_create_params.py +++ b/src/groq/types/audio/speech_create_params.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Union from typing_extensions import Literal, Required, TypedDict __all__ = ["SpeechCreateParams"] @@ -11,7 +12,7 @@ class SpeechCreateParams(TypedDict, total=False): input: Required[str] """The text to generate audio for.""" - model: Required[str] + model: Required[Union[str, Literal["playai-tts", "playai-tts-arabic"]]] """One of the [available TTS models](/docs/text-to-speech).""" voice: Required[str] diff --git a/src/groq/types/audio/transcription_create_params.py b/src/groq/types/audio/transcription_create_params.py index 4752f2d2..1837470b 100644 --- a/src/groq/types/audio/transcription_create_params.py +++ b/src/groq/types/audio/transcription_create_params.py @@ -11,8 +11,11 @@ class TranscriptionCreateParams(TypedDict, total=False): - model: Required[Union[str, Literal["whisper-large-v3"]]] - """ID of the model to use. Only `whisper-large-v3` is currently available.""" + model: Required[Union[str, Literal["whisper-large-v3", "whisper-large-v3-turbo"]]] + """ID of the model to use. + + `whisper-large-v3` and `whisper-large-v3-turbo` are currently available. + """ file: FileTypes """ diff --git a/src/groq/types/audio/translation_create_params.py b/src/groq/types/audio/translation_create_params.py index 7ee76e2c..c5894cce 100644 --- a/src/groq/types/audio/translation_create_params.py +++ b/src/groq/types/audio/translation_create_params.py @@ -11,8 +11,11 @@ class TranslationCreateParams(TypedDict, total=False): - model: Required[Union[str, Literal["whisper-large-v3"]]] - """ID of the model to use. Only `whisper-large-v3` is currently available.""" + model: Required[Union[str, Literal["whisper-large-v3", "whisper-large-v3-turbo"]]] + """ID of the model to use. + + `whisper-large-v3` and `whisper-large-v3-turbo` are currently available. + """ file: FileTypes """ diff --git a/src/groq/types/chat/chat_completion_message.py b/src/groq/types/chat/chat_completion_message.py index 4212e1d5..fa1c55fb 100644 --- a/src/groq/types/chat/chat_completion_message.py +++ b/src/groq/types/chat/chat_completion_message.py @@ -6,7 +6,35 @@ from ..._models import BaseModel from .chat_completion_message_tool_call import ChatCompletionMessageToolCall -__all__ = ["ChatCompletionMessage", "ExecutedTool", "FunctionCall"] +__all__ = [ + "ChatCompletionMessage", + "ExecutedTool", + "ExecutedToolSearchResults", + "ExecutedToolSearchResultsResult", + "FunctionCall", +] + + +class ExecutedToolSearchResultsResult(BaseModel): + content: Optional[str] = None + """The content of the search result""" + + score: Optional[float] = None + """The relevance score of the search result""" + + title: Optional[str] = None + """The title of the search result""" + + url: Optional[str] = None + """The URL of the search result""" + + +class ExecutedToolSearchResults(BaseModel): + images: Optional[List[str]] = None + """List of image URLs returned by the search""" + + results: Optional[List[ExecutedToolSearchResultsResult]] = None + """List of search results""" class ExecutedTool(BaseModel): @@ -22,6 +50,9 @@ class ExecutedTool(BaseModel): output: Optional[str] = None """The output returned by the tool.""" + search_results: Optional[ExecutedToolSearchResults] = None + """The search results returned by the tool, if applicable.""" + class FunctionCall(BaseModel): arguments: str diff --git a/src/groq/types/chat/completion_create_params.py b/src/groq/types/chat/completion_create_params.py index 428fb5c4..c5638589 100644 --- a/src/groq/types/chat/completion_create_params.py +++ b/src/groq/types/chat/completion_create_params.py @@ -11,7 +11,17 @@ from .chat_completion_tool_choice_option_param import ChatCompletionToolChoiceOptionParam from .chat_completion_function_call_option_param import ChatCompletionFunctionCallOptionParam -__all__ = ["CompletionCreateParams", "FunctionCall", "Function", "ResponseFormat"] +__all__ = [ + "CompletionCreateParams", + "FunctionCall", + "Function", + "ResponseFormat", + "ResponseFormatResponseFormatText", + "ResponseFormatResponseFormatJsonSchema", + "ResponseFormatResponseFormatJsonSchemaJsonSchema", + "ResponseFormatResponseFormatJsonObject", + "SearchSettings", +] class CompletionCreateParams(TypedDict, total=False): @@ -39,8 +49,8 @@ class CompletionCreateParams(TypedDict, total=False): exclude_domains: Optional[List[str]] """ - A list of domains to exclude from the search results when the model uses a web - search tool. + Deprecated: Use search_settings.exclude_domains instead. A list of domains to + exclude from the search results when the model uses a web search tool. """ frequency_penalty: Optional[float] @@ -71,8 +81,8 @@ class CompletionCreateParams(TypedDict, total=False): include_domains: Optional[List[str]] """ - A list of domains to include in the search results when the model uses a web - search tool. + Deprecated: Use search_settings.include_domains instead. A list of domains to + include in the search results when the model uses a web search tool. """ logit_bias: Optional[Dict[str, int]] @@ -128,13 +138,17 @@ class CompletionCreateParams(TypedDict, total=False): response_format: Optional[ResponseFormat] """An object specifying the format that the model must output. - Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. + Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured + Outputs which ensures the model will match your supplied JSON schema. + json_schema response format is only supported on llama 4 models. Setting to + `{ "type": "json_object" }` enables the older JSON mode, which ensures the + message the model generates is valid JSON. Using `json_schema` is preferred for + models that support it. """ + search_settings: Optional[SearchSettings] + """Settings for web search functionality when the model uses a web search tool.""" + seed: Optional[int] """ If specified, our system will make a best effort to sample deterministically, @@ -249,6 +263,65 @@ class Function(TypedDict, total=False): """ -class ResponseFormat(TypedDict, total=False): - type: Literal["text", "json_object"] - """Must be one of `text` or `json_object`.""" +class ResponseFormatResponseFormatText(TypedDict, total=False): + type: Required[Literal["text"]] + """The type of response format being defined. Always `text`.""" + + +class ResponseFormatResponseFormatJsonSchemaJsonSchema(TypedDict, total=False): + name: Required[str] + """The name of the response format. + + Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length + of 64. + """ + + description: str + """ + A description of what the response format is for, used by the model to determine + how to respond in the format. + """ + + schema: Dict[str, object] + """ + The schema for the response format, described as a JSON Schema object. Learn how + to build JSON schemas [here](https://json-schema.org/). + """ + + strict: Optional[bool] + """Whether to enable strict schema adherence when generating the output. + + If set to true, the model will always follow the exact schema defined in the + `schema` field. Only a subset of JSON Schema is supported when `strict` is + `true`. To learn more, read the + [Structured Outputs guide](/docs/guides/structured-outputs). + """ + + +class ResponseFormatResponseFormatJsonSchema(TypedDict, total=False): + json_schema: Required[ResponseFormatResponseFormatJsonSchemaJsonSchema] + """Structured Outputs configuration options, including a JSON Schema.""" + + type: Required[Literal["json_schema"]] + """The type of response format being defined. Always `json_schema`.""" + + +class ResponseFormatResponseFormatJsonObject(TypedDict, total=False): + type: Required[Literal["json_object"]] + """The type of response format being defined. Always `json_object`.""" + + +ResponseFormat: TypeAlias = Union[ + ResponseFormatResponseFormatText, ResponseFormatResponseFormatJsonSchema, ResponseFormatResponseFormatJsonObject +] + + +class SearchSettings(TypedDict, total=False): + exclude_domains: Optional[List[str]] + """A list of domains to exclude from the search results.""" + + include_domains: Optional[List[str]] + """A list of domains to include in the search results.""" + + include_images: Optional[bool] + """Whether to include images in the search results.""" diff --git a/tests/api_resources/audio/test_speech.py b/tests/api_resources/audio/test_speech.py index d2fa9860..ee22ed65 100644 --- a/tests/api_resources/audio/test_speech.py +++ b/tests/api_resources/audio/test_speech.py @@ -28,9 +28,9 @@ class TestSpeech: def test_method_create(self, client: Groq, respx_mock: MockRouter) -> None: respx_mock.post("/openai/v1/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"})) speech = client.audio.speech.create( - input="input", - model="model", - voice="voice", + input="The quick brown fox jumped over the lazy dog", + model="playai-tts", + voice="Fritz-PlayAI", ) assert speech.is_closed assert speech.json() == {"foo": "bar"} @@ -42,9 +42,9 @@ def test_method_create(self, client: Groq, respx_mock: MockRouter) -> None: def test_method_create_with_all_params(self, client: Groq, respx_mock: MockRouter) -> None: respx_mock.post("/openai/v1/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"})) speech = client.audio.speech.create( - input="input", - model="model", - voice="voice", + input="The quick brown fox jumped over the lazy dog", + model="playai-tts", + voice="Fritz-PlayAI", response_format="wav", speed=1, ) @@ -59,9 +59,9 @@ def test_raw_response_create(self, client: Groq, respx_mock: MockRouter) -> None respx_mock.post("/openai/v1/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"})) speech = client.audio.speech.with_raw_response.create( - input="input", - model="model", - voice="voice", + input="The quick brown fox jumped over the lazy dog", + model="playai-tts", + voice="Fritz-PlayAI", ) assert speech.is_closed is True @@ -74,9 +74,9 @@ def test_raw_response_create(self, client: Groq, respx_mock: MockRouter) -> None def test_streaming_response_create(self, client: Groq, respx_mock: MockRouter) -> None: respx_mock.post("/openai/v1/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"})) with client.audio.speech.with_streaming_response.create( - input="input", - model="model", - voice="voice", + input="The quick brown fox jumped over the lazy dog", + model="playai-tts", + voice="Fritz-PlayAI", ) as speech: assert not speech.is_closed assert speech.http_request.headers.get("X-Stainless-Lang") == "python" @@ -96,9 +96,9 @@ class TestAsyncSpeech: async def test_method_create(self, async_client: AsyncGroq, respx_mock: MockRouter) -> None: respx_mock.post("/openai/v1/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"})) speech = await async_client.audio.speech.create( - input="input", - model="model", - voice="voice", + input="The quick brown fox jumped over the lazy dog", + model="playai-tts", + voice="Fritz-PlayAI", ) assert speech.is_closed assert await speech.json() == {"foo": "bar"} @@ -110,9 +110,9 @@ async def test_method_create(self, async_client: AsyncGroq, respx_mock: MockRout async def test_method_create_with_all_params(self, async_client: AsyncGroq, respx_mock: MockRouter) -> None: respx_mock.post("/openai/v1/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"})) speech = await async_client.audio.speech.create( - input="input", - model="model", - voice="voice", + input="The quick brown fox jumped over the lazy dog", + model="playai-tts", + voice="Fritz-PlayAI", response_format="wav", speed=1, ) @@ -127,9 +127,9 @@ async def test_raw_response_create(self, async_client: AsyncGroq, respx_mock: Mo respx_mock.post("/openai/v1/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"})) speech = await async_client.audio.speech.with_raw_response.create( - input="input", - model="model", - voice="voice", + input="The quick brown fox jumped over the lazy dog", + model="playai-tts", + voice="Fritz-PlayAI", ) assert speech.is_closed is True @@ -142,9 +142,9 @@ async def test_raw_response_create(self, async_client: AsyncGroq, respx_mock: Mo async def test_streaming_response_create(self, async_client: AsyncGroq, respx_mock: MockRouter) -> None: respx_mock.post("/openai/v1/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"})) async with async_client.audio.speech.with_streaming_response.create( - input="input", - model="model", - voice="voice", + input="The quick brown fox jumped over the lazy dog", + model="playai-tts", + voice="Fritz-PlayAI", ) as speech: assert not speech.is_closed assert speech.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/audio/test_transcriptions.py b/tests/api_resources/audio/test_transcriptions.py index 342d1666..b70ec588 100644 --- a/tests/api_resources/audio/test_transcriptions.py +++ b/tests/api_resources/audio/test_transcriptions.py @@ -21,7 +21,7 @@ class TestTranscriptions: @parametrize def test_method_create(self, client: Groq) -> None: transcription = client.audio.transcriptions.create( - model="whisper-large-v3", + model="whisper-large-v3-turbo", ) assert_matches_type(Transcription, transcription, path=["response"]) @@ -29,7 +29,7 @@ def test_method_create(self, client: Groq) -> None: @parametrize def test_method_create_with_all_params(self, client: Groq) -> None: transcription = client.audio.transcriptions.create( - model="whisper-large-v3", + model="whisper-large-v3-turbo", file=b"raw file contents", language="string", prompt="prompt", @@ -44,7 +44,7 @@ def test_method_create_with_all_params(self, client: Groq) -> None: @parametrize def test_raw_response_create(self, client: Groq) -> None: response = client.audio.transcriptions.with_raw_response.create( - model="whisper-large-v3", + model="whisper-large-v3-turbo", ) assert response.is_closed is True @@ -56,7 +56,7 @@ def test_raw_response_create(self, client: Groq) -> None: @parametrize def test_streaming_response_create(self, client: Groq) -> None: with client.audio.transcriptions.with_streaming_response.create( - model="whisper-large-v3", + model="whisper-large-v3-turbo", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -74,7 +74,7 @@ class TestAsyncTranscriptions: @parametrize async def test_method_create(self, async_client: AsyncGroq) -> None: transcription = await async_client.audio.transcriptions.create( - model="whisper-large-v3", + model="whisper-large-v3-turbo", ) assert_matches_type(Transcription, transcription, path=["response"]) @@ -82,7 +82,7 @@ async def test_method_create(self, async_client: AsyncGroq) -> None: @parametrize async def test_method_create_with_all_params(self, async_client: AsyncGroq) -> None: transcription = await async_client.audio.transcriptions.create( - model="whisper-large-v3", + model="whisper-large-v3-turbo", file=b"raw file contents", language="string", prompt="prompt", @@ -97,7 +97,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncGroq) -> N @parametrize async def test_raw_response_create(self, async_client: AsyncGroq) -> None: response = await async_client.audio.transcriptions.with_raw_response.create( - model="whisper-large-v3", + model="whisper-large-v3-turbo", ) assert response.is_closed is True @@ -109,7 +109,7 @@ async def test_raw_response_create(self, async_client: AsyncGroq) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncGroq) -> None: async with async_client.audio.transcriptions.with_streaming_response.create( - model="whisper-large-v3", + model="whisper-large-v3-turbo", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/audio/test_translations.py b/tests/api_resources/audio/test_translations.py index 1a6645c2..d9858cf1 100644 --- a/tests/api_resources/audio/test_translations.py +++ b/tests/api_resources/audio/test_translations.py @@ -21,7 +21,7 @@ class TestTranslations: @parametrize def test_method_create(self, client: Groq) -> None: translation = client.audio.translations.create( - model="whisper-1", + model="whisper-large-v3-turbo", ) assert_matches_type(Translation, translation, path=["response"]) @@ -29,7 +29,7 @@ def test_method_create(self, client: Groq) -> None: @parametrize def test_method_create_with_all_params(self, client: Groq) -> None: translation = client.audio.translations.create( - model="whisper-1", + model="whisper-large-v3-turbo", file=b"raw file contents", prompt="prompt", response_format="json", @@ -42,7 +42,7 @@ def test_method_create_with_all_params(self, client: Groq) -> None: @parametrize def test_raw_response_create(self, client: Groq) -> None: response = client.audio.translations.with_raw_response.create( - model="whisper-1", + model="whisper-large-v3-turbo", ) assert response.is_closed is True @@ -54,7 +54,7 @@ def test_raw_response_create(self, client: Groq) -> None: @parametrize def test_streaming_response_create(self, client: Groq) -> None: with client.audio.translations.with_streaming_response.create( - model="whisper-1", + model="whisper-large-v3-turbo", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -72,7 +72,7 @@ class TestAsyncTranslations: @parametrize async def test_method_create(self, async_client: AsyncGroq) -> None: translation = await async_client.audio.translations.create( - model="whisper-1", + model="whisper-large-v3-turbo", ) assert_matches_type(Translation, translation, path=["response"]) @@ -80,7 +80,7 @@ async def test_method_create(self, async_client: AsyncGroq) -> None: @parametrize async def test_method_create_with_all_params(self, async_client: AsyncGroq) -> None: translation = await async_client.audio.translations.create( - model="whisper-1", + model="whisper-large-v3-turbo", file=b"raw file contents", prompt="prompt", response_format="json", @@ -93,7 +93,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncGroq) -> N @parametrize async def test_raw_response_create(self, async_client: AsyncGroq) -> None: response = await async_client.audio.translations.with_raw_response.create( - model="whisper-1", + model="whisper-large-v3-turbo", ) assert response.is_closed is True @@ -105,7 +105,7 @@ async def test_raw_response_create(self, async_client: AsyncGroq) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncGroq) -> None: async with async_client.audio.translations.with_streaming_response.create( - model="whisper-1", + model="whisper-large-v3-turbo", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index 0f65ce0b..d1d422e9 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -26,7 +26,7 @@ def test_method_create(self, client: Groq) -> None: "role": "system", } ], - model="string", + model="meta-llama/llama-4-scout-17b-16e-instruct", ) assert_matches_type(ChatCompletion, completion, path=["response"]) @@ -40,7 +40,7 @@ def test_method_create_with_all_params(self, client: Groq) -> None: "name": "name", } ], - model="string", + model="meta-llama/llama-4-scout-17b-16e-instruct", exclude_domains=["string"], frequency_penalty=-2, function_call="none", @@ -61,7 +61,12 @@ def test_method_create_with_all_params(self, client: Groq) -> None: parallel_tool_calls=True, presence_penalty=-2, reasoning_format="hidden", - response_format={"type": "json_object"}, + response_format={"type": "text"}, + search_settings={ + "exclude_domains": ["string"], + "include_domains": ["string"], + "include_images": True, + }, seed=0, service_tier="auto", stop="\n", @@ -94,7 +99,7 @@ def test_raw_response_create(self, client: Groq) -> None: "role": "system", } ], - model="string", + model="meta-llama/llama-4-scout-17b-16e-instruct", ) assert response.is_closed is True @@ -111,7 +116,7 @@ def test_streaming_response_create(self, client: Groq) -> None: "role": "system", } ], - model="string", + model="meta-llama/llama-4-scout-17b-16e-instruct", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -134,7 +139,7 @@ async def test_method_create(self, async_client: AsyncGroq) -> None: "role": "system", } ], - model="string", + model="meta-llama/llama-4-scout-17b-16e-instruct", ) assert_matches_type(ChatCompletion, completion, path=["response"]) @@ -148,7 +153,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncGroq) -> N "name": "name", } ], - model="string", + model="meta-llama/llama-4-scout-17b-16e-instruct", exclude_domains=["string"], frequency_penalty=-2, function_call="none", @@ -169,7 +174,12 @@ async def test_method_create_with_all_params(self, async_client: AsyncGroq) -> N parallel_tool_calls=True, presence_penalty=-2, reasoning_format="hidden", - response_format={"type": "json_object"}, + response_format={"type": "text"}, + search_settings={ + "exclude_domains": ["string"], + "include_domains": ["string"], + "include_images": True, + }, seed=0, service_tier="auto", stop="\n", @@ -202,7 +212,7 @@ async def test_raw_response_create(self, async_client: AsyncGroq) -> None: "role": "system", } ], - model="string", + model="meta-llama/llama-4-scout-17b-16e-instruct", ) assert response.is_closed is True @@ -219,7 +229,7 @@ async def test_streaming_response_create(self, async_client: AsyncGroq) -> None: "role": "system", } ], - model="string", + model="meta-llama/llama-4-scout-17b-16e-instruct", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/test_client.py b/tests/test_client.py index 500322e3..78d8087e 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -797,7 +797,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: "role": "system", } ], - model="string", + model="meta-llama/llama-4-scout-17b-16e-instruct", ) assert response.retries_taken == failures_before_success @@ -827,7 +827,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: "role": "system", } ], - model="string", + model="meta-llama/llama-4-scout-17b-16e-instruct", extra_headers={"x-stainless-retry-count": Omit()}, ) @@ -859,7 +859,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: "role": "system", } ], - model="string", + model="meta-llama/llama-4-scout-17b-16e-instruct", extra_headers={"x-stainless-retry-count": "42"}, ) @@ -1624,7 +1624,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: "role": "system", } ], - model="string", + model="meta-llama/llama-4-scout-17b-16e-instruct", ) assert response.retries_taken == failures_before_success @@ -1657,7 +1657,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: "role": "system", } ], - model="string", + model="meta-llama/llama-4-scout-17b-16e-instruct", extra_headers={"x-stainless-retry-count": Omit()}, ) @@ -1690,7 +1690,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: "role": "system", } ], - model="string", + model="meta-llama/llama-4-scout-17b-16e-instruct", extra_headers={"x-stainless-retry-count": "42"}, ) diff --git a/tests/test_utils/test_proxy.py b/tests/test_utils/test_proxy.py index 2fa9c4a9..4c48c14b 100644 --- a/tests/test_utils/test_proxy.py +++ b/tests/test_utils/test_proxy.py @@ -21,3 +21,14 @@ def test_recursive_proxy() -> None: assert dir(proxy) == [] assert type(proxy).__name__ == "RecursiveLazyProxy" assert type(operator.attrgetter("name.foo.bar.baz")(proxy)).__name__ == "RecursiveLazyProxy" + + +def test_isinstance_does_not_error() -> None: + class AlwaysErrorProxy(LazyProxy[Any]): + @override + def __load__(self) -> Any: + raise RuntimeError("Mocking missing dependency") + + proxy = AlwaysErrorProxy() + assert not isinstance(proxy, dict) + assert isinstance(proxy, LazyProxy)