Instructions to use Ex0bit/jit-lora with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use Ex0bit/jit-lora with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] huggingface-cli download --local-dir jit-lora Ex0bit/jit-lora
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
| """ | |
| export_to_lms.py — Export LoRA adapter back to LM Studio. | |
| Workflow: | |
| 1. Fuse LoRA adapter with base model via MLX | |
| 2. Export to GGUF format | |
| 3. Copy to LM Studio models directory | |
| 4. Load via lms CLI | |
| """ | |
| import json | |
| import logging | |
| import shutil | |
| import subprocess | |
| import time | |
| from pathlib import Path | |
| from typing import Optional | |
| log = logging.getLogger("export_to_lms") | |
| def export_adapter_to_lms(config, version: Optional[int] = None) -> dict: | |
| """Export current LoRA adapter as GGUF to LM Studio. | |
| Args: | |
| config: NeuralConfig instance | |
| version: adapter version tag (auto if None) | |
| Returns: | |
| dict with export details | |
| """ | |
| try: | |
| import mlx_lm | |
| except ImportError: | |
| raise RuntimeError("mlx-lm required for export") | |
| config.resolve_paths() | |
| if version is None: | |
| version = int(time.time()) % 100000 | |
| model_dir = str(Path(config.model_path).parent) | |
| adapter_dir = config.adapter_dir | |
| export_name = f"{config.model_key}-tuned-v{version}" | |
| export_dir = Path(config.base_dir) / "exports" / export_name | |
| export_dir.mkdir(parents=True, exist_ok=True) | |
| log.info(f"Exporting adapter: {adapter_dir} + {model_dir} → {export_dir}") | |
| # Step 1: Fuse adapter with base model | |
| # mlx_lm.fuse writes merged weights to output dir | |
| try: | |
| mlx_lm.fuse( | |
| model=model_dir, | |
| adapter_path=adapter_dir, | |
| save_path=str(export_dir / "merged"), | |
| ) | |
| log.info("LoRA adapter fused with base model") | |
| except Exception as e: | |
| log.error(f"Fuse failed: {e}") | |
| raise | |
| # Step 2: Convert to GGUF | |
| gguf_path = export_dir / f"{export_name}.gguf" | |
| try: | |
| # Use mlx_lm convert if available | |
| result = subprocess.run( | |
| ["python3", "-m", "mlx_lm.convert", | |
| "--model", str(export_dir / "merged"), | |
| "--quantize", "--q-bits", "4", | |
| "-o", str(gguf_path)], | |
| capture_output=True, text=True, timeout=600) | |
| if result.returncode != 0: | |
| log.warning(f"GGUF convert failed: {result.stderr}") | |
| # Fallback: just copy the merged model | |
| gguf_path = export_dir / "merged" | |
| except Exception as e: | |
| log.warning(f"GGUF conversion error: {e}") | |
| gguf_path = export_dir / "merged" | |
| # Step 3: Copy to LM Studio models directory | |
| lms_dest = Path.home() / ".lmstudio" / "models" / "jarvis-tuned" / export_name | |
| try: | |
| lms_dest.mkdir(parents=True, exist_ok=True) | |
| if gguf_path.is_file(): | |
| shutil.copy2(str(gguf_path), str(lms_dest)) | |
| else: | |
| # Copy directory | |
| shutil.copytree(str(gguf_path), str(lms_dest), dirs_exist_ok=True) | |
| log.info(f"Copied to LM Studio: {lms_dest}") | |
| except Exception as e: | |
| log.warning(f"Copy to LM Studio failed: {e}") | |
| # Step 4: Load via lms CLI | |
| lms = config.lms_cli_path | |
| if lms: | |
| try: | |
| subprocess.run( | |
| [lms, "load", str(lms_dest)], | |
| capture_output=True, timeout=120) | |
| log.info(f"Loaded {export_name} in LM Studio") | |
| except Exception as e: | |
| log.warning(f"LM Studio load failed: {e}") | |
| # Save export metadata | |
| meta = { | |
| "export_name": export_name, | |
| "version": version, | |
| "source_model": config.model_key, | |
| "adapter_dir": adapter_dir, | |
| "gguf_path": str(gguf_path), | |
| "lms_path": str(lms_dest), | |
| "timestamp": time.time(), | |
| } | |
| with open(export_dir / "export_meta.json", "w") as f: | |
| json.dump(meta, f, indent=2) | |
| return meta | |