symfony/ai-ollama-platform
Symfony AI bridge for the Ollama platform. Connect Symfony AI to Ollama’s chat and embedding APIs, including NDJSON streaming, using Ollama models and Modelfile capabilities. Links to docs, issues, and contributions in the main Symfony AI repo.
Install the Package:
composer require symfony/ai-ollama-platform
Note: Requires PHP 8.1+ and Symfony’s HTTP Client (install via symfony/http-client if missing).
Basic Chat Example:
use Symfony\Component\AI\Ollama\OllamaClient;
use Symfony\Component\HttpClient\HttpClient;
$client = new OllamaClient(HttpClient::create());
$response = $client->chat('llama3', 'Explain Laravel to a 5-year-old');
echo $response->getContent();
Laravel Integration (HTTP Facade):
use Illuminate\Support\Facades\Http;
use Symfony\Component\AI\Ollama\OllamaClient;
// Register a macro to adapt Laravel's HTTP to Symfony's client
Http::macro('createClient', fn() => HttpClient::create());
$ollama = new OllamaClient(Http::createClient());
$result = $ollama->chat('mistral', 'Write a poem about Laravel');
First Use Case:
$stream = $ollama->chatStream('llama3', 'Tell me a joke');
foreach ($stream as $chunk) {
echo $chunk->getContent(); // NDJSON chunk
}
$embedding = $ollama->embed('nomic-embed-text', 'Laravel is awesome');
chat, embed, and streaming).Provider.OllamaClient and HttpClient integration—avoid Symfony-specific components (e.g., Messenger) unless needed.$response = $ollama->chat('llama3', 'Summarize this: ' . $longText);
$content = $response->getContent(); // JSON string
$data = json_decode($content, true);
$stream = $ollama->chatStream('llama3', 'Explain Laravel');
foreach ($stream as $chunk) {
$delta = $chunk->getDelta(); // DeltaInterface
echo $delta->getContent(); // Incremental text
}
$stream->onEach(function ($chunk) {
broadcast(new OllamaChunk($chunk->getDelta()->getContent()));
});
$embedding = $ollama->embed('nomic-embed-text', 'Laravel vs Symfony');
$vector = $embedding->getEmbedding(); // Normalized array
// Store in vector DB (e.g., Qdrant)
$response = $ollama->chat(
'llama3',
'Extract {name, age} from: "John Doe, 30"',
['structured_output' => true]
);
$data = json_decode($response->getContent(), true);
// $data = ['name' => 'John Doe', 'age' => 30]
class OllamaModelProvider implements ProviderInterface {
public function getModel(string $name): string {
return match ($name) {
'poetry' => 'mistral',
'math' => 'llama3',
default => $name,
};
}
}
OllamaClient:
$client = new OllamaClient(HttpClient::create(), new OllamaModelProvider());
$response = $ollama->chat('gemma:2b', 'Transcribe this audio: [base64]');
OllamaClient as a singleton:
$app->singleton(OllamaClient::class, fn($app) =>
new OllamaClient($app->make(HttpClient::class))
);
try-catch for OllamaException:
try {
$response = $ollama->chat('invalid-model', '...');
} catch (OllamaException $e) {
Log::error('Ollama failed: ' . $e->getMessage());
}
// config/ollama.php
return [
'endpoint' => env('OLLAMA_ENDPOINT', 'http://localhost:11434'),
];
Then inject into OllamaClient:
$client = new OllamaClient(
HttpClient::create(['base_uri' => config('ollama.endpoint')])
);
Symfony Abstraction Leakage:
Messenger, AI traits) in Laravel. Stick to OllamaClient and HttpClient.ProviderInterface).Streaming in Laravel:
$stream->onEach(function ($chunk) {
OllamaChunkJob::dispatch($chunk->getDelta()->getContent());
});
Model Catalog Management:
OllamaApiCatalog to list models. Cache results in Laravel’s cache or database to avoid repeated API calls:
$catalog = $ollama->getCatalog();
Cache::put('ollama_models', $catalog, now()->addHours(1));
Audio/Data Payloads:
$audio = base64_encode(file_get_contents('audio.wav'));
$response = $ollama->chat('gemma:2b', "Transcribe: $audio");
PHP Version Conflicts:
composer.json enforces:
"config": {
"platform": {
"php": "8.1"
}
}
Enable HTTP Logging:
$client = new OllamaClient(
HttpClient::create(['headers' => ['Accept' => 'application/json']])
);
// Add middleware for debugging
$client->getHttpClient()->addSubscriber(new \Symfony\Component\HttpClient\EventListener\DebugListener());
Validate NDJSON Streaming:
{"content":"Hello"} // Missing newline between chunks
\n).Ollama Server Issues:
curl http://localhost:11434/api/tags
journalctl -u ollama -f
Structured Output Parsing:
structured_output:
$response = $ollama->chat('llama3', '...', ['structured_output' => true]);
$data = json_decode($response->getContent(), true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \RuntimeException('Invalid structured output');
}
Custom Providers:
ProviderInterface for dynamic model routing:
class CustomProvider implements ProviderInterface {
public function getModel(string $name): string {
// Logic to map user-friendly names to Ollama models
}
}
Middleware for Requests:
How can I help you explore Laravel packages today?