livekit-plugins-aws 1.1.3__tar.gz → 1.1.5__tar.gz

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 livekit-plugins-aws might be problematic. Click here for more details.

Files changed (19) hide show
  1. {livekit_plugins_aws-1.1.3 → livekit_plugins_aws-1.1.5}/PKG-INFO +11 -5
  2. {livekit_plugins_aws-1.1.3 → livekit_plugins_aws-1.1.5}/README.md +5 -2
  3. {livekit_plugins_aws-1.1.3 → livekit_plugins_aws-1.1.5}/livekit/plugins/aws/__init__.py +32 -8
  4. livekit_plugins_aws-1.1.5/livekit/plugins/aws/experimental/realtime/__init__.py +15 -0
  5. livekit_plugins_aws-1.1.5/livekit/plugins/aws/experimental/realtime/events.py +521 -0
  6. livekit_plugins_aws-1.1.5/livekit/plugins/aws/experimental/realtime/pretty_printer.py +49 -0
  7. livekit_plugins_aws-1.1.5/livekit/plugins/aws/experimental/realtime/realtime_model.py +1208 -0
  8. livekit_plugins_aws-1.1.5/livekit/plugins/aws/experimental/realtime/turn_tracker.py +172 -0
  9. livekit_plugins_aws-1.1.5/livekit/plugins/aws/log.py +7 -0
  10. {livekit_plugins_aws-1.1.3 → livekit_plugins_aws-1.1.5}/livekit/plugins/aws/tts.py +0 -2
  11. {livekit_plugins_aws-1.1.3 → livekit_plugins_aws-1.1.5}/livekit/plugins/aws/version.py +1 -1
  12. {livekit_plugins_aws-1.1.3 → livekit_plugins_aws-1.1.5}/pyproject.toml +8 -2
  13. livekit_plugins_aws-1.1.3/livekit/plugins/aws/log.py +0 -3
  14. {livekit_plugins_aws-1.1.3 → livekit_plugins_aws-1.1.5}/.gitignore +0 -0
  15. {livekit_plugins_aws-1.1.3 → livekit_plugins_aws-1.1.5}/livekit/plugins/aws/llm.py +0 -0
  16. {livekit_plugins_aws-1.1.3 → livekit_plugins_aws-1.1.5}/livekit/plugins/aws/models.py +0 -0
  17. {livekit_plugins_aws-1.1.3 → livekit_plugins_aws-1.1.5}/livekit/plugins/aws/py.typed +0 -0
  18. {livekit_plugins_aws-1.1.3 → livekit_plugins_aws-1.1.5}/livekit/plugins/aws/stt.py +0 -0
  19. {livekit_plugins_aws-1.1.3 → livekit_plugins_aws-1.1.5}/livekit/plugins/aws/utils.py +0 -0
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: livekit-plugins-aws
3
- Version: 1.1.3
3
+ Version: 1.1.5
4
4
  Summary: LiveKit Agents Plugin for services from AWS
5
5
  Project-URL: Documentation, https://docs.livekit.io
6
6
  Project-URL: Website, https://livekit.io/
7
7
  Project-URL: Source, https://github.com/livekit/agents
8
8
  Author-email: LiveKit <hello@livekit.io>
9
9
  License-Expression: Apache-2.0
10
- Keywords: audio,aws,livekit,realtime,video,webrtc
10
+ Keywords: audio,aws,livekit,nova,realtime,sonic,video,webrtc
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: License :: OSI Approved :: Apache Software License
13
13
  Classifier: Programming Language :: Python :: 3
@@ -20,12 +20,15 @@ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
20
  Requires-Python: >=3.9.0
21
21
  Requires-Dist: aioboto3>=14.1.0
22
22
  Requires-Dist: amazon-transcribe>=0.6.2
23
- Requires-Dist: livekit-agents>=1.1.3
23
+ Requires-Dist: livekit-agents>=1.1.5
24
+ Provides-Extra: realtime
25
+ Requires-Dist: aws-sdk-bedrock-runtime==0.0.2; (python_version >= '3.12') and extra == 'realtime'
26
+ Requires-Dist: boto3>1.35.10; extra == 'realtime'
24
27
  Description-Content-Type: text/markdown
25
28
 
26
29
  # AWS plugin for LiveKit Agents
27
30
 
28
- Support for AWS AI including Bedrock, Polly, and Transcribe.
31
+ Support for AWS AI including Bedrock, Polly, Transcribe and optionally Nova Sonic (realtime STS model).
29
32
 
30
33
  See [https://docs.livekit.io/agents/integrations/aws/](https://docs.livekit.io/agents/integrations/aws/) for more information.
31
34
 
@@ -33,8 +36,11 @@ See [https://docs.livekit.io/agents/integrations/aws/](https://docs.livekit.io/a
33
36
 
34
37
  ```bash
35
38
  pip install livekit-plugins-aws
39
+
40
+ # for access to Nova Sonic
41
+ pip install livekit-plugins-aws[realtime]
36
42
  ```
37
43
 
38
44
  ## Pre-requisites
39
45
 
40
- You'll need to specify an AWS Access Key and a Deployment Region. They can be set as environment variables: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and `AWS_DEFAULT_REGION`, respectively.
46
+ You'll need to specify an AWS Access Key and a Deployment Region. They can be set as environment variables: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and `AWS_DEFAULT_REGION`, respectively.
@@ -1,6 +1,6 @@
1
1
  # AWS plugin for LiveKit Agents
2
2
 
3
- Support for AWS AI including Bedrock, Polly, and Transcribe.
3
+ Support for AWS AI including Bedrock, Polly, Transcribe and optionally Nova Sonic (realtime STS model).
4
4
 
5
5
  See [https://docs.livekit.io/agents/integrations/aws/](https://docs.livekit.io/agents/integrations/aws/) for more information.
6
6
 
@@ -8,8 +8,11 @@ See [https://docs.livekit.io/agents/integrations/aws/](https://docs.livekit.io/a
8
8
 
9
9
  ```bash
10
10
  pip install livekit-plugins-aws
11
+
12
+ # for access to Nova Sonic
13
+ pip install livekit-plugins-aws[realtime]
11
14
  ```
12
15
 
13
16
  ## Pre-requisites
14
17
 
15
- You'll need to specify an AWS Access Key and a Deployment Region. They can be set as environment variables: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and `AWS_DEFAULT_REGION`, respectively.
18
+ You'll need to specify an AWS Access Key and a Deployment Region. They can be set as environment variables: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and `AWS_DEFAULT_REGION`, respectively.
@@ -14,24 +14,48 @@
14
14
 
15
15
  """AWS plugin for LiveKit Agents
16
16
 
17
- Support for AWS AI including Bedrock, Polly, and Transcribe.
17
+ Support for AWS AI including Bedrock, Polly, Transcribe and optionally Nova Sonic.
18
18
 
19
19
  See https://docs.livekit.io/agents/integrations/aws/ for more information.
20
20
  """
21
21
 
22
- from .llm import LLM
23
- from .stt import STT, SpeechStream
24
- from .tts import TTS, ChunkedStream
25
- from .version import __version__
22
+ import typing # noqa: I001
26
23
 
27
- __all__ = ["STT", "SpeechStream", "TTS", "ChunkedStream", "LLM", "__version__"]
28
24
 
29
- from livekit.agents import Plugin
25
+ if typing.TYPE_CHECKING:
26
+ from .experimental import realtime
27
+
28
+
29
+ def __getattr__(name: str) -> typing.Any:
30
+ if name == "realtime":
31
+ try:
32
+ from .experimental import realtime
33
+ except ImportError as e:
34
+ raise ImportError(
35
+ "The 'realtime' module requires optional dependencies. "
36
+ "Please install them with: pip install 'livekit-plugins-aws[realtime]'"
37
+ ) from e
38
+
39
+ return realtime
40
+
41
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
42
+
43
+
44
+ from .llm import LLM # noqa: E402
45
+ from .stt import STT, SpeechStream # noqa: E402
46
+ from .tts import TTS, ChunkedStream # noqa: E402
47
+ from .version import __version__ # noqa: E402
48
+
49
+ __all__ = ["STT", "SpeechStream", "TTS", "ChunkedStream", "LLM", "realtime", "__version__"]
50
+
51
+ from livekit.agents import Plugin # noqa: E402
52
+
53
+ from .log import logger # noqa: E402
30
54
 
31
55
 
32
56
  class AWSPlugin(Plugin):
33
57
  def __init__(self) -> None:
34
- super().__init__(__name__, __version__, __package__)
58
+ super().__init__(__name__, __version__, __package__, logger)
35
59
 
36
60
 
37
61
  Plugin.register_plugin(AWSPlugin())
@@ -0,0 +1,15 @@
1
+ from .realtime_model import RealtimeModel, RealtimeSession
2
+
3
+ __all__ = [
4
+ "RealtimeSession",
5
+ "RealtimeModel",
6
+ ]
7
+
8
+ # Cleanup docs of unexported modules
9
+ _module = dir()
10
+ NOT_IN_ALL = [m for m in _module if m not in __all__]
11
+
12
+ __pdoc__ = {}
13
+
14
+ for n in NOT_IN_ALL:
15
+ __pdoc__[n] = False
@@ -0,0 +1,521 @@
1
+ import json
2
+ import uuid
3
+ from typing import Any, Literal, Optional, Union
4
+
5
+ from pydantic import BaseModel, ConfigDict, Field
6
+
7
+ from livekit.agents import llm
8
+
9
+ from ...log import logger
10
+
11
+ MEDIA_TYPE = Literal["text/plain", "audio/lpcm", "application/json"]
12
+ TYPE = Literal["TEXT", "AUDIO", "TOOL"]
13
+ VOICE_ID = Literal["matthew", "tiffany", "amy"]
14
+ ROLE = Literal["USER", "ASSISTANT", "TOOL", "SYSTEM"]
15
+ GENERATION_STAGE = Literal["SPECULATIVE", "FINAL"]
16
+ STOP_REASON = Literal["PARTIAL_TURN", "END_TURN", "INTERRUPTED"]
17
+ SAMPLE_RATE_HERTZ = Literal[8_000, 16_000, 24_000]
18
+ AUDIO_ENCODING = Literal["base64"] # all audio data must be base64 encoded
19
+ SAMPLE_SIZE_BITS = Literal[16] # only supports 16-bit audio
20
+ CHANNEL_COUNT = Literal[1] # only supports monochannel audio
21
+
22
+
23
+ class BaseModel(BaseModel):
24
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
25
+
26
+
27
+ class InferenceConfiguration(BaseModel):
28
+ maxTokens: int = Field(default=1024, ge=1, le=10_000, frozen=True)
29
+ topP: float = Field(default=0.9, ge=0.0, le=1.0, frozen=True)
30
+ temperature: float = Field(default=0.7, ge=0.0, le=1.0, frozen=True)
31
+
32
+
33
+ class AudioInputConfiguration(BaseModel):
34
+ mediaType: MEDIA_TYPE = "audio/lpcm"
35
+ sampleRateHertz: SAMPLE_RATE_HERTZ = Field(default=16000)
36
+ sampleSizeBits: SAMPLE_SIZE_BITS = 16
37
+ channelCount: CHANNEL_COUNT = 1
38
+ audioType: str = "SPEECH"
39
+ encoding: AUDIO_ENCODING = "base64"
40
+
41
+
42
+ class AudioOutputConfiguration(BaseModel):
43
+ mediaType: MEDIA_TYPE = "audio/lpcm"
44
+ sampleRateHertz: SAMPLE_RATE_HERTZ = Field(default=24_000)
45
+ sampleSizeBits: SAMPLE_SIZE_BITS = 16
46
+ channelCount: CHANNEL_COUNT = 1
47
+ voiceId: VOICE_ID = Field(...)
48
+ encoding: AUDIO_ENCODING = "base64"
49
+ audioType: str = "SPEECH"
50
+
51
+
52
+ class TextInputConfiguration(BaseModel):
53
+ mediaType: MEDIA_TYPE = "text/plain"
54
+
55
+
56
+ class TextOutputConfiguration(BaseModel):
57
+ mediaType: MEDIA_TYPE = "text/plain"
58
+
59
+
60
+ class ToolUseOutputConfiguration(BaseModel):
61
+ mediaType: MEDIA_TYPE = "application/json"
62
+
63
+
64
+ class ToolResultInputConfiguration(BaseModel):
65
+ toolUseId: str
66
+ type: TYPE = "TEXT"
67
+ textInputConfiguration: TextInputConfiguration = TextInputConfiguration()
68
+
69
+
70
+ class ToolInputSchema(BaseModel):
71
+ json_: str = Field(
72
+ default_factory=lambda: json.dumps(
73
+ {
74
+ "type": "object",
75
+ "properties": {},
76
+ "required": [],
77
+ }
78
+ ),
79
+ alias="json",
80
+ )
81
+
82
+
83
+ class ToolSpec(BaseModel):
84
+ name: str
85
+ description: str
86
+ inputSchema: ToolInputSchema
87
+
88
+
89
+ class Tool(BaseModel):
90
+ toolSpec: ToolSpec
91
+
92
+
93
+ class ToolConfiguration(BaseModel):
94
+ toolChoice: dict[str, dict[str, str]] | None = None
95
+ tools: list[Tool]
96
+
97
+
98
+ class SessionStart(BaseModel):
99
+ inferenceConfiguration: InferenceConfiguration
100
+
101
+
102
+ class InputTextContentStart(BaseModel):
103
+ promptName: str
104
+ contentName: str
105
+ type: TYPE = "TEXT"
106
+ interactive: bool = False
107
+ role: ROLE
108
+ textInputConfiguration: TextInputConfiguration
109
+
110
+
111
+ class InputAudioContentStart(BaseModel):
112
+ promptName: str
113
+ contentName: str
114
+ type: TYPE = "AUDIO"
115
+ interactive: bool = True
116
+ role: ROLE = "USER"
117
+ audioInputConfiguration: AudioInputConfiguration
118
+
119
+
120
+ class InputToolContentStart(BaseModel):
121
+ promptName: str
122
+ contentName: str
123
+ type: TYPE = "TOOL"
124
+ interactive: bool = False
125
+ role: ROLE = "TOOL"
126
+ toolResultInputConfiguration: ToolResultInputConfiguration
127
+
128
+
129
+ class PromptStart(BaseModel):
130
+ promptName: str
131
+ textOutputConfiguration: TextOutputConfiguration
132
+ audioOutputConfiguration: AudioOutputConfiguration
133
+ toolUseOutputConfiguration: ToolUseOutputConfiguration
134
+ toolConfiguration: ToolConfiguration
135
+
136
+
137
+ class TextInput(BaseModel):
138
+ promptName: str
139
+ contentName: str
140
+ content: str
141
+
142
+
143
+ class AudioInput(BaseModel):
144
+ promptName: str
145
+ contentName: str
146
+ content: str
147
+
148
+
149
+ class ToolResult(BaseModel):
150
+ promptName: str
151
+ contentName: str
152
+ content: str
153
+
154
+
155
+ class ContentEndEvent(BaseModel):
156
+ promptName: str
157
+ contentName: str
158
+
159
+
160
+ class PromptEnd(BaseModel):
161
+ promptName: str
162
+
163
+
164
+ class SessionEnd(BaseModel):
165
+ pass
166
+
167
+
168
+ class SessionStartEvent(BaseModel):
169
+ sessionStart: SessionStart
170
+
171
+
172
+ class InputTextContentStartEvent(BaseModel):
173
+ contentStart: InputTextContentStart
174
+
175
+
176
+ class InputAudioContentStartEvent(BaseModel):
177
+ contentStart: InputAudioContentStart
178
+
179
+
180
+ class InputToolContentStartEvent(BaseModel):
181
+ contentStart: InputToolContentStart
182
+
183
+
184
+ class PromptStartEvent(BaseModel):
185
+ promptStart: PromptStart
186
+
187
+
188
+ class TextInputContentEvent(BaseModel):
189
+ textInput: TextInput
190
+
191
+
192
+ class AudioInputContentEvent(BaseModel):
193
+ audioInput: AudioInput
194
+
195
+
196
+ class ToolResultContentEvent(BaseModel):
197
+ toolResult: ToolResult
198
+
199
+
200
+ class InputContentEndEvent(BaseModel):
201
+ contentEnd: ContentEndEvent
202
+
203
+
204
+ class PromptEndEvent(BaseModel):
205
+ promptEnd: PromptEnd
206
+
207
+
208
+ class SessionEndEvent(BaseModel):
209
+ sessionEnd: SessionEnd
210
+
211
+
212
+ class Event(BaseModel):
213
+ event: Union[
214
+ SessionStartEvent,
215
+ InputTextContentStartEvent,
216
+ InputAudioContentStartEvent,
217
+ InputToolContentStartEvent,
218
+ PromptStartEvent,
219
+ TextInputContentEvent,
220
+ AudioInputContentEvent,
221
+ ToolResultContentEvent,
222
+ InputContentEndEvent,
223
+ PromptEndEvent,
224
+ SessionEndEvent,
225
+ ]
226
+
227
+
228
+ class SonicEventBuilder:
229
+ def __init__(self, prompt_name: str, audio_content_name: str):
230
+ self.prompt_name = prompt_name
231
+ self.audio_content_name = audio_content_name
232
+
233
+ @classmethod
234
+ def get_event_type(cls, json_data: dict) -> str:
235
+ if event := json_data.get("event"):
236
+ if event.get("contentStart", {}).get("type") == "AUDIO":
237
+ return "audio_output_content_start"
238
+ elif event.get("contentEnd", {}).get("type") == "AUDIO":
239
+ return "audio_output_content_end"
240
+ elif event.get("contentStart", {}).get("type") == "TEXT":
241
+ return "text_output_content_start"
242
+ elif event.get("contentEnd", {}).get("type") == "TEXT":
243
+ return "text_output_content_end"
244
+ elif event.get("contentStart", {}).get("type") == "TOOL":
245
+ return "tool_output_content_start"
246
+ elif event.get("contentEnd", {}).get("type") == "TOOL":
247
+ return "tool_output_content_end"
248
+ elif event.get("textOutput"):
249
+ return "text_output_content"
250
+ elif event.get("audioOutput"):
251
+ return "audio_output_content"
252
+ elif event.get("toolUse"):
253
+ return "tool_output_content"
254
+ elif "completionStart" in event:
255
+ return "completion_start"
256
+ elif "completionEnd" in event:
257
+ return "completion_end"
258
+ elif "usageEvent" in event:
259
+ return "usage"
260
+ else:
261
+ return "other_event"
262
+
263
+ def create_text_content_block(
264
+ self,
265
+ content_name: str,
266
+ role: ROLE,
267
+ content: str,
268
+ ) -> list[str]:
269
+ return [
270
+ self.create_text_content_start_event(content_name, role),
271
+ self.create_text_content_event(content_name, content),
272
+ self.create_content_end_event(content_name),
273
+ ]
274
+
275
+ def create_tool_content_block(
276
+ self,
277
+ content_name: str,
278
+ tool_use_id: str,
279
+ content: str,
280
+ ) -> list[str]:
281
+ return [
282
+ self.create_tool_content_start_event(content_name, tool_use_id),
283
+ self.create_tool_result_event(content_name, content),
284
+ self.create_content_end_event(content_name),
285
+ ]
286
+
287
+ def create_prompt_end_block(self) -> list[str]:
288
+ return [
289
+ self.create_content_end_event(self.audio_content_name, is_audio=True),
290
+ self.create_prompt_end_event(),
291
+ self.create_session_end_event(),
292
+ ]
293
+
294
+ def create_prompt_start_block(
295
+ self,
296
+ voice_id: VOICE_ID,
297
+ sample_rate: SAMPLE_RATE_HERTZ,
298
+ system_content: str,
299
+ chat_ctx: llm.ChatContext,
300
+ tool_configuration: Optional[Union[ToolConfiguration, dict[str, Any], str]] = None,
301
+ max_tokens: int = 1024,
302
+ top_p: float = 0.9,
303
+ temperature: float = 0.7,
304
+ ) -> list[str]:
305
+ system_content_name = str(uuid.uuid4())
306
+ init_events = [
307
+ self.create_session_start_event(max_tokens, top_p, temperature),
308
+ self.create_prompt_start_event(voice_id, sample_rate, tool_configuration),
309
+ *self.create_text_content_block(system_content_name, "SYSTEM", system_content),
310
+ ]
311
+
312
+ # note: tool call events are not supported yet
313
+ if chat_ctx.items:
314
+ logger.debug("initiating session with chat context")
315
+ for item in chat_ctx.items:
316
+ ctx_content_name = str(uuid.uuid4())
317
+ init_events.extend(
318
+ self.create_text_content_block(
319
+ ctx_content_name, item.role.upper(), "".join(item.content)
320
+ )
321
+ )
322
+
323
+ return init_events
324
+
325
+ def create_session_start_event(
326
+ self,
327
+ max_tokens: int = 1024,
328
+ top_p: float = 0.9,
329
+ temperature: float = 0.7,
330
+ ) -> str:
331
+ event = Event(
332
+ event=SessionStartEvent(
333
+ sessionStart=SessionStart(
334
+ inferenceConfiguration=InferenceConfiguration(
335
+ maxTokens=max_tokens,
336
+ topP=top_p,
337
+ temperature=temperature,
338
+ )
339
+ )
340
+ )
341
+ )
342
+ return event.model_dump_json(exclude_none=False)
343
+
344
+ def create_audio_content_start_event(
345
+ self,
346
+ sample_rate: SAMPLE_RATE_HERTZ = 16_000,
347
+ ) -> str:
348
+ event = Event(
349
+ event=InputAudioContentStartEvent(
350
+ contentStart=InputAudioContentStart(
351
+ promptName=self.prompt_name,
352
+ contentName=self.audio_content_name,
353
+ audioInputConfiguration=AudioInputConfiguration(
354
+ sampleRateHertz=sample_rate,
355
+ ),
356
+ )
357
+ )
358
+ )
359
+ return event.model_dump_json(exclude_none=True, by_alias=True)
360
+
361
+ def create_text_content_start_event(
362
+ self,
363
+ content_name: str,
364
+ role: ROLE,
365
+ ) -> str:
366
+ event = Event(
367
+ event=InputTextContentStartEvent(
368
+ contentStart=InputTextContentStart(
369
+ promptName=self.prompt_name,
370
+ contentName=content_name,
371
+ role=role,
372
+ textInputConfiguration=TextInputConfiguration(),
373
+ )
374
+ )
375
+ )
376
+ return event.model_dump_json(exclude_none=True, by_alias=True)
377
+
378
+ def create_tool_content_start_event(
379
+ self,
380
+ content_name: str,
381
+ tool_use_id: str,
382
+ ) -> str:
383
+ event = Event(
384
+ event=InputToolContentStartEvent(
385
+ contentStart=InputToolContentStart(
386
+ promptName=self.prompt_name,
387
+ contentName=content_name,
388
+ toolResultInputConfiguration=ToolResultInputConfiguration(
389
+ toolUseId=tool_use_id,
390
+ textInputConfiguration=TextInputConfiguration(),
391
+ ),
392
+ )
393
+ )
394
+ )
395
+ return event.model_dump_json(exclude_none=True, by_alias=True)
396
+
397
+ def create_audio_input_event(
398
+ self,
399
+ audio_content: str,
400
+ ) -> str:
401
+ event = Event(
402
+ event=AudioInputContentEvent(
403
+ audioInput=AudioInput(
404
+ promptName=self.prompt_name,
405
+ contentName=self.audio_content_name,
406
+ content=audio_content,
407
+ )
408
+ )
409
+ )
410
+ return event.model_dump_json(exclude_none=True, by_alias=True)
411
+
412
+ def create_text_content_event(
413
+ self,
414
+ content_name: str,
415
+ content: str,
416
+ ) -> str:
417
+ event = Event(
418
+ event=TextInputContentEvent(
419
+ textInput=TextInput(
420
+ promptName=self.prompt_name,
421
+ contentName=content_name,
422
+ content=content,
423
+ )
424
+ )
425
+ )
426
+ return event.model_dump_json(exclude_none=True, by_alias=True)
427
+
428
+ def create_tool_result_event(
429
+ self,
430
+ content_name: str,
431
+ content: Union[str, dict[str, Any]],
432
+ ) -> str:
433
+ if isinstance(content, dict):
434
+ content_str = json.dumps(content)
435
+ else:
436
+ content_str = content
437
+
438
+ event = Event(
439
+ event=ToolResultContentEvent(
440
+ toolResult=ToolResult(
441
+ promptName=self.prompt_name,
442
+ contentName=content_name,
443
+ content=content_str,
444
+ )
445
+ )
446
+ )
447
+ return event.model_dump_json(exclude_none=True, by_alias=True)
448
+
449
+ def create_content_end_event(
450
+ self,
451
+ content_name: str,
452
+ is_audio: bool = False,
453
+ ) -> str:
454
+ event = Event(
455
+ event=InputContentEndEvent(
456
+ contentEnd=ContentEndEvent(
457
+ promptName=self.prompt_name,
458
+ contentName=content_name if not is_audio else self.audio_content_name,
459
+ )
460
+ )
461
+ )
462
+ return event.model_dump_json(exclude_none=True, by_alias=True)
463
+
464
+ def create_prompt_end_event(self) -> str:
465
+ event = Event(
466
+ event=PromptEndEvent(
467
+ promptEnd=PromptEnd(promptName=self.prompt_name),
468
+ )
469
+ )
470
+ return event.model_dump_json(exclude_none=True, by_alias=True)
471
+
472
+ def create_session_end_event(self) -> str:
473
+ event = Event(
474
+ event=SessionEndEvent(sessionEnd=SessionEnd()),
475
+ )
476
+ return event.model_dump_json(exclude_none=True, by_alias=True)
477
+
478
+ def create_prompt_start_event(
479
+ self,
480
+ voice_id: VOICE_ID,
481
+ sample_rate: SAMPLE_RATE_HERTZ,
482
+ tool_configuration: Optional[Union[ToolConfiguration, dict[str, Any], str]] = None,
483
+ ) -> str:
484
+ tool_configuration = tool_configuration or ToolConfiguration(tools=[])
485
+ for tool in tool_configuration.tools:
486
+ logger.debug(f"TOOL JSON SCHEMA: {tool.toolSpec.inputSchema}")
487
+ tool_objects = [
488
+ Tool(
489
+ toolSpec=ToolSpec(
490
+ name=tool.toolSpec.name,
491
+ description=tool.toolSpec.description,
492
+ inputSchema=ToolInputSchema(json_=tool.toolSpec.inputSchema.json_),
493
+ )
494
+ )
495
+ for tool in tool_configuration.tools
496
+ ]
497
+
498
+ if tool_configuration is None:
499
+ tool_configuration = ToolConfiguration(tools=[])
500
+ elif isinstance(tool_configuration, str):
501
+ tool_configuration = ToolConfiguration(**json.loads(tool_configuration))
502
+ elif isinstance(tool_configuration, dict):
503
+ tool_configuration = ToolConfiguration(**tool_configuration)
504
+
505
+ tool_objects = list(tool_configuration.tools)
506
+ event = Event(
507
+ event=PromptStartEvent(
508
+ promptStart=PromptStart(
509
+ promptName=self.prompt_name,
510
+ textOutputConfiguration=TextOutputConfiguration(),
511
+ audioOutputConfiguration=AudioOutputConfiguration(
512
+ voiceId=voice_id, sampleRateHertz=sample_rate
513
+ ),
514
+ toolUseOutputConfiguration=ToolUseOutputConfiguration(),
515
+ toolConfiguration=ToolConfiguration(
516
+ tools=tool_objects, toolChoice=tool_configuration.toolChoice
517
+ ),
518
+ )
519
+ )
520
+ )
521
+ return event.model_dump_json(exclude_none=True, by_alias=True)