AI Provider Setup

All AI calls go through one service -- AiService. Point it at OpenAI or Anthropic and everything works: content generation, SEO analysis, accessibility checks, image comparison, the chat assistant.

Supported providers

Provider Key Env prefix
OpenAI openai OPENAI_
Anthropic Claude anthropic ANTHROPIC_

Both handle text, chat, vision, and tool calls.

Quick start

OpenAI

TEXTSTEM_AI_PROVIDER=openai
OPENAI_API_KEY=sk-...
OPENAI_MODEL=gpt-4o-mini

Anthropic

TEXTSTEM_AI_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-...
ANTHROPIC_MODEL=claude-haiku-4-5-20251001

TEXTSTEM_AI_PROVIDER decides which one runs. If you have keys for both, only the active provider is used.

Configuration

Active provider

TEXTSTEM_AI_PROVIDER=openai   # 'openai' or 'anthropic' (default: openai)
TEXTSTEM_AI_MODEL=            # blank = use the provider's default

TEXTSTEM_AI_MODEL overrides the model for everything. Leave it blank and it falls back to OPENAI_MODEL or ANTHROPIC_MODEL.

OpenAI

OPENAI_API_KEY=sk-...
OPENAI_MODEL=gpt-4o-mini
OPENAI_USE_QUEUE=true        # default: true

Get a key at platform.openai.com. Models starting with gpt-, o1, or o3 are auto-routed to OpenAI if you don't set TEXTSTEM_AI_PROVIDER.

Anthropic

ANTHROPIC_API_KEY=sk-ant-...
ANTHROPIC_MODEL=claude-haiku-4-5-20251001

Get a key at console.anthropic.com. Models starting with claude- are auto-routed to Anthropic.

What uses AI

With a provider configured:

  • Content generation -- article body, descriptions, teasers, tags
  • Alt text -- generated when you upload an image
  • Keywords -- pulled from page content
  • SEO analysis -- scored and annotated (see SEO_USE_AI)
  • Accessibility analysis -- WCAG 2.1 checks against the live page HTML
  • Image duplicates -- vision comparison on upload (requires textstemapp.images.comparison_driver=openai; defaults to fingerprint matching)
  • Chat assistant -- admin panel chat that can read and write content

Disable anything you don't need -- see the SEO and accessibility docs.

Queue

Jobs run through the queue by default. You need a worker running:

php artisan queue:work

To run synchronously (development only):

OPENAI_USE_QUEUE=false
ACCESSIBILITY_USE_QUEUE=false
SEO_USE_QUEUE=false

Usage tracking

Every call is logged to ai_token_usage -- provider, model, feature, token counts, cost. Find it in the admin panel under Tools > OpenAI Usage, or query it directly.

Custom providers

Implement LlmProvider and register it:

use Medialight\Textstem\Orchestration\Providers\LlmProviderRegistry;

$this->app->resolving(LlmProviderRegistry::class, function (LlmProviderRegistry $registry) {
    $registry->register(new MyCustomProvider());
});

Set TEXTSTEM_AI_PROVIDER to whatever key() returns.

esc