Implement WebRTC offer handling and ICE candidate management in voice_webrtc.py
- Add new HTTP endpoints for handling WebRTC offers and ICE candidates, enhancing the signaling process for voice interactions. - Introduce dynamic variable decoding from request headers to support flexible offer payloads. - Refactor existing WebSocket handling to accommodate new offer processing logic. - Update frontend dependencies to include Pipecat client libraries for improved WebRTC transport management. - Streamline voice preview functionality by integrating SmallWebRTCTransport for better media handling.
This commit is contained in:
@@ -9,9 +9,11 @@
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import base64
|
||||
import json
|
||||
|
||||
from db.session import SessionLocal
|
||||
from fastapi import APIRouter, Depends, WebSocket
|
||||
from fastapi import APIRouter, Body, Depends, Request, WebSocket
|
||||
from loguru import logger
|
||||
from models import AssistantConfig, SignalingOffer
|
||||
from services.auth import require_admin, require_admin_websocket
|
||||
@@ -24,6 +26,7 @@ from services.webrtc_ice import aiortc_ice_servers, client_ice_servers
|
||||
# 注意:pipecat 是重依赖(语音才用),在 _handle_offer 等处惰性导入。
|
||||
|
||||
router = APIRouter(tags=["voice"])
|
||||
_http_peers: dict[str, object] = {}
|
||||
|
||||
|
||||
@router.get("/api/webrtc/ice-servers", dependencies=[Depends(require_admin)])
|
||||
@@ -32,6 +35,45 @@ async def ice_servers():
|
||||
return {"iceServers": client_ice_servers()}
|
||||
|
||||
|
||||
@router.post("/api/webrtc/offer", dependencies=[Depends(require_admin)])
|
||||
async def http_offer(request: Request, payload: dict = Body(...)):
|
||||
"""Official SmallWebRTC JS transport offer endpoint."""
|
||||
request_data = payload.get("requestData") or {}
|
||||
encoded_variables = request.headers.get("x-pipecat-dynamic-variables", "")
|
||||
header_variables = {}
|
||||
if encoded_variables:
|
||||
padding = "=" * (-len(encoded_variables) % 4)
|
||||
header_variables = json.loads(
|
||||
base64.urlsafe_b64decode(encoded_variables + padding).decode("utf-8")
|
||||
)
|
||||
offer_payload = {
|
||||
**payload,
|
||||
"assistant_id": request.headers.get("x-pipecat-assistant-id"),
|
||||
"dynamic_variables": header_variables,
|
||||
**request_data,
|
||||
}
|
||||
answer = await _handle_offer_payload(offer_payload, _http_peers)
|
||||
return answer
|
||||
|
||||
|
||||
@router.patch("/api/webrtc/offer", dependencies=[Depends(require_admin)])
|
||||
async def http_ice_candidates(payload: dict = Body(...)):
|
||||
"""Accept the batched trickle ICE format used by the official JS client."""
|
||||
pc_id = payload.get("pc_id")
|
||||
pc = _http_peers.get(pc_id) if pc_id else None
|
||||
if not pc:
|
||||
return {"ok": False}
|
||||
|
||||
from aiortc.sdp import candidate_from_sdp
|
||||
|
||||
for item in payload.get("candidates") or []:
|
||||
candidate = candidate_from_sdp(item.get("candidate", ""))
|
||||
candidate.sdpMid = item.get("sdp_mid")
|
||||
candidate.sdpMLineIndex = item.get("sdp_mline_index")
|
||||
await pc.add_ice_candidate(candidate)
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@router.websocket("/ws/voice")
|
||||
async def voice_signaling(websocket: WebSocket):
|
||||
if not await require_admin_websocket(websocket):
|
||||
@@ -92,6 +134,17 @@ async def _resolve_config(offer: SignalingOffer) -> AssistantConfig:
|
||||
|
||||
|
||||
async def _handle_offer(websocket, payload, peers):
|
||||
answer = await _handle_offer_payload(payload, peers)
|
||||
if websocket.application_state == WebSocketState.CONNECTED:
|
||||
await websocket.send_json(
|
||||
{
|
||||
"type": "answer",
|
||||
"payload": answer,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def _handle_offer_payload(payload, peers):
|
||||
from pipecat.transports.smallwebrtc.connection import SmallWebRTCConnection
|
||||
from services.pipecat.pipeline import run_pipeline
|
||||
from services.pipecat.transports import build_webrtc_transport
|
||||
@@ -99,6 +152,11 @@ async def _handle_offer(websocket, payload, peers):
|
||||
offer = SignalingOffer(**payload)
|
||||
pc_id = offer.pc_id
|
||||
|
||||
restart_pc = bool(payload.get("restart_pc"))
|
||||
if restart_pc and pc_id and pc_id in peers:
|
||||
old_pc = peers.pop(pc_id)
|
||||
await old_pc.disconnect()
|
||||
|
||||
if pc_id and pc_id in peers:
|
||||
pc = peers[pc_id]
|
||||
await pc.renegotiate(sdp=offer.sdp, type=offer.type, restart_pc=False)
|
||||
@@ -144,17 +202,11 @@ async def _handle_offer(websocket, payload, peers):
|
||||
)
|
||||
|
||||
answer = pc.get_answer()
|
||||
if websocket.application_state == WebSocketState.CONNECTED:
|
||||
await websocket.send_json(
|
||||
{
|
||||
"type": "answer",
|
||||
"payload": {
|
||||
"pc_id": answer["pc_id"],
|
||||
"sdp": answer["sdp"],
|
||||
"type": answer["type"],
|
||||
},
|
||||
}
|
||||
)
|
||||
return {
|
||||
"pc_id": answer["pc_id"],
|
||||
"sdp": answer["sdp"],
|
||||
"type": answer["type"],
|
||||
}
|
||||
|
||||
|
||||
async def _handle_ice(payload, peers):
|
||||
|
||||
254
frontend/package-lock.json
generated
254
frontend/package-lock.json
generated
@@ -8,6 +8,8 @@
|
||||
"name": "ai-video-admin-frontend",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@pipecat-ai/client-js": "^1.12.0",
|
||||
"@pipecat-ai/small-webrtc-transport": "^1.10.5",
|
||||
"@xyflow/react": "^12.11.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
@@ -404,6 +406,15 @@
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.29.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz",
|
||||
"integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.29.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz",
|
||||
@@ -449,6 +460,22 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@daily-co/daily-js": {
|
||||
"version": "0.90.0",
|
||||
"resolved": "https://registry.npmjs.org/@daily-co/daily-js/-/daily-js-0.90.0.tgz",
|
||||
"integrity": "sha512-XnuuNIxLt8GOv+rFYoU+OPTSmVj+Mg9hRPK2EM6WYVY62F6rcw7vwzZBOSCisVuu1VnTIF/2J9V0VEBa83lDzw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@sentry/browser": "^8.33.1",
|
||||
"bowser": "^2.8.1",
|
||||
"dequal": "^2.0.3",
|
||||
"events": "^3.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@dotenvx/dotenvx": {
|
||||
"version": "1.71.0",
|
||||
"resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.71.0.tgz",
|
||||
@@ -1888,6 +1915,34 @@
|
||||
"integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@pipecat-ai/client-js": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@pipecat-ai/client-js/-/client-js-1.12.0.tgz",
|
||||
"integrity": "sha512-TKHuxTfnO5Eq9VpmSqaPsV0y9lQ+jkb7aEG5MRsmjkhxyhhOW2ljMPwMDzOt+lwS89ZRtk12FUKEaRR/+yBGGg==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@types/events": "^3.0.3",
|
||||
"bowser": "^2.11.0",
|
||||
"clone-deep": "^4.0.1",
|
||||
"events": "^3.3.0",
|
||||
"typed-emitter": "^2.1.0",
|
||||
"uuid": "^11.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@pipecat-ai/small-webrtc-transport": {
|
||||
"version": "1.10.5",
|
||||
"resolved": "https://registry.npmjs.org/@pipecat-ai/small-webrtc-transport/-/small-webrtc-transport-1.10.5.tgz",
|
||||
"integrity": "sha512-TF2TV/GQUVuC8Pr69fG/MSvUtuwEGcPcUg/H5d8O0RmSthVief0APgC5cKuyrjh/Rtl7+AjhxxWbrkuACdxulQ==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@daily-co/daily-js": "^0.90.0",
|
||||
"dequal": "^2.0.3",
|
||||
"lodash": "^4.17.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@pipecat-ai/client-js": "~1.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/number": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz",
|
||||
@@ -3399,6 +3454,81 @@
|
||||
"integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@sentry-internal/browser-utils": {
|
||||
"version": "8.55.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.55.2.tgz",
|
||||
"integrity": "sha512-GnKod+gL/Y+1FUM/RGV8q6le1CoyiGbT40MitEK7eVwWe+bfTRq1gN7ioupyHFMUg1RlQkDQ4/sENmio/uow5A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry/core": "8.55.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/feedback": {
|
||||
"version": "8.55.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.55.2.tgz",
|
||||
"integrity": "sha512-XQy//NWbL0mLLM5w8wNDWMNpXz39VUyW2397dUrH8++kR63WhUVAvTOtL0o0GMVadSAzl1b08oHP9zSUNFQwcg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry/core": "8.55.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/replay": {
|
||||
"version": "8.55.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.55.2.tgz",
|
||||
"integrity": "sha512-+W43Z697EVe/OgpGW07B773sa8xO1UbpnW0Cr+E+3FMDb6ZbXlaBUoagPTUkkQPdwBe35SDh6r8y2M3EOPGbxg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry-internal/browser-utils": "8.55.2",
|
||||
"@sentry/core": "8.55.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/replay-canvas": {
|
||||
"version": "8.55.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.55.2.tgz",
|
||||
"integrity": "sha512-P/jGiuR7dRLG9IzD/463fLgiibyYceauav/9prRG0ZxJm1AtuO02OKball2Fs3bbzdzwHCTlcsUuL2ivDF4b5A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry-internal/replay": "8.55.2",
|
||||
"@sentry/core": "8.55.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/browser": {
|
||||
"version": "8.55.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.55.2.tgz",
|
||||
"integrity": "sha512-xHuPIEKhx9zw5quWvv4YgZprnwoVMCfxIhmOIf6KJ9iizyUHeUDcKpLS59xERroqwX4RpvK+l/27AZu4zfZlzQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sentry-internal/browser-utils": "8.55.2",
|
||||
"@sentry-internal/feedback": "8.55.2",
|
||||
"@sentry-internal/replay": "8.55.2",
|
||||
"@sentry-internal/replay-canvas": "8.55.2",
|
||||
"@sentry/core": "8.55.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/core": {
|
||||
"version": "8.55.2",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.55.2.tgz",
|
||||
"integrity": "sha512-YlEBwybUcOQ/KjMHDmof1vwweVnBtBxYlQp7DE3fOdtW4pqqdHWTnTntQs4VgYfxzjJYgtkd9LHlGtg8qy+JVQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sindresorhus/merge-streams": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
|
||||
@@ -3833,6 +3963,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/events": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.3.tgz",
|
||||
"integrity": "sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||
@@ -4977,6 +5113,12 @@
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/bowser": {
|
||||
"version": "2.14.1",
|
||||
"resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz",
|
||||
"integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.15",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz",
|
||||
@@ -5245,6 +5387,20 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/clone-deep": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
|
||||
"integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-plain-object": "^2.0.4",
|
||||
"kind-of": "^6.0.2",
|
||||
"shallow-clone": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/clsx": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||
@@ -5723,6 +5879,15 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/dequal": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||
@@ -6507,6 +6672,15 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/events": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
|
||||
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.8.x"
|
||||
}
|
||||
},
|
||||
"node_modules/eventsource": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz",
|
||||
@@ -7786,6 +7960,18 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-plain-object": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
|
||||
"integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"isobject": "^3.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-promise": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
|
||||
@@ -8001,6 +8187,15 @@
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/isobject": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
||||
"integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/iterator.prototype": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz",
|
||||
@@ -8161,6 +8356,15 @@
|
||||
"json-buffer": "3.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/kind-of": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
||||
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/kleur": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
|
||||
@@ -8487,6 +8691,12 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
|
||||
"integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
@@ -10028,6 +10238,16 @@
|
||||
"queue-microtask": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/rxjs": {
|
||||
"version": "7.8.2",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
||||
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-array-concat": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz",
|
||||
@@ -10306,6 +10526,18 @@
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
},
|
||||
"node_modules/shallow-clone": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
|
||||
"integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"kind-of": "^6.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/sharp": {
|
||||
"version": "0.34.5",
|
||||
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
|
||||
@@ -11165,6 +11397,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/typed-emitter": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-2.1.0.tgz",
|
||||
"integrity": "sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==",
|
||||
"license": "MIT",
|
||||
"optionalDependencies": {
|
||||
"rxjs": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
@@ -11403,6 +11644,19 @@
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "11.1.1",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz",
|
||||
"integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist/esm/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/validate-npm-package-name": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz",
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
"lint": "eslint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pipecat-ai/client-js": "^1.12.0",
|
||||
"@pipecat-ai/small-webrtc-transport": "^1.10.5",
|
||||
"@xyflow/react": "^12.11.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user