Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ai Hugging Face Platform Laravel Package

symfony/ai-hugging-face-platform

The Symfony AI HuggingFace bridge integrates the HuggingFace Inference API, giving access to thousands of models across multiple providers. It supports 40+ AI tasks like chat, vision, audio, and embeddings, with model discovery and type-safe results.

View on GitHub
Deep Wiki
Context7

Getting Started

Know what you're wiring up first. This is a Symfony AI bridge, not a Laravel package. There is no config/ai.php to publish, no facade, and no auto-discovery. It gives you Factory::createPlatform() plus Task/Provider constants, and you own the Laravel-side plumbing. Budget 15 minutes of setup, not 2.

Install:

composer require symfony/ai-hugging-face-platform symfony/http-client

You need symfony/http-client because Factory::createPlatform() expects a Symfony\Contracts\HttpClient\HttpClientInterface — Laravel's Http facade is not compatible. The Symfony client coexists fine inside a Laravel app.

Config (keep env() out of your app code, Laravel-style):

// config/services.php
'huggingface' => [
    'key'      => env('HF_TOKEN'),
    'provider' => env('HF_PROVIDER', 'hf-inference'),
    'timeout'  => env('HF_TIMEOUT', 30),
],

Bind the platform as a singleton so you don't rebuild the client per request:

// app/Providers/AiServiceProvider.php
public function register(): void
{
    $this->app->singleton(PlatformInterface::class, function ($app) {
        $cfg = config('services.huggingface');

        return Factory::createPlatform(
            apiKey: $cfg['key'],
            provider: $cfg['provider'],
            httpClient: new HttpClient(['timeout' => $cfg['timeout']]),
        );
    });
}

Wrap it behind your own tiny interface (App\Ai\Embedder, App\Ai\ChatClient) rather than injecting the raw platform into controllers — you'll want to fake it in tests, and you'll want one place to enforce timeouts, caching, and logging.

Where to look first: the Task.php and Provider.php interfaces in the package (they're the actual API surface — the README only lists examples), then the HuggingFace Tasks reference linked in the README.

First use case: embeddings, not chat. It's the lowest-risk, highest-ROI entry point and doesn't depend on prompt quality:

$result = $platform->invoke('sentence-transformers/all-MiniLM-L6-v2', 'Hello world', [
    'task' => Task::FEATURE_EXTRACTION,
]);

$vectors = $result->asVectors();

Prove that out, store the vectors, then move to chat completion once you trust the auth and quota story.

Implementation Patterns

Chat: build the MessageBag in an app-level service, not the controller.

$messages = new MessageBag(Message::ofUser($prompt));

$result = $platform->invoke('HuggingFaceH4/zephyr-7b-beta', $messages, [
    'task'          => Task::CHAT_COMPLETION,
    'temperature'   => 0.7,
    'max_new_tokens'=> 256,
]);

return $result->asText();

Keep the model id in config/services.php, not inline — you will swap it after model discovery.

Per-request provider routing is the killer feature for day-to-day cost/latency control. Set a sane default in config, override at the call site:

$result = $platform->invoke($model, $messages, [
    'task'     => Task::CHAT_COMPLETION,
    'provider' => Provider::GROQ,   // fast path for interactive UI
]);

Pattern that works well: interactive/request-cycle calls → Groq; batch/queued jobs → HuggingFace inference (cheaper, cold starts don't matter); niche tasks (audio, segmentation) → whatever provider actually hosts the model. Put that mapping in a config array keyed by task, and resolve it in your service.

Push slow tasks onto the queue. Audio transcription, image segmentation, and anything with a cold start will blow past PHP-FPM's timeout. Wrap the invoke in a job, store results, broadcast on completion via an event. Treat every non-chat task as async by default.

Multimodal input. Image::fromFile() wants a local path. With Storage::disk('s3') you get bytes, not paths — write to tempnam() / a storage/app/tmp file in the job, invoke, then unlink in a finally. Don't leak temp files on exception.

Result handling is task-specific. asText(), asObject(), asVectors() are not interchangeable:

$result = $platform->invoke('google/vit-base-patch16-224', $image, [
    'task' => Task::IMAGE_CLASSIFICATION,
]);

foreach ($result->asObject()->getClassifications() as $c) {
    $label = $c->getLabel();
    $score = $c->getScore();
}

Normalize into your own DTOs immediately — never let a getClassifications() object escape into a Blade view or an API resource.

Model discovery before you code. The two commands don't burn inference credits, which makes them a legitimate part of your workflow:

ai:huggingface:model-list --task=text-generation --warm
ai:huggingface:model-list --provider=hf-inference --search=llama
ai:huggingface:model-info meta-llama/Llama-2-7b-chat

They're Symfony Console commands, so register them in AiServiceProvider::boot() via $this->commands([...]) (Laravel resolves Symfony commands fine) or run them via a one-off php artisan tinker invocation. Verify each one registers cleanly — they may expect Symfony's console framework conventions.

Integration tip — cache by input hash. Wrap embeddings in Cache::remember('emb:' . $model . ':' . sha1($text), ...). Embeddings are deterministic for a given model, and you'll re-run seeders and tests far more often than you expect.

Gotchas and Tips

This is a 0.x package with 4 stars and 0 dependents. Pin it ("^0.14") and read the changelog before every bump. Real API breaks already happened in the 0.x line: the Provider abstraction landed in v0.8.0, base URL handling was reworked in v0.11.0, and v0.10.0 shipped a fix for malformed UTF-8 in request bodies. If you pin below 0.10, sanitize user input yourself before sending.

HttpClientInterface is non-negotiable. Don't try to pass Laravel's HTTP client. If you want retries/logging, use Symfony HttpClient's retry_failed and middleware — that's the natural extension point, and it's where you should handle 429s and 503 "model loading" responses with exponential backoff.

Cold starts are the #1 production surprise. A model that's not warm can take 10–60s or return a 503. Mitigations: filter models with --warm during discovery, keep a known-good warm model as fallback, and never call a cold model synchronously in a web request.

task must match the model. Sending Task::CHAT_COMPLETION to an embeddings model yields an opaque 400/404 from the provider. Validate the (model, task) pair in your config and fail fast at boot with a clear message rather than at runtime.

Model ids contain slashes (meta-llama/Llama-2-7b-chat). Fine in config arrays, broken in route segments or cache keys without hashing/encoding. Use str_replace('/', '--', $model) for keys.

Result object shape varies per task. asObject() returns different result classes depending on the task; asVectors() may be a nested array. Don't write one generic "read the result" helper — map each task you actually use.

Don't mix embedding models in one table. Dimensions differ between models (all-MiniLM-L6-v2 = 384, others 768/1024). Version your vector column alongside a model column, or you'll get silent garbage in similarity search when you swap models.

Secrets and scopes. HuggingFace tokens are read/write-scoped — issue a read-only token for inference and keep it in .env/SSM, never in config/ committed files. Rotate before you go public; the bridge has no way to redact it from logs you write around it.

Extension point worth knowing: since Provider and Task are interfaces of constants, string literals generally work where a constant isn't defined yet — you're not blocked waiting for a package release when a new provider or task ships upstream. Just add the constant to your own config map and keep a note to migrate.

Debugging recipe: log the model id, task, provider, and the resolved base URL on every failure; nine out of ten "it broke" reports are a provider/model mismatch or an expired token. Then reproduce with ai:huggingface:model-info before touching code.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen
seampact/hooks
seampact/ir
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk