ix-tools/tools/organ.py
SALKA 5b3d4e0e1d feat: Complete toolchain - organ, forge, store, compilation, installer, site source, architecture docs
- 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)
2026-02-24 20:39:52 +00:00

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()