LLMContext: async create_image_message/create_audio_message fixes
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user