Pulling models from Hugging Face
Download Hugging Face models into your PHP project from the command line or from PHP, with only the files the local runners can read.
Runners only work with models you pulled into your project first. Public models need no API key; private and gated models use the key saved by setup (see Hugging Face API key).
From the command line#
vendor/bin/loves-ai pull openai-community/gpt2 [--revision=main] [--token=hf_...] [--all] [--log-file=PATH] [--debug]
☕ Pulling openai-community/gpt2… Big downloads take a moment — perfect time for a cup of tea and some cookies 🍪
If you wish to see all logs, re-run the command with the "--debug" option.
🎉 Pulled openai-community/gpt2 into /var/www/my-app/.local/models/openai-community/gpt2
Skipped 3 files (450.0 MB) the runners cannot read: other frameworks or training leftovers.
pull downloads one model at a time into .local/models/<model id>. The puller's own output is hidden unless --debug is given.
| Option | Meaning |
|---|---|
--revision=REVISION |
Branch, tag or commit to pull (default: main) |
--token=hf_... |
Hugging Face API key for private and gated models; it is saved for next time |
--all |
Download every file in the repository, skipping nothing |
--log-file=PATH |
Append each run to this file, with a timestamp, the puller's output and the outcome |
--debug |
Show the puller's output while downloading |
Output is colored on terminals; set NO_COLOR=1 to disable colors. Exit codes: 0 success, 1 pull failed, 2 invalid usage.
Only the files the runners can read#
Hugging Face repositories often publish the same weights several times, for PyTorch, TensorFlow, Flax and ONNX. The runners read PyTorch only, so pull leaves the rest out:
| Model | Repository | Pulled |
|---|---|---|
openai/whisper-tiny | 0.61 GB | 0.16 GB |
SfinOe/stable-diffusion-v1.5 | 10.96 GB | 5.48 GB |
facebook/mms-tts-eng | 0.29 GB | 0.15 GB |
nlpconnect/vit-gpt2-image-captioning | 0.98 GB | 0.98 GB |
Skipped are weights for other frameworks (.h5, .msgpack, .onnx, .gguf, .ckpt), single-file copies of a diffusers pipeline, alternative versions such as fp16 and non_ema, training leftovers (optimizer.pt, trainer_state.json, checkpoint-*) and sample media.
A .bin file is skipped only when the same repository also publishes it as .safetensors, so models that ship .bin alone, like the last row above, are pulled untouched. Pass --all if a model ever needs a file these rules leave out.
Gated and private models#
When Hugging Face refuses a model, pull explains why and what to do:
Error: meta-llama/Llama-3.2-1B is not available: it is a gated model, which needs a Hugging Face API key.
Re-run with your key: vendor/bin/loves-ai pull meta-llama/Llama-3.2-1B --token=<your Hugging Face API key>
A gated model also needs its terms accepted on its Hugging Face page, with the account the key belongs to.
From PHP#
use PhpLovesAi\Process\ModelPuller;
$paths = (new ModelPuller())->pull(
['openai-community/gpt2', 'distilbert/distilbert-base-uncased'],
onProgress: fn (string $chunk) => fwrite(STDERR, $chunk),
// allFiles: true, // download every file, as `pull --all` does
onSkipped: fn (string $model, int $files, int $bytes) => fwrite(STDERR, "{$model}: skipped {$files} files\n"),
);
// ['openai-community/gpt2' => '/var/www/my-app/.local/models/openai-community/gpt2', ...]
To save a key from PHP, use (new PhpLovesAi\HuggingFace\Credentials())->saveApiKey('hf_...').
Errors#
Failures throw exceptions implementing PhpLovesAi\Exception\PhpLovesAiException:
ModelAccessDeniedExceptionwhen Hugging Face refuses a model, with$model,$reason(gatedornot_found) and$apiKeyUsed.PullFailedExceptionfor any other failure.
Both list the models pulled before the failure in $pulled.
Configuration#
Defaults come from config/pull.php:
| Key | Default | Overridden by |
|---|---|---|
revision | main | --revision |
log_file | null (output discarded) | --log-file |