diff --git a/api/controllers/common/errors.py b/api/controllers/common/errors.py index 252cf3549a..88a0c39c98 100644 --- a/api/controllers/common/errors.py +++ b/api/controllers/common/errors.py @@ -41,3 +41,9 @@ class NoFileUploadedError(BaseHTTPException): error_code = "no_file_uploaded" description = "Please upload your file." code = 400 + + +class ProviderNotSupportTextToSpeechError(BaseHTTPException): + error_code = "provider_not_support_text_to_speech" + description = "Provider does not support text-to-speech functionality." + code = 400 diff --git a/api/controllers/console/app/audio.py b/api/controllers/console/app/audio.py index 2c5e8d29ee..5d907c2346 100644 --- a/api/controllers/console/app/audio.py +++ b/api/controllers/console/app/audio.py @@ -6,6 +6,7 @@ from pydantic import BaseModel, Field from werkzeug.exceptions import InternalServerError import services +from controllers.common.errors import ProviderNotSupportTextToSpeechError from controllers.common.schema import register_schema_models from controllers.console import console_ns from controllers.console.app.error import ( @@ -30,6 +31,7 @@ from services.errors.audio import ( AudioTooLargeServiceError, NoAudioUploadedServiceError, ProviderNotSupportSpeechToTextServiceError, + ProviderNotSupportTextToSpeechServiceError, UnsupportedAudioTypeServiceError, ) @@ -134,14 +136,8 @@ class ChatMessageTextApi(Resource): except services.errors.app_model_config.AppModelConfigBrokenError: logger.exception("App model config broken.") raise AppUnavailableError() - except NoAudioUploadedServiceError: - raise NoAudioUploadedError() - except AudioTooLargeServiceError as e: - raise AudioTooLargeError(str(e)) - except UnsupportedAudioTypeServiceError: - raise UnsupportedAudioTypeError() - except ProviderNotSupportSpeechToTextServiceError: - raise ProviderNotSupportSpeechToTextError() + except ProviderNotSupportTextToSpeechServiceError: + raise ProviderNotSupportTextToSpeechError() except ProviderTokenNotInitError as ex: raise ProviderNotInitializeError(ex.description) except QuotaExceededError: @@ -183,14 +179,8 @@ class TextModesApi(Resource): return response except services.errors.audio.ProviderNotSupportTextToSpeechLanageServiceError: raise AppUnavailableError("Text to audio voices language parameter loss.") - except NoAudioUploadedServiceError: - raise NoAudioUploadedError() - except AudioTooLargeServiceError as e: - raise AudioTooLargeError(str(e)) - except UnsupportedAudioTypeServiceError: - raise UnsupportedAudioTypeError() - except ProviderNotSupportSpeechToTextServiceError: - raise ProviderNotSupportSpeechToTextError() + except ProviderNotSupportTextToSpeechServiceError: + raise ProviderNotSupportTextToSpeechError() except ProviderTokenNotInitError as ex: raise ProviderNotInitializeError(ex.description) except QuotaExceededError: diff --git a/api/controllers/service_api/app/audio.py b/api/controllers/service_api/app/audio.py index 38d292d0b9..381df8ff81 100644 --- a/api/controllers/service_api/app/audio.py +++ b/api/controllers/service_api/app/audio.py @@ -6,6 +6,7 @@ from pydantic import BaseModel, Field from werkzeug.exceptions import InternalServerError import services +from controllers.common.errors import ProviderNotSupportTextToSpeechError from controllers.common.schema import register_schema_model from controllers.service_api import service_api_ns from controllers.service_api.app.error import ( @@ -28,6 +29,7 @@ from services.errors.audio import ( AudioTooLargeServiceError, NoAudioUploadedServiceError, ProviderNotSupportSpeechToTextServiceError, + ProviderNotSupportTextToSpeechServiceError, UnsupportedAudioTypeServiceError, ) @@ -129,14 +131,8 @@ class TextApi(Resource): except services.errors.app_model_config.AppModelConfigBrokenError: logger.exception("App model config broken.") raise AppUnavailableError() - except NoAudioUploadedServiceError: - raise NoAudioUploadedError() - except AudioTooLargeServiceError as e: - raise AudioTooLargeError(str(e)) - except UnsupportedAudioTypeServiceError: - raise UnsupportedAudioTypeError() - except ProviderNotSupportSpeechToTextServiceError: - raise ProviderNotSupportSpeechToTextError() + except ProviderNotSupportTextToSpeechServiceError: + raise ProviderNotSupportTextToSpeechError() except ProviderTokenNotInitError as ex: raise ProviderNotInitializeError(ex.description) except QuotaExceededError: diff --git a/api/controllers/web/audio.py b/api/controllers/web/audio.py index 2b8f752668..6e48826b1c 100644 --- a/api/controllers/web/audio.py +++ b/api/controllers/web/audio.py @@ -6,6 +6,8 @@ from pydantic import BaseModel, field_validator from werkzeug.exceptions import InternalServerError import services +from controllers.common.errors import ProviderNotSupportTextToSpeechError +from controllers.common.schema import register_schema_models from controllers.web import web_ns from controllers.web.error import ( AppUnavailableError, @@ -28,11 +30,10 @@ from services.errors.audio import ( AudioTooLargeServiceError, NoAudioUploadedServiceError, ProviderNotSupportSpeechToTextServiceError, + ProviderNotSupportTextToSpeechServiceError, UnsupportedAudioTypeServiceError, ) -from ..common.schema import register_schema_models - class TextToAudioPayload(BaseModel): message_id: str | None = None @@ -137,14 +138,8 @@ class TextApi(WebApiResource): except services.errors.app_model_config.AppModelConfigBrokenError: logger.exception("App model config broken.") raise AppUnavailableError() - except NoAudioUploadedServiceError: - raise NoAudioUploadedError() - except AudioTooLargeServiceError as e: - raise AudioTooLargeError(str(e)) - except UnsupportedAudioTypeServiceError: - raise UnsupportedAudioTypeError() - except ProviderNotSupportSpeechToTextServiceError: - raise ProviderNotSupportSpeechToTextError() + except ProviderNotSupportTextToSpeechServiceError: + raise ProviderNotSupportTextToSpeechError() except ProviderTokenNotInitError as ex: raise ProviderNotInitializeError(ex.description) except QuotaExceededError: diff --git a/api/tests/unit_tests/controllers/service_api/app/test_audio.py b/api/tests/unit_tests/controllers/service_api/app/test_audio.py index 1923ab7fa7..f3d30a141e 100644 --- a/api/tests/unit_tests/controllers/service_api/app/test_audio.py +++ b/api/tests/unit_tests/controllers/service_api/app/test_audio.py @@ -16,6 +16,7 @@ import pytest from werkzeug.datastructures import FileStorage from werkzeug.exceptions import InternalServerError +from controllers.common.errors import ProviderNotSupportTextToSpeechError from controllers.service_api.app.audio import AudioApi, TextApi, TextToAudioPayload from controllers.service_api.app.error import ( AppUnavailableError, @@ -36,6 +37,7 @@ from services.errors.audio import ( AudioTooLargeServiceError, NoAudioUploadedServiceError, ProviderNotSupportSpeechToTextServiceError, + ProviderNotSupportTextToSpeechServiceError, UnsupportedAudioTypeServiceError, ) @@ -156,6 +158,11 @@ class TestServiceErrorTypes: error = ProviderNotSupportSpeechToTextServiceError() assert error is not None + def test_provider_not_support_text_to_speech_service_error(self): + """Test ProviderNotSupportTextToSpeechServiceError exists.""" + error = ProviderNotSupportTextToSpeechServiceError() + assert error is not None + # --------------------------------------------------------------------------- # Mocked Behavior Tests @@ -283,10 +290,19 @@ class TestTextApi: assert response == {"audio": "ok"} - def test_error_mapping(self, app, monkeypatch: pytest.MonkeyPatch) -> None: - monkeypatch.setattr( - AudioService, "transcript_tts", lambda **_kwargs: (_ for _ in ()).throw(QuotaExceededError()) - ) + @pytest.mark.parametrize( + ("exc", "expected"), + [ + (AppModelConfigBrokenError(), AppUnavailableError), + (ProviderNotSupportTextToSpeechServiceError(), ProviderNotSupportTextToSpeechError), + (ProviderTokenNotInitError("token"), ProviderNotInitializeError), + (QuotaExceededError(), ProviderQuotaExceededError), + (ModelCurrentlyNotSupportError(), ProviderModelCurrentlyNotSupportError), + (InvokeError("invoke"), CompletionRequestError), + ], + ) + def test_error_mapping(self, app, monkeypatch: pytest.MonkeyPatch, exc, expected) -> None: + monkeypatch.setattr(AudioService, "transcript_tts", lambda **_kwargs: (_ for _ in ()).throw(exc)) api = TextApi() handler = _unwrap(api.post) @@ -294,5 +310,5 @@ class TestTextApi: end_user = SimpleNamespace(external_user_id="ext") with app.test_request_context("/text-to-audio", method="POST", json={"text": "hello"}): - with pytest.raises(ProviderQuotaExceededError): + with pytest.raises(expected): handler(api, app_model=app_model, end_user=end_user)