voice-agent / agent.py
abc1181's picture
Update agent.py
be45068 verified
import asyncio
import os
import httpx
from aiohttp import web
from livekit import api
from livekit.agents import Agent, AgentSession, JobContext, WorkerOptions, cli
from livekit.plugins import openai, silero, google
async def entrypoint(ctx: JobContext):
await ctx.connect()
# 1. Grab Secrets
hf_token = os.getenv("HF_TOKEN")
# 2. Setup ultra-patient timeout for Hugging Face Free Tier
custom_client = httpx.AsyncClient(timeout=httpx.Timeout(90.0))
try:
# 3. Initialize Session (REPLACE YOUR_USER AND SPACE NAMES BELOW)
session = AgentSession(
vad=silero.VAD.load(),
stt=openai.STT(
base_url="https://abc1181-livekit-stt.hf.space/v1",
api_key=hf_token,
http_client=custom_client
),
llm=google.LLM(model="gemini-2.5-flash"),
tts=openai.TTS(
base_url="https://abc1181-livekit-tts.hf.space",
api_key=hf_token,
http_client=custom_client
),
)
agent = Agent(instructions="You are Cortana. Keep your answers to one sentence.")
# 4. Start the session
await session.start(agent=agent, room=ctx.room)
# 5. The absolute proof that the TTS and Agent are working
await session.say("Systems online. I am ready.", allow_interruptions=True)
except Exception as e:
print(f"CRITICAL ERROR IN AGENT: {e}")
# 6. Generate a Token dynamically based on the room the frontend asks for
async def generate_token(request):
try:
# 1. Get Secrets with error handling
api_key = os.getenv("LIVEKIT_API_KEY")
api_secret = os.getenv("LIVEKIT_API_SECRET")
livekit_url = os.getenv("LIVEKIT_URL")
# Check if any secret is missing to avoid the 500 crash
missing = [k for k, v in {
"LIVEKIT_API_KEY": api_key,
"LIVEKIT_API_SECRET": api_secret,
"LIVEKIT_URL": livekit_url
}.items() if not v]
if missing:
return web.json_response(
{"error": f"Missing secrets: {', '.join(missing)}"},
status_code=400
)
# 2. Get params from the React Frontend
room_name = request.query.get("room", "voice_assistant_room")
identity = request.query.get("participantName", "replit_user")
# 3. Create the Token
token = api.AccessToken(api_key, api_secret) \
.with_identity(identity) \
.with_grants(api.VideoGrants(room_join=True, room=room_name)) \
.to_jwt()
# 4. Return the exact JSON format React expects
data = {
"serverUrl": livekit_url,
"participantToken": token
}
print(f"DEBUG: Successfully generated token for room {room_name}")
return web.json_response(data, headers={"Access-Control-Allow-Origin": "*"})
except Exception as e:
print(f"ERROR in generate_token: {e}")
return web.json_response({"error": str(e)}, status_code=500)
def run_worker():
app = web.Application()
app.router.add_get("/", lambda r: web.Response(text="Agent Online"))
# The React repo hits this exact path:
app.router.add_get("/api/connection-details", generate_token)
# ... (rest of your start_web and cli.run_app logic)
async def start_web():
runner = web.AppRunner(app)
await runner.setup()
await web.TCPSite(runner, "0.0.0.0", 7860).start()
loop = asyncio.get_event_loop()
loop.run_until_complete(start_web())
cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint))
if __name__ == "__main__":
run_worker()