dv-pipecat-ai 0.0.85.dev821__py3-none-any.whl → 0.0.85.dev823__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.85.dev821.dist-info → dv_pipecat_ai-0.0.85.dev823.dist-info}/METADATA +1 -1
- {dv_pipecat_ai-0.0.85.dev821.dist-info → dv_pipecat_ai-0.0.85.dev823.dist-info}/RECORD +9 -9
- pipecat/frames/frames.py +12 -0
- pipecat/processors/aggregators/llm_response.py +17 -3
- pipecat/processors/frame_processor.py +7 -7
- pipecat/processors/transcript_processor.py +21 -1
- {dv_pipecat_ai-0.0.85.dev821.dist-info → dv_pipecat_ai-0.0.85.dev823.dist-info}/WHEEL +0 -0
- {dv_pipecat_ai-0.0.85.dev821.dist-info → dv_pipecat_ai-0.0.85.dev823.dist-info}/licenses/LICENSE +0 -0
- {dv_pipecat_ai-0.0.85.dev821.dist-info → dv_pipecat_ai-0.0.85.dev823.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
dv_pipecat_ai-0.0.85.
|
|
1
|
+
dv_pipecat_ai-0.0.85.dev823.dist-info/licenses/LICENSE,sha256=DWY2QGf2eMCFhuu2ChairtT6CB7BEFffNVhXWc4Od08,1301
|
|
2
2
|
pipecat/__init__.py,sha256=j0Xm6adxHhd7D06dIyyPV_GlBYLlBnTAERVvD_jAARQ,861
|
|
3
3
|
pipecat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
pipecat/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -79,7 +79,7 @@ pipecat/extensions/voicemail/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
|
|
|
79
79
|
pipecat/extensions/voicemail/voicemail_detector.py,sha256=JxmU2752iWP_1_GmzZReNESUTFAeyEa4XBPL20_C208,30004
|
|
80
80
|
pipecat/frames/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
81
81
|
pipecat/frames/frames.proto,sha256=JXZm3VXLR8zMOUcOuhVoe2mhM3MQIQGMJXLopdJO_5Y,839
|
|
82
|
-
pipecat/frames/frames.py,sha256=
|
|
82
|
+
pipecat/frames/frames.py,sha256=CxlrFst5DuD6kDp2CE6kWigVezF94y-Snf6h8w1pwVU,49522
|
|
83
83
|
pipecat/frames/protobufs/frames_pb2.py,sha256=VHgGV_W7qQ4sfQK6RHb5_DggLm3PiSYMr6aBZ8_p1cQ,2590
|
|
84
84
|
pipecat/metrics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
85
85
|
pipecat/metrics/metrics.py,sha256=bdZNciEtLTtA-xgoKDz2RJAy6fKrXkTwz3pryVHzc2M,2713
|
|
@@ -108,12 +108,12 @@ pipecat/processors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
|
|
|
108
108
|
pipecat/processors/async_generator.py,sha256=qPOZxk5eOad_NrF_Z06vWZ6deXIxb9AKZKYO2e5pkJs,2385
|
|
109
109
|
pipecat/processors/consumer_processor.py,sha256=DrWCKnfblknZJ0bLmR_unIeJ1axQw4IPUn2IB3KLGGA,3228
|
|
110
110
|
pipecat/processors/dtmf_aggregator.py,sha256=mo_IXUlsnVl-_Xn8sbTGnRF4Lkts0h6E3uauGbeFyWs,10204
|
|
111
|
-
pipecat/processors/frame_processor.py,sha256=
|
|
111
|
+
pipecat/processors/frame_processor.py,sha256=uBu6Waa0_diMXdQXMZ5V5a_KwaaPzcieyuv5gO9u-ME,33841
|
|
112
112
|
pipecat/processors/idle_frame_processor.py,sha256=z8AuhGap61lA5K35P6XCaOpn4kkmK_9NZNppbpQxheU,3124
|
|
113
113
|
pipecat/processors/logger.py,sha256=8xa4KKekXQIETlQR7zoGnwUpLNo8CeDVm7YjyXePN-w,2385
|
|
114
114
|
pipecat/processors/producer_processor.py,sha256=iIIOHZd77APvUGP7JqFbznAHUnCULcq_qYiSEjwXHcc,3265
|
|
115
115
|
pipecat/processors/text_transformer.py,sha256=LnfWJYzntJhZhrQ1lgSSY4D4VbHtrQJgrC227M69ZYU,1718
|
|
116
|
-
pipecat/processors/transcript_processor.py,sha256=
|
|
116
|
+
pipecat/processors/transcript_processor.py,sha256=fr5JtlTOfmKnfmYG8ZwRj4DpZWP-uuGi6aNNKtlLxRg,12491
|
|
117
117
|
pipecat/processors/two_stage_user_idle_processor.py,sha256=uf2aZh_lfW-eMxmFogP3R4taAJ1yXOSqjKsR7oXtD0Y,2938
|
|
118
118
|
pipecat/processors/user_idle_processor.py,sha256=Dl-Kcg0B4JZqWXXiyGuvYszGimbu2oKOyOJC92R9_hE,9140
|
|
119
119
|
pipecat/processors/aggregators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -122,7 +122,7 @@ pipecat/processors/aggregators/gated.py,sha256=tii0sRrBkRW6y9Xq5iTWPnqlOEejU4VqP
|
|
|
122
122
|
pipecat/processors/aggregators/gated_llm_context.py,sha256=CPv6sMA8irD1zZ3fU1gSv6D7qcPvCA0MdpFhBtJ_ekI,3007
|
|
123
123
|
pipecat/processors/aggregators/gated_open_ai_llm_context.py,sha256=DgqmdPj1u3fP_SVmxtfP7NjHqnyhN_RVVTDfmjbkxAs,361
|
|
124
124
|
pipecat/processors/aggregators/llm_context.py,sha256=wNbZA0Vt0FzNc5cu06xiv1z7DIClIlfqR1ZD8EusbVw,11085
|
|
125
|
-
pipecat/processors/aggregators/llm_response.py,sha256=
|
|
125
|
+
pipecat/processors/aggregators/llm_response.py,sha256=cBNGU8Ld4zT36-QsE1EJemrNA12q7lc9i-vLM9qmLcQ,48075
|
|
126
126
|
pipecat/processors/aggregators/llm_response_universal.py,sha256=5PqmpATpekD8BVWyBExZgatKHsNbZem8M-A7_VwTbiQ,34334
|
|
127
127
|
pipecat/processors/aggregators/openai_llm_context.py,sha256=cC8DXdVPERRN04i0i-1Ys6kusvnbMALeH-Z8Pu5K684,12999
|
|
128
128
|
pipecat/processors/aggregators/sentence.py,sha256=E7e3knfQl6HEGpYMKPklF1aO_gOn-rr7SnynErwfkQk,2235
|
|
@@ -415,7 +415,7 @@ pipecat/utils/tracing/service_decorators.py,sha256=fwzxFpi8DJl6BJbK74G0UEB4ccMJg
|
|
|
415
415
|
pipecat/utils/tracing/setup.py,sha256=7TEgPNpq6M8lww8OQvf0P9FzYc5A30xICGklVA-fua0,2892
|
|
416
416
|
pipecat/utils/tracing/turn_context_provider.py,sha256=ikon3plFOx0XbMrH6DdeHttNpb-U0gzMZIm3bWLc9eI,2485
|
|
417
417
|
pipecat/utils/tracing/turn_trace_observer.py,sha256=dma16SBJpYSOE58YDWy89QzHyQFc_9gQZszKeWixuwc,9725
|
|
418
|
-
dv_pipecat_ai-0.0.85.
|
|
419
|
-
dv_pipecat_ai-0.0.85.
|
|
420
|
-
dv_pipecat_ai-0.0.85.
|
|
421
|
-
dv_pipecat_ai-0.0.85.
|
|
418
|
+
dv_pipecat_ai-0.0.85.dev823.dist-info/METADATA,sha256=QzFZChlDc4joKwMeDE3JSyM7EQzpJLPuIyfsNhrVgzE,32924
|
|
419
|
+
dv_pipecat_ai-0.0.85.dev823.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
420
|
+
dv_pipecat_ai-0.0.85.dev823.dist-info/top_level.txt,sha256=kQzG20CxGf-nSsHmtXHx3hY2-8zHA3jYg8jk0TajqXc,8
|
|
421
|
+
dv_pipecat_ai-0.0.85.dev823.dist-info/RECORD,,
|
pipecat/frames/frames.py
CHANGED
|
@@ -457,6 +457,7 @@ class TranscriptionMessage:
|
|
|
457
457
|
content: str
|
|
458
458
|
user_id: Optional[str] = None
|
|
459
459
|
timestamp: Optional[str] = None
|
|
460
|
+
message_id: Optional[int] = None
|
|
460
461
|
|
|
461
462
|
|
|
462
463
|
@dataclass
|
|
@@ -510,6 +511,17 @@ class TranscriptionUpdateFrame(DataFrame):
|
|
|
510
511
|
return f"{self.name}(pts: {pts}, messages: {len(self.messages)})"
|
|
511
512
|
|
|
512
513
|
|
|
514
|
+
@dataclass
|
|
515
|
+
class TranscriptDropFrame(DataFrame):
|
|
516
|
+
"""Frame indicating previously emitted transcript chunks should be discarded.
|
|
517
|
+
|
|
518
|
+
Parameters:
|
|
519
|
+
transcript_ids: List of frame/message identifiers to drop.
|
|
520
|
+
"""
|
|
521
|
+
|
|
522
|
+
transcript_ids: List[int]
|
|
523
|
+
|
|
524
|
+
|
|
513
525
|
@dataclass
|
|
514
526
|
class LLMContextFrame(Frame):
|
|
515
527
|
"""Frame containing a universal LLM context.
|
|
@@ -48,9 +48,10 @@ from pipecat.frames.frames import (
|
|
|
48
48
|
LLMTextFrame,
|
|
49
49
|
OpenAILLMContextAssistantTimestampFrame,
|
|
50
50
|
SpeechControlParamsFrame,
|
|
51
|
-
StartInterruptionFrame,
|
|
52
51
|
StartFrame,
|
|
52
|
+
StartInterruptionFrame,
|
|
53
53
|
TextFrame,
|
|
54
|
+
TranscriptDropFrame,
|
|
54
55
|
TranscriptionFrame,
|
|
55
56
|
UserImageRawFrame,
|
|
56
57
|
UserStartedSpeakingFrame,
|
|
@@ -446,6 +447,7 @@ class LLMUserContextAggregator(LLMContextResponseAggregator):
|
|
|
446
447
|
self._latest_final_transcript = ""
|
|
447
448
|
self._last_user_speaking_time = 0
|
|
448
449
|
self._last_aggregation_push_time = 0
|
|
450
|
+
self._pending_transcription_ids: List[int] = []
|
|
449
451
|
|
|
450
452
|
async def reset(self):
|
|
451
453
|
"""Reset the aggregation state and interruption strategies."""
|
|
@@ -453,6 +455,7 @@ class LLMUserContextAggregator(LLMContextResponseAggregator):
|
|
|
453
455
|
self._was_bot_speaking = False
|
|
454
456
|
self._seen_interim_results = False
|
|
455
457
|
self._waiting_for_aggregation = False
|
|
458
|
+
self._pending_transcription_ids.clear()
|
|
456
459
|
[await s.reset() for s in self._interruption_strategies]
|
|
457
460
|
|
|
458
461
|
async def handle_aggregation(self, aggregation: str):
|
|
@@ -588,6 +591,17 @@ class LLMUserContextAggregator(LLMContextResponseAggregator):
|
|
|
588
591
|
|
|
589
592
|
return any([await should_interrupt(s) for s in self._interruption_strategies])
|
|
590
593
|
|
|
594
|
+
async def _discard_pending_transcriptions(self, reason: str):
|
|
595
|
+
"""Notify upstream processors that pending transcripts should be dropped."""
|
|
596
|
+
if self._pending_transcription_ids:
|
|
597
|
+
drop_frame = TranscriptDropFrame(transcript_ids=list(self._pending_transcription_ids))
|
|
598
|
+
self.logger.debug(
|
|
599
|
+
f"Dropping {len(self._pending_transcription_ids)} transcript chunk(s) due to {reason}"
|
|
600
|
+
)
|
|
601
|
+
await self.push_frame(drop_frame, FrameDirection.UPSTREAM)
|
|
602
|
+
self._pending_transcription_ids.clear()
|
|
603
|
+
self._aggregation = ""
|
|
604
|
+
|
|
591
605
|
async def _start(self, frame: StartFrame):
|
|
592
606
|
self._create_aggregation_task()
|
|
593
607
|
|
|
@@ -616,8 +630,7 @@ class LLMUserContextAggregator(LLMContextResponseAggregator):
|
|
|
616
630
|
|
|
617
631
|
async def _handle_user_started_speaking(self, frame: UserStartedSpeakingFrame):
|
|
618
632
|
if len(self._aggregation) > 0:
|
|
619
|
-
self.
|
|
620
|
-
self._aggregation = ""
|
|
633
|
+
await self._discard_pending_transcriptions("user_started_speaking")
|
|
621
634
|
self._latest_final_transcript = ""
|
|
622
635
|
self._last_user_speaking_time = time.time()
|
|
623
636
|
self._user_speaking = True
|
|
@@ -662,6 +675,7 @@ class LLMUserContextAggregator(LLMContextResponseAggregator):
|
|
|
662
675
|
return
|
|
663
676
|
|
|
664
677
|
self._aggregation += f" {text}" if self._aggregation else text
|
|
678
|
+
self._pending_transcription_ids.append(frame.id)
|
|
665
679
|
# We just got a final result, so let's reset interim results.
|
|
666
680
|
self._seen_interim_results = False
|
|
667
681
|
|
|
@@ -591,7 +591,7 @@ class FrameProcessor(BaseObject):
|
|
|
591
591
|
|
|
592
592
|
async def pause_processing_system_frames(self):
|
|
593
593
|
"""Pause processing of queued system frames."""
|
|
594
|
-
logger.trace(f"{self}: pausing system frame processing")
|
|
594
|
+
self.logger.trace(f"{self}: pausing system frame processing")
|
|
595
595
|
self.__should_block_system_frames = True
|
|
596
596
|
if self.__input_event:
|
|
597
597
|
self.__input_event.clear()
|
|
@@ -812,7 +812,7 @@ class FrameProcessor(BaseObject):
|
|
|
812
812
|
True if the processor has been started.
|
|
813
813
|
"""
|
|
814
814
|
if not self.__started:
|
|
815
|
-
logger.error(f"{self} Trying to process {frame} but StartFrame not received yet")
|
|
815
|
+
self.logger.error(f"{self} Trying to process {frame} but StartFrame not received yet")
|
|
816
816
|
return self.__started
|
|
817
817
|
|
|
818
818
|
def __create_input_task(self):
|
|
@@ -876,7 +876,7 @@ class FrameProcessor(BaseObject):
|
|
|
876
876
|
|
|
877
877
|
await self._call_event_handler("on_after_process_frame", frame)
|
|
878
878
|
except Exception as e:
|
|
879
|
-
logger.exception(f"{self}: error processing frame: {e}")
|
|
879
|
+
self.logger.exception(f"{self}: error processing frame: {e}")
|
|
880
880
|
await self.push_error(ErrorFrame(str(e)))
|
|
881
881
|
|
|
882
882
|
async def __input_frame_task_handler(self):
|
|
@@ -890,11 +890,11 @@ class FrameProcessor(BaseObject):
|
|
|
890
890
|
(frame, direction, callback) = await self.__input_queue.get()
|
|
891
891
|
|
|
892
892
|
if self.__should_block_system_frames and self.__input_event:
|
|
893
|
-
logger.trace(f"{self}: system frame processing paused")
|
|
893
|
+
self.logger.trace(f"{self}: system frame processing paused")
|
|
894
894
|
await self.__input_event.wait()
|
|
895
895
|
self.__input_event.clear()
|
|
896
896
|
self.__should_block_system_frames = False
|
|
897
|
-
logger.trace(f"{self}: system frame processing resumed")
|
|
897
|
+
self.logger.trace(f"{self}: system frame processing resumed")
|
|
898
898
|
|
|
899
899
|
if isinstance(frame, SystemFrame):
|
|
900
900
|
await self.__process_frame(frame, direction, callback)
|
|
@@ -913,11 +913,11 @@ class FrameProcessor(BaseObject):
|
|
|
913
913
|
(frame, direction, callback) = await self.__process_queue.get()
|
|
914
914
|
|
|
915
915
|
if self.__should_block_frames and self.__process_event:
|
|
916
|
-
logger.trace(f"{self}: frame processing paused")
|
|
916
|
+
self.logger.trace(f"{self}: frame processing paused")
|
|
917
917
|
await self.__process_event.wait()
|
|
918
918
|
self.__process_event.clear()
|
|
919
919
|
self.__should_block_frames = False
|
|
920
|
-
logger.trace(f"{self}: frame processing resumed")
|
|
920
|
+
self.logger.trace(f"{self}: frame processing resumed")
|
|
921
921
|
|
|
922
922
|
await self.__process_frame(frame, direction, callback)
|
|
923
923
|
|
|
@@ -20,6 +20,7 @@ from pipecat.frames.frames import (
|
|
|
20
20
|
EndFrame,
|
|
21
21
|
Frame,
|
|
22
22
|
InterruptionFrame,
|
|
23
|
+
TranscriptDropFrame,
|
|
23
24
|
TranscriptionFrame,
|
|
24
25
|
TranscriptionMessage,
|
|
25
26
|
TranscriptionUpdateFrame,
|
|
@@ -44,6 +45,7 @@ class BaseTranscriptProcessor(FrameProcessor):
|
|
|
44
45
|
super().__init__(**kwargs)
|
|
45
46
|
self._processed_messages: List[TranscriptionMessage] = []
|
|
46
47
|
self._register_event_handler("on_transcript_update")
|
|
48
|
+
self._register_event_handler("on_transcript_drop")
|
|
47
49
|
|
|
48
50
|
async def _emit_update(self, messages: List[TranscriptionMessage]):
|
|
49
51
|
"""Emit transcript updates for new messages.
|
|
@@ -57,6 +59,18 @@ class BaseTranscriptProcessor(FrameProcessor):
|
|
|
57
59
|
await self._call_event_handler("on_transcript_update", update_frame)
|
|
58
60
|
await self.push_frame(update_frame)
|
|
59
61
|
|
|
62
|
+
async def _handle_transcript_drop(self, frame: TranscriptDropFrame):
|
|
63
|
+
"""Handle transcript drop notifications by removing stored messages."""
|
|
64
|
+
if not frame.transcript_ids:
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
drop_ids = set(frame.transcript_ids)
|
|
68
|
+
if drop_ids:
|
|
69
|
+
self._processed_messages = [
|
|
70
|
+
msg for msg in self._processed_messages if msg.message_id not in drop_ids
|
|
71
|
+
]
|
|
72
|
+
await self._call_event_handler("on_transcript_drop", frame)
|
|
73
|
+
|
|
60
74
|
|
|
61
75
|
class UserTranscriptProcessor(BaseTranscriptProcessor):
|
|
62
76
|
"""Processes user transcription frames into timestamped conversation messages."""
|
|
@@ -72,9 +86,15 @@ class UserTranscriptProcessor(BaseTranscriptProcessor):
|
|
|
72
86
|
|
|
73
87
|
if isinstance(frame, TranscriptionFrame):
|
|
74
88
|
message = TranscriptionMessage(
|
|
75
|
-
role="user",
|
|
89
|
+
role="user",
|
|
90
|
+
user_id=frame.user_id,
|
|
91
|
+
content=frame.text,
|
|
92
|
+
timestamp=frame.timestamp,
|
|
93
|
+
message_id=frame.id,
|
|
76
94
|
)
|
|
77
95
|
await self._emit_update([message])
|
|
96
|
+
elif isinstance(frame, TranscriptDropFrame):
|
|
97
|
+
await self._handle_transcript_drop(frame)
|
|
78
98
|
|
|
79
99
|
await self.push_frame(frame, direction)
|
|
80
100
|
|
|
File without changes
|
{dv_pipecat_ai-0.0.85.dev821.dist-info → dv_pipecat_ai-0.0.85.dev823.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{dv_pipecat_ai-0.0.85.dev821.dist-info → dv_pipecat_ai-0.0.85.dev823.dist-info}/top_level.txt
RENAMED
|
File without changes
|