Skip to content

Latest commit

 

History

History
463 lines (312 loc) · 20.4 KB

File metadata and controls

463 lines (312 loc) · 20.4 KB

AiM: The AI Brain for Your TYPO3 Website

One extension. Every AI provider. Full control.

AiM connects your TYPO3 website to the world of artificial intelligence without locking you into a single vendor, without exposing your API keys to every extension, and without losing visibility into what AI is doing on your site.

Think of AiM as the central switchboard for all AI operations in TYPO3. Your extensions ask for what they need: "describe this image", "translate this text", "generate a meta description". AiM handles everything else: picking the right provider, routing to the right model, logging the request, tracking costs, and enforcing your security policies.


Why AiM?

The problem without AiM

Every TYPO3 extension that wants to use AI needs its own OpenAI integration. That means:

  • API keys scattered across multiple extensions
  • No overview of what AI is being used for
  • No cost control, any extension can burn through your budget
  • No way to switch providers without changing extension code
  • No security boundaries, HR data could end up at a cloud provider

The AiM approach

AiM sits between your extensions and AI providers. Extensions never touch API keys, never choose models, never talk to providers directly. They simply say what they need, and AiM delivers.

For site administrators, this means:

  • One place to manage all AI provider configurations
  • Full visibility into every AI request (who, what, when, how much)
  • Budget limits per user or group
  • Privacy controls for sensitive data
  • The freedom to switch providers anytime

For extension developers, this means:

  • Three lines of code to add AI to any feature
  • No need to implement provider-specific APIs
  • Automatic fallback if a provider goes down
  • Smart routing that picks the cheapest model for simple tasks

What can AiM do?

Image analysis and alt text generation

Upload an image, get a description back. Perfect for accessibility: generate alt text for every image in your media library automatically.

Content generation

Write meta descriptions, generate summaries, create content drafts. Tell AiM what you need and which tone to use.

Translation

Translate content between any languages your AI provider supports. Tone, context, and meaning are maintained automatically.

Conversations and chatbots

Build interactive chat experiences in the TYPO3 backend or frontend. Multi-turn conversations with context awareness, including streaming support for real-time token output.

Embeddings and semantic search

Generate vector embeddings for content. Enable semantic search, find related content, build recommendation engines.

Tool calling and agentic workflows

Let AI interact with your TYPO3 data. AI can call functions you define: query records, trigger actions, process data.

Image generation

Every editor prompting an image generator on their own produces a different look, inconsistent styles, colors, and composition scattered across the site. Instead, pass an existing on-brand image as a style reference alongside the prompt. AiM asks the provider to generate an image-to-image edit guided by it, so headers, teasers, and illustrations stay visually consistent site-wide instead of looking like they came from ten different tools. Requires a provider/model that supports image output (e.g. OpenAI's gpt-image-1).


How it works for administrators

Everything lives in one place: the AiM module under Admin Tools, with three sub-modules for providers, request monitoring, and page tone.

AiM module overview

1. Install AiM and a provider bridge

composer require b13/aim

AiM itself has no AI provider built in. You choose what you need:

Provider Package Use case
OpenAI (GPT-4.1, GPT-4o) symfony/ai-open-ai-platform Best all-rounder, vision, embeddings
Anthropic (Claude) symfony/ai-anthropic-platform Strong reasoning, long context
Google Gemini symfony/ai-gemini-platform 1M token context window
Mistral symfony/ai-mistral-platform European hosting, fast
Ollama (local) symfony/ai-ollama-platform On-premise, no data leaves your server

Install any bridge and AiM detects it automatically. No configuration needed beyond the Composer install. Of course, you can also create your own providers.

2. Create a provider configuration

In the TYPO3 backend, go to Admin Tools > AiM > Providers and create a new configuration:

  • Pick your provider from the dropdown (auto-populated from installed bridges)
  • Enter your API key (or endpoint URL for Ollama)
  • Select a model
  • Optionally mark as default

Click the verify button to confirm the connection works. You'll see "connected" with the timestamp.

Alternative: site settings YAML. Extensions can also resolve provider configurations from your site's settings.yaml without any database records. This is useful for simple setups or automated deployments where you want to keep AI configuration in version control alongside your site config.

3. You're done

Every extension using AiM now has AI capabilities. No further configuration needed for basic usage.


Smart features that save money

Intelligent model routing

AiM analyzes each prompt's complexity before sending it to an AI provider. A simple "What is PHP?" doesn't need GPT-4.1. A smaller, cheaper model handles it just fine. AiM learns from your request history which models work well for which types of questions and automatically routes to the most cost-effective option.

If you also enable response quality grading, routing gets smarter still: a cheaper model is only chosen if its past answers were actually graded as good. Not just "didn't error". A model that runs cheaply but produces weak responses is left out of the downgrade. Until enough graded requests exist for a model, routing falls back to cost and reliability alone, so nothing changes for setups that don't use grading.

This happens transparently. Your extensions don't need to change anything.

Auto model switching

You configured OpenAI with GPT-4.1 for chat. But an extension needs embeddings, and GPT-4.1 can't do that. Instead of failing, AiM automatically switches to the cheapest capable model (e.g. text-embedding-3-small) using the same API key. The selection is data-driven: AiM uses historical cost data from the request log to pick the cheapest model with a proven success rate. One configuration covers all AI capabilities.

The auto switch is controllable:

  • Per configuration: toggle on/off in the provider record
  • Per user/group: aim.autoModelSwitch = 0 in TSconfig
  • Admins always bypass restrictions

Fallback chains

If your primary provider is down or returns an error, AiM automatically retries with the next available provider. Your users never see a failure.


Security and governance

Who can use what

Restrict AI capabilities per backend user group using TYPO3's standard permission system:

  • Text generation: allow or deny per group
  • Vision (image analysis): restrict to editors who need it
  • Translation: enable for translators only
  • Embeddings, tool calling: keep for developers

If no restrictions are configured, everything is allowed (permissive by default). Restrictions only kick in when you explicitly set them in any group.

Provider access control

Different teams, different providers. Your HR department uses a local Ollama instance for confidential employee data. Marketing uses OpenAI for content generation. AiM ensures:

  • Group-based provider restrictions: only HR group members can access the HR Ollama configuration
  • Rerouting protection: the smart router will never send HR data to a cloud provider
  • Privacy levels: mark the HR configuration as "no logging" so prompts and responses aren't stored

Budget limits

Set spending limits per user or group via TYPO3's UserTSconfig:

aim.budget.period = monthly
aim.budget.maxCost = 50.00
aim.budget.maxTokens = 500000
aim.budget.maxRequests = 1000

When the limit is reached, requests are blocked with a clear message. Budgets are tracked per user in rolling periods (daily/weekly/monthly).

This applies to everyone, including admins. AI requests can get expensive, especially with vision or reasoning models. Budget limits act as a safety net: even an admin who accidentally triggers a bulk operation will be stopped before costs escalate. Admins can set their own limits via UserTSconfig.

Rate limiting

Prevent individual users from making too many requests:

aim.rateLimit.requestsPerMinute = 10

Full visibility

Request log

Every AI request is tracked in the AiM > Request Log module:

  • What was asked: prompt and response content is stored per request (respects privacy levels), accessible via the database for debugging
  • Which model answered: requested model vs. actually used model
  • How much it cost: token counts (prompt, completion, cached, reasoning) and calculated cost
  • How complex it was: AiM's complexity classification (simple/moderate/complex) with the scoring reason
  • How good it was: when grading is enabled, an LLM-as-a-judge quality score, label, and reason
  • How long it took: wall-clock duration in milliseconds
  • Who asked: the backend username is displayed for each request, so you can see which user triggered it. Automated/CLI requests show no user.
  • Which extension: the calling extension key is shown per request
  • Rerouting details: whether the request was rerouted (fallback, capability validation, smart routing) and why

Filter by provider, extension, request type, or success/failure. Statistics dashboard shows totals at a glance.

Request Log

Click any row (or its dedicated details button) to open the full request detail view: the complete, untruncated prompt and response - the list only ever shows a short preview - alongside every other field recorded for that request. It's reachable via a stable, linkable URL (aim_request_log.show), so other extensions logging through AiM can link straight from their own UI to the exact request behind a piece of generated content, instead of sending editors to search the list manually.

Request Log detail view

Response quality grading

How good are the AI responses your site produces? AiM can answer that automatically. Enable LLM grading on any provider configuration and AiM scores each response with a second AI model acting as an impartial judge ("LLM-as-a-judge").

You write the rubric ("evaluate factual accuracy and relevance", "check the tone is friendly and professional", ...) and pick which configuration acts as the judge, typically a cheaper model. After each response is delivered, AiM asks the judge to score it and records a grade (poor / fair / good / excellent), a 0–1 score, and a one-sentence reason on the request log row.

Grading runs after the response reaches the user, so it never slows anything down. It applies to text and conversation requests, and only when full logging is active, since the judge needs to see the content it is scoring. Grading is delivered by a shutdown handler on the live request, with a scheduler task (aim:grade-pending) as a safety net for anything it misses.

This turns the request log into a quality dashboard: spot which models or prompts produce weak answers, compare providers on real output, and catch quality regressions before your editors do.

Provider verification

Click the verify button next to any provider configuration to test the connection. See "connected" or "disconnected" with the exact error message. Results are persisted so you see the last check status on every page load.

Provider Management

Disabled models

In the Available Providers modal, click any model badge to disable it. Disabled models:

  • Don't appear in the model selection dropdown
  • Are never picked by the resolver, smart router, or auto model switch
  • Are blocked by the capability validation middleware as a safety net

Available Providers modal with clickable model badges

Dashboard widgets

If the TYPO3 Dashboard extension is installed, AiM adds five widgets you can place on any dashboard:

  • Recent Requests: a live table of the latest AI requests with model, tokens, cost, and status
  • Provider Usage: doughnut chart showing how requests are distributed across providers
  • Model Usage: bar chart showing request counts per model
  • Success Rate: doughnut chart of successful vs failed requests
  • Extension Usage: doughnut chart showing which extensions use AI the most

A pre-configured dashboard preset ("AiM: AI Analytics") is available when creating a new dashboard, placing all five widgets at once.

Dashboard Widgets


A consistent tone of voice, site-wide

Every extension calling AiM can inherit a shared brand voice automatically, without changing a line of its own code.

How the voice is defined

Editors add named prompt fragments directly on any page (a repeatable "AI" tab, right next to the page's other properties): an instruction ("write in a warm, second-person voice"), optional example text to steer the model further, and which AI capability it applies to. A fragment on a page also applies to everything below it in the page tree by default, so setting the tone once on a site's root page covers the whole site; a subsection can add its own fragment on top, or opt out of what it would otherwise inherit entirely.

For AI requests with no page context at all (e.g. generating alt text for a file in the media library), a single site-wide fallback tone applies instead. Either way, a provider-specific addendum and any organization-wide policy an extension developer registers in code (a watermark instruction, a compliance disclaimer) are layered in automatically, last.

Inspecting what will actually be sent

The AiM > Prompt Preview module lists every page that has a configured fragment (only pages you're actually allowed to see), searchable and filterable by capability. Select a page in the built-in page tree to narrow the list to it and everything below it.

Prompt Preview module, filtered to a site's pages

Click "Preview" on any row to see, without spending a single AI call, exactly what would be composed and sent for that page: the page's own tone, anything assigned to you personally, and any organization-wide policy, with a running character/token count.

Compose and inspect preview showing the layered prompt composition

Calibrating the voice from real content

Writing a good tone-of-voice instruction by hand is tedious, and it's easy for it to drift from how the site actually reads. The "Calibrate Voice" button (in the Prompt Preview module) does it for you: paste a sample of on-brand copy, or pick one or more existing pages directly from the page tree, and AiM derives a tone instruction plus illustrative example text from that real content, ready to copy into a fragment.

Calibrate Voice modal with a rendered page inserted

For a whole site at once, run:

vendor/bin/typo3 aim:calibrateVoice

This crawls a site's root page and a representative slice of its subpages, derives the same tone instruction and examples from the combined real content, and saves the result directly as a fragment on the site's root page, schedulable as a recurring task, so a site's tone of voice can refresh itself as its content evolves.


For extension developers

Adding AI to your TYPO3 extension takes a few lines:

public function __construct(
    private readonly \B13\Aim\Ai $ai,
) {}

// Generate alt text for an image
$response = $this->ai->vision(
    imageData: base64_encode($imageContent),
    mimeType: 'image/jpeg',
    prompt: 'Generate alt text for this image',
    extensionKey: 'my_extension',
);

echo $response->content;
// "A golden retriever playing fetch in a sunny park"

Your extension doesn't know or care which AI provider is used. The admin decides. You just describe what you need.

All proxy methods

// Vision
$response = $this->ai->vision($imageData, 'image/jpeg', 'Describe this', extensionKey: 'my_ext');

// Text generation
$response = $this->ai->text('Write a summary of...', maxTokens: 200, extensionKey: 'my_ext');

// Translation
$response = $this->ai->translate('Hello', 'English', 'German', extensionKey: 'my_ext');

// Conversation
$response = $this->ai->conversation([new UserMessage('Hi')], extensionKey: 'my_ext');

// Streaming conversation
$response = $this->ai->conversationStream([new UserMessage('Tell me about TYPO3')], extensionKey: 'my_ext');
foreach ($response->streamIterator as $chunk) {
    echo $chunk;
    flush();
}

// Embeddings
$response = $this->ai->embed('TYPO3 is a CMS', dimensions: 256, extensionKey: 'my_ext');

// Image generation
$response = $this->ai->generateImage(
    prompt: 'A minimalist header illustration of a lighthouse at sunset',
    options: ['size' => '1536x1024', 'quality' => 'high'], // provider-specific, passed through as-is
    extensionKey: 'my_ext',
);
if ($response instanceof \B13\Aim\Response\ImageGenerationResponse) {
    foreach ($response->images as $image) {
        if ($image->isUrl()) {
            // Some providers return a temporary URL instead of the bytes.
            file_put_contents('header.png', file_get_contents($image->url));
        } else {
            // $image->data is base64-encoded, $image->mimeType e.g. "image/png"
            file_put_contents('header.png', base64_decode($image->data));
        }
    }
}

// Image generation guided by a reference image (style transfer)
$response = $this->ai->generateImage(
    prompt: 'The same lighthouse scene, but as a header for the "About us" page',
    referenceImageData: base64_encode(file_get_contents('brand-style-reference.png')),
    referenceMimeType: 'image/png',
    extensionKey: 'my_ext',
);

Request a specific provider

If your extension specifically needs OpenAI (e.g. for vision quality), request it but gracefully fall back if it's not available:

$response = $this->ai->vision(
    imageData: $data,
    mimeType: 'image/jpeg',
    prompt: 'Describe this product photo',
    provider: 'openai:*',  // prefer OpenAI, admin picks the model
    extensionKey: 'my_shop',
);

If OpenAI isn't configured, AiM uses whatever default provider the admin set up. Your extension never breaks.

Fluent builder for more control

$response = $this->ai->request()
    ->vision($imageData, 'image/jpeg')
    ->prompt('Generate alt text')
    ->systemPrompt('You are an accessibility expert.')
    ->maxTokens(100)
    ->temperature(0.3)
    ->provider('openai:*')
    ->from('my_extension')
    ->send();

The same builder covers image generation:

$response = $this->ai->request()
    ->image()
    ->prompt('A minimalist header illustration of a lighthouse at sunset')
    ->referenceImage($imageData, 'image/png')
    ->options(['size' => '1536x1024'])
    ->from('my_extension')
    ->send();

Register your own AI provider

Any extension can add AI providers:

#[AsAiProvider(
    identifier: 'my-provider',
    name: 'My Custom AI',
    supportedModels: ['my-model-v1' => 'My Model v1'],
)]
class MyProvider implements AiProviderInterface, TextGenerationCapableInterface
{
    public function processTextGenerationRequest(TextGenerationRequest $request): TextResponse
    {
        // Your implementation
    }
}

Auto-discovered via the PHP attribute. No registration code needed.

Add custom middleware

Intercept all AI requests for custom logic:

#[AsAiMiddleware(priority: 50)]
class MyMiddleware implements AiMiddlewareInterface
{
    public function process(
        AiRequestInterface $request,
        AiProviderInterface $provider,
        ProviderConfiguration $configuration,
        AiMiddlewareHandler $next,
    ): TextResponse {
        // Before: inspect, modify, or block the request
        $response = $next->handle($request, $provider, $configuration);
        // After: inspect or modify the response
        return $response;
    }
}

Requirements

  • TYPO3 v12.4, v13.4, or v14.0+
  • PHP 8.1+
  • At least one AI provider bridge (see table above)

License

GPL-2.0-or-later

Credits

Created by Oli Bartsch for b13 GmbH, Stuttgart.