improve error handling and don't swallow exceptions

This commit is contained in:
Aleix Conchillo Flaqué
2024-06-28 16:10:58 -07:00
parent abd65a93b2
commit fc0920504d
16 changed files with 38 additions and 35 deletions

View File

@@ -15,6 +15,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Fixed an issue where exceptions that occurred inside frame processors were
being swallowed and not displayed.
- Fixed an issue in `FastAPIWebsocketTransport` where it would still try to send
data to the websocket after being closed.

View File

@@ -82,5 +82,5 @@ class WakeCheckFilter(FrameProcessor):
await self.push_frame(frame, direction)
except Exception as e:
error_msg = f"Error in wake word filter: {e}"
logger.error(error_msg)
logger.exception(error_msg)
await self.push_error(ErrorFrame(error_msg))

View File

@@ -147,12 +147,15 @@ class FrameProcessor:
await self.push_frame(error, FrameDirection.UPSTREAM)
async def push_frame(self, frame: Frame, direction: FrameDirection = FrameDirection.DOWNSTREAM):
if direction == FrameDirection.DOWNSTREAM and self._next:
logger.trace(f"Pushing {frame} from {self} to {self._next}")
await self._next.process_frame(frame, direction)
elif direction == FrameDirection.UPSTREAM and self._prev:
logger.trace(f"Pushing {frame} upstream from {self} to {self._prev}")
await self._prev.process_frame(frame, direction)
try:
if direction == FrameDirection.DOWNSTREAM and self._next:
logger.trace(f"Pushing {frame} from {self} to {self._next}")
await self._next.process_frame(frame, direction)
elif direction == FrameDirection.UPSTREAM and self._prev:
logger.trace(f"Pushing {frame} upstream from {self} to {self._prev}")
await self._prev.process_frame(frame, direction)
except Exception as e:
logger.exception(f"Uncaught exception in {self}: {e}")
def __str__(self):
return self.name

View File

@@ -75,5 +75,6 @@ class LangchainProcessor(FrameProcessor):
except GeneratorExit:
logger.warning(f"{self} generator was closed prematurely")
except Exception as e:
logger.error(f"{self} an unknown error occurred: {e}")
await self.push_frame(LLMFullResponseEndFrame())
logger.exception(f"{self} an unknown error occurred: {e}")
finally:
await self.push_frame(LLMFullResponseEndFrame())

View File

@@ -122,7 +122,7 @@ class AnthropicLLMService(LLMService):
await self.push_frame(LLMResponseEndFrame())
except Exception as e:
logger.error(f"{self} exception: {e}")
logger.exception(f"{self} exception: {e}")
finally:
await self.push_frame(LLMFullResponseEndFrame())

View File

@@ -39,7 +39,7 @@ class CartesiaTTSService(TTSService):
self._client = AsyncCartesia(api_key=self._api_key)
self._voice = self._client.voices.get(id=voice_id)
except Exception as e:
logger.error(f"{self} initialization error: {e}")
logger.exception(f"{self} initialization error: {e}")
def can_generate_metrics(self) -> bool:
return True
@@ -62,4 +62,4 @@ class CartesiaTTSService(TTSService):
await self.stop_ttfb_metrics()
yield AudioRawFrame(chunk["audio"], self._output_format["sample_rate"], 1)
except Exception as e:
logger.error(f"{self} exception: {e}")
logger.exception(f"{self} exception: {e}")

View File

@@ -91,7 +91,7 @@ class DeepgramTTSService(TTSService):
frame = AudioRawFrame(audio=data, sample_rate=16000, num_channels=1)
yield frame
except Exception as e:
logger.error(f"{self} exception: {e}")
logger.exception(f"{self} exception: {e}")
class DeepgramSTTService(AIService):

View File

@@ -104,10 +104,10 @@ class GoogleLLMService(LLMService):
logger.debug(
f"LLM refused to generate content for safety reasons - {messages}.")
else:
logger.error(f"{self} error: {e}")
logger.exception(f"{self} error: {e}")
except Exception as e:
logger.error(f"{self} exception: {e}")
logger.exception(f"{self} exception: {e}")
finally:
await self.push_frame(LLMFullResponseEndFrame())

View File

@@ -53,7 +53,7 @@ except ModuleNotFoundError as e:
raise Exception(f"Missing module: {e}")
class OpenAIUnhandledFunctionException(BaseException):
class OpenAIUnhandledFunctionException(Exception):
pass
@@ -109,10 +109,7 @@ class BaseOpenAILLMService(LLMService):
del message["data"]
del message["mime_type"]
try:
chunks = await self.get_chat_completions(context, messages)
except Exception as e:
logger.error(f"{self} exception: {e}")
chunks = await self.get_chat_completions(context, messages)
return chunks
@@ -214,7 +211,7 @@ class BaseOpenAILLMService(LLMService):
elif isinstance(result, type(None)):
pass
else:
raise BaseException(f"Unknown return type from function callback: {type(result)}")
raise TypeError(f"Unknown return type from function callback: {type(result)}")
async def process_frame(self, frame: Frame, direction: FrameDirection):
await super().process_frame(frame, direction)
@@ -336,4 +333,4 @@ class OpenAITTSService(TTSService):
frame = AudioRawFrame(chunk, 24_000, 1)
yield frame
except BadRequestError as e:
logger.error(f"{self} error generating TTS: {e}")
logger.exception(f"{self} error generating TTS: {e}")

View File

@@ -80,4 +80,4 @@ class PlayHTTTSService(TTSService):
frame = AudioRawFrame(chunk, 16000, 1)
yield frame
except Exception as e:
logger.error(f"{self} error generating TTS: {e}")
logger.exception(f"{self} error generating TTS: {e}")

View File

@@ -173,5 +173,5 @@ class BaseInputTransport(FrameProcessor):
await self._internal_push_frame(frame)
except asyncio.CancelledError:
break
except BaseException as e:
logger.error(f"{self} error reading audio frames: {e}")
except Exception as e:
logger.exception(f"{self} error reading audio frames: {e}")

View File

@@ -180,8 +180,8 @@ class BaseOutputTransport(FrameProcessor):
self._sink_queue.task_done()
except asyncio.CancelledError:
break
except BaseException as e:
logger.error(f"{self} error processing sink queue: {e}")
except Exception as e:
logger.exception(f"{self} error processing sink queue: {e}")
#
# Push frames task
@@ -250,7 +250,7 @@ class BaseOutputTransport(FrameProcessor):
except asyncio.CancelledError:
break
except Exception as e:
logger.error(f"{self} error writing to camera: {e}")
logger.exception(f"{self} error writing to camera: {e}")
#
# Audio out

View File

@@ -82,5 +82,4 @@ class BaseTransport(ABC):
else:
handler(self, *args, **kwargs)
except Exception as e:
logger.error(f"Exception in event handler {event_name}: {e}")
raise e
logger.exception(f"Exception in event handler {event_name}: {e}")

View File

@@ -835,8 +835,8 @@ class DailyTransport(BaseTransport):
logger.debug("Event dialin-ready was handled successfully")
except asyncio.TimeoutError:
logger.error(f"Timeout handling dialin-ready event ({url})")
except BaseException as e:
logger.error(f"Error handling dialin-ready event ({url}): {e}")
except Exception as e:
logger.exception(f"Error handling dialin-ready event ({url}): {e}")
async def _on_dialin_ready(self, sip_endpoint):
if self._params.dialin_settings:

View File

@@ -2,7 +2,7 @@ from typing import List
from pipecat.processors.frame_processor import FrameProcessor
class TestException(BaseException):
class TestException(Exception):
pass

View File

@@ -72,9 +72,9 @@ class SileroVADAnalyzer(VADAnalyzer):
self._last_reset_time = curr_time
return new_confidence
except BaseException as e:
except Exception as e:
# This comes from an empty audio array
logger.error(f"Error analyzing audio with Silero VAD: {e}")
logger.exception(f"Error analyzing audio with Silero VAD: {e}")
return 0