livekit-plugins-volcenginee 1.3.6__tar.gz → 1.3.9__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.
- {livekit_plugins_volcenginee-1.3.6 → livekit_plugins_volcenginee-1.3.9}/PKG-INFO +1 -1
- {livekit_plugins_volcenginee-1.3.6 → livekit_plugins_volcenginee-1.3.9}/livekit/plugins/volcengine/llm.py +44 -0
- {livekit_plugins_volcenginee-1.3.6 → livekit_plugins_volcenginee-1.3.9}/livekit/plugins/volcengine/stt.py +45 -1
- {livekit_plugins_volcenginee-1.3.6 → livekit_plugins_volcenginee-1.3.9}/livekit/plugins/volcengine/tts.py +42 -0
- livekit_plugins_volcenginee-1.3.9/livekit/plugins/volcengine/version.py +1 -0
- livekit_plugins_volcenginee-1.3.6/livekit/plugins/volcengine/version.py +0 -1
- {livekit_plugins_volcenginee-1.3.6 → livekit_plugins_volcenginee-1.3.9}/.gitignore +0 -0
- {livekit_plugins_volcenginee-1.3.6 → livekit_plugins_volcenginee-1.3.9}/README.md +0 -0
- {livekit_plugins_volcenginee-1.3.6 → livekit_plugins_volcenginee-1.3.9}/livekit/plugins/volcengine/__init__.py +0 -0
- {livekit_plugins_volcenginee-1.3.6 → livekit_plugins_volcenginee-1.3.9}/livekit/plugins/volcengine/log.py +0 -0
- {livekit_plugins_volcenginee-1.3.6 → livekit_plugins_volcenginee-1.3.9}/livekit/plugins/volcengine/py.typed +0 -0
- {livekit_plugins_volcenginee-1.3.6 → livekit_plugins_volcenginee-1.3.9}/livekit/plugins/volcengine/realtime.py +0 -0
- {livekit_plugins_volcenginee-1.3.6 → livekit_plugins_volcenginee-1.3.9}/livekit/plugins/volcengine/utils.py +0 -0
- {livekit_plugins_volcenginee-1.3.6 → livekit_plugins_volcenginee-1.3.9}/pyproject.toml +0 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import asyncio
|
|
3
4
|
import os
|
|
5
|
+
import time
|
|
4
6
|
from dataclasses import dataclass
|
|
5
7
|
from typing import Any, Literal
|
|
6
8
|
|
|
@@ -110,6 +112,48 @@ class LLM(llm.LLM):
|
|
|
110
112
|
),
|
|
111
113
|
)
|
|
112
114
|
|
|
115
|
+
self._prewarm_task: asyncio.Task[None] | None = None
|
|
116
|
+
|
|
117
|
+
def prewarm(self) -> None:
|
|
118
|
+
"""Issue a tiny 1-token chat completion to warm the model and prime
|
|
119
|
+
the HTTP connection.
|
|
120
|
+
|
|
121
|
+
Doubao's first call typically pays 1–3 s of model warm-up cost; a
|
|
122
|
+
discardable 1-token call ahead of the first real turn hides that
|
|
123
|
+
cost from the per-turn TTFT — the single largest knob for first-turn
|
|
124
|
+
latency on this plugin. The cost is ~5–10 tokens per session start.
|
|
125
|
+
|
|
126
|
+
Mirrors the ``connection_pool.prewarm`` convention: schedule a
|
|
127
|
+
background task and return immediately.
|
|
128
|
+
"""
|
|
129
|
+
if self._prewarm_task is not None and not self._prewarm_task.done():
|
|
130
|
+
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
|
+
|
|
137
|
+
model = self._opts.model
|
|
138
|
+
|
|
139
|
+
async def _impl() -> None:
|
|
140
|
+
t0 = time.perf_counter()
|
|
141
|
+
try:
|
|
142
|
+
await self._client.chat.completions.create(
|
|
143
|
+
model=model,
|
|
144
|
+
messages=[{"role": "user", "content": "hi"}],
|
|
145
|
+
max_tokens=1,
|
|
146
|
+
stream=False,
|
|
147
|
+
)
|
|
148
|
+
logger.info(
|
|
149
|
+
"llm prewarm: warmup call completed in %.0f ms",
|
|
150
|
+
(time.perf_counter() - t0) * 1000,
|
|
151
|
+
)
|
|
152
|
+
except Exception as exc: # noqa: BLE001
|
|
153
|
+
logger.warning("llm prewarm failed: %s", exc)
|
|
154
|
+
|
|
155
|
+
self._prewarm_task = loop.create_task(_impl(), name="volcengine.llm.prewarm")
|
|
156
|
+
|
|
113
157
|
def chat(
|
|
114
158
|
self,
|
|
115
159
|
*,
|
|
@@ -80,7 +80,7 @@ class STTOptions:
|
|
|
80
80
|
source_type: Literal["duration", "concurrent"] = "duration"
|
|
81
81
|
resource_id: str | None = None
|
|
82
82
|
|
|
83
|
-
base_url: str = "wss://openspeech.bytedance.com/api/v3/sauc/
|
|
83
|
+
base_url: str = "wss://openspeech.bytedance.com/api/v3/sauc/bigmodel_async"
|
|
84
84
|
format: Literal["pcm", "wav", "ogg"] = "pcm"
|
|
85
85
|
sample_rate: int = 16000
|
|
86
86
|
bits: int = 16
|
|
@@ -118,6 +118,10 @@ class STTOptions:
|
|
|
118
118
|
"enable_itn": self.enable_itn,
|
|
119
119
|
"enable_punc": self.enable_punc,
|
|
120
120
|
"enable_ddc": self.enable_ddc,
|
|
121
|
+
"enable_nonstream": True,
|
|
122
|
+
"enable_speaker_info": True,
|
|
123
|
+
"ssd_version": "200",
|
|
124
|
+
"enable_gender_detection": True,
|
|
121
125
|
"show_utterance": self.show_utterance,
|
|
122
126
|
"result_type": self.result_type,
|
|
123
127
|
"vad_segment_duration": self.vad_segment_duration,
|
|
@@ -221,12 +225,52 @@ class STT(stt.STT):
|
|
|
221
225
|
|
|
222
226
|
self._session = http_session
|
|
223
227
|
self._streams = weakref.WeakSet[SpeechStream]()
|
|
228
|
+
self._prewarm_task: asyncio.Task[None] | None = None
|
|
224
229
|
|
|
225
230
|
def _ensure_session(self) -> aiohttp.ClientSession:
|
|
226
231
|
if not self._session:
|
|
227
232
|
self._session = utils.http_context.http_session()
|
|
228
233
|
return self._session
|
|
229
234
|
|
|
235
|
+
def prewarm(self) -> None:
|
|
236
|
+
"""Open the STT WebSocket and send the handshake payload so the first
|
|
237
|
+
user turn doesn't pay the TLS + WS-upgrade + auth round-trip cost.
|
|
238
|
+
|
|
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.
|
|
244
|
+
"""
|
|
245
|
+
if self._prewarm_task is not None and not self._prewarm_task.done():
|
|
246
|
+
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
|
+
|
|
253
|
+
async def _impl() -> None:
|
|
254
|
+
try:
|
|
255
|
+
session = self._ensure_session()
|
|
256
|
+
async with session.ws_connect(
|
|
257
|
+
self._opts.get_ws_url(),
|
|
258
|
+
headers=self._opts.get_ws_header(),
|
|
259
|
+
max_msg_size=1000000000,
|
|
260
|
+
) as ws:
|
|
261
|
+
await ws.send_bytes(self._opts.get_ws_query_params())
|
|
262
|
+
# Wait briefly so we also eat the auth roundtrip; the
|
|
263
|
+
# server ack arrives within a few hundred ms.
|
|
264
|
+
try:
|
|
265
|
+
await asyncio.wait_for(ws.receive(), timeout=2.0)
|
|
266
|
+
except asyncio.TimeoutError:
|
|
267
|
+
pass
|
|
268
|
+
logger.info("stt prewarm: ws handshake completed")
|
|
269
|
+
except Exception as exc: # noqa: BLE001
|
|
270
|
+
logger.warning("stt prewarm failed: %s", exc)
|
|
271
|
+
|
|
272
|
+
self._prewarm_task = loop.create_task(_impl(), name="volcengine.stt.prewarm")
|
|
273
|
+
|
|
230
274
|
async def _recognize_impl(
|
|
231
275
|
self,
|
|
232
276
|
buffer: AudioBuffer,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import asyncio
|
|
3
4
|
import base64
|
|
4
5
|
import gzip
|
|
5
6
|
import json
|
|
@@ -164,12 +165,53 @@ class TTS(tts.TTS):
|
|
|
164
165
|
self._session = http_session
|
|
165
166
|
self._min_sentence_length = min_sentence_length
|
|
166
167
|
self._streams = weakref.WeakSet[SynthesizeStream]()
|
|
168
|
+
self._prewarm_task: asyncio.Task[None] | None = None
|
|
167
169
|
|
|
168
170
|
def _ensure_session(self) -> aiohttp.ClientSession:
|
|
169
171
|
if self._session is None:
|
|
170
172
|
self._session = utils.http_context.http_session()
|
|
171
173
|
return self._session
|
|
172
174
|
|
|
175
|
+
def prewarm(self) -> None:
|
|
176
|
+
"""Make a tiny HTTP synthesize call to prime the TLS connection and
|
|
177
|
+
warm the TTS model.
|
|
178
|
+
|
|
179
|
+
Shaves the per-call TLS + model load cost off the first turn's TTS
|
|
180
|
+
TTFB. The warmup text is two characters; the audio is discarded.
|
|
181
|
+
|
|
182
|
+
Mirrors the ``connection_pool.prewarm`` convention: schedule a
|
|
183
|
+
background task and return immediately.
|
|
184
|
+
"""
|
|
185
|
+
if self._prewarm_task is not None and not self._prewarm_task.done():
|
|
186
|
+
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
|
+
|
|
193
|
+
async def _impl() -> None:
|
|
194
|
+
t0 = time.perf_counter()
|
|
195
|
+
try:
|
|
196
|
+
session = self._ensure_session()
|
|
197
|
+
payload = self._opts.get_http_request("你好")
|
|
198
|
+
headers = self._opts.get_http_header()
|
|
199
|
+
async with session.post(
|
|
200
|
+
self._opts.get_http_url(),
|
|
201
|
+
json=payload,
|
|
202
|
+
timeout=aiohttp.ClientTimeout(total=30, sock_connect=10),
|
|
203
|
+
headers=headers,
|
|
204
|
+
) as resp:
|
|
205
|
+
await resp.read()
|
|
206
|
+
logger.info(
|
|
207
|
+
"tts prewarm: warmup synthesize completed in %.0f ms",
|
|
208
|
+
(time.perf_counter() - t0) * 1000,
|
|
209
|
+
)
|
|
210
|
+
except Exception as exc: # noqa: BLE001
|
|
211
|
+
logger.warning("tts prewarm failed: %s", exc)
|
|
212
|
+
|
|
213
|
+
self._prewarm_task = loop.create_task(_impl(), name="volcengine.tts.prewarm")
|
|
214
|
+
|
|
173
215
|
def synthesize(
|
|
174
216
|
self, text, *, conn_options: APIConnectOptions = DEFAULT_API_CONNECT_OPTIONS
|
|
175
217
|
):
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.3.9"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.3.6"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|