120 lines
4.3 KiB
Python
120 lines
4.3 KiB
Python
import json
|
|
import re
|
|
from dataclasses import dataclass, asdict
|
|
from pathlib import Path
|
|
from typing import List, Optional
|
|
|
|
APP_HEADER_RE = re.compile(r"^### App: (?P<name>.+?)\s*$")
|
|
IMAGE_RE = re.compile(r"image=(?P<image>[^\s]+)")
|
|
PORT_MAP_RE = re.compile(r"- tcp (?P<container>\d+) -> (?P<host>\d+|0\.0\.0\.0:(?P<host_ip_port>\d+))")
|
|
PORT_LINE_RE = re.compile(r"- tcp (?P<container>\d+) -> (?P<host_ip>[^:]+):(?P<host>\d+)")
|
|
VOLUME_RE = re.compile(r"- (?P<host>/[^\s]+) -> (?P<container>/[^\s]+)")
|
|
NETWORK_RE = re.compile(r"- (?P<name>ix-[^\s]+)_default")
|
|
SUBNET_RE = re.compile(r"subnets=\[(?P<subnets>[^\]]+)\]")
|
|
MODELS_RE = re.compile(r"Models in /models: (?P<models>.+)$")
|
|
PORTAL_RE = re.compile(r"Portals: \{\'Web UI\': \'(?P<url>[^\']+)\'\}")
|
|
GPU_RE = re.compile(r"GPUs:\s*(?P<count>\d+)x\s*(?P<name>.+)$")
|
|
CONTAINER_NAME_RE = re.compile(r"^(?P<name>ix-llamacpp-[^\s]+)")
|
|
|
|
@dataclass
|
|
class LlamacppConfig:
|
|
image: Optional[str] = None
|
|
container_name: Optional[str] = None
|
|
host_port: Optional[int] = None
|
|
container_port: Optional[int] = None
|
|
web_ui_url: Optional[str] = None
|
|
model_host_path: Optional[str] = None
|
|
model_container_path: Optional[str] = None
|
|
models: List[str] = None
|
|
network: Optional[str] = None
|
|
subnets: List[str] = None
|
|
gpu_count: Optional[int] = None
|
|
gpu_name: Optional[str] = None
|
|
|
|
|
|
def _find_section(lines: List[str], app_name: str) -> List[str]:
|
|
start = None
|
|
for i, line in enumerate(lines):
|
|
m = APP_HEADER_RE.match(line.strip())
|
|
if m and m.group("name") == app_name:
|
|
start = i
|
|
break
|
|
if start is None:
|
|
return []
|
|
for j in range(start + 1, len(lines)):
|
|
if APP_HEADER_RE.match(lines[j].strip()):
|
|
return lines[start:j]
|
|
return lines[start:]
|
|
|
|
|
|
def parse_agents(path: Path) -> LlamacppConfig:
|
|
text = path.read_text(encoding="utf-8", errors="ignore")
|
|
lines = text.splitlines()
|
|
section = _find_section(lines, "llamacpp")
|
|
cfg = LlamacppConfig(models=[], subnets=[])
|
|
|
|
for line in section:
|
|
if cfg.image is None:
|
|
m = IMAGE_RE.search(line)
|
|
if m:
|
|
cfg.image = m.group("image")
|
|
if cfg.web_ui_url is None:
|
|
m = PORTAL_RE.search(line)
|
|
if m:
|
|
cfg.web_ui_url = m.group("url")
|
|
if cfg.container_port is None or cfg.host_port is None:
|
|
m = PORT_LINE_RE.search(line)
|
|
if m:
|
|
cfg.container_port = int(m.group("container"))
|
|
cfg.host_port = int(m.group("host"))
|
|
if cfg.model_host_path is None or cfg.model_container_path is None:
|
|
m = VOLUME_RE.search(line)
|
|
if m and "/models" in m.group("container"):
|
|
cfg.model_host_path = m.group("host")
|
|
cfg.model_container_path = m.group("container")
|
|
if cfg.network is None:
|
|
m = NETWORK_RE.search(line)
|
|
if m:
|
|
cfg.network = f"{m.group('name')}_default"
|
|
if "subnets=" in line:
|
|
m = SUBNET_RE.search(line)
|
|
if m:
|
|
subnets_raw = m.group("subnets")
|
|
subnets = [s.strip().strip("'") for s in subnets_raw.split(",")]
|
|
cfg.subnets.extend([s for s in subnets if s])
|
|
if "Models in /models:" in line:
|
|
m = MODELS_RE.search(line)
|
|
if m:
|
|
models_raw = m.group("models")
|
|
cfg.models = [s.strip() for s in models_raw.split(",") if s.strip()]
|
|
|
|
for line in lines:
|
|
if cfg.gpu_count is None:
|
|
m = GPU_RE.search(line)
|
|
if m:
|
|
cfg.gpu_count = int(m.group("count"))
|
|
cfg.gpu_name = m.group("name").strip()
|
|
if cfg.container_name is None:
|
|
m = CONTAINER_NAME_RE.match(line.strip())
|
|
if m:
|
|
cfg.container_name = m.group("name")
|
|
|
|
return cfg
|
|
|
|
|
|
def main() -> None:
|
|
import argparse
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--agents", default="AGENTS.md")
|
|
parser.add_argument("--out", default="app/agents_config.json")
|
|
args = parser.parse_args()
|
|
|
|
cfg = parse_agents(Path(args.agents))
|
|
out_path = Path(args.out)
|
|
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
out_path.write_text(json.dumps(asdict(cfg), indent=2), encoding="utf-8")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|