livekit-plugins-volcenginee 1.3.9__tar.gz → 1.3.11__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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: livekit-plugins-volcenginee
3
- Version: 1.3.9
3
+ Version: 1.3.11
4
4
  Summary: LiveKit Agent Plugins for Volcengine
5
5
  Author-email: linsanzhu <2287225730@qq.com>
6
6
  Keywords: audio,livekit,realtime,video,webrtc
@@ -114,6 +114,15 @@ class LLM(llm.LLM):
114
114
 
115
115
  self._prewarm_task: asyncio.Task[None] | None = None
116
116
 
117
+ @property
118
+ def model(self) -> str:
119
+ """The underlying Doubao model name (e.g. ``"doubao-1-5-lite-32k-250115"``)."""
120
+ return self._opts.model
121
+
122
+ @property
123
+ def provider(self) -> str:
124
+ return "volcengine"
125
+
117
126
  def prewarm(self) -> None:
118
127
  """Issue a tiny 1-token chat completion to warm the model and prime
119
128
  the HTTP connection.
@@ -123,16 +132,16 @@ class LLM(llm.LLM):
123
132
  cost from the per-turn TTFT — the single largest knob for first-turn
124
133
  latency on this plugin. The cost is ~5–10 tokens per session start.
125
134
 
126
- Mirrors the ``connection_pool.prewarm`` convention: schedule a
127
- background task and return immediately.
135
+ Mirrors the ``connection_pool.prewarm`` convention when a running
136
+ event loop is available (schedule a background task and return
137
+ immediately). LiveKit Agents may call this synchronously from a
138
+ context without a running loop — in that case we fall back to
139
+ ``asyncio.run`` and execute the warmup to completion before
140
+ returning, so the first user turn still benefits from a warm model
141
+ + keep-alive connection.
128
142
  """
129
143
  if self._prewarm_task is not None and not self._prewarm_task.done():
130
144
  return
131
- try:
132
- loop = asyncio.get_running_loop()
133
- except RuntimeError:
134
- logger.debug("llm prewarm skipped: no running event loop")
135
- return
136
145
 
137
146
  model = self._opts.model
138
147
 
@@ -152,6 +161,18 @@ class LLM(llm.LLM):
152
161
  except Exception as exc: # noqa: BLE001
153
162
  logger.warning("llm prewarm failed: %s", exc)
154
163
 
164
+ try:
165
+ loop = asyncio.get_running_loop()
166
+ except RuntimeError:
167
+ # No running event loop — run the warmup synchronously to
168
+ # completion. ``asyncio.run`` builds and tears down its own
169
+ # loop, so it's safe to call from a plain sync context.
170
+ try:
171
+ asyncio.run(_impl())
172
+ except Exception as exc: # noqa: BLE001
173
+ logger.warning("llm prewarm failed: %s", exc)
174
+ return
175
+
155
176
  self._prewarm_task = loop.create_task(_impl(), name="volcengine.llm.prewarm")
156
177
 
157
178
  def chat(
@@ -232,23 +232,29 @@ class STT(stt.STT):
232
232
  self._session = utils.http_context.http_session()
233
233
  return self._session
234
234
 
235
+ @property
236
+ def model(self) -> str:
237
+ """The underlying ASR model name (e.g. ``"bigmodel"``)."""
238
+ return self._opts.model_name
239
+
240
+ @property
241
+ def provider(self) -> str:
242
+ return "volcengine"
243
+
235
244
  def prewarm(self) -> None:
236
245
  """Open the STT WebSocket and send the handshake payload so the first
237
246
  user turn doesn't pay the TLS + WS-upgrade + auth round-trip cost.
238
247
 
239
- Mirrors the ``connection_pool.prewarm`` convention: schedule a
240
- background task and return immediately. The framework calls this
241
- synchronously before the session starts, so the actual WS work
242
- happens concurrently while the user is still getting ready to
243
- speak.
248
+ Mirrors the ``connection_pool.prewarm`` convention when a running
249
+ event loop is available (schedule a background task and return
250
+ immediately). LiveKit Agents may call this synchronously from a
251
+ context without a running loop, in which case we fall back to
252
+ ``asyncio.run`` and execute the warmup to completion before
253
+ returning — the framework still benefits because the next user
254
+ turn will reuse the now-warm DNS / TLS / WS-upgrade path.
244
255
  """
245
256
  if self._prewarm_task is not None and not self._prewarm_task.done():
246
257
  return
247
- try:
248
- loop = asyncio.get_running_loop()
249
- except RuntimeError:
250
- logger.debug("stt prewarm skipped: no running event loop")
251
- return
252
258
 
253
259
  async def _impl() -> None:
254
260
  try:
@@ -269,6 +275,18 @@ class STT(stt.STT):
269
275
  except Exception as exc: # noqa: BLE001
270
276
  logger.warning("stt prewarm failed: %s", exc)
271
277
 
278
+ try:
279
+ loop = asyncio.get_running_loop()
280
+ except RuntimeError:
281
+ # No running event loop — run the warmup synchronously to
282
+ # completion. ``asyncio.run`` builds and tears down its own
283
+ # loop, so it's safe to call from a plain sync context.
284
+ try:
285
+ asyncio.run(_impl())
286
+ except Exception as exc: # noqa: BLE001
287
+ logger.warning("stt prewarm failed: %s", exc)
288
+ return
289
+
272
290
  self._prewarm_task = loop.create_task(_impl(), name="volcengine.stt.prewarm")
273
291
 
274
292
  async def _recognize_impl(
@@ -172,6 +172,25 @@ class TTS(tts.TTS):
172
172
  self._session = utils.http_context.http_session()
173
173
  return self._session
174
174
 
175
+ @property
176
+ def model(self) -> str:
177
+ """The TTS model identifier, composed as ``"{resource_id}/{voice}"``.
178
+
179
+ Both pieces matter: ``resource_id`` selects the model family
180
+ (``"seed-tts-2.0"``, ``"seed-tts-1.0"``, ``"seed-icl-2.0"``, …) and
181
+ ``voice`` selects the speaker profile. The effective ``resource_id``
182
+ falls back to ``VOLCENGINE_TTS_RESOURCE_ID`` and then ``"seed-tts-2.0"``,
183
+ matching ``_TTSOptions.get_http_header``.
184
+ """
185
+ resource_id = self._opts.resource_id or os.getenv(
186
+ "VOLCENGINE_TTS_RESOURCE_ID", "seed-tts-2.0"
187
+ )
188
+ return f"{resource_id}/{self._opts.voice}"
189
+
190
+ @property
191
+ def provider(self) -> str:
192
+ return "volcengine"
193
+
175
194
  def prewarm(self) -> None:
176
195
  """Make a tiny HTTP synthesize call to prime the TLS connection and
177
196
  warm the TTS model.
@@ -179,16 +198,16 @@ class TTS(tts.TTS):
179
198
  Shaves the per-call TLS + model load cost off the first turn's TTS
180
199
  TTFB. The warmup text is two characters; the audio is discarded.
181
200
 
182
- Mirrors the ``connection_pool.prewarm`` convention: schedule a
183
- background task and return immediately.
201
+ LiveKit Agents invokes ``prewarm`` synchronously from a setup hook
202
+ that may run **without** a running event loop (e.g. when the user
203
+ calls it from a sync context, or before the worker's loop is up).
204
+ To stay useful in both contexts, we try a non-blocking
205
+ ``loop.create_task`` first; if no loop is running we fall back to
206
+ ``asyncio.run`` and execute the warmup synchronously to completion
207
+ before returning.
184
208
  """
185
209
  if self._prewarm_task is not None and not self._prewarm_task.done():
186
210
  return
187
- try:
188
- loop = asyncio.get_running_loop()
189
- except RuntimeError:
190
- logger.debug("tts prewarm skipped: no running event loop")
191
- return
192
211
 
193
212
  async def _impl() -> None:
194
213
  t0 = time.perf_counter()
@@ -210,6 +229,18 @@ class TTS(tts.TTS):
210
229
  except Exception as exc: # noqa: BLE001
211
230
  logger.warning("tts prewarm failed: %s", exc)
212
231
 
232
+ try:
233
+ loop = asyncio.get_running_loop()
234
+ except RuntimeError:
235
+ # No running event loop — run the warmup synchronously to
236
+ # completion. ``asyncio.run`` builds and tears down its own
237
+ # loop, so it's safe to call from a plain sync context.
238
+ try:
239
+ asyncio.run(_impl())
240
+ except Exception as exc: # noqa: BLE001
241
+ logger.warning("tts prewarm failed: %s", exc)
242
+ return
243
+
213
244
  self._prewarm_task = loop.create_task(_impl(), name="volcengine.tts.prewarm")
214
245
 
215
246
  def synthesize(
@@ -0,0 +1 @@
1
+ __version__ = "1.3.11"
@@ -1 +0,0 @@
1
- __version__ = "1.3.9"