Files
leon-ai--leon/tcp_server/src/main.py
T
2026-07-13 12:44:08 +08:00

173 lines
5.1 KiB
Python

import argparse
import ctypes
import glob
import os
import sys
import threading
from os.path import join
from dotenv import load_dotenv
DEFAULT_LEON_PROFILE = "just-me"
DEFAULT_TCP_SERVER_HOST = "127.0.0.1"
DEFAULT_TCP_SERVER_PORT = 5_367
def resolve_leon_home() -> str:
configured_leon_home = os.getenv("LEON_HOME", "").strip()
if configured_leon_home:
return os.path.abspath(configured_leon_home)
return os.path.join(os.path.expanduser("~"), ".leon")
def resolve_leon_profile() -> str:
return os.getenv("LEON_PROFILE", "").strip() or DEFAULT_LEON_PROFILE
def resolve_leon_profile_path() -> str:
configured_profile_path = os.getenv("LEON_PROFILE_PATH", "").strip()
if configured_profile_path:
return os.path.abspath(configured_profile_path)
return os.path.join(resolve_leon_home(), "profiles", resolve_leon_profile())
def _resolve_torch_root(pytorch_path: str) -> str | None:
normalized_path = os.path.abspath(pytorch_path)
if os.path.basename(normalized_path) == "torch" and os.path.isfile(
os.path.join(normalized_path, "__init__.py")
):
return normalized_path
torch_candidate = os.path.join(normalized_path, "torch")
if os.path.isfile(os.path.join(torch_candidate, "__init__.py")):
return torch_candidate
torch_nested_candidate = os.path.join(normalized_path, "torch", "torch")
if os.path.isfile(os.path.join(torch_nested_candidate, "__init__.py")):
return torch_nested_candidate
return None
def _add_pytorch_path(pytorch_path: str | None) -> str | None:
if not pytorch_path:
return None
torch_root = _resolve_torch_root(pytorch_path)
if torch_root:
sys.path.insert(0, os.path.dirname(torch_root))
return torch_root
sys.path.insert(0, os.path.abspath(pytorch_path))
return None
def _set_library_paths(paths: list[str]) -> None:
if not paths:
return
existing_path = ""
if sys.platform.startswith("win"):
add_dll_directory = getattr(os, "add_dll_directory", None)
for path in paths:
if os.path.isdir(path) and add_dll_directory:
add_dll_directory(path)
existing_path = os.environ.get("PATH", "")
os.environ["PATH"] = (
os.pathsep.join([*paths, existing_path])
if existing_path
else os.pathsep.join(paths)
)
return
if sys.platform == "darwin":
existing_path = os.environ.get("DYLD_LIBRARY_PATH", "")
os.environ["DYLD_LIBRARY_PATH"] = (
os.pathsep.join([*paths, existing_path])
if existing_path
else os.pathsep.join(paths)
)
return
existing_path = os.environ.get("LD_LIBRARY_PATH", "")
os.environ["LD_LIBRARY_PATH"] = (
os.pathsep.join([*paths, existing_path])
if existing_path
else os.pathsep.join(paths)
)
def _configure_external_libraries(
pytorch_path: str | None, nvidia_path: str | None
) -> None:
lib_paths = []
torch_root = _add_pytorch_path(pytorch_path)
if torch_root:
torch_lib_path = os.path.join(torch_root, "lib")
if os.path.isdir(torch_lib_path):
lib_paths.append(torch_lib_path)
if nvidia_path:
nvidia_root = os.path.abspath(nvidia_path)
nvjitlink_pattern = os.path.join(
nvidia_root, "nvjitlink", "lib", "libnvJitLink.so.*"
)
for library in [
"cublas",
"cudnn",
"cusparse",
"cusparse_full",
"nccl",
"nvshmem",
"nvjitlink",
]:
candidate = os.path.join(nvidia_root, library, "lib")
if os.path.isdir(candidate):
lib_paths.append(candidate)
if sys.platform.startswith("linux"):
nvjitlink_candidates = sorted(glob.glob(nvjitlink_pattern), reverse=True)
if nvjitlink_candidates:
ctypes.CDLL(nvjitlink_candidates[0], mode=ctypes.RTLD_GLOBAL)
_set_library_paths(lib_paths)
def _parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Leon TCP server")
parser.add_argument(
"lang", nargs="?", default="en", help="Language code (e.g. en, fr)"
)
parser.add_argument("--pytorch-path", dest="pytorch_path", type=str, default=None)
parser.add_argument("--nvidia-path", dest="nvidia_path", type=str, default=None)
return parser.parse_args()
args = _parse_args()
os.environ["LEON_PY_TCP_SERVER_LANG"] = args.lang
_configure_external_libraries(args.pytorch_path, args.nvidia_path)
dotenv_path = join(resolve_leon_profile_path(), ".env")
load_dotenv(dotenv_path)
from lib.tcp_server import TCPServer
tcp_server_host = os.environ.get("LEON_PY_TCP_SERVER_HOST", DEFAULT_TCP_SERVER_HOST)
tcp_server_port = os.environ.get("LEON_PY_TCP_SERVER_PORT", DEFAULT_TCP_SERVER_PORT)
tcp_server = TCPServer(tcp_server_host, tcp_server_port)
# Use thread as ASR starts recording audio and it blocks the main thread
asr_thread = threading.Thread(target=tcp_server.init_asr)
asr_thread.start()
tcp_server.init_tts()
tcp_server_thread = threading.Thread(target=tcp_server.init)
tcp_server_thread.start()