You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
01/software/main.py

176 lines
5.7 KiB

4 weeks ago
import subprocess
import time
import os
import typer
import platform
4 weeks ago
import webbrowser
import psutil
import ngrok
import segno
4 weeks ago
import json
from pathlib import Path
5 months ago
from livekit import api
from source.server.livekit.worker import main as worker_main
from source.server.livekit.multimodal import main as multimodal_main
4 weeks ago
from dotenv import load_dotenv
4 weeks ago
load_dotenv()
system_type = platform.system()
app = typer.Typer()
ROOM_NAME = "my-room"
4 weeks ago
def pre_clean_process(port):
"""Find and kill process running on specified port"""
for proc in psutil.process_iter(['pid', 'name', 'connections']):
try:
for conn in proc.connections():
if conn.laddr.port == port:
print(f"Killing process {proc.pid} ({proc.name()}) on port {port}")
proc.terminate()
proc.wait()
return True
except (psutil.NoSuchProcess, psutil.AccessDenied):
pass
return False
def cleanup_processes(processes):
for process in processes:
if process.poll() is None: # if process is still running
process.terminate()
process.wait() # wait for process to terminate
@app.command()
def run(
lk_host: str = typer.Option(
"0.0.0.0",
"--lk-host",
4 weeks ago
help="Specify the server host where the livekit server will deploy. For other devices on your network to connect to it, keep it on default `0.0.0.0`",
),
lk_port: int = typer.Option(
10101,
"--lk-port",
4 weeks ago
help="Specify the server port where the livekit server will deploy",
),
4 weeks ago
domain: str = typer.Option(None, "--domain", help="Pass in a custom ngrok domain to expose the livekit server over the internet"),
client: str = typer.Option(None, "--client", help="Run client of a particular type. Accepts `meet` or `mobile`, defaults to `meet`"),
profiles: bool = typer.Option(
False,
"--profiles",
help="Opens the folder where profiles are contained",
),
profile: str = typer.Option(
"default.py",
"--profile",
help="Specify the path to the profile, or the name of the file if it's in the `profiles` directory (run `--profiles` to open the profiles directory)",
),
7 months ago
debug: bool = typer.Option(
False,
"--debug",
help="Print latency measurements and save microphone recordings locally for manual playback",
),
multimodal: bool = typer.Option(
False,
"--multimodal",
help="Run the multimodal agent",
4 weeks ago
)
):
# preprocess ports
ports = [10101, 8000, 3000]
for port in ports:
pre_clean_process(port)
if profiles:
if platform.system() == "Windows":
subprocess.Popen(['explorer', profiles_dir])
elif platform.system() == "Darwin":
subprocess.Popen(['open', profiles_dir])
elif platform.system() == "Linux":
subprocess.Popen(['xdg-open', profiles_dir])
else:
subprocess.Popen(['open', profiles_dir])
exit(0)
4 weeks ago
profiles_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "source", "server", "profiles")
if profile:
if not os.path.isfile(profile):
profile = os.path.join(profiles_dir, profile)
if not os.path.isfile(profile):
profile += ".py"
if not os.path.isfile(profile):
print(f"Invalid profile path: {profile}")
exit(1)
4 weeks ago
OI_CMD = f"interpreter --serve --profile {profile}"
oi_server = subprocess.Popen(OI_CMD, shell=True)
print("Interpreter server started")
4 weeks ago
print("Starting livekit server...")
if debug:
LK_CMD = f"livekit-server --dev --bind {lk_host} --port {lk_port}"
4 weeks ago
else:
LK_CMD = f"livekit-server --dev --bind {lk_host} --port {lk_port} > /dev/null 2>&1"
4 weeks ago
lk_server = subprocess.Popen(LK_CMD, shell=True)
print("Livekit server started")
time.sleep(2)
lk_url = f"http://{lk_host}:{lk_port}"
4 weeks ago
participant_token = str(api.AccessToken('devkey', 'secret') \
2 months ago
.with_identity("Participant") \
.with_name("You") \
.with_grants(api.VideoGrants(
room_join=True,
room=ROOM_NAME,))
.to_jwt())
4 weeks ago
processes = [lk_server, oi_server]
5 months ago
4 weeks ago
if client == 'mobile':
listener = ngrok.forward(f"{lk_host}:{lk_port}", authtoken_from_env=True, domain=domain)
4 weeks ago
lk_url = listener.url()
print(f"Livekit server forwarded to: {lk_url}")
5 months ago
4 weeks ago
print("Scan the QR code below with your mobile app to connect to the livekit server.")
content = json.dumps({"livekit_server": lk_url, "token": participant_token})
qr_code = segno.make(content)
qr_code.terminal(compact=True)
else: # meet client
# Get the path to the meet client directory
meet_client_path = Path(__file__).parent / "source" / "clients" / "meet"
4 weeks ago
print("Starting Next.js dev server...")
next_server = subprocess.Popen(["pnpm", "dev"], cwd=meet_client_path,)
print("Next.js dev server started")
4 weeks ago
time.sleep(2)
meet_url = f'http://localhost:3000/custom?liveKitUrl={lk_url.replace("http", "ws")}&token={participant_token}'
4 weeks ago
print(f"\nOpening meet interface at: {meet_url}")
webbrowser.open(meet_url)
4 weeks ago
processes.append(next_server)
try:
print("Starting worker...")
if multimodal:
multimodal_main(lk_url)
else:
worker_main(lk_url)
print("Worker started")
except KeyboardInterrupt:
4 weeks ago
print("\nReceived interrupt signal, shutting down...")
finally:
print("Cleaning up processes...")
cleanup_processes(processes)