processors(audiobuffer): make functions public
This commit is contained in:
@@ -1,18 +1,17 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2024, Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
import wave
|
import wave
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
AudioRawFrame,
|
AudioRawFrame,
|
||||||
BotInterruptionFrame,
|
|
||||||
BotStartedSpeakingFrame,
|
|
||||||
BotStoppedSpeakingFrame,
|
|
||||||
Frame,
|
Frame,
|
||||||
InputAudioRawFrame,
|
InputAudioRawFrame,
|
||||||
OutputAudioRawFrame,
|
OutputAudioRawFrame,
|
||||||
StartInterruptionFrame,
|
|
||||||
StopInterruptionFrame,
|
|
||||||
UserStartedSpeakingFrame,
|
|
||||||
UserStoppedSpeakingFrame,
|
|
||||||
)
|
)
|
||||||
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
||||||
|
|
||||||
@@ -39,18 +38,18 @@ class AudioBufferProcessor(FrameProcessor):
|
|||||||
def _buffer_has_audio(self, buffer: bytearray):
|
def _buffer_has_audio(self, buffer: bytearray):
|
||||||
return buffer is not None and len(buffer) > 0
|
return buffer is not None and len(buffer) > 0
|
||||||
|
|
||||||
def _has_audio(self):
|
def has_audio(self):
|
||||||
return (
|
return (
|
||||||
self._buffer_has_audio(self._user_audio_buffer)
|
self._buffer_has_audio(self._user_audio_buffer)
|
||||||
and self._buffer_has_audio(self._assistant_audio_buffer)
|
and self._buffer_has_audio(self._assistant_audio_buffer)
|
||||||
and self._sample_rate is not None
|
and self._sample_rate is not None
|
||||||
)
|
)
|
||||||
|
|
||||||
def _reset_audio_buffer(self):
|
def reset_audio_buffer(self):
|
||||||
self._user_audio_buffer = bytearray()
|
self._user_audio_buffer = bytearray()
|
||||||
self._assistant_audio_buffer = bytearray()
|
self._assistant_audio_buffer = bytearray()
|
||||||
|
|
||||||
def _merge_audio_buffers(self):
|
def merge_audio_buffers(self):
|
||||||
with BytesIO() as buffer:
|
with BytesIO() as buffer:
|
||||||
with wave.open(buffer, "wb") as wf:
|
with wave.open(buffer, "wb") as wf:
|
||||||
wf.setnchannels(2)
|
wf.setnchannels(2)
|
||||||
|
|||||||
@@ -1,9 +1,21 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2024, Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Dict, List, Tuple
|
from typing import Dict, List, Tuple
|
||||||
|
|
||||||
import aiohttp
|
from pipecat.frames.frames import CancelFrame, EndFrame, Frame
|
||||||
|
from pipecat.processors.audio.audio_buffer_processor import AudioBufferProcessor
|
||||||
|
from pipecat.processors.frame_processor import FrameDirection
|
||||||
|
from pipecat.services.ai_services import AIService
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -18,27 +30,18 @@ except ModuleNotFoundError as e:
|
|||||||
raise Exception(f"Missing module: {e}")
|
raise Exception(f"Missing module: {e}")
|
||||||
|
|
||||||
|
|
||||||
from pipecat.frames.frames import CancelFrame, EndFrame, Frame
|
|
||||||
from pipecat.processors.audio.audio_buffer_processor import AudioBufferProcessor
|
|
||||||
from pipecat.processors.frame_processor import FrameDirection
|
|
||||||
from pipecat.services.ai_services import AIService
|
|
||||||
|
|
||||||
# Multipart upload part size in bytes, cannot be smaller than 5MB
|
# Multipart upload part size in bytes, cannot be smaller than 5MB
|
||||||
PART_SIZE = 1024 * 1024 * 5
|
PART_SIZE = 1024 * 1024 * 5
|
||||||
"""
|
|
||||||
This class extends AudioBufferProcessor to handle audio processing and uploading
|
|
||||||
for the Canonical Voice API.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class CanonicalMetricsService(AIService):
|
class CanonicalMetricsService(AIService):
|
||||||
"""
|
"""Initialize a CanonicalAudioProcessor instance.
|
||||||
Initialize a CanonicalAudioProcessor instance.
|
|
||||||
|
|
||||||
This class extends AudioBufferProcessor to handle audio processing and uploading
|
This class uses an AudioBufferProcessor to get the conversation audio and
|
||||||
for the Canonical Voice API.
|
uploads it to Canonical Voice API for audio processing.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
||||||
call_id (str): Your unique identifier for the call. This is used to match the call in the Canonical Voice system to the call in your system.
|
call_id (str): Your unique identifier for the call. This is used to match the call in the Canonical Voice system to the call in your system.
|
||||||
assistant (str): Identifier for the AI assistant. This can be whatever you want, it's intended for you convenience so you can distinguish
|
assistant (str): Identifier for the AI assistant. This can be whatever you want, it's intended for you convenience so you can distinguish
|
||||||
between different assistants and a grouping mechanism for calls.
|
between different assistants and a grouping mechanism for calls.
|
||||||
@@ -52,7 +55,6 @@ class CanonicalMetricsService(AIService):
|
|||||||
output_dir (str): Directory path for saving temporary audio files.
|
output_dir (str): Directory path for saving temporary audio files.
|
||||||
|
|
||||||
The constructor also ensures that the output directory exists.
|
The constructor also ensures that the output directory exists.
|
||||||
This class requires a Canonical API key to be set in the CANONICAL_API_KEY environment variable.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -90,17 +92,17 @@ class CanonicalMetricsService(AIService):
|
|||||||
|
|
||||||
async def _process_audio(self):
|
async def _process_audio(self):
|
||||||
pipeline = self._audio_buffer_processor
|
pipeline = self._audio_buffer_processor
|
||||||
if pipeline._has_audio():
|
if pipeline.has_audio():
|
||||||
os.makedirs(self._output_dir, exist_ok=True)
|
os.makedirs(self._output_dir, exist_ok=True)
|
||||||
filename = self._get_output_filename()
|
filename = self._get_output_filename()
|
||||||
wave_data = pipeline._merge_audio_buffers()
|
wave_data = pipeline.merge_audio_buffers()
|
||||||
|
|
||||||
async with aiofiles.open(filename, "wb") as file:
|
async with aiofiles.open(filename, "wb") as file:
|
||||||
await file.write(wave_data)
|
await file.write(wave_data)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await self._multipart_upload(filename)
|
await self._multipart_upload(filename)
|
||||||
pipeline._reset_audio_buffer()
|
pipeline.reset_audio_buffer()
|
||||||
await aiofiles.os.remove(filename)
|
await aiofiles.os.remove(filename)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2024, Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any, Awaitable, Callable, List
|
from typing import Any, Awaitable, Callable, List
|
||||||
|
|||||||
Reference in New Issue
Block a user