Skip to content

Eden AI

Edit this page

Eden AI is an AI gateway exposing hundreds of models from many providers behind a single API, addressed with provider/model identifiers. The bridge covers both halves of the v3 API: the OpenAI-compatible endpoints (/v3/chat/completions and /v3/embeddings, reusing the Generic bridge, including streaming and tool calling) and the expert models of the /v3/universal-ai endpoints.

For comprehensive information about Eden AI, see the Eden AI API reference.

Installation

To use Eden AI with Symfony AI Platform, install the bridge:

1
$ composer require symfony/ai-eden-ai-platform

Setup

Authentication

Eden AI requires an API key, which you can create from the Eden AI dashboard. Configure it in your environment file:

1
EDENAI_API_KEY=your-eden-ai-api-key

Usage

Chat and Embeddings

The bridge supports OpenAI-compatible chat and embeddings endpoints, so streaming and tool calling work as with any Generic-bridge platform:

1
2
3
4
5
6
7
8
9
10
use Symfony\AI\Platform\Bridge\EdenAi\Factory;
use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;

$platform = Factory::createPlatform($apiKey);

$messages = new MessageBag(Message::ofUser('What is the Symfony framework?'));
echo $platform->invoke('openai/gpt-4o-mini', $messages)->asText();

$vectors = $platform->invoke('openai/text-embedding-3-small', 'Some text')->asVectors();

OCR and Document Parsing

Eden AI exposes OCR and document parsing (invoices, resumes, identity documents) from multiple providers through its /v3/universal-ai endpoint, using ocr/{subfeature}/{provider} model names. Models are invoked with a DocumentUrl or ImageUrl, or with a plain string holding a direct file URL or a file ID from Eden AI's upload API. Input parameters like language or document_type are passed as options, or inline in the model name (ocr/ocr/google?language=en):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
use Symfony\AI\Platform\Bridge\EdenAi\DocumentParser\Result\DocumentParsingResult;
use Symfony\AI\Platform\Bridge\EdenAi\Factory;
use Symfony\AI\Platform\Bridge\EdenAi\Ocr\Result\OcrResult;
use Symfony\AI\Platform\Message\Content\DocumentUrl;
use Symfony\AI\Platform\Message\Content\ImageUrl;

$platform = Factory::createPlatform($apiKey);

// OCR: extract raw text and bounding boxes
$result = $platform->invoke('ocr/ocr/google', new ImageUrl('https://example.com/scan.jpg'), [
    'language' => 'en',
]);

$ocr = $result->asObject();
\assert($ocr instanceof OcrResult);

echo $ocr->getText();

// Document parsing: extract structured data from an invoice
$result = $platform->invoke('ocr/financial_parser/affinda', new DocumentUrl('https://example.com/invoice.pdf'), [
    'language' => 'en',
    'document_type' => 'invoice',
]);

$parsing = $result->asObject();
\assert($parsing instanceof DocumentParsingResult);

$extractedData = $parsing->getExtractedData();

Note

Not every provider reads an uploaded file. ocr/financial_parser/openai answers a successful but empty result when its input is a file ID, while it parses the very same document handed over as a URL. ocr/financial_parser/affinda reads both. Pass a DocumentUrl to the providers behaving that way.

Expert Models

Beyond OCR and document parsing, the Eden AI bridge exposes the other expert models of the /v3/universal-ai endpoints: text-to-speech, speech-to-text, image analysis (object detection, explicit content, logo detection, face detection, AI detection and deepfake detection) and image generation. Binary content (Audio, Document or Image) is transparently uploaded through Eden AI's /v3/upload endpoint before the request:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
use Symfony\AI\Platform\Bridge\EdenAi\Factory;
use Symfony\AI\Platform\Message\Content\Audio;
use Symfony\AI\Platform\Message\Content\ImageUrl;

$platform = Factory::createPlatform($apiKey);

// Text-to-speech: returns the synthesized audio as binary data
$result = $platform->invoke('audio/tts/amazon/neural', 'Welcome to Symfony AI!');
$result->asFile('welcome.mp3');

// Speech-to-text: diarization is exposed as result metadata
$result = $platform->invoke('audio/speech_to_text_async/openai', 'https://example.com/audio.mp3');
echo $result->asText();

// Speech-to-text from a local file, uploaded automatically
$result = $platform->invoke('audio/speech_to_text_async/deepgram', Audio::fromFile('./audio.mp3'));

// Object detection
$analysis = $platform->invoke('image/object_detection/google', new ImageUrl('https://example.com/photo.jpg'))->asObject();
foreach ($analysis->getItems() as $item) {
    echo $item['label'];
}

// Image generation: every generated image is returned, so requesting several yields a
// MultiPartResult instead of a single BinaryResult
$result = $platform->invoke('image/generation/stabilityai', 'A red apple on a white table');
$result->asFile('apple.png');

Asynchronous Transcription

Speech-to-text runs on /v3/universal-ai/async. Providers that are done by the time Eden AI answers put the transcription straight into the response, and the invocation is over. The others report a job that is still running, and the invocation returns a JobResult instead - a handle that can be waited for right away, or stored and picked up by a worker later, since it holds no connection:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use Symfony\AI\Platform\Bridge\EdenAi\Factory;
use Symfony\AI\Platform\Job\JobRunner;
use Symfony\AI\Platform\Result\JobResult;

$result = $platform->invoke('audio/speech_to_text_async/deepgram', 'https://example.com/audio.mp3');

if ($result->getResult() instanceof JobResult) {
    $jobClient = Factory::createJobClient($apiKey);

    // The handle states how long transcription may run through the gateway, so the caller
    // does not have to know; pass maxDuration to overrule it.
    $result = (new JobRunner())->wait($jobClient, $result->asJob(), maxDuration: 60);
}

echo $result->asText();

The bridge never blocks inside invoke(): how long to wait for a job, and whether to wait at all, is the caller's decision. Pass a webhook_receiver option to be notified out of band instead, and resolve the handle when the webhook fires.

In a Symfony application the job client is available as a service, autowirable by name:

1
2
3
4
5
6
public function __construct(
    #[Autowire(service: 'ai.platform.job_client.edenai')]
    private JobClientInterface $edenaiJobClient,
    private JobRunner $jobRunner,
) {
}

Eden AI fronts more than a thousand models, and ModelCatalog only curates a subset of them. Register any other one through its $additionalModels argument, or hand the factory a ModelApiCatalog, which discovers everything Eden AI currently serves from its public /v3/models, /v3/embeddings/models and /v3/info endpoints:

1
2
3
4
5
6
7
use Symfony\AI\Platform\Bridge\EdenAi\Factory;
use Symfony\AI\Platform\Bridge\EdenAi\ModelApiCatalog;

$platform = Factory::createPlatform($apiKey, $httpClient, new ModelApiCatalog($httpClient));

// No catalog entry needed for this one
$result = $platform->invoke('audio/tts/elevenlabs/eleven_multilingual_v2', 'Welcome!');

Expert subfeatures the bridge has no result converter for stay hidden from that catalog, so an unsupported model fails at lookup time rather than during conversion.

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version