-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathagent.py
More file actions
92 lines (76 loc) · 3.75 KB
/
agent.py
File metadata and controls
92 lines (76 loc) · 3.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
from dotenv import load_dotenv
import json
from livekit import api
from livekit import agents, rtc
from livekit.agents import AgentServer,AgentSession, Agent, room_io
from livekit.plugins import noise_cancellation, silero
from livekit.plugins.turn_detector.multilingual import MultilingualModel
load_dotenv(".env.local")
class Assistant(Agent):
def __init__(self) -> None:
super().__init__(
instructions="""You are a helpful voice AI assistant.
You eagerly assist users with their questions by providing information from your extensive knowledge.
Your responses are concise, to the point, and without any complex formatting or punctuation including emojis, asterisks, or other symbols.
You are curious, friendly, and have a sense of humor.""",
)
server = AgentServer()
@server.rtc_session(agent_name="hechen-bot2")
async def my_agent(ctx: agents.JobContext):
# If a phone number was provided in job metadata, place an outbound call.
# In console mode (or when metadata is empty), skip and run as a normal voice session.
phone_number = None
metadata = getattr(ctx.job, "metadata", None) or ""
if metadata.strip():
dial_info = json.loads(metadata)
phone_number = dial_info["phone_number"]
# The participant's identity can be anything you want, but this example uses the phone number itself
sip_participant_identity = phone_number
if phone_number is not None:
# The outbound call will be placed after this method is executed
try:
await ctx.api.sip.create_sip_participant(api.CreateSIPParticipantRequest(
# This ensures the participant joins the correct room
room_name=ctx.room.name,
# This is the outbound trunk ID to use (i.e. which phone number the call will come from)
# You can get this from LiveKit CLI with `lk sip outbound list`
sip_trunk_id='ST_wJ7K3e964ow5',
# The outbound phone number to dial and identity to use
sip_call_to=phone_number,
participant_identity=sip_participant_identity,
# Headers sent on the INVITE (e.g. for VoIPmonitor RTP capture)
headers={"X-LIVEKIT-STORE-RTP": "1"},
# This will wait until the call is answered before returning
wait_until_answered=True,
))
print("call picked up successfully")
except api.TwirpError as e:
print(f"error creating SIP participant: {e.message}, "
f"SIP status: {e.metadata.get('sip_status_code')} "
f"{e.metadata.get('sip_status')}")
ctx.shutdown()
session = AgentSession(
stt="deepgram/nova-3:multi",
llm="openai/gpt-4.1-mini",
tts="cartesia/sonic-3:9626c31c-bec5-4cca-baa8-f8ba9e84c8bc",
vad=silero.VAD.load(),
turn_detection=MultilingualModel(),
)
await session.start(
room=ctx.room,
agent=Assistant(),
room_options=room_io.RoomOptions(
audio_input=room_io.AudioInputOptions(
noise_cancellation=lambda params: noise_cancellation.BVCTelephony() if params.participant.kind == rtc.ParticipantKind.PARTICIPANT_KIND_SIP else noise_cancellation.BVC(),
),
),
)
# Add this guard to ensure the agent only speaks first in an inbound scenario.
# When placing an outbound call, its more customary for the recipient to speak first
# The agent will automatically respond after the user's turn has ended.
if phone_number is None:
await session.generate_reply(
instructions="Greet the user and offer your assistance."
)
if __name__ == "__main__":
agents.cli.run_app(server)