diff --git a/CHANGELOG.md b/CHANGELOG.md index 845a1319b..1e5bb8849 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,9 +60,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Deprecated -- Function calls with parameters `(function_name, tool_call_id, args, llm, - context, result_callback)` are deprectated, use a single `FunctionCallParams` - parameter instead. +- Function calls with parameters + `(function_name, tool_call_id, args, llm, context, result_callback)` are + deprectated, use a single `FunctionCallParams` parameter instead. - `TransportParams.camera_*` parameters are now deprecated, use `TransportParams.video_*` instead. @@ -75,6 +75,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Fixed an issue with HTTP Smart Turn handling, where the service returns a 500 + error. Previously, this would cause an unhandled exception. Now, a 500 error + is treated as an incomplete response. + - Fixed a TTS services issue that could cause assistant output not to be aggregated to the context when also using `TTSSpeakFrame`s. diff --git a/src/pipecat/audio/turn/smart_turn/http_smart_turn.py b/src/pipecat/audio/turn/smart_turn/http_smart_turn.py index 4f542f81d..5bd3743ed 100644 --- a/src/pipecat/audio/turn/smart_turn/http_smart_turn.py +++ b/src/pipecat/audio/turn/smart_turn/http_smart_turn.py @@ -40,7 +40,7 @@ class HttpSmartTurnAnalyzer(BaseSmartTurn): async def _send_raw_request(self, data_bytes: bytes) -> Dict[str, Any]: headers = {"Content-Type": "application/octet-stream"} headers.update(self._headers) - logger.trace(f"Sending {len(data_bytes)} bytes as raw body to {self._url}...") + try: timeout = aiohttp.ClientTimeout(total=self._params.stop_secs) @@ -50,23 +50,30 @@ class HttpSmartTurnAnalyzer(BaseSmartTurn): logger.trace("\n--- Response ---") logger.trace(f"Status Code: {response.status}") - if response.status == 200: - try: - json_data = await response.json() - logger.trace("Response JSON:") - logger.trace(json_data) - return json_data - except aiohttp.ContentTypeError: - # Non-JSON response - text = await response.text() - logger.trace("Response Content (non-JSON):") - logger.trace(text) - raise Exception(f"Non-JSON response: {text}") - else: + # Check if successful + if response.status != 200: error_text = await response.text() logger.trace("Response Content (Error):") logger.trace(error_text) - response.raise_for_status() + + if response.status == 500: + logger.warning(f"Smart turn service returned 500 error: {error_text}") + raise Exception(f"Server returned HTTP 500: {error_text}") + else: + response.raise_for_status() + + # Process successful response + try: + json_data = await response.json() + logger.trace("Response JSON:") + logger.trace(json_data) + return json_data + except aiohttp.ContentTypeError: + # Non-JSON response + text = await response.text() + logger.trace("Response Content (non-JSON):") + logger.trace(text) + raise Exception(f"Non-JSON response: {text}") except asyncio.TimeoutError: logger.error(f"Request timed out after {self._params.stop_secs} seconds") @@ -76,5 +83,14 @@ class HttpSmartTurnAnalyzer(BaseSmartTurn): raise Exception("Failed to send raw request to Daily Smart Turn.") async def _predict_endpoint(self, audio_array: np.ndarray) -> Dict[str, Any]: - serialized_array = self._serialize_array(audio_array) - return await self._send_raw_request(serialized_array) + try: + serialized_array = self._serialize_array(audio_array) + return await self._send_raw_request(serialized_array) + except Exception as e: + logger.error(f"Smart turn prediction failed: {str(e)}") + # Return an incomplete prediction when a failure occurs + return { + "prediction": 0, + "probability": 0.0, + "metrics": {"inference_time": 0.0, "total_time": 0.0}, + }