Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
66 changes: 66 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# You only need to fill in the values when running the examples, see examples/

# For using GPT on OpenAI
OPENAI_API_KEY=

# For using Claude on Anthropic
ANTHROPIC_API_KEY=

# For using Mistral
MISTRAL_API_KEY=

# For using Voyage
VOYAGE_API_KEY=

# For using Replicate
REPLICATE_API_KEY=

# For using Ollama
OLLAMA_HOST_URL=

# For using GPT on Azure
AZURE_OPENAI_BASEURL=
AZURE_OPENAI_KEY=
AZURE_OPENAI_GPT_DEPLOYMENT=
AZURE_OPENAI_GPT_API_VERSION=
AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT=
AZURE_OPENAI_EMBEDDINGS_API_VERSION=
AZURE_OPENAI_WHISPER_DEPLOYMENT=
AZURE_OPENAI_WHISPER_API_VERSION=

# For using Llama on Azure
AZURE_LLAMA_BASEURL=
AZURE_LLAMA_KEY=

# For using Bedrock
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=

# Hugging Face Access Token
HUGGINGFACE_KEY=

# For using OpenRouter
OPENROUTER_KEY=

# For using SerpApi (tool)
SERP_API_KEY=

# For using Tavily (tool)
TAVILY_API_KEY=

# For using Brave (tool)
BRAVE_API_KEY=

# For using MongoDB Atlas (store)
MONGODB_URI=

# For using Pinecone (store)
PINECONE_API_KEY=
PINECONE_HOST=

# Some examples are expensive to run, so we disable them by default
RUN_EXPENSIVE_EXAMPLES=false

# For using Gemini
GOOGLE_API_KEY=
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.doctor-rst.cache
.php-cs-fixer.cache
.phpunit.result.cache
.env.local

/composer.lock
/vendor
17 changes: 17 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,25 @@
],
"require-dev": {
"php": ">=8.1",
"symfony/ai-agent": "@dev",
"symfony/ai-platform": "@dev",
"symfony/console": "^6.4|^7.0",
"symfony/css-selector": "^6.4|^7.0",
"symfony/dom-crawler": "^6.4|^7.0",
"symfony/dotenv": "^6.4|^7.0",
"symfony/filesystem": "^6.4|^7.0",
"symfony/finder": "^6.4|^7.0",
"symfony/process": "^6.4|^7.0",
"symfony/var-dumper": "^6.4|^7.0",
"php-cs-fixer/shim": "^3.75"
},
"repositories": [
{ "type": "path", "url": "src/agent" },
{ "type": "path", "url": "src/platform" }
],
"autoload-dev": {
"psr-4": {
"Symfony\\AI\\Fixtures\\": "fixtures/"
}
}
}
110 changes: 110 additions & 0 deletions example
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env php
<?php

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\SingleCommandApplication;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use Symfony\Component\Process\Process;

require_once __DIR__.'/vendor/autoload.php';

$app = (new SingleCommandApplication('Symfony AI Example Runner'))
->setDescription('Runs all Symfony AI examples in folder examples/')
->addArgument('subdirectory', InputArgument::OPTIONAL, 'Subdirectory to run examples from, e.g. "anthropic" or "huggingface".')
->setCode(function (InputInterface $input, OutputInterface $output) {
$io = new SymfonyStyle($input, $output);
$io->title('Symfony AI Examples');

$directory = __DIR__.'/examples';

if ($subdirectory = $input->getArgument('subdirectory')) {
$directory .= '/'.$subdirectory;
if (!is_dir($directory)) {
$io->error(sprintf('Subdirectory "%s" does not exist.', $subdirectory));
return Command::FAILURE;
}
}

$examples = (new Finder())
->in($directory)
->name('*.php')
->sortByName()
->files();

/** @var array{example: SplFileInfo, process: Process} $exampleRuns */
$exampleRuns = [];
foreach ($examples as $example) {
$exampleRuns[] = [
'example' => $example,
'process' => $process = new Process(['php', $example->getRealPath()]),
];
$process->start();
}

$section = $output->section();
$renderTable = function () use ($exampleRuns, $section) {
$section->clear();
$table = new Table($section);
$table->setHeaders(['Example', 'State', 'Output']);
foreach ($exampleRuns as $run) {
/** @var SplFileInfo $example */
/** @var Process $process */
['example' => $example, 'process' => $process] = $run;

$output = str_replace(PHP_EOL, ' ', $process->getOutput());
$output = strlen($output) <= 100 ? $output : substr($output, 0, 100).'...';
$emptyOutput = 0 === strlen(trim($output));

$state = 'Running';
if ($process->isTerminated()) {
$success = $process->isSuccessful() && !$emptyOutput;
$state = $success ? '<info>Finished</info>'
: (1 === $run['process']->getExitCode() || $emptyOutput ? '<error>Failed</error>' : '<comment>Skipped</comment>');
}

$table->addRow([$example->getRelativePathname(), $state, $output]);
}
$table->render();
};

$examplesRunning = fn () => array_reduce($exampleRuns, fn ($running, $example) => $running || $example['process']->isRunning(), false);
while ($examplesRunning()) {
$renderTable();
sleep(1);
}

$renderTable();
$io->newLine();

$successCount = array_reduce($exampleRuns, function ($count, $example) {
if ($example['process']->isSuccessful() && strlen(trim($example['process']->getOutput())) > 0) {
return $count + 1;
}
return $count;
}, 0);

$totalCount = count($exampleRuns);

if ($successCount < $totalCount) {
$io->warning(sprintf('%d out of %d examples ran successfully.', $successCount, $totalCount));
} else {
$io->success(sprintf('All %d examples ran successfully!', $totalCount));
}

foreach ($exampleRuns as $run) {
if (!$run['process']->isSuccessful()) {
$io->section('Error in ' . $run['example']->getRelativePathname());
$io->text($run['process']->getOutput());
$io->text($run['process']->getErrorOutput());
}
}

return Command::SUCCESS;
})
->run();
28 changes: 28 additions & 0 deletions examples/anthropic/chat.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

use Symfony\AI\Agent\Agent;
use Symfony\AI\Platform\Bridge\Anthropic\Claude;
use Symfony\AI\Platform\Bridge\Anthropic\PlatformFactory;
use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;
use Symfony\Component\Dotenv\Dotenv;

require_once dirname(__DIR__, 2).'/vendor/autoload.php';
(new Dotenv())->loadEnv(dirname(__DIR__, 2).'/.env');

if (empty($_ENV['ANTHROPIC_API_KEY'])) {
echo 'Please set the ANTHROPIC_API_KEY environment variable.'.\PHP_EOL;
exit(1);
}

$platform = PlatformFactory::create($_ENV['ANTHROPIC_API_KEY']);
$model = new Claude(Claude::SONNET_37);

$agent = new Agent($platform, $model);
$messages = new MessageBag(
Message::forSystem('You are a pirate and you write funny.'),
Message::ofUser('What is the Symfony framework?'),
);
$response = $agent->call($messages);

echo $response->getContent().\PHP_EOL;
32 changes: 32 additions & 0 deletions examples/anthropic/image-input-binary.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

use Symfony\AI\Agent\Agent;
use Symfony\AI\Platform\Bridge\Anthropic\Claude;
use Symfony\AI\Platform\Bridge\Anthropic\PlatformFactory;
use Symfony\AI\Platform\Message\Content\Image;
use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;
use Symfony\Component\Dotenv\Dotenv;

require_once dirname(__DIR__, 2).'/vendor/autoload.php';
(new Dotenv())->loadEnv(dirname(__DIR__, 2).'/.env');

if (empty($_ENV['ANTHROPIC_API_KEY'])) {
echo 'Please set the ANTHROPIC_API_KEY environment variable.'.\PHP_EOL;
exit(1);
}

$platform = PlatformFactory::create($_ENV['ANTHROPIC_API_KEY']);
$model = new Claude(Claude::SONNET_37);

$agent = new Agent($platform, $model);
$messages = new MessageBag(
Message::forSystem('You are an image analyzer bot that helps identify the content of images.'),
Message::ofUser(
Image::fromFile(dirname(__DIR__, 2).'/tests/Fixture/image.jpg'),
'Describe this image.',
),
);
$response = $agent->call($messages);

echo $response->getContent().\PHP_EOL;
32 changes: 32 additions & 0 deletions examples/anthropic/image-input-url.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

use Symfony\AI\Agent\Agent;
use Symfony\AI\Platform\Bridge\Anthropic\Claude;
use Symfony\AI\Platform\Bridge\Anthropic\PlatformFactory;
use Symfony\AI\Platform\Message\Content\ImageUrl;
use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;
use Symfony\Component\Dotenv\Dotenv;

require_once dirname(__DIR__, 2).'/vendor/autoload.php';
(new Dotenv())->loadEnv(dirname(__DIR__, 2).'/.env');

if (empty($_ENV['ANTHROPIC_API_KEY'])) {
echo 'Please set the ANTHROPIC_API_KEY environment variable.'.\PHP_EOL;
exit(1);
}

$platform = PlatformFactory::create($_ENV['ANTHROPIC_API_KEY']);
$model = new Claude(Claude::SONNET_37);

$agent = new Agent($platform, $model);
$messages = new MessageBag(
Message::forSystem('You are an image analyzer bot that helps identify the content of images.'),
Message::ofUser(
new ImageUrl('https://upload.wikimedia.org/wikipedia/commons/a/a7/Camponotus_flavomarginatus_ant.jpg'),
'Describe this image.',
),
);
$response = $agent->call($messages);

echo $response->getContent().\PHP_EOL;
31 changes: 31 additions & 0 deletions examples/anthropic/pdf-input-binary.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

use Symfony\AI\Agent\Agent;
use Symfony\AI\Platform\Bridge\Anthropic\Claude;
use Symfony\AI\Platform\Bridge\Anthropic\PlatformFactory;
use Symfony\AI\Platform\Message\Content\Document;
use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;
use Symfony\Component\Dotenv\Dotenv;

require_once dirname(__DIR__, 2).'/vendor/autoload.php';
(new Dotenv())->loadEnv(dirname(__DIR__, 2).'/.env');

if (empty($_ENV['ANTHROPIC_API_KEY'])) {
echo 'Please set the ANTHROPIC_API_KEY environment variable.'.\PHP_EOL;
exit(1);
}

$platform = PlatformFactory::create($_ENV['ANTHROPIC_API_KEY']);
$model = new Claude(Claude::SONNET_37);

$agent = new Agent($platform, $model);
$messages = new MessageBag(
Message::ofUser(
Document::fromFile(dirname(__DIR__, 2).'/tests/Fixture/document.pdf'),
'What is this document about?',
),
);
$response = $agent->call($messages);

echo $response->getContent().\PHP_EOL;
31 changes: 31 additions & 0 deletions examples/anthropic/pdf-input-url.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

use Symfony\AI\Agent\Agent;
use Symfony\AI\Platform\Bridge\Anthropic\Claude;
use Symfony\AI\Platform\Bridge\Anthropic\PlatformFactory;
use Symfony\AI\Platform\Message\Content\DocumentUrl;
use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;
use Symfony\Component\Dotenv\Dotenv;

require_once dirname(__DIR__, 2).'/vendor/autoload.php';
(new Dotenv())->loadEnv(dirname(__DIR__, 2).'/.env');

if (empty($_ENV['ANTHROPIC_API_KEY'])) {
echo 'Please set the ANTHROPIC_API_KEY environment variable.'.\PHP_EOL;
exit(1);
}

$platform = PlatformFactory::create($_ENV['ANTHROPIC_API_KEY']);
$model = new Claude(Claude::SONNET_37);

$agent = new Agent($platform, $model);
$messages = new MessageBag(
Message::ofUser(
new DocumentUrl('https://upload.wikimedia.org/wikipedia/commons/2/20/Re_example.pdf'),
'What is this document about?',
),
);
$response = $agent->call($messages);

echo $response->getContent().\PHP_EOL;
Loading
Loading