livekit-plugins-spatialreal 1.3.12__tar.gz → 1.4.3__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.
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: livekit-plugins-spatialreal
3
- Version: 1.3.12
3
+ Version: 1.4.3
4
4
  Summary: Agent Framework plugin for SpatialReal Avatar
5
5
  Project-URL: Documentation, https://docs.spatialreal.com
6
- Project-URL: Website, https://spatialreal.com/
7
- Project-URL: Source, https://github.com/spatialreal/livekit-plugins-spatialreal
6
+ Project-URL: Website, https://www.spatialreal.ai/
7
+ Project-URL: Source, https://github.com/spatialwalk/livekit-plugins-spatialreal
8
8
  Author-email: 3DRX <3drxkjy@gmail.com>
9
9
  License-Expression: MIT
10
10
  License-File: LICENSE
@@ -13,14 +13,16 @@ Classifier: Intended Audience :: Developers
13
13
  Classifier: License :: OSI Approved :: MIT License
14
14
  Classifier: Programming Language :: Python :: 3
15
15
  Classifier: Programming Language :: Python :: 3 :: Only
16
- Classifier: Programming Language :: Python :: 3.9
17
16
  Classifier: Programming Language :: Python :: 3.10
18
17
  Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
19
21
  Classifier: Topic :: Multimedia :: Sound/Audio
20
22
  Classifier: Topic :: Multimedia :: Video
21
23
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
- Requires-Python: >=3.9.0
23
- Requires-Dist: avatarkit>=0.1.3
24
+ Requires-Python: >=3.10.0
25
+ Requires-Dist: avatarkit>=0.1.4
24
26
  Requires-Dist: livekit-agents>=1.2.9
25
27
  Description-Content-Type: text/markdown
26
28
 
@@ -113,12 +115,16 @@ Main class for integrating SpatialReal avatars with LiveKit agents.
113
115
  | `console_endpoint_url` | `str` | Custom console endpoint URL |
114
116
  | `ingress_endpoint_url` | `str` | Custom ingress endpoint URL |
115
117
  | `avatar_participant_identity` | `str` | LiveKit identity for avatar participant |
118
+ | `idle_timeout_seconds` | `int` | LiveKit egress idle timeout in seconds (`0` uses server defaults) |
116
119
 
117
120
  #### Methods
118
121
 
119
122
  - `start(agent_session, room, *, livekit_url, livekit_api_key, livekit_api_secret)`: Start the avatar session and hook into the agent's audio output.
120
123
  - `aclose()`: Clean up avatar session resources.
121
124
 
125
+ When starting, the plugin automatically sets `lk.publish_on_behalf` to the
126
+ agent participant identity for avatar worker association in LiveKit frontends.
127
+
122
128
  ### `SpatialRealException`
123
129
 
124
130
  Exception raised for SpatialReal-related errors.
@@ -87,12 +87,16 @@ Main class for integrating SpatialReal avatars with LiveKit agents.
87
87
  | `console_endpoint_url` | `str` | Custom console endpoint URL |
88
88
  | `ingress_endpoint_url` | `str` | Custom ingress endpoint URL |
89
89
  | `avatar_participant_identity` | `str` | LiveKit identity for avatar participant |
90
+ | `idle_timeout_seconds` | `int` | LiveKit egress idle timeout in seconds (`0` uses server defaults) |
90
91
 
91
92
  #### Methods
92
93
 
93
94
  - `start(agent_session, room, *, livekit_url, livekit_api_key, livekit_api_secret)`: Start the avatar session and hook into the agent's audio output.
94
95
  - `aclose()`: Clean up avatar session resources.
95
96
 
97
+ When starting, the plugin automatically sets `lk.publish_on_behalf` to the
98
+ agent participant identity for avatar worker association in LiveKit frontends.
99
+
96
100
  ### `SpatialRealException`
97
101
 
98
102
  Exception raised for SpatialReal-related errors.
@@ -10,6 +10,7 @@ from __future__ import annotations
10
10
  import asyncio
11
11
  import os
12
12
  from datetime import datetime, timedelta, timezone
13
+ from typing import Any
13
14
 
14
15
  from avatarkit import (
15
16
  AvatarSession as AvatarkitSession,
@@ -18,7 +19,7 @@ from avatarkit import (
18
19
  LiveKitEgressConfig,
19
20
  new_avatar_session,
20
21
  )
21
- from livekit.agents import AgentSession
22
+ from livekit.agents import AgentSession, UserStateChangedEvent
22
23
  from livekit.agents.voice.avatar import AudioSegmentEnd, QueueAudioOutput
23
24
 
24
25
  from livekit import rtc
@@ -30,7 +31,6 @@ __all__ = ["AvatarSession", "SpatialRealException"]
30
31
  DEFAULT_AVATAR_PARTICIPANT_IDENTITY = "spatialreal-avatar"
31
32
  DEFAULT_SAMPLE_RATE = 24000
32
33
 
33
- # Default endpoints (China)
34
34
  DEFAULT_CONSOLE_ENDPOINT = "https://console.us-west.spatialwalk.cloud/v1/console"
35
35
  DEFAULT_INGRESS_ENDPOINT = "wss://api.us-west.spatialwalk.cloud/v2/driveningress"
36
36
 
@@ -56,6 +56,8 @@ class AvatarSession:
56
56
  ingress_endpoint_url: Ingress endpoint URL. Falls back to
57
57
  SPATIALREAL_INGRESS_ENDPOINT env var or default.
58
58
  avatar_participant_identity: LiveKit identity for the avatar participant.
59
+ idle_timeout_seconds: Idle timeout in seconds for the egress connection.
60
+ A value of 0 uses server defaults.
59
61
 
60
62
  Usage:
61
63
  avatar = AvatarSession()
@@ -71,6 +73,7 @@ class AvatarSession:
71
73
  console_endpoint_url: str | None = None,
72
74
  ingress_endpoint_url: str | None = None,
73
75
  avatar_participant_identity: str | None = None,
76
+ idle_timeout_seconds: int = 0,
74
77
  ) -> None:
75
78
  # Resolve API key
76
79
  self._api_key = api_key or os.getenv("SPATIALREAL_API_KEY")
@@ -102,6 +105,10 @@ class AvatarSession:
102
105
  # Avatar participant configuration
103
106
  self._avatar_participant_identity = avatar_participant_identity or DEFAULT_AVATAR_PARTICIPANT_IDENTITY
104
107
 
108
+ if idle_timeout_seconds < 0:
109
+ raise SpatialRealException("idle_timeout_seconds must be greater than or equal to 0")
110
+ self._idle_timeout_seconds = idle_timeout_seconds
111
+
105
112
  # Internal state
106
113
  self._avatarkit_session: AvatarkitSession | None = None
107
114
  self._agent_session: AgentSession | None = None
@@ -146,18 +153,24 @@ class AvatarSession:
146
153
  )
147
154
 
148
155
  room_name = room.name
156
+ agent_participant_identity = room.local_participant.identity
149
157
  logger.info(f"Initializing SpatialReal avatar session for room: {room_name}")
150
158
  logger.debug(f"Console endpoint: {self._console_endpoint_url}")
151
159
  logger.debug(f"Ingress endpoint: {self._ingress_endpoint_url}")
152
160
 
161
+ egress_attributes = {"lk.publish_on_behalf": agent_participant_identity}
162
+
153
163
  # Create LiveKit egress configuration for the avatar to join the room
154
- livekit_egress = LiveKitEgressConfig(
155
- url=lk_url,
156
- api_key=lk_api_key,
157
- api_secret=lk_api_secret,
158
- room_name=room_name,
159
- publisher_id=self._avatar_participant_identity,
160
- )
164
+ livekit_egress_kwargs: dict[str, Any] = {
165
+ "url": lk_url,
166
+ "api_key": lk_api_key,
167
+ "api_secret": lk_api_secret,
168
+ "room_name": room_name,
169
+ "publisher_id": self._avatar_participant_identity,
170
+ "extra_attributes": egress_attributes,
171
+ "idle_timeout": self._idle_timeout_seconds,
172
+ }
173
+ livekit_egress = LiveKitEgressConfig(**livekit_egress_kwargs)
161
174
 
162
175
  # Create avatar session with LiveKit egress mode
163
176
  self._avatarkit_session = new_avatar_session(
@@ -190,6 +203,12 @@ class AvatarSession:
190
203
  def on_clear_buffer() -> None:
191
204
  asyncio.create_task(self._handle_interrupt())
192
205
 
206
+ # Register for user_state_changed events (interrupt on user speaking)
207
+ @agent_session.on("user_state_changed")
208
+ def on_user_state_changed(ev: UserStateChangedEvent) -> None:
209
+ if ev.new_state == "speaking":
210
+ asyncio.create_task(self._handle_interrupt())
211
+
193
212
  # Start the main task that forwards audio to avatar
194
213
  self._main_task = asyncio.create_task(self._run_main_task())
195
214
 
@@ -0,0 +1 @@
1
+ __version__ = "1.4.3"
@@ -8,7 +8,7 @@ dynamic = ["version"]
8
8
  description = "Agent Framework plugin for SpatialReal Avatar"
9
9
  readme = "README.md"
10
10
  license = "MIT"
11
- requires-python = ">=3.9.0"
11
+ requires-python = ">=3.10.0"
12
12
  authors = [{ name = "3DRX", email = "3drxkjy@gmail.com" }]
13
13
  keywords = ["voice", "ai", "realtime", "audio", "video", "livekit", "webrtc", "avatar", "spatialreal"]
14
14
  classifiers = [
@@ -18,20 +18,22 @@ classifiers = [
18
18
  "Topic :: Multimedia :: Video",
19
19
  "Topic :: Scientific/Engineering :: Artificial Intelligence",
20
20
  "Programming Language :: Python :: 3",
21
- "Programming Language :: Python :: 3.9",
22
21
  "Programming Language :: Python :: 3.10",
23
22
  "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Programming Language :: Python :: 3.14",
24
26
  "Programming Language :: Python :: 3 :: Only",
25
27
  ]
26
28
  dependencies = [
27
29
  "livekit-agents>=1.2.9",
28
- "avatarkit>=0.1.3",
30
+ "avatarkit>=0.1.4",
29
31
  ]
30
32
 
31
33
  [project.urls]
32
34
  Documentation = "https://docs.spatialreal.com"
33
- Website = "https://spatialreal.com/"
34
- Source = "https://github.com/spatialreal/livekit-plugins-spatialreal"
35
+ Website = "https://www.spatialreal.ai/"
36
+ Source = "https://github.com/spatialwalk/livekit-plugins-spatialreal"
35
37
 
36
38
  [tool.hatch.version]
37
39
  path = "livekit/plugins/spatialreal/version.py"
@@ -43,7 +45,7 @@ packages = ["livekit"]
43
45
  include = ["/livekit"]
44
46
 
45
47
  [tool.ruff]
46
- target-version = "py39"
48
+ target-version = "py310"
47
49
  line-length = 120
48
50
 
49
51
  [tool.ruff.lint]
@@ -1 +0,0 @@
1
- __version__ = "1.3.12"