boundless-summer-54220
02/12/2025, 9:37 PMgray-monkey-83525
02/12/2025, 9:37 PMdisconnect
method. According to LiveKit documentation, you can programmatically disconnect a participant by calling the disconnect
method on the room object. You might set an async timer to track inactivity and trigger this method when the timer expires.
Would you like more details on implementing this?
Sources:
- https://livekit-users.slack.com/archives/C07FVFM5NA1/p1731495431.174829
- https://livekit-users.slack.com/archives/C07FVFM5NA1/p1729704710.265049 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.boundless-summer-54220
02/12/2025, 9:39 PMgray-monkey-83525
02/12/2025, 9:39 PMparticipant_connected
, participant_disconnected
, and any other relevant events that indicate activity, like track_published
or track_unpublished
.
2. Track Activity: Maintain a record of the last activity time for each participant. Update this record whenever an activity event is detected.
3. Inactivity Timer: Set up a timer that periodically checks the last activity time for each participant. If the current time exceeds the last activity time by a predefined threshold (e.g., 5 minutes), consider the participant inactive.
4. Disconnect Inactive Participants: For participants deemed inactive, call the disconnect
method on the room object to remove them from the room. This can be done using the LiveKit SDK's disconnect
method, as described in the LiveKit documentation.
Here's a basic example in Python:
import asyncio
from datetime import datetime, timedelta
# Dictionary to track last activity time for each participant
last_activity = {}
# Function to update activity
def update_activity(participant_id):
last_activity[participant_id] = datetime.now()
# Function to check for inactivity
async def check_inactivity(room, inactivity_threshold):
while True:
now = datetime.now()
for participant_id, last_active in list(last_activity.items()):
if now - last_active > inactivity_threshold:
# Disconnect inactive participant
await room.disconnect(participant_id)
del last_activity[participant_id]
await asyncio.sleep(60) # Check every minute
# Example usage
inactivity_threshold = timedelta(minutes=5)
room = ... # Assume room is initialized
asyncio.create_task(check_inactivity(room, inactivity_threshold))
This code sets up a loop that checks every minute for participants who have been inactive for more than the specified threshold and disconnects them.
Would you like further clarification or assistance with a specific part of this implementation?
Sources:
- https://livekit-users.slack.com/archives/C07FVFM5NA1/p1731495431.174829
- LiveKit documentation 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.boundless-summer-54220
02/12/2025, 9:49 PMgray-monkey-83525
02/12/2025, 9:49 PMgray-monkey-83525
02/12/2025, 9:49 PMimport asyncio
from datetime import datetime, timedelta
from livekit import rtc
from livekit.agents import AutoSubscribe, JobContext, WorkerOptions, cli, llm
from livekit.agents.voice_assistant import VoiceAssistant
from livekit.plugins import deepgram, openai, silero
# Dictionary to track last activity time for each participant
last_activity = {}
# Function to update activity
def update_activity(participant_id):
last_activity[participant_id] = datetime.now()
# Function to check for inactivity
async def check_inactivity(room, inactivity_threshold):
while True:
now = datetime.now()
for participant_id, last_active in list(last_activity.items()):
if now - last_active > inactivity_threshold:
# Disconnect inactive participant
await room.disconnect(participant_id)
del last_activity[participant_id]
await asyncio.sleep(60) # Check every minute
async def entrypoint(ctx: JobContext):
initial_ctx = llm.ChatContext().append(
role="system",
text=(
"You are a voice assistant created by LiveKit. Your interface with users will be voice. "
"You should use short and concise responses, avoiding unpronounceable punctuation."
),
)
await ctx.connect(auto_subscribe=AutoSubscribe.AUDIO_ONLY)
assistant = VoiceAssistant(
vad=silero.VAD.load(),
stt=deepgram.STT(),
llm=openai.LLM(),
tts=openai.TTS(),
chat_ctx=initial_ctx,
)
assistant.start(ctx.room)
# Listen for participant activity
@ctx.room.on("participant_connected")
def on_participant_connected(participant: rtc.RemoteParticipant):
update_activity(participant.identity)
@ctx.room.on("participant_disconnected")
def on_participant_disconnected(participant: rtc.RemoteParticipant):
if participant.identity in last_activity:
del last_activity[participant.identity]
@assistant.on("user_speech_committed")
def on_user_speech_committed(*args):
participant = args[0]
update_activity(participant.identity)
# Start inactivity check
inactivity_threshold = timedelta(minutes=5)
asyncio.create_task(check_inactivity(ctx.room, inactivity_threshold))
await assistant.say("Hey, how can I help you today?", allow_interruptions=True)
if __name__ == "__main__":
cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint))
gray-monkey-83525
02/12/2025, 9:50 PMboundless-summer-54220
02/12/2025, 9:57 PMgray-monkey-83525
02/12/2025, 9:57 PMuser_speech_committed
event provides a ChatMessage
object rather than a participant object. To correctly track participant activity, you should use the participant's identity from the context where the message is received. Here's how you can adjust the code:
1. Track Activity Using Participant Identity: Ensure you have access to the participant's identity when updating activity.
2. Correct Event Handling: Use the correct attributes from the ChatMessage
or related context to update activity.
Here's the revised code snippet:gray-monkey-83525
02/12/2025, 9:58 PMimport asyncio
from datetime import datetime, timedelta
from livekit import rtc
from livekit.agents import AutoSubscribe, JobContext, WorkerOptions, cli, llm
from livekit.agents.voice_assistant import VoiceAssistant
from livekit.plugins import deepgram, openai, silero
# Dictionary to track last activity time for each participant
last_activity = {}
# Function to update activity
def update_activity(participant_id):
last_activity[participant_id] = datetime.now()
# Function to check for inactivity
async def check_inactivity(room, inactivity_threshold):
while True:
now = datetime.now()
for participant_id, last_active in list(last_activity.items()):
if now - last_active > inactivity_threshold:
# Disconnect inactive participant
participant = room.get_participant(participant_id)
if participant:
await participant.disconnect()
del last_activity[participant_id]
await asyncio.sleep(60) # Check every minute
async def entrypoint(ctx: JobContext):
initial_ctx = llm.ChatContext().append(
role="system",
text=(
"You are a voice assistant created by LiveKit. Your interface with users will be voice. "
"You should use short and concise responses, avoiding unpronounceable punctuation."
),
)
await ctx.connect(auto_subscribe=AutoSubscribe.AUDIO_ONLY)
assistant = VoiceAssistant(
vad=silero.VAD.load(),
stt=deepgram.STT(),
llm=openai.LLM(),
tts=openai.TTS(),
chat_ctx=initial_ctx,
)
assistant.start(ctx.room)
# Listen for participant activity
@ctx.room.on("participant_connected")
def on_participant_connected(participant: rtc.RemoteParticipant):
update_activity(participant.identity)
@ctx.room.on("participant_disconnected")
def on_participant_disconnected(participant: rtc.RemoteParticipant):
if participant.identity in last_activity:
del last_activity[participant.identity]
@assistant.on("user_speech_committed")
def on_user_speech_committed(msg: llm.ChatMessage):
# Assuming msg has a participant identity attribute
participant_id = msg.participant_identity
update_activity(participant_id)
# Start inactivity check
inactivity_threshold = timedelta(minutes=5)
asyncio.create_task(check_inactivity(ctx.room, inactivity_threshold))
await assistant.say("Hey, how can I help you today?", allow_interruptions=True)
if __name__ == "__main__":
cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint))
gray-monkey-83525
02/12/2025, 9:58 PMChatMessage
object or the context in which it is used provides a way to access the participant's identity. Adjust the participant_id
extraction based on the actual attributes available in your environment.
Let me know if you need further clarification!
Sources:
- https://docs.livekit.io/components-android/livekit-compose-components/io.livekit.android.compose.flow/-data-message/participant.html
- https://docs.livekit.io/components-android/livekit-compose-components/io.livekit.android.compose.chat/-chat-message/participant.html 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.boundless-summer-54220
02/12/2025, 10:06 PMgray-monkey-83525
02/12/2025, 10:06 PMChatMessage
object does not directly provide participant identity. Instead, you can track participant activity by using the participant_connected
and participant_disconnected
events to manage a mapping of participant identities to their last activity timestamps. Here's a refined approach:
1. Track Activity on Connection: Update the last activity timestamp when a participant connects.
2. Use Speech Events: Use speech-related events to update activity timestamps, assuming you can access participant identity through the room context.
3. Inactivity Timer: Periodically check for inactivity and disconnect participants as needed.
Here's how you can implement this:gray-monkey-83525
02/12/2025, 10:07 PMimport asyncio
from datetime import datetime, timedelta
from livekit import rtc
from livekit.agents import AutoSubscribe, JobContext, WorkerOptions, cli, llm
from livekit.agents.voice_assistant import VoiceAssistant
from livekit.plugins import deepgram, openai, silero
# Dictionary to track last activity time for each participant
last_activity = {}
# Function to update activity
def update_activity(participant_id):
last_activity[participant_id] = datetime.now()
# Function to check for inactivity
async def check_inactivity(room, inactivity_threshold):
while True:
now = datetime.now()
for participant_id, last_active in list(last_activity.items()):
if now - last_active > inactivity_threshold:
# Disconnect inactive participant
participant = room.get_participant(participant_id)
if participant:
await participant.disconnect()
del last_activity[participant_id]
await asyncio.sleep(60) # Check every minute
async def entrypoint(ctx: JobContext):
initial_ctx = llm.ChatContext().append(
role="system",
text=(
"You are a voice assistant created by LiveKit. Your interface with users will be voice. "
"You should use short and concise responses, avoiding unpronounceable punctuation."
),
)
await ctx.connect(auto_subscribe=AutoSubscribe.AUDIO_ONLY)
assistant = VoiceAssistant(
vad=silero.VAD.load(),
stt=deepgram.STT(),
llm=openai.LLM(),
tts=openai.TTS(),
chat_ctx=initial_ctx,
)
assistant.start(ctx.room)
# Listen for participant activity
@ctx.room.on("participant_connected")
def on_participant_connected(participant: rtc.RemoteParticipant):
update_activity(participant.identity)
@ctx.room.on("participant_disconnected")
def on_participant_disconnected(participant: rtc.RemoteParticipant):
if participant.identity in last_activity:
del last_activity[participant.identity]
@assistant.on("user_started_speaking")
def on_user_started_speaking(participant: rtc.RemoteParticipant):
update_activity(participant.identity)
# Start inactivity check
inactivity_threshold = timedelta(minutes=5)
asyncio.create_task(check_inactivity(ctx.room, inactivity_threshold))
await assistant.say("Hey, how can I help you today?", allow_interruptions=True)
if __name__ == "__main__":
cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint))
gray-monkey-83525
02/12/2025, 10:07 PMuser_started_speaking
event to update the last activity timestamp, assuming you can access the participant identity from the event context. Adjust the event handling as needed based on your specific setup.
Let me know if you need further assistance!
Sources:
- https://docs.livekit.io/client-sdk-flutter/livekit_client/Participant/identity.html
- https://docs.livekit.io/home/concepts/api-primitives/ 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.