dv-pipecat-ai 0.0.74.dev770__py3-none-any.whl → 0.0.82.dev776__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of dv-pipecat-ai might be problematic. Click here for more details.
- {dv_pipecat_ai-0.0.74.dev770.dist-info → dv_pipecat_ai-0.0.82.dev776.dist-info}/METADATA +137 -93
- dv_pipecat_ai-0.0.82.dev776.dist-info/RECORD +340 -0
- pipecat/__init__.py +17 -0
- pipecat/adapters/base_llm_adapter.py +36 -1
- pipecat/adapters/schemas/direct_function.py +296 -0
- pipecat/adapters/schemas/function_schema.py +15 -6
- pipecat/adapters/schemas/tools_schema.py +55 -7
- pipecat/adapters/services/anthropic_adapter.py +22 -3
- pipecat/adapters/services/aws_nova_sonic_adapter.py +23 -3
- pipecat/adapters/services/bedrock_adapter.py +22 -3
- pipecat/adapters/services/gemini_adapter.py +16 -3
- pipecat/adapters/services/open_ai_adapter.py +17 -2
- pipecat/adapters/services/open_ai_realtime_adapter.py +23 -3
- pipecat/audio/filters/base_audio_filter.py +30 -6
- pipecat/audio/filters/koala_filter.py +37 -2
- pipecat/audio/filters/krisp_filter.py +59 -6
- pipecat/audio/filters/noisereduce_filter.py +37 -0
- pipecat/audio/interruptions/base_interruption_strategy.py +25 -5
- pipecat/audio/interruptions/min_words_interruption_strategy.py +21 -4
- pipecat/audio/mixers/base_audio_mixer.py +30 -7
- pipecat/audio/mixers/soundfile_mixer.py +53 -6
- pipecat/audio/resamplers/base_audio_resampler.py +17 -9
- pipecat/audio/resamplers/resampy_resampler.py +26 -1
- pipecat/audio/resamplers/soxr_resampler.py +32 -1
- pipecat/audio/resamplers/soxr_stream_resampler.py +101 -0
- pipecat/audio/utils.py +194 -1
- pipecat/audio/vad/silero.py +60 -3
- pipecat/audio/vad/vad_analyzer.py +114 -30
- pipecat/clocks/base_clock.py +19 -0
- pipecat/clocks/system_clock.py +25 -0
- pipecat/extensions/voicemail/__init__.py +0 -0
- pipecat/extensions/voicemail/voicemail_detector.py +707 -0
- pipecat/frames/frames.py +590 -156
- pipecat/metrics/metrics.py +64 -1
- pipecat/observers/base_observer.py +58 -19
- pipecat/observers/loggers/debug_log_observer.py +56 -64
- pipecat/observers/loggers/llm_log_observer.py +8 -1
- pipecat/observers/loggers/transcription_log_observer.py +19 -7
- pipecat/observers/loggers/user_bot_latency_log_observer.py +32 -5
- pipecat/observers/turn_tracking_observer.py +26 -1
- pipecat/pipeline/base_pipeline.py +5 -7
- pipecat/pipeline/base_task.py +52 -9
- pipecat/pipeline/parallel_pipeline.py +121 -177
- pipecat/pipeline/pipeline.py +129 -20
- pipecat/pipeline/runner.py +50 -1
- pipecat/pipeline/sync_parallel_pipeline.py +132 -32
- pipecat/pipeline/task.py +263 -280
- pipecat/pipeline/task_observer.py +85 -34
- pipecat/pipeline/to_be_updated/merge_pipeline.py +32 -2
- pipecat/processors/aggregators/dtmf_aggregator.py +29 -22
- pipecat/processors/aggregators/gated.py +25 -24
- pipecat/processors/aggregators/gated_openai_llm_context.py +22 -2
- pipecat/processors/aggregators/llm_response.py +398 -89
- pipecat/processors/aggregators/openai_llm_context.py +161 -13
- pipecat/processors/aggregators/sentence.py +25 -14
- pipecat/processors/aggregators/user_response.py +28 -3
- pipecat/processors/aggregators/vision_image_frame.py +24 -14
- pipecat/processors/async_generator.py +28 -0
- pipecat/processors/audio/audio_buffer_processor.py +78 -37
- pipecat/processors/consumer_processor.py +25 -6
- pipecat/processors/filters/frame_filter.py +23 -0
- pipecat/processors/filters/function_filter.py +30 -0
- pipecat/processors/filters/identity_filter.py +17 -2
- pipecat/processors/filters/null_filter.py +24 -1
- pipecat/processors/filters/stt_mute_filter.py +56 -21
- pipecat/processors/filters/wake_check_filter.py +46 -3
- pipecat/processors/filters/wake_notifier_filter.py +21 -3
- pipecat/processors/frame_processor.py +488 -131
- pipecat/processors/frameworks/langchain.py +38 -3
- pipecat/processors/frameworks/rtvi.py +719 -34
- pipecat/processors/gstreamer/pipeline_source.py +41 -0
- pipecat/processors/idle_frame_processor.py +26 -3
- pipecat/processors/logger.py +23 -0
- pipecat/processors/metrics/frame_processor_metrics.py +77 -4
- pipecat/processors/metrics/sentry.py +42 -4
- pipecat/processors/producer_processor.py +34 -14
- pipecat/processors/text_transformer.py +22 -10
- pipecat/processors/transcript_processor.py +48 -29
- pipecat/processors/user_idle_processor.py +31 -21
- pipecat/runner/__init__.py +1 -0
- pipecat/runner/daily.py +132 -0
- pipecat/runner/livekit.py +148 -0
- pipecat/runner/run.py +543 -0
- pipecat/runner/types.py +67 -0
- pipecat/runner/utils.py +515 -0
- pipecat/serializers/base_serializer.py +42 -0
- pipecat/serializers/exotel.py +17 -6
- pipecat/serializers/genesys.py +95 -0
- pipecat/serializers/livekit.py +33 -0
- pipecat/serializers/plivo.py +16 -15
- pipecat/serializers/protobuf.py +37 -1
- pipecat/serializers/telnyx.py +18 -17
- pipecat/serializers/twilio.py +32 -16
- pipecat/services/ai_service.py +5 -3
- pipecat/services/anthropic/llm.py +113 -43
- pipecat/services/assemblyai/models.py +63 -5
- pipecat/services/assemblyai/stt.py +64 -11
- pipecat/services/asyncai/__init__.py +0 -0
- pipecat/services/asyncai/tts.py +501 -0
- pipecat/services/aws/llm.py +185 -111
- pipecat/services/aws/stt.py +217 -23
- pipecat/services/aws/tts.py +118 -52
- pipecat/services/aws/utils.py +101 -5
- pipecat/services/aws_nova_sonic/aws.py +82 -64
- pipecat/services/aws_nova_sonic/context.py +15 -6
- pipecat/services/azure/common.py +10 -2
- pipecat/services/azure/image.py +32 -0
- pipecat/services/azure/llm.py +9 -7
- pipecat/services/azure/stt.py +65 -2
- pipecat/services/azure/tts.py +154 -23
- pipecat/services/cartesia/stt.py +125 -8
- pipecat/services/cartesia/tts.py +102 -38
- pipecat/services/cerebras/llm.py +15 -23
- pipecat/services/deepgram/stt.py +19 -11
- pipecat/services/deepgram/tts.py +36 -0
- pipecat/services/deepseek/llm.py +14 -23
- pipecat/services/elevenlabs/tts.py +330 -64
- pipecat/services/fal/image.py +43 -0
- pipecat/services/fal/stt.py +48 -10
- pipecat/services/fireworks/llm.py +14 -21
- pipecat/services/fish/tts.py +109 -9
- pipecat/services/gemini_multimodal_live/__init__.py +1 -0
- pipecat/services/gemini_multimodal_live/events.py +83 -2
- pipecat/services/gemini_multimodal_live/file_api.py +189 -0
- pipecat/services/gemini_multimodal_live/gemini.py +218 -21
- pipecat/services/gladia/config.py +17 -10
- pipecat/services/gladia/stt.py +82 -36
- pipecat/services/google/frames.py +40 -0
- pipecat/services/google/google.py +2 -0
- pipecat/services/google/image.py +39 -2
- pipecat/services/google/llm.py +176 -58
- pipecat/services/google/llm_openai.py +26 -4
- pipecat/services/google/llm_vertex.py +37 -15
- pipecat/services/google/rtvi.py +41 -0
- pipecat/services/google/stt.py +65 -17
- pipecat/services/google/test-google-chirp.py +45 -0
- pipecat/services/google/tts.py +390 -19
- pipecat/services/grok/llm.py +8 -6
- pipecat/services/groq/llm.py +8 -6
- pipecat/services/groq/stt.py +13 -9
- pipecat/services/groq/tts.py +40 -0
- pipecat/services/hamsa/__init__.py +9 -0
- pipecat/services/hamsa/stt.py +241 -0
- pipecat/services/heygen/__init__.py +5 -0
- pipecat/services/heygen/api.py +281 -0
- pipecat/services/heygen/client.py +620 -0
- pipecat/services/heygen/video.py +338 -0
- pipecat/services/image_service.py +5 -3
- pipecat/services/inworld/__init__.py +1 -0
- pipecat/services/inworld/tts.py +592 -0
- pipecat/services/llm_service.py +127 -45
- pipecat/services/lmnt/tts.py +80 -7
- pipecat/services/mcp_service.py +85 -44
- pipecat/services/mem0/memory.py +42 -13
- pipecat/services/minimax/tts.py +74 -15
- pipecat/services/mistral/__init__.py +0 -0
- pipecat/services/mistral/llm.py +185 -0
- pipecat/services/moondream/vision.py +55 -10
- pipecat/services/neuphonic/tts.py +275 -48
- pipecat/services/nim/llm.py +8 -6
- pipecat/services/ollama/llm.py +27 -7
- pipecat/services/openai/base_llm.py +54 -16
- pipecat/services/openai/image.py +30 -0
- pipecat/services/openai/llm.py +7 -5
- pipecat/services/openai/stt.py +13 -9
- pipecat/services/openai/tts.py +42 -10
- pipecat/services/openai_realtime_beta/azure.py +11 -9
- pipecat/services/openai_realtime_beta/context.py +7 -5
- pipecat/services/openai_realtime_beta/events.py +10 -7
- pipecat/services/openai_realtime_beta/openai.py +37 -18
- pipecat/services/openpipe/llm.py +30 -24
- pipecat/services/openrouter/llm.py +9 -7
- pipecat/services/perplexity/llm.py +15 -19
- pipecat/services/piper/tts.py +26 -12
- pipecat/services/playht/tts.py +227 -65
- pipecat/services/qwen/llm.py +8 -6
- pipecat/services/rime/tts.py +128 -17
- pipecat/services/riva/stt.py +160 -22
- pipecat/services/riva/tts.py +67 -2
- pipecat/services/sambanova/llm.py +19 -17
- pipecat/services/sambanova/stt.py +14 -8
- pipecat/services/sarvam/tts.py +60 -13
- pipecat/services/simli/video.py +82 -21
- pipecat/services/soniox/__init__.py +0 -0
- pipecat/services/soniox/stt.py +398 -0
- pipecat/services/speechmatics/stt.py +29 -17
- pipecat/services/stt_service.py +47 -11
- pipecat/services/tavus/video.py +94 -25
- pipecat/services/together/llm.py +8 -6
- pipecat/services/tts_service.py +77 -53
- pipecat/services/ultravox/stt.py +46 -43
- pipecat/services/vision_service.py +5 -3
- pipecat/services/websocket_service.py +12 -11
- pipecat/services/whisper/base_stt.py +58 -12
- pipecat/services/whisper/stt.py +69 -58
- pipecat/services/xtts/tts.py +59 -2
- pipecat/sync/base_notifier.py +19 -0
- pipecat/sync/event_notifier.py +24 -0
- pipecat/tests/utils.py +73 -5
- pipecat/transcriptions/language.py +24 -0
- pipecat/transports/base_input.py +112 -8
- pipecat/transports/base_output.py +235 -13
- pipecat/transports/base_transport.py +119 -0
- pipecat/transports/local/audio.py +76 -0
- pipecat/transports/local/tk.py +84 -0
- pipecat/transports/network/fastapi_websocket.py +174 -15
- pipecat/transports/network/small_webrtc.py +383 -39
- pipecat/transports/network/webrtc_connection.py +214 -8
- pipecat/transports/network/websocket_client.py +171 -1
- pipecat/transports/network/websocket_server.py +147 -9
- pipecat/transports/services/daily.py +792 -70
- pipecat/transports/services/helpers/daily_rest.py +122 -129
- pipecat/transports/services/livekit.py +339 -4
- pipecat/transports/services/tavus.py +273 -38
- pipecat/utils/asyncio/task_manager.py +92 -186
- pipecat/utils/base_object.py +83 -1
- pipecat/utils/network.py +2 -0
- pipecat/utils/string.py +114 -58
- pipecat/utils/text/base_text_aggregator.py +44 -13
- pipecat/utils/text/base_text_filter.py +46 -0
- pipecat/utils/text/markdown_text_filter.py +70 -14
- pipecat/utils/text/pattern_pair_aggregator.py +18 -14
- pipecat/utils/text/simple_text_aggregator.py +43 -2
- pipecat/utils/text/skip_tags_aggregator.py +21 -13
- pipecat/utils/time.py +36 -0
- pipecat/utils/tracing/class_decorators.py +32 -7
- pipecat/utils/tracing/conversation_context_provider.py +12 -2
- pipecat/utils/tracing/service_attributes.py +80 -64
- pipecat/utils/tracing/service_decorators.py +48 -21
- pipecat/utils/tracing/setup.py +13 -7
- pipecat/utils/tracing/turn_context_provider.py +12 -2
- pipecat/utils/tracing/turn_trace_observer.py +27 -0
- pipecat/utils/utils.py +14 -14
- dv_pipecat_ai-0.0.74.dev770.dist-info/RECORD +0 -319
- pipecat/examples/daily_runner.py +0 -64
- pipecat/examples/run.py +0 -265
- pipecat/utils/asyncio/watchdog_async_iterator.py +0 -72
- pipecat/utils/asyncio/watchdog_event.py +0 -42
- pipecat/utils/asyncio/watchdog_priority_queue.py +0 -48
- pipecat/utils/asyncio/watchdog_queue.py +0 -48
- {dv_pipecat_ai-0.0.74.dev770.dist-info → dv_pipecat_ai-0.0.82.dev776.dist-info}/WHEEL +0 -0
- {dv_pipecat_ai-0.0.74.dev770.dist-info → dv_pipecat_ai-0.0.82.dev776.dist-info}/licenses/LICENSE +0 -0
- {dv_pipecat_ai-0.0.74.dev770.dist-info → dv_pipecat_ai-0.0.82.dev776.dist-info}/top_level.txt +0 -0
- /pipecat/{examples → extensions}/__init__.py +0 -0
pipecat/metrics/metrics.py
CHANGED
|
@@ -1,39 +1,102 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2024–2025, Daily
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: BSD 2-Clause License
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
"""Metrics data models for Pipecat framework.
|
|
8
|
+
|
|
9
|
+
This module defines Pydantic models for various types of metrics data
|
|
10
|
+
collected throughout the pipeline, including timing, token usage, and
|
|
11
|
+
processing statistics.
|
|
12
|
+
"""
|
|
13
|
+
|
|
1
14
|
from typing import Optional
|
|
2
15
|
|
|
3
16
|
from pydantic import BaseModel
|
|
4
17
|
|
|
5
18
|
|
|
6
19
|
class MetricsData(BaseModel):
|
|
20
|
+
"""Base class for all metrics data.
|
|
21
|
+
|
|
22
|
+
Parameters:
|
|
23
|
+
processor: Name of the processor generating the metrics.
|
|
24
|
+
model: Optional model name associated with the metrics.
|
|
25
|
+
"""
|
|
26
|
+
|
|
7
27
|
processor: str
|
|
8
28
|
model: Optional[str] = None
|
|
9
29
|
|
|
10
30
|
|
|
11
31
|
class TTFBMetricsData(MetricsData):
|
|
32
|
+
"""Time To First Byte (TTFB) metrics data.
|
|
33
|
+
|
|
34
|
+
Parameters:
|
|
35
|
+
value: TTFB measurement in seconds.
|
|
36
|
+
"""
|
|
37
|
+
|
|
12
38
|
value: float
|
|
13
39
|
|
|
14
40
|
|
|
15
41
|
class ProcessingMetricsData(MetricsData):
|
|
42
|
+
"""General processing time metrics data.
|
|
43
|
+
|
|
44
|
+
Parameters:
|
|
45
|
+
value: Processing time measurement in seconds.
|
|
46
|
+
"""
|
|
47
|
+
|
|
16
48
|
value: float
|
|
17
49
|
|
|
18
50
|
|
|
19
51
|
class LLMTokenUsage(BaseModel):
|
|
52
|
+
"""Token usage statistics for LLM operations.
|
|
53
|
+
|
|
54
|
+
Parameters:
|
|
55
|
+
prompt_tokens: Number of tokens in the input prompt.
|
|
56
|
+
completion_tokens: Number of tokens in the generated completion.
|
|
57
|
+
total_tokens: Total number of tokens used (prompt + completion).
|
|
58
|
+
cache_read_input_tokens: Number of tokens read from cache, if applicable.
|
|
59
|
+
cache_creation_input_tokens: Number of tokens used to create cache entries, if applicable.
|
|
60
|
+
"""
|
|
61
|
+
|
|
20
62
|
prompt_tokens: int
|
|
21
63
|
completion_tokens: int
|
|
22
64
|
total_tokens: int
|
|
23
65
|
cache_read_input_tokens: Optional[int] = None
|
|
24
66
|
cache_creation_input_tokens: Optional[int] = None
|
|
67
|
+
reasoning_tokens: Optional[int] = None
|
|
25
68
|
|
|
26
69
|
|
|
27
70
|
class LLMUsageMetricsData(MetricsData):
|
|
71
|
+
"""LLM token usage metrics data.
|
|
72
|
+
|
|
73
|
+
Parameters:
|
|
74
|
+
value: Token usage statistics for the LLM operation.
|
|
75
|
+
"""
|
|
76
|
+
|
|
28
77
|
value: LLMTokenUsage
|
|
29
78
|
|
|
30
79
|
|
|
31
80
|
class TTSUsageMetricsData(MetricsData):
|
|
81
|
+
"""Text-to-Speech usage metrics data.
|
|
82
|
+
|
|
83
|
+
Parameters:
|
|
84
|
+
value: Number of characters processed by TTS.
|
|
85
|
+
"""
|
|
86
|
+
|
|
32
87
|
value: int
|
|
33
88
|
|
|
34
89
|
|
|
35
90
|
class SmartTurnMetricsData(MetricsData):
|
|
36
|
-
"""Metrics data for smart turn predictions.
|
|
91
|
+
"""Metrics data for smart turn predictions.
|
|
92
|
+
|
|
93
|
+
Parameters:
|
|
94
|
+
is_complete: Whether the turn is predicted to be complete.
|
|
95
|
+
probability: Confidence probability of the turn completion prediction.
|
|
96
|
+
inference_time_ms: Time taken for inference in milliseconds.
|
|
97
|
+
server_total_time_ms: Total server processing time in milliseconds.
|
|
98
|
+
e2e_processing_time_ms: End-to-end processing time in milliseconds.
|
|
99
|
+
"""
|
|
37
100
|
|
|
38
101
|
is_complete: bool
|
|
39
102
|
probability: float
|
|
@@ -4,7 +4,13 @@
|
|
|
4
4
|
# SPDX-License-Identifier: BSD 2-Clause License
|
|
5
5
|
#
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
"""Base observer classes for monitoring frame flow in the Pipecat pipeline.
|
|
8
|
+
|
|
9
|
+
This module provides the foundation for observing frame transfers between
|
|
10
|
+
processors without modifying the pipeline structure. Observers can be used
|
|
11
|
+
for logging, debugging, analytics, and monitoring pipeline behavior.
|
|
12
|
+
"""
|
|
13
|
+
|
|
8
14
|
from dataclasses import dataclass
|
|
9
15
|
|
|
10
16
|
from typing_extensions import TYPE_CHECKING
|
|
@@ -17,22 +23,44 @@ if TYPE_CHECKING:
|
|
|
17
23
|
|
|
18
24
|
|
|
19
25
|
@dataclass
|
|
20
|
-
class
|
|
21
|
-
"""
|
|
22
|
-
within the pipeline.
|
|
26
|
+
class FrameProcessed:
|
|
27
|
+
"""Event data for frame processing in the pipeline.
|
|
23
28
|
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
Represents an event where a frame is being processed by a processor. This
|
|
30
|
+
data structure is typically used by observers to track the flow of frames
|
|
31
|
+
through the pipeline for logging, debugging, or analytics purposes.
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
timestamp (int): The time when the frame was pushed, based on the pipeline clock.
|
|
33
|
+
Parameters:
|
|
34
|
+
processor: The processor processing the frame.
|
|
35
|
+
frame: The frame being processed.
|
|
36
|
+
direction: The direction of the frame (e.g., downstream or upstream).
|
|
37
|
+
timestamp: The time when the frame was pushed, based on the pipeline clock.
|
|
33
38
|
|
|
34
39
|
"""
|
|
35
40
|
|
|
41
|
+
processor: "FrameProcessor"
|
|
42
|
+
frame: Frame
|
|
43
|
+
direction: "FrameDirection"
|
|
44
|
+
timestamp: int
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass
|
|
48
|
+
class FramePushed:
|
|
49
|
+
"""Event data for frame transfers between processors in the pipeline.
|
|
50
|
+
|
|
51
|
+
Represents an event where a frame is pushed from one processor to another
|
|
52
|
+
within the pipeline. This data structure is typically used by observers
|
|
53
|
+
to track the flow of frames through the pipeline for logging, debugging,
|
|
54
|
+
or analytics purposes.
|
|
55
|
+
|
|
56
|
+
Parameters:
|
|
57
|
+
source: The processor sending the frame.
|
|
58
|
+
destination: The processor receiving the frame.
|
|
59
|
+
frame: The frame being transferred.
|
|
60
|
+
direction: The direction of the transfer (e.g., downstream or upstream).
|
|
61
|
+
timestamp: The time when the frame was pushed, based on the pipeline clock.
|
|
62
|
+
"""
|
|
63
|
+
|
|
36
64
|
source: "FrameProcessor"
|
|
37
65
|
destination: "FrameProcessor"
|
|
38
66
|
frame: Frame
|
|
@@ -41,14 +69,26 @@ class FramePushed:
|
|
|
41
69
|
|
|
42
70
|
|
|
43
71
|
class BaseObserver(BaseObject):
|
|
44
|
-
"""
|
|
45
|
-
all the frames that go through the pipeline without the need to inject
|
|
46
|
-
processors in the pipeline. This can be useful, for example, to implement
|
|
47
|
-
frame loggers or debuggers among other things.
|
|
72
|
+
"""Base class for pipeline frame observers.
|
|
48
73
|
|
|
74
|
+
Observers can view all frames that flow through the pipeline without
|
|
75
|
+
needing to inject processors into the pipeline structure. This enables
|
|
76
|
+
non-intrusive monitoring capabilities such as frame logging, debugging,
|
|
77
|
+
performance analysis, and analytics collection.
|
|
49
78
|
"""
|
|
50
79
|
|
|
51
|
-
|
|
80
|
+
async def on_process_frame(self, data: FrameProcessed):
|
|
81
|
+
"""Handle the event when a frame is being processed by a processor.
|
|
82
|
+
|
|
83
|
+
This method should be implemented by subclasses to define specific
|
|
84
|
+
behavior (e.g., logging, monitoring, debugging) when a frame is
|
|
85
|
+
being processed by a processor.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
data: The event data containing details about the frame processing.
|
|
89
|
+
"""
|
|
90
|
+
pass
|
|
91
|
+
|
|
52
92
|
async def on_push_frame(self, data: FramePushed):
|
|
53
93
|
"""Handle the event when a frame is pushed from one processor to another.
|
|
54
94
|
|
|
@@ -57,7 +97,6 @@ class BaseObserver(BaseObject):
|
|
|
57
97
|
transferred through the pipeline.
|
|
58
98
|
|
|
59
99
|
Args:
|
|
60
|
-
data
|
|
61
|
-
|
|
100
|
+
data: The event data containing details about the frame transfer.
|
|
62
101
|
"""
|
|
63
102
|
pass
|
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
# SPDX-License-Identifier: BSD 2-Clause License
|
|
5
5
|
#
|
|
6
6
|
|
|
7
|
+
"""Debug logging observer for frame activity monitoring.
|
|
8
|
+
|
|
9
|
+
This module provides a debug observer that logs detailed frame activity
|
|
10
|
+
to the console, making it useful for debugging pipeline behavior and
|
|
11
|
+
understanding frame flow between processors.
|
|
12
|
+
"""
|
|
13
|
+
|
|
7
14
|
from dataclasses import fields, is_dataclass
|
|
8
15
|
from enum import Enum, auto
|
|
9
16
|
from typing import Dict, Optional, Set, Tuple, Type, Union
|
|
@@ -16,7 +23,12 @@ from pipecat.processors.frame_processor import FrameDirection
|
|
|
16
23
|
|
|
17
24
|
|
|
18
25
|
class FrameEndpoint(Enum):
|
|
19
|
-
"""Specifies which endpoint (source or destination) to filter on.
|
|
26
|
+
"""Specifies which endpoint (source or destination) to filter on.
|
|
27
|
+
|
|
28
|
+
Parameters:
|
|
29
|
+
SOURCE: Filter on the source component that is pushing the frame.
|
|
30
|
+
DESTINATION: Filter on the destination component receiving the frame.
|
|
31
|
+
"""
|
|
20
32
|
|
|
21
33
|
SOURCE = auto()
|
|
22
34
|
DESTINATION = auto()
|
|
@@ -28,44 +40,37 @@ class DebugLogObserver(BaseObserver):
|
|
|
28
40
|
Automatically extracts and formats data from any frame type, making it useful
|
|
29
41
|
for debugging pipeline behavior without needing frame-specific observers.
|
|
30
42
|
|
|
31
|
-
Args:
|
|
32
|
-
frame_types: Optional tuple of frame types to log, or a dict with frame type
|
|
33
|
-
filters. If None, logs all frame types.
|
|
34
|
-
exclude_fields: Optional set of field names to exclude from logging.
|
|
35
|
-
|
|
36
43
|
Examples:
|
|
37
|
-
Log all frames from all services
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
],
|
|
68
|
-
```
|
|
44
|
+
Log all frames from all services::
|
|
45
|
+
|
|
46
|
+
observers = DebugLogObserver()
|
|
47
|
+
|
|
48
|
+
Log specific frame types from any source/destination::
|
|
49
|
+
|
|
50
|
+
from pipecat.frames.frames import LLMTextFrame, TranscriptionFrame
|
|
51
|
+
observers=[
|
|
52
|
+
DebugLogObserver(frame_types=(LLMTextFrame,TranscriptionFrame,)),
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
Log frames with specific source/destination filters::
|
|
56
|
+
|
|
57
|
+
from pipecat.frames.frames import StartInterruptionFrame, UserStartedSpeakingFrame, LLMTextFrame
|
|
58
|
+
from pipecat.observers.loggers.debug_log_observer import DebugLogObserver, FrameEndpoint
|
|
59
|
+
from pipecat.transports.base_output import BaseOutputTransport
|
|
60
|
+
from pipecat.services.stt_service import STTService
|
|
61
|
+
|
|
62
|
+
observers=[
|
|
63
|
+
DebugLogObserver(
|
|
64
|
+
frame_types={
|
|
65
|
+
# Only log StartInterruptionFrame when source is BaseOutputTransport
|
|
66
|
+
StartInterruptionFrame: (BaseOutputTransport, FrameEndpoint.SOURCE),
|
|
67
|
+
# Only log UserStartedSpeakingFrame when destination is STTService
|
|
68
|
+
UserStartedSpeakingFrame: (STTService, FrameEndpoint.DESTINATION),
|
|
69
|
+
# Log LLMTextFrame regardless of source or destination type
|
|
70
|
+
LLMTextFrame: None,
|
|
71
|
+
}
|
|
72
|
+
),
|
|
73
|
+
]
|
|
69
74
|
"""
|
|
70
75
|
|
|
71
76
|
def __init__(
|
|
@@ -79,14 +84,17 @@ class DebugLogObserver(BaseObserver):
|
|
|
79
84
|
"""Initialize the debug log observer.
|
|
80
85
|
|
|
81
86
|
Args:
|
|
82
|
-
frame_types:
|
|
83
|
-
|
|
84
|
-
-
|
|
85
|
-
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
frame_types: Frame types to log. Can be:
|
|
88
|
+
|
|
89
|
+
- Tuple of frame types to log all instances
|
|
90
|
+
- Dict mapping frame types to filter configurations
|
|
91
|
+
- None to log all frames
|
|
92
|
+
|
|
93
|
+
Filter configurations can be None (log all instances) or a tuple
|
|
94
|
+
of (service_type, endpoint) to filter on specific services.
|
|
95
|
+
exclude_fields: Field names to exclude from logging. Defaults to
|
|
96
|
+
excluding binary data fields like 'audio', 'image', 'images'.
|
|
97
|
+
**kwargs: Additional arguments passed to parent class.
|
|
90
98
|
"""
|
|
91
99
|
super().__init__(**kwargs)
|
|
92
100
|
|
|
@@ -113,14 +121,7 @@ class DebugLogObserver(BaseObserver):
|
|
|
113
121
|
)
|
|
114
122
|
|
|
115
123
|
def _format_value(self, value):
|
|
116
|
-
"""Format a value for logging.
|
|
117
|
-
|
|
118
|
-
Args:
|
|
119
|
-
value: The value to format.
|
|
120
|
-
|
|
121
|
-
Returns:
|
|
122
|
-
str: A string representation of the value suitable for logging.
|
|
123
|
-
"""
|
|
124
|
+
"""Format a value for logging."""
|
|
124
125
|
if value is None:
|
|
125
126
|
return "None"
|
|
126
127
|
elif isinstance(value, str):
|
|
@@ -143,16 +144,7 @@ class DebugLogObserver(BaseObserver):
|
|
|
143
144
|
return str(value)
|
|
144
145
|
|
|
145
146
|
def _should_log_frame(self, frame, src, dst):
|
|
146
|
-
"""Determine if a frame should be logged based on filters.
|
|
147
|
-
|
|
148
|
-
Args:
|
|
149
|
-
frame: The frame being processed
|
|
150
|
-
src: The source component
|
|
151
|
-
dst: The destination component
|
|
152
|
-
|
|
153
|
-
Returns:
|
|
154
|
-
bool: True if the frame should be logged, False otherwise
|
|
155
|
-
"""
|
|
147
|
+
"""Determine if a frame should be logged based on filters."""
|
|
156
148
|
# If no filters, log all frames
|
|
157
149
|
if not self.frame_filters:
|
|
158
150
|
return True
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
# SPDX-License-Identifier: BSD 2-Clause License
|
|
5
5
|
#
|
|
6
6
|
|
|
7
|
+
"""LLM logging observer for Pipecat."""
|
|
8
|
+
|
|
7
9
|
from loguru import logger
|
|
8
10
|
|
|
9
11
|
from pipecat.frames.frames import (
|
|
@@ -34,10 +36,15 @@ class LLMLogObserver(BaseObserver):
|
|
|
34
36
|
|
|
35
37
|
This allows you to track when the LLM starts responding, what it generates,
|
|
36
38
|
and when it finishes.
|
|
37
|
-
|
|
38
39
|
"""
|
|
39
40
|
|
|
40
41
|
async def on_push_frame(self, data: FramePushed):
|
|
42
|
+
"""Handle frame push events and log LLM-related activities.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
data: The frame push event data containing source, destination,
|
|
46
|
+
frame, direction, and timestamp information.
|
|
47
|
+
"""
|
|
41
48
|
src = data.source
|
|
42
49
|
dst = data.destination
|
|
43
50
|
frame = data.frame
|
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
# SPDX-License-Identifier: BSD 2-Clause License
|
|
5
5
|
#
|
|
6
6
|
|
|
7
|
+
"""Transcription logging observer for Pipecat.
|
|
8
|
+
|
|
9
|
+
This module provides an observer that logs transcription frames to the console,
|
|
10
|
+
allowing developers to monitor speech-to-text activity in real-time.
|
|
11
|
+
"""
|
|
12
|
+
|
|
7
13
|
from loguru import logger
|
|
8
14
|
|
|
9
15
|
from pipecat.frames.frames import (
|
|
@@ -17,17 +23,23 @@ from pipecat.services.stt_service import STTService
|
|
|
17
23
|
class TranscriptionLogObserver(BaseObserver):
|
|
18
24
|
"""Observer to log transcription activity to the console.
|
|
19
25
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- InterimTranscriptionFrame
|
|
24
|
-
|
|
25
|
-
This allows you to track when the LLM starts responding, what it generates,
|
|
26
|
-
and when it finishes.
|
|
26
|
+
Monitors and logs all transcription frames from STT services, including
|
|
27
|
+
both final transcriptions and interim results. This allows developers
|
|
28
|
+
to track speech recognition activity and debug transcription issues.
|
|
27
29
|
|
|
30
|
+
Only processes frames from STTService instances to avoid logging
|
|
31
|
+
unrelated transcription frames from other sources.
|
|
28
32
|
"""
|
|
29
33
|
|
|
30
34
|
async def on_push_frame(self, data: FramePushed):
|
|
35
|
+
"""Handle frame push events and log transcription frames.
|
|
36
|
+
|
|
37
|
+
Logs TranscriptionFrame and InterimTranscriptionFrame instances
|
|
38
|
+
with timestamps and user information for debugging purposes.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
data: Frame push event data containing source, frame, and timestamp.
|
|
42
|
+
"""
|
|
31
43
|
src = data.source
|
|
32
44
|
frame = data.frame
|
|
33
45
|
timestamp = data.timestamp
|
|
@@ -4,12 +4,17 @@
|
|
|
4
4
|
# SPDX-License-Identifier: BSD 2-Clause License
|
|
5
5
|
#
|
|
6
6
|
|
|
7
|
+
"""Observer for measuring user-to-bot response latency."""
|
|
8
|
+
|
|
7
9
|
import time
|
|
10
|
+
from statistics import mean
|
|
8
11
|
|
|
9
12
|
from loguru import logger
|
|
10
13
|
|
|
11
14
|
from pipecat.frames.frames import (
|
|
12
15
|
BotStartedSpeakingFrame,
|
|
16
|
+
CancelFrame,
|
|
17
|
+
EndFrame,
|
|
13
18
|
UserStartedSpeakingFrame,
|
|
14
19
|
UserStoppedSpeakingFrame,
|
|
15
20
|
)
|
|
@@ -18,19 +23,29 @@ from pipecat.processors.frame_processor import FrameDirection
|
|
|
18
23
|
|
|
19
24
|
|
|
20
25
|
class UserBotLatencyLogObserver(BaseObserver):
|
|
21
|
-
"""Observer that
|
|
22
|
-
when the bot starts speaking.
|
|
23
|
-
|
|
24
|
-
This helps measure how quickly the AI services respond.
|
|
26
|
+
"""Observer that measures time between user stopping speech and bot starting speech.
|
|
25
27
|
|
|
28
|
+
This helps measure how quickly the AI services respond by tracking
|
|
29
|
+
conversation turn timing and logging latency metrics.
|
|
26
30
|
"""
|
|
27
31
|
|
|
28
32
|
def __init__(self):
|
|
33
|
+
"""Initialize the latency observer.
|
|
34
|
+
|
|
35
|
+
Sets up tracking for processed frames and user speech timing
|
|
36
|
+
to calculate response latencies.
|
|
37
|
+
"""
|
|
29
38
|
super().__init__()
|
|
30
39
|
self._processed_frames = set()
|
|
31
40
|
self._user_stopped_time = 0
|
|
41
|
+
self._latencies = []
|
|
32
42
|
|
|
33
43
|
async def on_push_frame(self, data: FramePushed):
|
|
44
|
+
"""Process frames to track speech timing and calculate latency.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
data: Frame push event containing the frame and direction information.
|
|
48
|
+
"""
|
|
34
49
|
# Only process downstream frames
|
|
35
50
|
if data.direction != FrameDirection.DOWNSTREAM:
|
|
36
51
|
return
|
|
@@ -45,6 +60,18 @@ class UserBotLatencyLogObserver(BaseObserver):
|
|
|
45
60
|
self._user_stopped_time = 0
|
|
46
61
|
elif isinstance(data.frame, UserStoppedSpeakingFrame):
|
|
47
62
|
self._user_stopped_time = time.time()
|
|
63
|
+
elif isinstance(data.frame, (EndFrame, CancelFrame)):
|
|
64
|
+
if self._latencies:
|
|
65
|
+
avg_latency = mean(self._latencies)
|
|
66
|
+
min_latency = min(self._latencies)
|
|
67
|
+
max_latency = max(self._latencies)
|
|
68
|
+
logger.info(
|
|
69
|
+
f"⏱️ LATENCY FROM USER STOPPED SPEAKING TO BOT STARTED SPEAKING - Avg: {avg_latency:.3f}s, Min: {min_latency:.3f}s, Max: {max_latency:.3f}s"
|
|
70
|
+
)
|
|
48
71
|
elif isinstance(data.frame, BotStartedSpeakingFrame) and self._user_stopped_time:
|
|
49
72
|
latency = time.time() - self._user_stopped_time
|
|
50
|
-
|
|
73
|
+
self._user_stopped_time = 0
|
|
74
|
+
self._latencies.append(latency)
|
|
75
|
+
logger.debug(
|
|
76
|
+
f"⏱️ LATENCY FROM USER STOPPED SPEAKING TO BOT STARTED SPEAKING: {latency:.3f}s"
|
|
77
|
+
)
|
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
# SPDX-License-Identifier: BSD 2-Clause License
|
|
5
5
|
#
|
|
6
6
|
|
|
7
|
+
"""Turn tracking observer for conversation flow monitoring.
|
|
8
|
+
|
|
9
|
+
This module provides an observer that monitors conversation turns in a pipeline,
|
|
10
|
+
tracking when turns start and end based on user and bot speech patterns.
|
|
11
|
+
"""
|
|
12
|
+
|
|
7
13
|
import asyncio
|
|
8
14
|
from collections import deque
|
|
9
15
|
|
|
@@ -23,15 +29,30 @@ from pipecat.observers.base_observer import BaseObserver, FramePushed
|
|
|
23
29
|
class TurnTrackingObserver(BaseObserver):
|
|
24
30
|
"""Observer that tracks conversation turns in a pipeline.
|
|
25
31
|
|
|
32
|
+
This observer monitors the flow of conversation by tracking when turns
|
|
33
|
+
start and end based on user and bot speaking patterns. It handles
|
|
34
|
+
interruptions, timeouts, and maintains turn state throughout the pipeline.
|
|
35
|
+
|
|
26
36
|
Turn tracking logic:
|
|
37
|
+
|
|
27
38
|
- The first turn starts immediately when the pipeline starts (StartFrame)
|
|
28
39
|
- Subsequent turns start when the user starts speaking
|
|
29
40
|
- A turn ends when the bot stops speaking and either:
|
|
41
|
+
|
|
30
42
|
- The user starts speaking again
|
|
31
43
|
- A timeout period elapses with no more bot speech
|
|
32
44
|
"""
|
|
33
45
|
|
|
34
46
|
def __init__(self, max_frames=100, turn_end_timeout_secs=2.5, **kwargs):
|
|
47
|
+
"""Initialize the turn tracking observer.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
max_frames: Maximum number of frame IDs to keep in history for
|
|
51
|
+
duplicate detection. Defaults to 100.
|
|
52
|
+
turn_end_timeout_secs: Timeout in seconds after bot stops speaking
|
|
53
|
+
before automatically ending the turn. Defaults to 2.5.
|
|
54
|
+
**kwargs: Additional arguments passed to the parent observer.
|
|
55
|
+
"""
|
|
35
56
|
super().__init__(**kwargs)
|
|
36
57
|
self._turn_count = 0
|
|
37
58
|
self._is_turn_active = False
|
|
@@ -49,7 +70,11 @@ class TurnTrackingObserver(BaseObserver):
|
|
|
49
70
|
self._register_event_handler("on_turn_ended")
|
|
50
71
|
|
|
51
72
|
async def on_push_frame(self, data: FramePushed):
|
|
52
|
-
"""Process frame events for turn tracking.
|
|
73
|
+
"""Process frame events for turn tracking.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
data: Frame push event data containing the frame and metadata.
|
|
77
|
+
"""
|
|
53
78
|
# Skip already processed frames
|
|
54
79
|
if data.frame.id in self._processed_frames:
|
|
55
80
|
return
|
|
@@ -4,16 +4,14 @@
|
|
|
4
4
|
# SPDX-License-Identifier: BSD 2-Clause License
|
|
5
5
|
#
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
from typing import List
|
|
7
|
+
"""Base pipeline implementation for frame processing."""
|
|
9
8
|
|
|
10
9
|
from pipecat.processors.frame_processor import FrameProcessor
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
class BasePipeline(FrameProcessor):
|
|
14
|
-
|
|
15
|
-
super().__init__()
|
|
13
|
+
"""Base class for all pipeline implementations."""
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
def __init__(self, **kwargs):
|
|
16
|
+
"""Initialize the base pipeline."""
|
|
17
|
+
super().__init__(**kwargs)
|