forked from livekit-examples/voice-pipeline-agent-python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathagent.py
148 lines (122 loc) · 4.82 KB
/
agent.py
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import logging
import os
import time
from dotenv import load_dotenv
from livekit.agents import (
AutoSubscribe,
JobContext,
JobProcess,
WorkerOptions,
cli,
llm,
)
from livekit.agents.pipeline import VoicePipelineAgent
from livekit.plugins import openai, silero, cartesia
from dify_llm import DifyLLM
from threading import Thread
# 加载 .env.local 文件
def load_env():
load_dotenv('.env.local')
logging.info("环境变量已加载/更新")
load_env()
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logging.getLogger("openai").setLevel(logging.WARNING)
logging.getLogger("openai._base_client").setLevel(logging.WARNING)
logger = logging.getLogger("voice-agent")
def watch_env_file(file_path: str, interval: int = 5):
"""
监控 .env.local 文件是否更新,并在更新时重新加载环境变量
"""
last_modified_time = os.path.getmtime(file_path)
while True:
try:
current_modified_time = os.path.getmtime(file_path)
if current_modified_time != last_modified_time:
load_env()
last_modified_time = current_modified_time
logger.info(".env.local 文件已更新,重新加载环境变量")
except Exception as e:
logger.error(f"监控 .env.local 文件时出错: {e}")
time.sleep(interval)
# 启动文件监控线程
Thread(target=watch_env_file, args=('.env.local',), daemon=True).start()
def prewarm(proc: JobProcess):
proc.userdata["vad"] = silero.VAD.load()
def setup_agent_events(agent: VoicePipelineAgent):
@agent.on("speech_started")
def on_speech_started():
print("\n用户开始说话...")
@agent.on("speech_ended")
def on_speech_ended():
print("用户停止说话")
@agent.on("transcribing")
def on_transcribing(partial):
print(f"\r正在识别: {partial}", end='', flush=True)
@agent.on("thinking")
def on_thinking():
print("\n正在思考...")
@agent.on("speaking")
def on_speaking():
print("\n正在回答...")
@agent.on("error")
def on_error(error):
print(f"\n错误: {error}")
async def entrypoint(ctx: JobContext):
logger.info(f"正在连接房间: {ctx.room.name}")
await ctx.connect(auto_subscribe=AutoSubscribe.AUDIO_ONLY)
participant = await ctx.wait_for_participant()
logger.info(f"为参与者 {participant.identity} 启动语音助手")
agent = VoicePipelineAgent(
vad=ctx.proc.userdata["vad"],
stt=openai.STT(language="zh"),
tts=cartesia.TTS(
model="sonic",
language="zh",
speed=os.getenv("CARTESIA_SPEED", "normal"),
emotion=os.getenv("CARTESIA_EMOTION", "anger:high,positivity:high").split(","),
voice=os.getenv("CARTESIA_VOICE_ID", "bafcab8d-d391-44fe-9711-e5c94e899f43"),
api_key=os.environ["CARTESIA_API_KEY"]
),
llm=DifyLLM(
api_key=os.getenv('DIFY_API_KEY'),
api_url=os.getenv('DIFY_BASE_URL')
),
)
# 设置事件监听器
setup_agent_events(agent)
agent.start(ctx.room, participant)
logger.info("语音助手启动成功")
try:
# 根据 AGENT_NAME 选择不同的问候语
greeting = {
"lawyer": "你好!我是张雨婷,很高兴为你解答法律相关的问题!",
"stewardess": "我是你的空姐朱莉娅。请问有什么我可以帮到你的吗?",
"xiaomei": "你好呀!我是小梅,很高兴能和你聊天。今天想聊些什么呢?😊",
"xiaonana": "亲爱的,人家是小娜娜哦~ 终于等到你了呢 💕 要不要和人家聊会天呀?🥰",
"psychologist": """你好!我是林心怡,一位AI心理咨询师,经过心理学教科书训练的人工智能。
请注意:
- 我的建议仅供参考,不应被理解为专业诊断
- 如遇严重心理问题,请务必寻求专业心理医生或心理治疗师的帮助
很高兴能倾听和交流,请问有什么想和我分享的吗?"""
}.get(os.getenv('AGENT_NAME', 'default_agent'))
if greeting:
await agent.say(greeting, allow_interruptions=True)
logger.info("发送初始问候")
else:
logger.warning(f"未知的 AGENT_NAME: {os.getenv('AGENT_NAME')}")
except Exception as e:
logger.error(f"初始问候发送失败: {e}")
if __name__ == "__main__":
agent_name = os.getenv('AGENT_NAME', 'default_agent')
logger.info(f"启动Agent: {agent_name}")
cli.run_app(
WorkerOptions(
entrypoint_fnc=entrypoint,
agent_name=agent_name,
prewarm_fnc=prewarm,
),
)