> ## Documentation Index
> Fetch the complete documentation index at: https://docs.filarank.com/llms.txt
> Use this file to discover all available pages before exploring further.

# AI features

> Bring-your-own-key OpenAI, Gemini, or Anthropic for SEO fixes, audit plans, keyword enrichment, and more.

FilaRank is bring-your-own-key. Add a key under **FilaRank SEO → SEO Settings** (stored encrypted via `Crypt`), or fall back to env: `OPENAI_API_KEY`, `GEMINI_API_KEY`, `ANTHROPIC_API_KEY`.

Nothing runs unless a key is configured. AI actions hide themselves when `AiService::isConfigured()` is false.

| Feature            | Where                          | What it does                                                                                        |
| ------------------ | ------------------------------ | --------------------------------------------------------------------------------------------------- |
| Fix with AI        | SEO section header, per record | Suggests title, meta description, and slug, shown as a before/after diff before anything is written |
| Audit fix plan     | SEO Health → Technical audit   | Turns an audit issue into a numbered remediation plan                                               |
| Keyword enrichment | Keyword Research               | Adds intent, difficulty, and volume estimates to a seed keyword                                     |
| Competitor gaps    | Competitors                    | Suggests keywords a competitor likely targets that you don't                                        |
| Backlink toxicity  | Backlinks                      | Scores a link 0–100 for spamminess                                                                  |

Every call is logged to `filarank_ai_logs` with provider, model, token counts, and estimated cost, surfaced as a monthly spend figure on the Overview dashboard.

Use **Test AI connection** in Settings to do a real round trip and surface a bad key or unsupported model immediately.

## Choosing a model

The model dropdown in **SEO Settings** is built from config, and that list is the allowlist. Add a model and it becomes selectable, with no code change:

```php theme={null}
'ai' => [
    'providers' => [
        'openai' => [
            'api_key' => env('OPENAI_API_KEY'),
            'models' => ['gpt-4o-mini', 'gpt-4o', 'your-new-model'],
            'rates' => [
                'default' => ['in' => 0.15, 'out' => 0.60],
                'gpt-4o' => ['in' => 2.50, 'out' => 10.00],
            ],
        ],
    ],
],
```

The first entry is the default when nothing has been chosen. A saved selection is validated against the list on every read, so removing a model from config quietly falls back to that first entry rather than erroring.

`rates` are USD per 1M tokens and drive the spend estimate. Key a rate by model name to price it exactly; anything without its own entry uses `default`. Getting this wrong only skews the dashboard figure, never a request.

<Warning>
  Requests are built per provider, not per model. The OpenAI provider sends `temperature` and a JSON response format, so reasoning-style models that reject a custom temperature will fail with a 400. Because publishing the config replaces the package's `ai` block wholesale, a published copy will not inherit providers added in later versions.
</Warning>

## Using the service in code

```php theme={null}
use Usamamuneerchaudhary\FilaRank\Ai\AiService;
use Usamamuneerchaudhary\FilaRank\Ai\Providers\FakeProvider;

$suggestion = app(AiService::class)->suggestSeoFix([
    'title' => $post->seo->title,
    'description' => $post->seo->description,
    'focus_keyword' => 'coffee beans',
    'slug' => $post->slug,
    'content' => $post->content,
]);

// Deterministic output for tests (local/testing environments only):
(new AiService)->useProvider(new FakeProvider)->suggestSeoFix([...]);
```

All provider failures are wrapped in `AiRequestException` with credentials stripped out, so a bad key or rate limit never leaks a secret into your logs or a notification. The fake provider is refused outside `local` and `testing`.
