duol-agent / entrypoint.py
Mapmaven's picture
Upload entrypoint.py with huggingface_hub
ba77d7c verified
Raw History Blame Contribute Delete
4.38 kB
import sys
import threading
from http.server import HTTPServer, BaseHTTPRequestHandler
import time
import requests
from dotenv import load_dotenv
load_dotenv()
# ── Simple status web server (HF Spaces requires port 7860) ──────────────────
STATUS_HTML = """<!DOCTYPE html>
<html lang="sw">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Habari Jarvis &mdash; Swahili AI Agent</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: 'Segoe UI', system-ui, sans-serif;
background: linear-gradient(135deg, #0f2027, #203a43, #2c5364);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
}
.card {
background: rgba(255,255,255,0.07);
backdrop-filter: blur(16px);
border: 1px solid rgba(255,255,255,0.15);
border-radius: 24px;
padding: 48px 56px;
text-align: center;
max-width: 520px;
width: 90%;
box-shadow: 0 24px 64px rgba(0,0,0,0.4);
}
.emoji { font-size: 64px; margin-bottom: 16px; animation: pulse 2s infinite; }
@keyframes pulse { 0%,100%{transform:scale(1)} 50%{transform:scale(1.08)} }
h1 { font-size: 2rem; font-weight: 700; margin-bottom: 8px; }
.sub { color: rgba(255,255,255,0.65); margin-bottom: 28px; font-size: 1.05rem; }
.badge {
display: inline-flex; align-items: center; gap: 8px;
background: rgba(52,211,153,0.15);
border: 1px solid rgba(52,211,153,0.4);
color: #34d399;
border-radius: 999px;
padding: 8px 20px;
font-size: 0.9rem;
font-weight: 600;
margin-bottom: 28px;
}
.dot { width: 10px; height: 10px; border-radius: 50%; background: #34d399;
animation: blink 1.4s infinite; }
@keyframes blink { 0%,100%{opacity:1} 50%{opacity:0.2} }
.info { font-size: 0.85rem; color: rgba(255,255,255,0.45); line-height: 1.6; }
code { background: rgba(255,255,255,0.1); border-radius: 6px; padding: 2px 8px; }
</style>
</head>
<body>
<div class="card">
<div class="emoji">πŸ€–</div>
<h1>Habari Jarvis</h1>
<p class="sub">Msaidizi wa Akili Bandia &bull; Swahili AI Voice Agent</p>
<div class="badge"><div class="dot"></div> Agent Running</div>
<p class="info">
Connect via <code>LiveKit</code> to start a voice conversation.<br/>
The agent listens and responds entirely in <strong>Kiswahili</strong>.<br/><br/>
Powered by Groq Whisper &bull; LLaMA 3.3 70B &bull; MMS/API TTS
</p>
</div>
</body>
</html>
"""
class StatusHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "text/html; charset=utf-8")
self.end_headers()
self.wfile.write(STATUS_HTML.encode("utf-8"))
def log_message(self, *args): # silence access logs
pass
def run_status_server():
server = HTTPServer(("0.0.0.0", 7860), StatusHandler)
server.serve_forever()
# ── Auto-ping mechanism to keep HF Space awake ───────────────────────────────
def keep_awake():
# Wait for the server to start
time.sleep(10)
url = "https://huggingface.co/spaces/Mapmaven/duol-agent"
while True:
try:
requests.get(url, timeout=10)
print(f"[OK] Auto-pinged {url} to prevent sleep")
except Exception as e:
print(f"[WARN] Auto-ping failed: {e}")
time.sleep(600) # Ping every 10 minutes
# ── Start LiveKit agent worker ────────────────────────────────────────────────
from livekit.agents import WorkerOptions, cli
from agent import entrypoint
if __name__ == "__main__":
# ── Start servers in background threads ───────────────────────────────────────
t1 = threading.Thread(target=run_status_server, daemon=True)
t1.start()
t2 = threading.Thread(target=keep_awake, daemon=True)
t2.start()
print("[OK] Status server started on port 7860")
cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint, agent_name="DUOL"))