421 lines
16 KiB
Python
421 lines
16 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
API server for organ operations.
|
|
|
|
Endpoints:
|
|
GET /health — Server health
|
|
GET /models — List available dissected models
|
|
GET /model/:name/anatomy — Show model anatomy (skeleton/organs/etc.)
|
|
POST /extract — Extract organs from a GGUF model
|
|
POST /measure — quality measure organs
|
|
POST /graft — Graft organs between models
|
|
POST /assemble — Assemble GGUF from organs
|
|
GET /organs/:model — List organs for a model
|
|
GET /compare/:a/:b — Compare two models for graft compatibility
|
|
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
import threading
|
|
import traceback
|
|
from http.server import HTTPServer, BaseHTTPRequestHandler
|
|
from pathlib import Path
|
|
from urllib.parse import urlparse, parse_qs
|
|
|
|
# Import organ tools
|
|
from organ_extract import extract_organs, GGUFReader, classify_tensor
|
|
from organ_measure import measure_directory, measure_organ
|
|
from organ_assemble import assemble_gguf
|
|
|
|
# ═══ CONFIG ═══
|
|
PORT = int(os.environ.get('ORGAN_PORT', '7936'))
|
|
MODEL_DIR = os.environ.get('MODEL_DIR', '/mnt/models')
|
|
ORGAN_DIR = os.environ.get('ORGAN_DIR', '/mnt/data/organs')
|
|
|
|
|
|
class OrganHandler(BaseHTTPRequestHandler):
|
|
|
|
def log_message(self, format, *args):
|
|
"""Minimal logging."""
|
|
print(f"[ORGAN-API] {args[0]}")
|
|
|
|
def send_json(self, data, status=200):
|
|
self.send_response(status)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.send_header('Access-Control-Allow-Origin', '*')
|
|
self.end_headers()
|
|
self.wfile.write(json.dumps(data, indent=2, default=str).encode())
|
|
|
|
def send_error_json(self, msg, status=400):
|
|
self.send_json({'error': msg, 'signature': SIGNATURE}, status)
|
|
|
|
def read_body(self):
|
|
length = int(self.headers.get('Content-Length', 0))
|
|
if length > 0:
|
|
return json.loads(self.rfile.read(length))
|
|
return {}
|
|
|
|
def do_OPTIONS(self):
|
|
self.send_response(204)
|
|
self.send_header('Access-Control-Allow-Origin', '*')
|
|
self.send_header('Access-Control-Allow-Methods', 'GET,POST,OPTIONS')
|
|
self.send_header('Access-Control-Allow-Headers', 'Content-Type')
|
|
self.end_headers()
|
|
|
|
def do_GET(self):
|
|
path = urlparse(self.path).path.rstrip('/')
|
|
|
|
# ═══ HEALTH ═══
|
|
if path == '/health' or path == '':
|
|
self.send_json({
|
|
'status': 'ok',
|
|
'signature': SIGNATURE,
|
|
'model_dir': MODEL_DIR,
|
|
'organ_dir': ORGAN_DIR,
|
|
})
|
|
return
|
|
|
|
# ═══ LIST AVAILABLE MODELS (GGUF files) ═══
|
|
if path == '/models':
|
|
models = []
|
|
model_path = Path(MODEL_DIR)
|
|
if model_path.exists():
|
|
for f in sorted(model_path.glob('*.gguf')):
|
|
size_gb = f.stat().st_size / (1024**3)
|
|
models.append({
|
|
'name': f.stem,
|
|
'file': f.name,
|
|
'size_gb': round(size_gb, 2),
|
|
})
|
|
|
|
# Also list dissected models
|
|
dissected = []
|
|
organ_path = Path(ORGAN_DIR)
|
|
if organ_path.exists():
|
|
for d in sorted(organ_path.iterdir()):
|
|
if d.is_dir() and (d / 'manifest.json').exists():
|
|
manifest = json.load(open(d / 'manifest.json'))
|
|
dissected.append({
|
|
'name': manifest.get('model', d.name),
|
|
'architecture': manifest.get('architecture', 'unknown'),
|
|
'n_layers': manifest.get('n_layers', 0),
|
|
'n_embed': manifest.get('n_embed', 0),
|
|
'organs': len(manifest.get('organs', {})),
|
|
'graft': manifest.get('graft', None),
|
|
})
|
|
|
|
self.send_json({
|
|
'gguf_models': models,
|
|
'dissected_models': dissected,
|
|
'signature': SIGNATURE,
|
|
})
|
|
return
|
|
|
|
# ═══ MODEL ANATOMY ═══
|
|
if path.startswith('/model/') and path.endswith('/anatomy'):
|
|
model_name = path.split('/')[2]
|
|
organ_path = Path(ORGAN_DIR) / model_name
|
|
|
|
if not (organ_path / 'manifest.json').exists():
|
|
self.send_error_json(f'Model not dissected: {model_name}', 404)
|
|
return
|
|
|
|
manifest = json.load(open(organ_path / 'manifest.json'))
|
|
|
|
# Group by type
|
|
anatomy = {}
|
|
for key, entry in manifest['organs'].items():
|
|
t = entry['type']
|
|
if t not in anatomy:
|
|
anatomy[t] = {'count': 0, 'bytes': 0, 'layers': set()}
|
|
anatomy[t]['count'] += 1
|
|
anatomy[t]['bytes'] += entry.get('byte_size', 0)
|
|
if entry['layer'] >= 0:
|
|
anatomy[t]['layers'].add(entry['layer'])
|
|
|
|
# Convert sets to sorted lists
|
|
for t in anatomy:
|
|
anatomy[t]['layers'] = sorted(anatomy[t]['layers'])
|
|
anatomy[t]['size_mb'] = round(anatomy[t]['bytes'] / (1024*1024), 1)
|
|
|
|
self.send_json({
|
|
'model': manifest['model'],
|
|
'architecture': manifest['architecture'],
|
|
'n_layers': manifest['n_layers'],
|
|
'n_embed': manifest['n_embed'],
|
|
'anatomy': anatomy,
|
|
'stats': manifest.get('stats', {}),
|
|
'signature': SIGNATURE,
|
|
})
|
|
return
|
|
|
|
# ═══ LIST ORGANS FOR A MODEL ═══
|
|
if path.startswith('/organs/'):
|
|
model_name = path.split('/')[2]
|
|
organ_path = Path(ORGAN_DIR) / model_name
|
|
|
|
if not (organ_path / 'manifest.json').exists():
|
|
self.send_error_json(f'Model not dissected: {model_name}', 404)
|
|
return
|
|
|
|
manifest = json.load(open(organ_path / 'manifest.json'))
|
|
|
|
# Parse query for type filter
|
|
query = parse_qs(urlparse(self.path).query)
|
|
type_filter = query.get('type', [None])[0]
|
|
|
|
organs = []
|
|
for key, entry in manifest['organs'].items():
|
|
if type_filter and entry['type'] != type_filter:
|
|
continue
|
|
organs.append(entry)
|
|
|
|
organs.sort(key=lambda o: (o['layer'], o['name']))
|
|
|
|
self.send_json({
|
|
'model': manifest['model'],
|
|
'organs': organs,
|
|
'count': len(organs),
|
|
'signature': SIGNATURE,
|
|
})
|
|
return
|
|
|
|
# ═══ COMPARE TWO MODELS ═══
|
|
if path.startswith('/compare/'):
|
|
parts = path.split('/')
|
|
if len(parts) >= 4:
|
|
name_a = parts[2]
|
|
name_b = parts[3]
|
|
|
|
path_a = Path(ORGAN_DIR) / name_a / 'manifest.json'
|
|
path_b = Path(ORGAN_DIR) / name_b / 'manifest.json'
|
|
|
|
if not path_a.exists():
|
|
self.send_error_json(f'Model not dissected: {name_a}', 404)
|
|
return
|
|
if not path_b.exists():
|
|
self.send_error_json(f'Model not dissected: {name_b}', 404)
|
|
return
|
|
|
|
ma = json.load(open(path_a))
|
|
mb = json.load(open(path_b))
|
|
|
|
compatible = ma['n_embed'] == mb['n_embed']
|
|
|
|
self.send_json({
|
|
'model_a': {
|
|
'name': ma['model'],
|
|
'architecture': ma['architecture'],
|
|
'n_layers': ma['n_layers'],
|
|
'n_embed': ma['n_embed'],
|
|
},
|
|
'model_b': {
|
|
'name': mb['model'],
|
|
'architecture': mb['architecture'],
|
|
'n_layers': mb['n_layers'],
|
|
'n_embed': mb['n_embed'],
|
|
},
|
|
'compatible': compatible,
|
|
'graftable': compatible,
|
|
'note': 'Organs can be transplanted' if compatible else 'Dimension mismatch — projection layer needed',
|
|
'signature': SIGNATURE,
|
|
})
|
|
return
|
|
|
|
self.send_error_json('Not found', 404)
|
|
|
|
def do_POST(self):
|
|
path = urlparse(self.path).path.rstrip('/')
|
|
|
|
# ═══ EXTRACT ═══
|
|
if path == '/extract':
|
|
try:
|
|
body = self.read_body()
|
|
model = body.get('model')
|
|
|
|
if not model:
|
|
self.send_error_json('Missing "model" field')
|
|
return
|
|
|
|
# Find model file
|
|
model_path = Path(MODEL_DIR) / model
|
|
if not model_path.exists():
|
|
model_path = Path(MODEL_DIR) / f"{model}.gguf"
|
|
if not model_path.exists():
|
|
self.send_error_json(f'Model not found: {model}')
|
|
return
|
|
|
|
model_name = model_path.stem
|
|
output_dir = str(Path(ORGAN_DIR) / model_name)
|
|
|
|
# Run extraction in background
|
|
def do_extract():
|
|
try:
|
|
extract_organs(str(model_path), output_dir)
|
|
except Exception as e:
|
|
print(f"[ERROR] Extraction failed: {e}")
|
|
traceback.print_exc()
|
|
|
|
t = threading.Thread(target=do_extract, daemon=True)
|
|
t.start()
|
|
|
|
self.send_json({
|
|
'status': 'started',
|
|
'model': model_name,
|
|
'output': output_dir,
|
|
'note': 'Extraction running in background. Check /model/{name}/anatomy for results.',
|
|
'signature': SIGNATURE,
|
|
})
|
|
|
|
except Exception as e:
|
|
self.send_error_json(str(e), 500)
|
|
return
|
|
|
|
# ═══ MEASURE ═══
|
|
if path == '/measure':
|
|
try:
|
|
body = self.read_body()
|
|
model = body.get('model')
|
|
|
|
if not model:
|
|
self.send_error_json('Missing "model" field')
|
|
return
|
|
|
|
organ_path = Path(ORGAN_DIR) / model
|
|
if not organ_path.exists():
|
|
self.send_error_json(f'Model not dissected: {model}')
|
|
return
|
|
|
|
results = measure_directory(str(organ_path))
|
|
|
|
# Summary
|
|
if results:
|
|
avg_theta = sum(r['theta_deg'] for r in results) / len(results)
|
|
avg_signal = sum(r['signal_ratio'] for r in results) / len(results)
|
|
else:
|
|
avg_theta = 0
|
|
avg_signal = 0
|
|
|
|
self.send_json({
|
|
'model': model,
|
|
'organs_measured': len(results),
|
|
'avg_theta_deg': round(avg_theta, 1),
|
|
'avg_signal': round(avg_signal, 3),
|
|
'results': results[:50], # Limit response size
|
|
'signature': SIGNATURE,
|
|
})
|
|
|
|
except Exception as e:
|
|
self.send_error_json(str(e), 500)
|
|
return
|
|
|
|
# ═══ GRAFT ═══
|
|
if path == '/graft':
|
|
try:
|
|
body = self.read_body()
|
|
source = body.get('source')
|
|
target = body.get('target')
|
|
layers = body.get('layers')
|
|
organ_type = body.get('type', 'organ')
|
|
|
|
if not source or not target:
|
|
self.send_error_json('Missing "source" and/or "target" fields')
|
|
return
|
|
|
|
source_path = Path(ORGAN_DIR) / source
|
|
target_path = Path(ORGAN_DIR) / target
|
|
|
|
if not source_path.exists():
|
|
self.send_error_json(f'Source not dissected: {source}')
|
|
return
|
|
if not target_path.exists():
|
|
self.send_error_json(f'Target not dissected: {target}')
|
|
return
|
|
|
|
output_name = f"{target}+{source}_{organ_type}"
|
|
output_path = str(Path(ORGAN_DIR) / output_name)
|
|
|
|
parsed_layers = parse_layers(layers) if layers else None
|
|
|
|
str(source_path), str(target_path), output_path,
|
|
parsed_layers, organ_type
|
|
)
|
|
|
|
self.send_json({
|
|
'status': 'complete',
|
|
'result': output_name,
|
|
'grafted_count': manifest['graft']['grafted_count'],
|
|
'grafted_mb': round(manifest['graft']['grafted_bytes'] / (1024*1024), 1),
|
|
'output': output_path,
|
|
'signature': SIGNATURE,
|
|
})
|
|
|
|
except Exception as e:
|
|
self.send_error_json(str(e), 500)
|
|
return
|
|
|
|
# ═══ ASSEMBLE ═══
|
|
if path == '/assemble':
|
|
try:
|
|
body = self.read_body()
|
|
model = body.get('model')
|
|
output = body.get('output')
|
|
|
|
if not model:
|
|
self.send_error_json('Missing "model" field')
|
|
return
|
|
|
|
organ_path = Path(ORGAN_DIR) / model
|
|
if not organ_path.exists():
|
|
self.send_error_json(f'Model not found: {model}')
|
|
return
|
|
|
|
if not output:
|
|
output = str(Path(MODEL_DIR) / f"{model}_assembled.gguf")
|
|
|
|
result = assemble_gguf(str(organ_path), output)
|
|
|
|
size_gb = os.path.getsize(result) / (1024**3)
|
|
|
|
self.send_json({
|
|
'status': 'complete',
|
|
'model': model,
|
|
'output': result,
|
|
'size_gb': round(size_gb, 2),
|
|
'signature': SIGNATURE,
|
|
})
|
|
|
|
except Exception as e:
|
|
self.send_error_json(str(e), 500)
|
|
return
|
|
|
|
self.send_error_json('Not found', 404)
|
|
|
|
|
|
def main():
|
|
Path(ORGAN_DIR).mkdir(parents=True, exist_ok=True)
|
|
|
|
server = HTTPServer(('0.0.0.0', PORT), OrganHandler)
|
|
print(f"[ORGAN-API] Models: {MODEL_DIR}")
|
|
print(f"[ORGAN-API] Organs: {ORGAN_DIR}")
|
|
print(f"[ORGAN-API] Signature {SIGNATURE}")
|
|
|
|
try:
|
|
server.serve_forever()
|
|
except KeyboardInterrupt:
|
|
print("\n[ORGAN-API] Shutdown.")
|
|
server.server_close()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|
|
# ╔══ SALKA ELMADANI AUTHORSHIP CERTIFICATE ══╗
|
|
# © Salka Elmadani 2025-2026 — ALL RIGHTS RESERVED
|
|
# Licensed under Business Source License 1.1 — https://inference-x.com
|
|
# ─────────────────────────────────────────────────────────
|
|
# SHA256: 79fb97f40f2959129d5d5c4356ddf455fc354fb629bf0892c00aa6babd968a0d
|
|
# SIG-ED25519: LGqexbOlZOIjTboFfMVbgeheBbZk8HI8K6g/WxExnJEMfs5euYQYxow6SyEHKTB2TgRbOjjHt/gpHPyEy2tBBQ==
|
|
# VERIFY: python3 verify_authorship.py organ_api.py
|