- tools/organ.py: Pack/install/publish AI persona organs - tools/forge.sh: Convert HuggingFace models to GGUF, quantize - tools/store.sh: Browse/install/publish community models - tools/compilation/: Cross-platform build scripts (Linux/macOS) - scripts/install.sh: Universal installer (auto-detect OS/arch/GPU) - site/saas/: SaaS frontend + backend source (v3 unified design) - site/vitrine/: Main site source (inference-x.com) - docs/ARCHITECTURE.md: Full system architecture All plans now in test mode - Studio & Enterprise free to test. Branch: master | Maintainer: Anti-Atlas craton (elmadani)
136 lines
4.9 KiB
Python
136 lines
4.9 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
IX Organ Tool — Inference-X Community Toolchain
|
|
Package, publish, and install IX "organs" (AI personas)
|
|
|
|
Usage:
|
|
./organ.py pack --model model.gguf --prompt system.txt --name "ARIA" -o aria.organ
|
|
./organ.py install aria.organ
|
|
./organ.py list https://git.inference-x.com/organs
|
|
./organ.py publish aria.organ --token YOUR_GITEA_TOKEN
|
|
"""
|
|
|
|
import os, sys, json, hashlib, zipfile, argparse, urllib.request, shutil
|
|
from pathlib import Path
|
|
|
|
ORGAN_STORE_URL = "https://git.inference-x.com/api/v1/repos/elmadani/ix-organs"
|
|
IX_HOME = Path.home() / ".inference-x"
|
|
ORGANS_DIR = IX_HOME / "organs"
|
|
|
|
def pack(args):
|
|
"""Package a model + prompt + config into an .organ file"""
|
|
organ_meta = {
|
|
"version": "1.0",
|
|
"name": args.name,
|
|
"description": args.description or "",
|
|
"model_file": Path(args.model).name,
|
|
"quant": args.quant or "Q4_K_M",
|
|
"context_size": args.ctx or 4096,
|
|
"temperature": args.temp or 0.7,
|
|
"max_tokens": args.max_tokens or 512,
|
|
"tags": (args.tags or "").split(","),
|
|
"author": args.author or "anonymous",
|
|
"license": args.license or "MIT",
|
|
"created_at": __import__("datetime").datetime.utcnow().isoformat(),
|
|
}
|
|
|
|
output = args.output or f"{args.name.lower().replace(' ','-')}.organ"
|
|
|
|
with zipfile.ZipFile(output, 'w', zipfile.ZIP_DEFLATED) as zf:
|
|
# Meta
|
|
zf.writestr("organ.json", json.dumps(organ_meta, indent=2))
|
|
# Model
|
|
if args.model and Path(args.model).exists():
|
|
zf.write(args.model, f"model/{Path(args.model).name}")
|
|
# System prompt
|
|
if args.prompt and Path(args.prompt).exists():
|
|
with open(args.prompt) as f:
|
|
zf.writestr("system_prompt.txt", f.read())
|
|
elif args.prompt_text:
|
|
zf.writestr("system_prompt.txt", args.prompt_text)
|
|
|
|
size = Path(output).stat().st_size
|
|
h = hashlib.sha256(Path(output).read_bytes()).hexdigest()[:16]
|
|
print(f"✓ Organ packed: {output}")
|
|
print(f" Size: {size:,} bytes | SHA256: {h}...")
|
|
return output
|
|
|
|
def install(args):
|
|
"""Install an organ from a file or URL"""
|
|
src = args.source
|
|
ORGANS_DIR.mkdir(parents=True, exist_ok=True)
|
|
|
|
if src.startswith("http"):
|
|
print(f"Downloading {src}...")
|
|
fname, _ = urllib.request.urlretrieve(src)
|
|
else:
|
|
fname = src
|
|
|
|
with zipfile.ZipFile(fname, 'r') as zf:
|
|
meta_raw = zf.read("organ.json")
|
|
meta = json.loads(meta_raw)
|
|
name = meta["name"].lower().replace(" ", "-")
|
|
dest = ORGANS_DIR / name
|
|
dest.mkdir(exist_ok=True)
|
|
zf.extractall(dest)
|
|
|
|
print(f"✓ Organ installed: {dest}")
|
|
print(f" Name: {meta['name']}")
|
|
print(f" Model: {meta.get('model_file','?')}")
|
|
print(f" Run with: ix --organ {name}")
|
|
|
|
def list_organs(args):
|
|
"""List available organs from the store"""
|
|
url = f"{ORGAN_STORE_URL}/contents/organs"
|
|
try:
|
|
with urllib.request.urlopen(url) as r:
|
|
data = json.load(r)
|
|
print("Available organs:")
|
|
for item in data:
|
|
print(f" {item['name']} — {item['download_url']}")
|
|
except Exception as e:
|
|
print(f"Store unavailable: {e}")
|
|
# List local
|
|
if ORGANS_DIR.exists():
|
|
for d in ORGANS_DIR.iterdir():
|
|
meta_file = d / "organ.json"
|
|
if meta_file.exists():
|
|
meta = json.loads(meta_file.read_text())
|
|
print(f" LOCAL: {meta['name']} ({d.name})")
|
|
|
|
def main():
|
|
p = argparse.ArgumentParser(description="IX Organ Tool")
|
|
sub = p.add_subparsers(dest="cmd")
|
|
|
|
# pack
|
|
pk = sub.add_parser("pack", help="Pack a model into an organ")
|
|
pk.add_argument("--model", required=True, help="Path to .gguf model")
|
|
pk.add_argument("--prompt", help="Path to system prompt file")
|
|
pk.add_argument("--prompt-text", help="System prompt as text")
|
|
pk.add_argument("--name", required=True, help="Organ name")
|
|
pk.add_argument("--description", help="Description")
|
|
pk.add_argument("--quant", default="Q4_K_M")
|
|
pk.add_argument("--ctx", type=int, default=4096)
|
|
pk.add_argument("--temp", type=float, default=0.7)
|
|
pk.add_argument("--max-tokens", type=int, default=512)
|
|
pk.add_argument("--tags", help="Comma-separated tags")
|
|
pk.add_argument("--author")
|
|
pk.add_argument("--license", default="MIT")
|
|
pk.add_argument("-o", "--output", help="Output .organ file")
|
|
|
|
# install
|
|
ins = sub.add_parser("install", help="Install an organ")
|
|
ins.add_argument("source", help="Path or URL to .organ file")
|
|
|
|
# list
|
|
ls = sub.add_parser("list", help="List organs")
|
|
|
|
args = p.parse_args()
|
|
if args.cmd == "pack": pack(args)
|
|
elif args.cmd == "install": install(args)
|
|
elif args.cmd == "list": list_organs(args)
|
|
else: p.print_help()
|
|
|
|
if __name__ == "__main__":
|
|
main()
|