dvalle08 commited on
Commit
1bf5975
·
1 Parent(s): 5ec72cd

Add LiveKit agent dispatch functionality and update settings for agent configuration. Enhance Streamlit app to dispatch agent upon room token creation.

Browse files
.env.example CHANGED
@@ -18,4 +18,6 @@ NVIDIA_VOICE_NAME=Magpie-Multilingual.EN-US.Aria
18
  LIVEKIT_URL=wss://your-livekit-server.example.com
19
  LIVEKIT_API_KEY=your_livekit_api_key_here
20
  LIVEKIT_API_SECRET=your_livekit_api_secret_here
 
 
21
 
 
18
  LIVEKIT_URL=wss://your-livekit-server.example.com
19
  LIVEKIT_API_KEY=your_livekit_api_key_here
20
  LIVEKIT_API_SECRET=your_livekit_api_secret_here
21
+ LIVEKIT_AGENT_NAME=open-voice-agent
22
+ LIVEKIT_NUM_IDLE_PROCESSES=2
23
 
src/agent/agent.py CHANGED
@@ -21,10 +21,10 @@ class Assistant(Agent):
21
  )
22
 
23
 
24
- server = AgentServer()
25
 
26
 
27
- @server.rtc_session()
28
  async def session_handler(ctx: agents.JobContext) -> None:
29
  session = AgentSession(
30
  stt=MoonshineSTT(model_id=settings.voice.MOONSHINE_MODEL_ID),
 
21
  )
22
 
23
 
24
+ server = AgentServer(num_idle_processes=settings.livekit.LIVEKIT_NUM_IDLE_PROCESSES)
25
 
26
 
27
+ @server.rtc_session(agent_name=settings.livekit.LIVEKIT_AGENT_NAME)
28
  async def session_handler(ctx: agents.JobContext) -> None:
29
  session = AgentSession(
30
  stt=MoonshineSTT(model_id=settings.voice.MOONSHINE_MODEL_ID),
src/api/livekit_tokens.py CHANGED
@@ -1,6 +1,7 @@
1
  from __future__ import annotations
2
 
3
  import uuid
 
4
  from dataclasses import dataclass
5
 
6
  from livekit import api
@@ -15,6 +16,58 @@ class LiveKitToken:
15
  identity: str
16
 
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  def create_room_token(room_name: str, identity: str | None = None) -> LiveKitToken:
19
  if not room_name:
20
  raise ValueError("room_name must not be empty")
@@ -32,4 +85,3 @@ def create_room_token(room_name: str, identity: str | None = None) -> LiveKitTok
32
  )
33
 
34
  return LiveKitToken(token=token, room_name=room_name, identity=participant_identity)
35
-
 
1
  from __future__ import annotations
2
 
3
  import uuid
4
+ import asyncio
5
  from dataclasses import dataclass
6
 
7
  from livekit import api
 
16
  identity: str
17
 
18
 
19
+ def _normalize_livekit_url(url: str | None) -> str:
20
+ if not url:
21
+ raise ValueError("LIVEKIT_URL must be set")
22
+ if url.startswith("wss://"):
23
+ return f"https://{url[6:]}"
24
+ if url.startswith("ws://"):
25
+ return f"http://{url[5:]}"
26
+ return url
27
+
28
+
29
+ async def dispatch_agent(
30
+ *,
31
+ room_name: str,
32
+ agent_name: str,
33
+ metadata: str | None = None,
34
+ ) -> api.AgentDispatch:
35
+ if not room_name:
36
+ raise ValueError("room_name must not be empty")
37
+ if not agent_name:
38
+ raise ValueError("agent_name must not be empty")
39
+
40
+ request = api.CreateAgentDispatchRequest(
41
+ agent_name=agent_name,
42
+ room=room_name,
43
+ metadata=metadata or "",
44
+ )
45
+ lkapi = api.LiveKitAPI(
46
+ url=_normalize_livekit_url(settings.livekit.LIVEKIT_URL),
47
+ api_key=settings.livekit.LIVEKIT_API_KEY,
48
+ api_secret=settings.livekit.LIVEKIT_API_SECRET,
49
+ )
50
+ try:
51
+ return await lkapi.agent_dispatch.create_dispatch(request)
52
+ finally:
53
+ await lkapi.aclose()
54
+
55
+
56
+ def dispatch_agent_sync(
57
+ *,
58
+ room_name: str,
59
+ agent_name: str,
60
+ metadata: str | None = None,
61
+ ) -> api.AgentDispatch:
62
+ return asyncio.run(
63
+ dispatch_agent(
64
+ room_name=room_name,
65
+ agent_name=agent_name,
66
+ metadata=metadata,
67
+ )
68
+ )
69
+
70
+
71
  def create_room_token(room_name: str, identity: str | None = None) -> LiveKitToken:
72
  if not room_name:
73
  raise ValueError("room_name must not be empty")
 
85
  )
86
 
87
  return LiveKitToken(token=token, room_name=room_name, identity=participant_identity)
 
src/core/settings.py CHANGED
@@ -80,6 +80,8 @@ class LiveKitSettings(CoreSettings):
80
  LIVEKIT_URL: Optional[str] = Field(default=None)
81
  LIVEKIT_API_KEY: Optional[str] = Field(default=None)
82
  LIVEKIT_API_SECRET: Optional[str] = Field(default=None)
 
 
83
 
84
 
85
  class Settings(CoreSettings):
 
80
  LIVEKIT_URL: Optional[str] = Field(default=None)
81
  LIVEKIT_API_KEY: Optional[str] = Field(default=None)
82
  LIVEKIT_API_SECRET: Optional[str] = Field(default=None)
83
+ LIVEKIT_AGENT_NAME: str = Field(default="open-voice-agent")
84
+ LIVEKIT_NUM_IDLE_PROCESSES: int = Field(default=2, ge=0)
85
 
86
 
87
  class Settings(CoreSettings):
src/streamlit_app.py CHANGED
@@ -6,7 +6,7 @@ from uuid import uuid4
6
 
7
  import streamlit as st
8
 
9
- from src.api.livekit_tokens import create_room_token
10
  from src.core.settings import settings
11
 
12
  UI_DIR = Path(__file__).parent / "ui"
@@ -47,6 +47,18 @@ def main() -> None:
47
  if start or "token" not in st.session_state:
48
  token_data = create_room_token(room_name=room_name)
49
  st.session_state["token"] = token_data.token
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
  token = st.session_state.get("token")
52
  if not token:
 
6
 
7
  import streamlit as st
8
 
9
+ from src.api.livekit_tokens import create_room_token, dispatch_agent_sync
10
  from src.core.settings import settings
11
 
12
  UI_DIR = Path(__file__).parent / "ui"
 
47
  if start or "token" not in st.session_state:
48
  token_data = create_room_token(room_name=room_name)
49
  st.session_state["token"] = token_data.token
50
+ st.session_state["agent_dispatched"] = False
51
+
52
+ if not st.session_state.get("agent_dispatched"):
53
+ try:
54
+ dispatch_agent_sync(
55
+ room_name=room_name,
56
+ agent_name=settings.livekit.LIVEKIT_AGENT_NAME,
57
+ )
58
+ st.session_state["agent_dispatched"] = True
59
+ except Exception as exc:
60
+ st.error(f"Failed to dispatch agent: {exc}")
61
+ return
62
 
63
  token = st.session_state.get("token")
64
  if not token: