diff --git a/README.md b/README.md index c04d204..f732655 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,16 @@ asyncio.run(main()) ### Text-to-Speech +**Selecting a model:** + +```python +# Recommended for production +production_audio = client.tts.convert( + text="Production speech", + model="s2.1-pro", +) +``` + **With custom voice:** ```python diff --git a/src/fishaudio/resources/tts.py b/src/fishaudio/resources/tts.py index 0167ce6..2a5114a 100644 --- a/src/fishaudio/resources/tts.py +++ b/src/fishaudio/resources/tts.py @@ -82,7 +82,7 @@ def stream( latency: Optional[LatencyMode] = None, speed: Optional[float] = None, config: TTSConfig = TTSConfig(), - model: Model = "s2-pro", + model: Union[Model, str] = "s2.1-pro", request_options: Optional[RequestOptions] = None, ) -> AudioStream: """ @@ -166,7 +166,7 @@ def convert( latency: Optional[LatencyMode] = None, speed: Optional[float] = None, config: TTSConfig = TTSConfig(), - model: Model = "s2-pro", + model: Union[Model, str] = "s2.1-pro", request_options: Optional[RequestOptions] = None, ) -> bytes: """ @@ -228,7 +228,7 @@ def stream_websocket( latency: Optional[LatencyMode] = None, speed: Optional[float] = None, config: TTSConfig = TTSConfig(), - model: Model = "s2-pro", + model: Union[Model, str] = "s2.1-pro", max_workers: int = 10, ws_options: Optional[WebSocketOptions] = None, ) -> Iterator[bytes]: @@ -386,7 +386,7 @@ async def stream( latency: Optional[LatencyMode] = None, speed: Optional[float] = None, config: TTSConfig = TTSConfig(), - model: Model = "s2-pro", + model: Union[Model, str] = "s2.1-pro", request_options: Optional[RequestOptions] = None, ) -> AsyncAudioStream: """ @@ -471,7 +471,7 @@ async def convert( latency: Optional[LatencyMode] = None, speed: Optional[float] = None, config: TTSConfig = TTSConfig(), - model: Model = "s2-pro", + model: Union[Model, str] = "s2.1-pro", request_options: Optional[RequestOptions] = None, ) -> bytes: """ @@ -534,7 +534,7 @@ async def stream_websocket( latency: Optional[LatencyMode] = None, speed: Optional[float] = None, config: TTSConfig = TTSConfig(), - model: Model = "s2-pro", + model: Union[Model, str] = "s2.1-pro", ws_options: Optional[WebSocketOptions] = None, ): """ diff --git a/src/fishaudio/types/shared.py b/src/fishaudio/types/shared.py index 879a012..a160e65 100644 --- a/src/fishaudio/types/shared.py +++ b/src/fishaudio/types/shared.py @@ -22,7 +22,7 @@ class PaginatedResponse(BaseModel, Generic[T]): # Model types -Model = Literal["speech-1.5", "speech-1.6", "s1", "s2-pro"] +Model = Literal["s1", "s2-pro", "s2.1-pro"] # Deprecated models DEPRECATED_MODELS = {"speech-1.5", "speech-1.6"} @@ -32,7 +32,7 @@ def warn_if_deprecated_model(model: str) -> None: """Emit a deprecation warning if a legacy model is used.""" if model in DEPRECATED_MODELS: warnings.warn( - f"Model '{model}' is deprecated. Use 's1' or 's2-pro' instead.", + f"Model '{model}' is deprecated. Use 's2.1-pro' instead.", DeprecationWarning, stacklevel=3, ) diff --git a/tests/unit/test_tts.py b/tests/unit/test_tts.py index 132038a..f6075a5 100644 --- a/tests/unit/test_tts.py +++ b/tests/unit/test_tts.py @@ -63,7 +63,7 @@ def test_stream_basic(self, tts_client, mock_client_wrapper): # Check headers assert call_args[1]["headers"]["Content-Type"] == "application/msgpack" - assert call_args[1]["headers"]["model"] == "s2-pro" # default model + assert call_args[1]["headers"]["model"] == "s2.1-pro" # default model # Check payload was msgpack encoded assert "content" in call_args[1] @@ -84,6 +84,8 @@ def test_convert_basic(self, tts_client, mock_client_wrapper): # Verify request was made correctly mock_client_wrapper.request.assert_called_once() + call_args = mock_client_wrapper.request.call_args + assert call_args[1]["headers"]["model"] == "s2.1-pro" def test_convert_with_reference_id(self, tts_client, mock_client_wrapper): """Test TTS with reference voice ID.""" @@ -510,6 +512,7 @@ async def async_iter_bytes(): assert call_args[0][0] == "POST" assert call_args[0][1] == "/v1/tts" + assert call_args[1]["headers"]["model"] == "s2.1-pro" @pytest.mark.asyncio async def test_convert_basic(self, async_tts_client, async_mock_client_wrapper): @@ -533,6 +536,8 @@ async def async_iter_bytes(): # Verify request was made async_mock_client_wrapper.request.assert_called_once() + call_args = async_mock_client_wrapper.request.call_args + assert call_args[1]["headers"]["model"] == "s2.1-pro" @pytest.mark.asyncio async def test_convert_with_reference_id( diff --git a/tests/unit/test_tts_realtime.py b/tests/unit/test_tts_realtime.py index c3b60a9..0a25e62 100644 --- a/tests/unit/test_tts_realtime.py +++ b/tests/unit/test_tts_realtime.py @@ -92,6 +92,7 @@ def test_stream_websocket_basic( # Verify WebSocket connection was created mock_connect_ws.assert_called_once() assert mock_connect_ws.call_args[0][0] == "/v1/tts/live" + assert mock_connect_ws.call_args[1]["headers"]["model"] == "s2.1-pro" @pytest.mark.filterwarnings("ignore::DeprecationWarning") @patch("fishaudio.resources.tts.connect_ws") @@ -425,6 +426,7 @@ async def text_stream(): # Verify WebSocket connection was created mock_aconnect_ws.assert_called_once() assert mock_aconnect_ws.call_args[0][0] == "/v1/tts/live" + assert mock_aconnect_ws.call_args[1]["headers"]["model"] == "s2.1-pro" @pytest.mark.filterwarnings("ignore::DeprecationWarning") @pytest.mark.asyncio