# This file was auto-generated by Fern from our API Definition.

import contextlib
import typing
from json.decoder import JSONDecodeError
from logging import error, warning

from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ...core.http_response import AsyncHttpResponse, HttpResponse
from ...core.http_sse._api import EventSource
from ...core.pydantic_utilities import parse_sse_obj
from ...core.request_options import RequestOptions
from ...core.unchecked_base_model import construct_type
from ..errors.bad_request_error import BadRequestError
from ..errors.internal_server_error import InternalServerError
from ..errors.unauthorized_error import UnauthorizedError
from ..types.lightningv2request_language import Lightningv2RequestLanguage
from ..types.lightningv2request_output_format import Lightningv2RequestOutputFormat

# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)


class RawLightningV2Client:
    def __init__(self, *, client_wrapper: SyncClientWrapper):
        self._client_wrapper = client_wrapper

    @contextlib.contextmanager
    def synthesize_lightningv2speech(
        self,
        *,
        text: str,
        voice_id: str,
        sample_rate: typing.Optional[int] = OMIT,
        speed: typing.Optional[float] = OMIT,
        consistency: typing.Optional[float] = OMIT,
        similarity: typing.Optional[float] = OMIT,
        enhancement: typing.Optional[float] = OMIT,
        language: typing.Optional[Lightningv2RequestLanguage] = OMIT,
        output_format: typing.Optional[Lightningv2RequestOutputFormat] = OMIT,
        pronunciation_dicts: typing.Optional[typing.Sequence[str]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> typing.Iterator[HttpResponse[typing.Iterator[bytes]]]:
        """
        Get speech for given text using the Waves API

        Parameters
        ----------
        text : str
            The text to convert to speech.

        voice_id : str
            The voice identifier to use for speech generation.

        sample_rate : typing.Optional[int]
            The sample rate for the generated audio.

        speed : typing.Optional[float]
            The speed of the generated speech.

        consistency : typing.Optional[float]
            This parameter controls word repetition and skipping. Decrease it to prevent skipped words, and increase it to prevent repetition.

        similarity : typing.Optional[float]
            This parameter controls the similarity between the generated speech and the reference audio. Increase it to make the speech more similar to the reference audio.

        enhancement : typing.Optional[float]
            Enhances speech quality at the cost of increased latency.

        language : typing.Optional[Lightningv2RequestLanguage]
            Determines how numbers are spelled out. If set to 'en', numbers will be read as individual digits in English. If set to 'hi', numbers will be read as individual digits in Hindi.

        output_format : typing.Optional[Lightningv2RequestOutputFormat]
            The format of the output audio.

        pronunciation_dicts : typing.Optional[typing.Sequence[str]]
            The IDs of the pronunciation dictionaries to use for speech generation.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration. You can pass in configuration such as `chunk_size`, and more to customize the request and response.

        Returns
        -------
        typing.Iterator[HttpResponse[typing.Iterator[bytes]]]
            Synthesized speech retrieved successfully.
        """
        with self._client_wrapper.httpx_client.stream(
            "api/v1/lightning-v2/get_speech",
            base_url=self._client_wrapper.get_environment().waves,
            method="POST",
            json={
                "text": text,
                "voice_id": voice_id,
                "sample_rate": sample_rate,
                "speed": speed,
                "consistency": consistency,
                "similarity": similarity,
                "enhancement": enhancement,
                "language": language,
                "output_format": output_format,
                "pronunciation_dicts": pronunciation_dicts,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        ) as _response:

            def _stream() -> HttpResponse[typing.Iterator[bytes]]:
                try:
                    if 200 <= _response.status_code < 300:
                        _chunk_size = request_options.get("chunk_size", None) if request_options is not None else None
                        return HttpResponse(
                            response=_response, data=(_chunk for _chunk in _response.iter_bytes(chunk_size=_chunk_size))
                        )
                    _response.read()
                    if _response.status_code == 400:
                        raise BadRequestError(
                            headers=dict(_response.headers),
                            body=typing.cast(
                                typing.Any,
                                construct_type(
                                    type_=typing.Any,  # type: ignore
                                    object_=_response.json(),
                                ),
                            ),
                        )
                    if _response.status_code == 401:
                        raise UnauthorizedError(
                            headers=dict(_response.headers),
                            body=typing.cast(
                                typing.Any,
                                construct_type(
                                    type_=typing.Any,  # type: ignore
                                    object_=_response.json(),
                                ),
                            ),
                        )
                    if _response.status_code == 500:
                        raise InternalServerError(
                            headers=dict(_response.headers),
                            body=typing.cast(
                                typing.Any,
                                construct_type(
                                    type_=typing.Any,  # type: ignore
                                    object_=_response.json(),
                                ),
                            ),
                        )
                    _response_json = _response.json()
                except JSONDecodeError:
                    raise ApiError(
                        status_code=_response.status_code, headers=dict(_response.headers), body=_response.text
                    )
                raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

            yield _stream()

    @contextlib.contextmanager
    def stream_lightningv2speech(
        self,
        *,
        text: str,
        voice_id: str,
        sample_rate: typing.Optional[int] = OMIT,
        speed: typing.Optional[float] = OMIT,
        consistency: typing.Optional[float] = OMIT,
        similarity: typing.Optional[float] = OMIT,
        enhancement: typing.Optional[float] = OMIT,
        language: typing.Optional[Lightningv2RequestLanguage] = OMIT,
        output_format: typing.Optional[Lightningv2RequestOutputFormat] = OMIT,
        pronunciation_dicts: typing.Optional[typing.Sequence[str]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> typing.Iterator[HttpResponse[typing.Iterator[typing.Any]]]:
        """
        The Lightning v2 SSE API provides real-time text-to-speech streaming capabilities with high-quality voice synthesis. This API uses Server-Sent Events (SSE) to deliver audio chunks as they're generated, enabling low-latency audio playback without waiting for the entire audio file to process.
        For an end-to-end example of how to use the Lightning v2 SSE API, check out [Text to Speech (SSE) Example](https://github.com/smallest-inc/waves-examples/blob/main/lightning_v2/http_streaming/http_streaming_api.py)

        ## When to Use

        - **Interactive Applications**: Perfect for chatbots, virtual assistants, and other applications requiring immediate voice responses
        - **Long-Form Content**: Efficiently stream audio for articles, stories, or other long-form content without buffering delays
        - **Voice User Interfaces**: Create natural-sounding voice interfaces with minimal perceived latency
        - **Accessibility Solutions**: Provide real-time audio versions of written content for users with visual impairments

        ## How It Works

        1. **Make a POST Request**: Send your text and voice settings to the API endpoint
        2. **Receive Audio Chunks**: The API processes your text and streams audio back as base64-encoded chunks with 1024 byte size
        3. **Process the Stream**: Handle the SSE events to decode and play audio chunks sequentially
        4. **End of Stream**: The API sends a completion event when all audio has been delivered

        Parameters
        ----------
        text : str
            The text to convert to speech.

        voice_id : str
            The voice identifier to use for speech generation.

        sample_rate : typing.Optional[int]
            The sample rate for the generated audio.

        speed : typing.Optional[float]
            The speed of the generated speech.

        consistency : typing.Optional[float]
            This parameter controls word repetition and skipping. Decrease it to prevent skipped words, and increase it to prevent repetition.

        similarity : typing.Optional[float]
            This parameter controls the similarity between the generated speech and the reference audio. Increase it to make the speech more similar to the reference audio.

        enhancement : typing.Optional[float]
            Enhances speech quality at the cost of increased latency.

        language : typing.Optional[Lightningv2RequestLanguage]
            Determines how numbers are spelled out. If set to 'en', numbers will be read as individual digits in English. If set to 'hi', numbers will be read as individual digits in Hindi.

        output_format : typing.Optional[Lightningv2RequestOutputFormat]
            The format of the output audio.

        pronunciation_dicts : typing.Optional[typing.Sequence[str]]
            The IDs of the pronunciation dictionaries to use for speech generation.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Yields
        ------
        typing.Iterator[HttpResponse[typing.Iterator[typing.Any]]]
            Synthesized speech retrieved successfully.
        """
        with self._client_wrapper.httpx_client.stream(
            "api/v1/lightning-v2/stream",
            base_url=self._client_wrapper.get_environment().waves,
            method="POST",
            json={
                "text": text,
                "voice_id": voice_id,
                "sample_rate": sample_rate,
                "speed": speed,
                "consistency": consistency,
                "similarity": similarity,
                "enhancement": enhancement,
                "language": language,
                "output_format": output_format,
                "pronunciation_dicts": pronunciation_dicts,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        ) as _response:

            def _stream() -> HttpResponse[typing.Iterator[typing.Any]]:
                try:
                    if 200 <= _response.status_code < 300:

                        def _iter():
                            _event_source = EventSource(_response)
                            for _sse in _event_source.iter_sse():
                                if _sse.data == None:
                                    return
                                try:
                                    yield typing.cast(
                                        typing.Any,
                                        parse_sse_obj(
                                            sse=_sse,
                                            type_=typing.Any,  # type: ignore
                                        ),
                                    )
                                except JSONDecodeError as e:
                                    warning(f"Skipping SSE event with invalid JSON: {e}, sse: {_sse!r}")
                                except (TypeError, ValueError, KeyError, AttributeError) as e:
                                    warning(
                                        f"Skipping SSE event due to model construction error: {type(e).__name__}: {e}, sse: {_sse!r}"
                                    )
                                except Exception as e:
                                    error(
                                        f"Unexpected error processing SSE event: {type(e).__name__}: {e}, sse: {_sse!r}"
                                    )
                            return

                        return HttpResponse(response=_response, data=_iter())
                    _response.read()
                    if _response.status_code == 400:
                        raise BadRequestError(
                            headers=dict(_response.headers),
                            body=typing.cast(
                                typing.Any,
                                construct_type(
                                    type_=typing.Any,  # type: ignore
                                    object_=_response.json(),
                                ),
                            ),
                        )
                    if _response.status_code == 401:
                        raise UnauthorizedError(
                            headers=dict(_response.headers),
                            body=typing.cast(
                                typing.Any,
                                construct_type(
                                    type_=typing.Any,  # type: ignore
                                    object_=_response.json(),
                                ),
                            ),
                        )
                    if _response.status_code == 500:
                        raise InternalServerError(
                            headers=dict(_response.headers),
                            body=typing.cast(
                                typing.Any,
                                construct_type(
                                    type_=typing.Any,  # type: ignore
                                    object_=_response.json(),
                                ),
                            ),
                        )
                    _response_json = _response.json()
                except JSONDecodeError:
                    raise ApiError(
                        status_code=_response.status_code, headers=dict(_response.headers), body=_response.text
                    )
                raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

            yield _stream()


class AsyncRawLightningV2Client:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._client_wrapper = client_wrapper

    @contextlib.asynccontextmanager
    async def synthesize_lightningv2speech(
        self,
        *,
        text: str,
        voice_id: str,
        sample_rate: typing.Optional[int] = OMIT,
        speed: typing.Optional[float] = OMIT,
        consistency: typing.Optional[float] = OMIT,
        similarity: typing.Optional[float] = OMIT,
        enhancement: typing.Optional[float] = OMIT,
        language: typing.Optional[Lightningv2RequestLanguage] = OMIT,
        output_format: typing.Optional[Lightningv2RequestOutputFormat] = OMIT,
        pronunciation_dicts: typing.Optional[typing.Sequence[str]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> typing.AsyncIterator[AsyncHttpResponse[typing.AsyncIterator[bytes]]]:
        """
        Get speech for given text using the Waves API

        Parameters
        ----------
        text : str
            The text to convert to speech.

        voice_id : str
            The voice identifier to use for speech generation.

        sample_rate : typing.Optional[int]
            The sample rate for the generated audio.

        speed : typing.Optional[float]
            The speed of the generated speech.

        consistency : typing.Optional[float]
            This parameter controls word repetition and skipping. Decrease it to prevent skipped words, and increase it to prevent repetition.

        similarity : typing.Optional[float]
            This parameter controls the similarity between the generated speech and the reference audio. Increase it to make the speech more similar to the reference audio.

        enhancement : typing.Optional[float]
            Enhances speech quality at the cost of increased latency.

        language : typing.Optional[Lightningv2RequestLanguage]
            Determines how numbers are spelled out. If set to 'en', numbers will be read as individual digits in English. If set to 'hi', numbers will be read as individual digits in Hindi.

        output_format : typing.Optional[Lightningv2RequestOutputFormat]
            The format of the output audio.

        pronunciation_dicts : typing.Optional[typing.Sequence[str]]
            The IDs of the pronunciation dictionaries to use for speech generation.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration. You can pass in configuration such as `chunk_size`, and more to customize the request and response.

        Returns
        -------
        typing.AsyncIterator[AsyncHttpResponse[typing.AsyncIterator[bytes]]]
            Synthesized speech retrieved successfully.
        """
        async with self._client_wrapper.httpx_client.stream(
            "api/v1/lightning-v2/get_speech",
            base_url=self._client_wrapper.get_environment().waves,
            method="POST",
            json={
                "text": text,
                "voice_id": voice_id,
                "sample_rate": sample_rate,
                "speed": speed,
                "consistency": consistency,
                "similarity": similarity,
                "enhancement": enhancement,
                "language": language,
                "output_format": output_format,
                "pronunciation_dicts": pronunciation_dicts,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        ) as _response:

            async def _stream() -> AsyncHttpResponse[typing.AsyncIterator[bytes]]:
                try:
                    if 200 <= _response.status_code < 300:
                        _chunk_size = request_options.get("chunk_size", None) if request_options is not None else None
                        return AsyncHttpResponse(
                            response=_response,
                            data=(_chunk async for _chunk in _response.aiter_bytes(chunk_size=_chunk_size)),
                        )
                    await _response.aread()
                    if _response.status_code == 400:
                        raise BadRequestError(
                            headers=dict(_response.headers),
                            body=typing.cast(
                                typing.Any,
                                construct_type(
                                    type_=typing.Any,  # type: ignore
                                    object_=_response.json(),
                                ),
                            ),
                        )
                    if _response.status_code == 401:
                        raise UnauthorizedError(
                            headers=dict(_response.headers),
                            body=typing.cast(
                                typing.Any,
                                construct_type(
                                    type_=typing.Any,  # type: ignore
                                    object_=_response.json(),
                                ),
                            ),
                        )
                    if _response.status_code == 500:
                        raise InternalServerError(
                            headers=dict(_response.headers),
                            body=typing.cast(
                                typing.Any,
                                construct_type(
                                    type_=typing.Any,  # type: ignore
                                    object_=_response.json(),
                                ),
                            ),
                        )
                    _response_json = _response.json()
                except JSONDecodeError:
                    raise ApiError(
                        status_code=_response.status_code, headers=dict(_response.headers), body=_response.text
                    )
                raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

            yield await _stream()

    @contextlib.asynccontextmanager
    async def stream_lightningv2speech(
        self,
        *,
        text: str,
        voice_id: str,
        sample_rate: typing.Optional[int] = OMIT,
        speed: typing.Optional[float] = OMIT,
        consistency: typing.Optional[float] = OMIT,
        similarity: typing.Optional[float] = OMIT,
        enhancement: typing.Optional[float] = OMIT,
        language: typing.Optional[Lightningv2RequestLanguage] = OMIT,
        output_format: typing.Optional[Lightningv2RequestOutputFormat] = OMIT,
        pronunciation_dicts: typing.Optional[typing.Sequence[str]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> typing.AsyncIterator[AsyncHttpResponse[typing.AsyncIterator[typing.Any]]]:
        """
        The Lightning v2 SSE API provides real-time text-to-speech streaming capabilities with high-quality voice synthesis. This API uses Server-Sent Events (SSE) to deliver audio chunks as they're generated, enabling low-latency audio playback without waiting for the entire audio file to process.
        For an end-to-end example of how to use the Lightning v2 SSE API, check out [Text to Speech (SSE) Example](https://github.com/smallest-inc/waves-examples/blob/main/lightning_v2/http_streaming/http_streaming_api.py)

        ## When to Use

        - **Interactive Applications**: Perfect for chatbots, virtual assistants, and other applications requiring immediate voice responses
        - **Long-Form Content**: Efficiently stream audio for articles, stories, or other long-form content without buffering delays
        - **Voice User Interfaces**: Create natural-sounding voice interfaces with minimal perceived latency
        - **Accessibility Solutions**: Provide real-time audio versions of written content for users with visual impairments

        ## How It Works

        1. **Make a POST Request**: Send your text and voice settings to the API endpoint
        2. **Receive Audio Chunks**: The API processes your text and streams audio back as base64-encoded chunks with 1024 byte size
        3. **Process the Stream**: Handle the SSE events to decode and play audio chunks sequentially
        4. **End of Stream**: The API sends a completion event when all audio has been delivered

        Parameters
        ----------
        text : str
            The text to convert to speech.

        voice_id : str
            The voice identifier to use for speech generation.

        sample_rate : typing.Optional[int]
            The sample rate for the generated audio.

        speed : typing.Optional[float]
            The speed of the generated speech.

        consistency : typing.Optional[float]
            This parameter controls word repetition and skipping. Decrease it to prevent skipped words, and increase it to prevent repetition.

        similarity : typing.Optional[float]
            This parameter controls the similarity between the generated speech and the reference audio. Increase it to make the speech more similar to the reference audio.

        enhancement : typing.Optional[float]
            Enhances speech quality at the cost of increased latency.

        language : typing.Optional[Lightningv2RequestLanguage]
            Determines how numbers are spelled out. If set to 'en', numbers will be read as individual digits in English. If set to 'hi', numbers will be read as individual digits in Hindi.

        output_format : typing.Optional[Lightningv2RequestOutputFormat]
            The format of the output audio.

        pronunciation_dicts : typing.Optional[typing.Sequence[str]]
            The IDs of the pronunciation dictionaries to use for speech generation.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Yields
        ------
        typing.AsyncIterator[AsyncHttpResponse[typing.AsyncIterator[typing.Any]]]
            Synthesized speech retrieved successfully.
        """
        async with self._client_wrapper.httpx_client.stream(
            "api/v1/lightning-v2/stream",
            base_url=self._client_wrapper.get_environment().waves,
            method="POST",
            json={
                "text": text,
                "voice_id": voice_id,
                "sample_rate": sample_rate,
                "speed": speed,
                "consistency": consistency,
                "similarity": similarity,
                "enhancement": enhancement,
                "language": language,
                "output_format": output_format,
                "pronunciation_dicts": pronunciation_dicts,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        ) as _response:

            async def _stream() -> AsyncHttpResponse[typing.AsyncIterator[typing.Any]]:
                try:
                    if 200 <= _response.status_code < 300:

                        async def _iter():
                            _event_source = EventSource(_response)
                            async for _sse in _event_source.aiter_sse():
                                if _sse.data == None:
                                    return
                                try:
                                    yield typing.cast(
                                        typing.Any,
                                        parse_sse_obj(
                                            sse=_sse,
                                            type_=typing.Any,  # type: ignore
                                        ),
                                    )
                                except JSONDecodeError as e:
                                    warning(f"Skipping SSE event with invalid JSON: {e}, sse: {_sse!r}")
                                except (TypeError, ValueError, KeyError, AttributeError) as e:
                                    warning(
                                        f"Skipping SSE event due to model construction error: {type(e).__name__}: {e}, sse: {_sse!r}"
                                    )
                                except Exception as e:
                                    error(
                                        f"Unexpected error processing SSE event: {type(e).__name__}: {e}, sse: {_sse!r}"
                                    )
                            return

                        return AsyncHttpResponse(response=_response, data=_iter())
                    await _response.aread()
                    if _response.status_code == 400:
                        raise BadRequestError(
                            headers=dict(_response.headers),
                            body=typing.cast(
                                typing.Any,
                                construct_type(
                                    type_=typing.Any,  # type: ignore
                                    object_=_response.json(),
                                ),
                            ),
                        )
                    if _response.status_code == 401:
                        raise UnauthorizedError(
                            headers=dict(_response.headers),
                            body=typing.cast(
                                typing.Any,
                                construct_type(
                                    type_=typing.Any,  # type: ignore
                                    object_=_response.json(),
                                ),
                            ),
                        )
                    if _response.status_code == 500:
                        raise InternalServerError(
                            headers=dict(_response.headers),
                            body=typing.cast(
                                typing.Any,
                                construct_type(
                                    type_=typing.Any,  # type: ignore
                                    object_=_response.json(),
                                ),
                            ),
                        )
                    _response_json = _response.json()
                except JSONDecodeError:
                    raise ApiError(
                        status_code=_response.status_code, headers=dict(_response.headers), body=_response.text
                    )
                raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

            yield await _stream()
