LlamaCppEx.Hub (LlamaCppEx v0.8.41)

Copy Markdown View Source

Download GGUF models from HuggingFace Hub.

Requires the optional req dependency. Add it to your mix.exs:

{:req, "~> 0.5"}

Examples

# Search for GGUF models
{:ok, results} = LlamaCppEx.Hub.search("qwen3 gguf", limit: 5)

# List GGUF files in a repository
{:ok, files} = LlamaCppEx.Hub.list_gguf_files("Qwen/Qwen3-4B-GGUF")

# Download a model (cached locally)
{:ok, path} = LlamaCppEx.Hub.download(
  "Qwen/Qwen3-4B-GGUF",
  "qwen3-4b-q4_k_m.gguf"
)

Authentication

For private or gated repositories, set the HF_TOKEN environment variable or pass the :token option:

LlamaCppEx.Hub.download("org/private-model", "model.gguf", token: "hf_...")

Caching

Downloaded files are cached in ~/.cache/llama_cpp_ex/models/ by default. Override with the :cache_dir option or LLAMA_CACHE_DIR environment variable. The cache directory is created with mode 0o700 and cached files with 0o600 — gated-repository content is credential-adjacent.

A cached file is returned as-is: download/3 makes no request to the Hub when the file is already present. The upstream ETag is recorded in a <file>.etag sidecar, but nothing reads it back yet, so a file that changed upstream is not detected — pass force: true to refresh it.

Integrity

A fresh download is verified against the SHA-256 that HuggingFace publishes for the file, and a file whose digest does not match is deleted rather than cached. See download/3 for the limits of that guarantee.

Offline Mode

Set LLAMA_OFFLINE=1 to use only cached files without network access.

Proxies

Requests honor the standard proxy environment variables automatically: HTTPS_PROXY/HTTP_PROXY (and their lowercase forms), falling back to ALL_PROXY, with NO_PROXY respected for host bypass. Because HuggingFace is served over HTTPS, the HTTPS_PROXY value is the one that applies; an HTTP proxy tunnels HTTPS via the CONNECT method.

# honored automatically
export HTTPS_PROXY=http://127.0.0.1:8118

Override or disable proxying per call with the :proxy (a URL string, a Mint {scheme, address, port, opts} tuple, or false) and :no_proxy options:

LlamaCppEx.Hub.search("qwen3 gguf", proxy: "http://user:pass@127.0.0.1:8118")
LlamaCppEx.Hub.download("org/model", "model.gguf", proxy: false)

SOCKS is not supported

The underlying HTTP client (Req → Finch → Mint) supports HTTP/1 proxies only — plain forwarding and HTTPS-over-CONNECT tunneling. It has no SOCKS support, so a socks5:// value (e.g. from ALL_PROXY) is ignored with a warning. To use a SOCKS upstream, run a local HTTP-to-SOCKS bridge such as Privoxy or gost and point HTTPS_PROXY at the bridge's HTTP port.

Summary

Functions

Build authentication headers from options or environment.

Build the download URL for a file in a HuggingFace repository.

Build the local cache path for a model file.

Download a GGUF file from HuggingFace Hub, returning the local path.

Filter a list of HuggingFace siblings entries to only GGUF files.

Get model repository metadata from HuggingFace Hub API.

List GGUF files available in a HuggingFace repository.

Search HuggingFace Hub for GGUF models.

Functions

auth_headers(opts)

@spec auth_headers(keyword()) :: [{String.t(), String.t()}]

Build authentication headers from options or environment.

Checks for tokens in order: :token option, HF_TOKEN env var, HUGGING_FACE_HUB_TOKEN env var (legacy).

build_download_url(repo_id, filename, opts \\ [])

@spec build_download_url(String.t(), String.t(), keyword()) :: String.t()

Build the download URL for a file in a HuggingFace repository.

cache_path(repo_id, filename, opts \\ [])

@spec cache_path(String.t(), String.t(), keyword()) :: String.t()

Build the local cache path for a model file.

The path is <cache_dir>/<repo_id>/<revision>/<filename>. revision is part of the key because otherwise pinning revision: "<sha>" returned whatever had been cached for main — the pin bought nothing, silently. It defaults to "main".

All three components are caller-supplied and become path components, so each is validated first: one that is absolute, empty, ".", "..", ~-prefixed, or contains a null byte would escape the cache and is rejected with an ArgumentError. download/3 performs the same validation but surfaces it as {:error, reason}.

download(repo_id, filename, opts \\ [])

@spec download(String.t(), String.t(), keyword()) ::
  {:ok, String.t()} | {:error, String.t()}

Download a GGUF file from HuggingFace Hub, returning the local path.

An already-cached file is returned immediately, without contacting the Hub. There is no upstream revalidation — the ETag written to the <file>.etag sidecar is never read back — so pass force: true to refresh a cached file. The cache key includes :revision, so two revisions of the same file cache separately.

A fresh download is streamed into a randomly named temporary file opened with O_EXCL, verified against the SHA-256 HuggingFace publishes for the file, and only then renamed into place with mode 0o600. A missing published digest is a failure, not a warning — see :verify_checksum.

Integrity is not authenticity

The digest comes from the same origin as the bytes, so it detects corruption or tampering between HuggingFace and you — not a malicious file published by the repository owner. GGUF parsing happens in C++, so for repositories you do not trust, also pass check_tensors: true to LlamaCppEx.Model.load/2.

Options

  • :cache_dir - Local cache directory. Defaults to ~/.cache/llama_cpp_ex/models/ or the LLAMA_CACHE_DIR environment variable.
  • :token - HuggingFace API token. Defaults to HF_TOKEN environment variable.
  • :revision - Git revision (branch, tag, or commit). Defaults to "main". Part of the cache key.
  • :force - Force re-download even if cached. Defaults to false.
  • :verify_checksum - Integrity policy. Defaults to true.
    • true — fail closed. The download is checked against the SHA-256 HuggingFace publishes, and a file the Hub lists without one is refused. Verification used to be downgradable by the metadata response itself: it fell back to a warning when siblings[].lfs.sha256 was absent, so stripping one JSON key was enough to have the bytes cached unverified.
    • :best_effort — warn and proceed when the Hub publishes no digest. For the rare non-LFS blob that is genuinely small enough to have none.
    • false — skip the check and the metadata request entirely. Logged as a warning.
  • :proxy, :no_proxy - Proxy overrides. See the "Proxies" section above.

filter_gguf_files(siblings)

@spec filter_gguf_files([map()]) :: [%{filename: String.t(), size: integer()}]

Filter a list of HuggingFace siblings entries to only GGUF files.

Returns maps with :filename and :size.

get_model_info(repo_id, opts \\ [])

@spec get_model_info(
  String.t(),
  keyword()
) :: {:ok, map()} | {:error, String.t()}

Get model repository metadata from HuggingFace Hub API.

Options

  • :token - HuggingFace API token.

list_gguf_files(repo_id, opts \\ [])

@spec list_gguf_files(
  String.t(),
  keyword()
) :: {:ok, [%{filename: String.t(), size: integer()}]} | {:error, String.t()}

List GGUF files available in a HuggingFace repository.

Returns a list of maps with :filename and :size (bytes).

Options

  • :token - HuggingFace API token.

Examples

{:ok, files} = LlamaCppEx.Hub.list_gguf_files("Qwen/Qwen3-4B-GGUF")
Enum.each(files, fn f ->
  size_mb = Float.round(f.size / 1_000_000, 1)
  IO.puts("#{f.filename} (#{size_mb} MB)")
end)

search(query, opts \\ [])

@spec search(
  String.t(),
  keyword()
) :: {:ok, [map()]} | {:error, String.t()}

Search HuggingFace Hub for GGUF models.

Returns a list of model info maps with :id, :downloads, :likes, :last_modified, and :tags.

Options

  • :limit - Maximum results. Defaults to 10.
  • :sort - Sort by "downloads", "likes", or "lastModified". Defaults to "downloads".
  • :direction - Sort direction, -1 for descending. Defaults to -1.
  • :token - HuggingFace API token.
  • :proxy, :no_proxy - Proxy overrides. See the "Proxies" section above.

Examples

{:ok, models} = LlamaCppEx.Hub.search("llama gguf q4")
Enum.each(models, fn m -> IO.puts("#{m.id} (#{m.downloads} downloads)") end)