Skip to content

Commit 7519f92

Browse files
Merge pull request #9 from joomla-projects/documentation
Add documentation overing overview, getting started guide, and comprehensive provider-specific guides
2 parents fdad96a + 086d2ad commit 7519f92

20 files changed

+1514
-78
lines changed

README.md

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# The Joomla! AI Package
2+
3+
## Installation via Composer
4+
5+
Add `"joomla/ai": "~4.0"` to the require block in your composer.json and then run `composer install`.
6+
7+
```json
8+
{
9+
"require": {
10+
"joomla/ai": "~4.0"
11+
}
12+
}
13+
```
14+
15+
Alternatively, you can simply run the following from the command line:
16+
17+
```sh
18+
composer require joomla/ai "~4.0"
19+
```
20+
21+
If you want to include the test sources and docs, use
22+
23+
```sh
24+
composer require --prefer-source joomla/ai "~4.0"
25+
```
26+
27+
## Using the AI Framework
28+
The AI Framework provides a straightforward, provider-agnostic interface for working with three main AI providers: OpenAI, Anthropic and Ollama. Instead of writing separate code for each provider’s SDK, developers write once and simply switch providers by changing configuration.
29+
30+
You can find the official provider APIs documentation here:
31+
- OpenAI API: https://platform.openai.com/docs/api-reference
32+
- Anthropic API: https://docs.anthropic.com/claude/docs
33+
- Ollama API: https://github.com/ollama/ollama/blob/main/docs/api.md
34+
35+
The AI framework is built upon the Http package which provides an easy way to consume URLs and web services in a transport independent way. Joomla\Http currently supports streams, sockets and cURL. The framework centralizes HTTP handling in the Abstract Provider. Providers encapsulate:
36+
- Base URLs, headers, and auth (API keys/tokens)
37+
- Request building (JSON/multipart)
38+
- Response normalization and error mapping into framework exceptions
39+
40+
## Instantiating a Provider
41+
42+
Each provider is instantiated with its configuration (API key, defaults such as model or base URL). You can override these defaults per call when needed.
43+
44+
### OpenAI:
45+
```php
46+
use Joomla\AI\AIFactory;
47+
48+
$openai = AIFactory::getAI('openai', [
49+
'api_key' => getenv('OPENAI_API_KEY'),
50+
// Optional defaults:
51+
// 'model' => 'gpt-4o',
52+
// 'base_url' => 'https://api.openai.com/v1',
53+
]);
54+
```
55+
56+
### Anthropic:
57+
```php
58+
use Joomla\AI\AIFactory;
59+
60+
$anthropic = AIFactory::getAI('anthropic', [
61+
'api_key' => getenv('ANTHROPIC_API_KEY'),
62+
// 'model' => 'claude-3-5-sonnet',
63+
]);
64+
```
65+
66+
### Ollama (local):
67+
```php
68+
use Joomla\AI\AIFactory;
69+
70+
$ollama = AIFactory::getAI('ollama', [
71+
// 'base_url' => 'http://localhost:11434',
72+
// 'model' => 'llama3',
73+
]);
74+
```
75+
76+
## Supported Methods
77+
78+
| Provider | Methods |
79+
| --- | --- |
80+
| OpenAI | `chat`, `vision`, `generateImage`, `createImageVariation`, `editImage`, `speech`, `transcribe`, `translate`, `createEmbeddings`, `moderate`, `isContentFlagged`|
81+
| Anthropic | `chat`, `vision`, `getModel`|
82+
| Ollama | `chat`, `generate`, `pullModel`, `copyModel`, `deleteModel`, `checkModelExists`, `getRunningModels`|
83+
84+
Not all providers implement every capability. The framework exposes capabilities via interfaces (e.g. ChatInterface, ImageInterface). Developers can use what each provider supports.
85+
86+
## Making your first request
87+
All providers implement a shared set of capability interfaces (e.g., Chat, Images, Audio). Invoke these methods directly, passing per-call options to override defaults.
88+
89+
```php
90+
// Chat example (OpenAI)
91+
$response = $openai->chat("Write a haiku about Joomla.", [
92+
'model' => 'gpt-4o-mini', // overrides constructor default if set
93+
]);
94+
echo $response->getContent(); // primary content (e.g. text)
95+
$meta = $response->getMetadata(); // metadata content (e.g. model, usage)
96+
```
97+
98+
## Error handling
99+
Provider HTTP errors are mapped to framework exceptions (e.g. auth, rate limit, invalid arguments). Catch and handle them as needed.
100+
```php
101+
try {
102+
$response = $openai->chat("Hello!");
103+
} catch (\Throwable $e) {
104+
// Log and surface a friendly message
105+
}
106+
```
107+
108+
## Documentation
109+
110+
- **[Overview](docs/overview.md)**
111+
Architecture & goals
112+
113+
- **[Getting Started](docs/getting-started.md)**
114+
Install, configure, first provider
115+
116+
- **[Guides](providers/)**
117+
Provider-specific guides with code examples
118+
---

Tests/FactoryTest.php

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
require_once '../vendor/autoload.php';
4+
5+
use Joomla\AI\AIFactory;
6+
use Joomla\AI\Exception\ProviderException;
7+
8+
$configFile = __DIR__ . '/../config.json';
9+
$config = json_decode(file_get_contents($configFile), true);
10+
$api_key = $config['openai_api_key'] ?? null;
11+
$anthropic_api_key = $config['anthropic_api_key'] ?? null;
12+
13+
echo "=== AI Factory Test Suite ===\n\n";
14+
15+
// Test Case 1: Invalid Provider
16+
echo "1. Testing invalid provider 'abcd':\n";
17+
try {
18+
$options = [
19+
'api_key' => $anthropic_api_key
20+
];
21+
22+
$ai = AIFactory::getAI('abcd', $options);
23+
$response = $ai->chat("Hey");
24+
echo $response->getContent();
25+
26+
} catch (ProviderException $e) {
27+
echo "Caught expected exception: " . $e->getMessage() . "\n";
28+
}
29+
echo "\n";
30+
31+
// Test Case 2: Valid Provider Creation
32+
echo "2. Testing valid provider creation (anthropic):\n";
33+
try {
34+
$options = [
35+
'api_key' => $anthropic_api_key
36+
];
37+
38+
$ai = AIFactory::getAI('anthropic', $options);
39+
echo "Provider name: " . $ai->getProvider()->getName() . "\n";
40+
$response = $ai->chat("Hey");
41+
echo $response->getContent();
42+
} catch (Exception $e) {
43+
echo "Failed to create Anthropic provider: " . $e->getMessage() . "\n";
44+
}
45+
echo "\n";
46+
47+
// Test Case 3: Non-existent Method Call
48+
echo "3. Testing non-existent method call:\n";
49+
try {
50+
$options = [
51+
'api_key' => $anthropic_api_key
52+
];
53+
54+
$ai = AIFactory::getAI('anthropic', $options);
55+
$response = $ai->nonExistentMethod("test");
56+
echo $response->getContent();
57+
} catch (ProviderException $e) {
58+
echo "Caught expected Exception for non-existent method: " . $e->getMessage() . "\n";
59+
}
60+
echo "\n";
61+
62+
// Test Case 4: Available Providers
63+
echo "4. Testing available providers:\n";
64+
try {
65+
$availableProviders = AIFactory::getAvailableProviders();
66+
echo "Available providers: " . implode(', ', $availableProviders) . "\n";
67+
68+
// Test each provider availability
69+
foreach ($availableProviders as $provider) {
70+
$isAvailable = AIFactory::isProviderAvailable($provider);
71+
echo "Provider '$provider' is available: " . ($isAvailable ? 'Yes' : 'No') . "\n";
72+
}
73+
74+
// Test non-existent provider
75+
$isAvailable = AIFactory::isProviderAvailable('non-existent');
76+
echo "Provider 'non-existent' is available: " . ($isAvailable ? 'Yes' : 'No') . "\n";
77+
} catch (Exception $e) {
78+
echo "Failed to get available providers: " . $e->getMessage() . "\n";
79+
}
80+
echo "\n";
81+
82+
// Test Case 5: Valid Method Call
83+
echo "5. Testing valid method calls:\n";
84+
try {
85+
$options = [
86+
'api_key' => $anthropic_api_key
87+
];
88+
89+
$ai = AIFactory::getAI('anthropic', $options);
90+
$response = $ai->chat("Hey");
91+
echo $response->getContent();
92+
} catch (Exception $e) {
93+
echo "Test Failed: " . $e->getMessage() . "\n";
94+
}
95+
96+
echo "\n=== Test Suite Complete ===\n";

0 commit comments

Comments
 (0)