LLMContext: async create_image_message/create_audio_message fixes

This commit is contained in:
Aleix Conchillo Flaqué
2025-11-18 12:08:09 -08:00
parent f93276c64f
commit ceaf53fdb0
4 changed files with 14 additions and 11 deletions

View File

@@ -26,9 +26,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- ⚠️ Breaking change: `LLMContext.create_image_message()` and - ⚠️ Breaking change: `LLMContext.create_image_message()`,
`LLMContext.create_audio_message()` are now async methods. This fixes and `LLMContext.create_audio_message()`, `LLMContext.add_image_frame_message()`
issue where the asyncio event loop would be blocked while encoding audio or and `LLMContext.add_audio_frames_message()` are now async methods. This fixes
an issue where the asyncio event loop would be blocked while encoding audio or
images. images.
- `ConsumerProcessor` now queues frames from the producer internally instead of - `ConsumerProcessor` now queues frames from the producer internally instead of

View File

@@ -391,7 +391,7 @@ class AudioAccumulator(FrameProcessor):
) )
self._user_speaking = False self._user_speaking = False
context = LLMContext() context = LLMContext()
context.add_audio_frames_message(audio_frames=self._audio_frames) await context.add_audio_frames_message(audio_frames=self._audio_frames)
await self.push_frame(LLMContextFrame(context=context)) await self.push_frame(LLMContextFrame(context=context))
elif isinstance(frame, InputAudioRawFrame): elif isinstance(frame, InputAudioRawFrame):
# Append the audio frame to our buffer. Treat the buffer as a ring buffer, dropping the oldest # Append the audio frame to our buffer. Treat the buffer as a ring buffer, dropping the oldest

View File

@@ -180,7 +180,7 @@ class LLMContext:
text: Optional text to include with the audio. text: Optional text to include with the audio.
""" """
def encode_audio(): async def encode_audio():
sample_rate = audio_frames[0].sample_rate sample_rate = audio_frames[0].sample_rate
num_channels = audio_frames[0].num_channels num_channels = audio_frames[0].num_channels
@@ -198,7 +198,7 @@ class LLMContext:
encoded_audio = base64.b64encode(buffer.getvalue()).decode("utf-8") encoded_audio = base64.b64encode(buffer.getvalue()).decode("utf-8")
return encoded_audio return encoded_audio
encoded_audio = asyncio.to_thread(encode_audio) encoded_audio = await asyncio.to_thread(encode_audio)
content.append( content.append(
{ {
@@ -333,7 +333,7 @@ class LLMContext:
""" """
self._tool_choice = tool_choice self._tool_choice = tool_choice
def add_image_frame_message( async def add_image_frame_message(
self, *, format: str, size: tuple[int, int], image: bytes, text: Optional[str] = None self, *, format: str, size: tuple[int, int], image: bytes, text: Optional[str] = None
): ):
"""Add a message containing an image frame. """Add a message containing an image frame.
@@ -344,10 +344,12 @@ class LLMContext:
image: Raw image bytes. image: Raw image bytes.
text: Optional text to include with the image. text: Optional text to include with the image.
""" """
message = LLMContext.create_image_message(format=format, size=size, image=image, text=text) message = await LLMContext.create_image_message(
format=format, size=size, image=image, text=text
)
self.add_message(message) self.add_message(message)
def add_audio_frames_message( async def add_audio_frames_message(
self, *, audio_frames: list[AudioRawFrame], text: str = "Audio follows" self, *, audio_frames: list[AudioRawFrame], text: str = "Audio follows"
): ):
"""Add a message containing audio frames. """Add a message containing audio frames.
@@ -356,7 +358,7 @@ class LLMContext:
audio_frames: List of audio frame objects to include. audio_frames: List of audio frame objects to include.
text: Optional text to include with the audio. text: Optional text to include with the audio.
""" """
message = LLMContext.create_audio_message(audio_frames=audio_frames, text=text) message = await LLMContext.create_audio_message(audio_frames=audio_frames, text=text)
self.add_message(message) self.add_message(message)
@staticmethod @staticmethod

View File

@@ -793,7 +793,7 @@ class LLMAssistantAggregator(LLMContextAggregator):
logger.debug(f"{self} Appending UserImageRawFrame to LLM context (size: {frame.size})") logger.debug(f"{self} Appending UserImageRawFrame to LLM context (size: {frame.size})")
self._context.add_image_frame_message( await self._context.add_image_frame_message(
format=frame.format, format=frame.format,
size=frame.size, size=frame.size,
image=frame.image, image=frame.image,