PHPackages                             paparascaldev/sidekick - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. paparascaldev/sidekick

ActiveLibrary[API Development](/categories/api)

paparascaldev/sidekick
======================

A fluent Laravel package for integrating with OpenAI, Anthropic Claude, Mistral, and Cohere AI services

v2.0.1(3mo ago)31173↓50%GPL-2.0-or-laterPHPPHP ^8.2CI passing

Since Aug 31Pushed 3mo ago1 watchersCompare

[ Source](https://github.com/PapaRascal2020/sidekick)[ Packagist](https://packagist.org/packages/paparascaldev/sidekick)[ RSS](/packages/paparascaldev-sidekick/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (3)Versions (23)Used By (0)

 [![Laravel Package](https://camo.githubusercontent.com/f227df6c7fcb9a2c773af275ecc0e3f2f0d2a032abc1f8258cb7b9e06dd46f76/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d3130253246313125324631322d7265643f6c6f676f3d6c61726176656c266c6f676f436f6c6f723d7768697465)](https://laravel.com) [![PHP](https://camo.githubusercontent.com/cae70153729dc18ed989a9097736b1f9854ac844f5669437147c575aaffb82ca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e322532422d626c75653f6c6f676f3d706870266c6f676f436f6c6f723d7768697465)](https://camo.githubusercontent.com/cae70153729dc18ed989a9097736b1f9854ac844f5669437147c575aaffb82ca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e322532422d626c75653f6c6f676f3d706870266c6f676f436f6c6f723d7768697465) [![Latest Version](https://camo.githubusercontent.com/f18c80e09616b6aa2223abc5cf2156452dcce3906acf3c1e955f2516b4accfe9/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7061706172617363616c6465762f736964656b69636b3f6c6162656c3d4c6174657374)](https://camo.githubusercontent.com/f18c80e09616b6aa2223abc5cf2156452dcce3906acf3c1e955f2516b4accfe9/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7061706172617363616c6465762f736964656b69636b3f6c6162656c3d4c6174657374) [![Packagist](https://camo.githubusercontent.com/42c326fed90abe39a1ef4aff26de2f830ee6268f703791662a672c216cd74a0e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5061636b61676973742d4632384431413f6c6f676f3d5061636b6167697374266c6f676f436f6c6f723d7768697465)](https://packagist.org/packages/paparascaldev/sidekick)

[![Sidekick](sidekick.png)](sidekick.png)

[![Full Documentation](https://camo.githubusercontent.com/24a68a0ef30d85111f5af754a063186b56ad566d273e572c2c80bc95a2a30194/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f46756c6c253230446f63756d656e746174696f6e2d736964656b69636b666f726c61726176656c2e636f6d2d6566343434343f7374796c653d666f722d7468652d6261646765)](https://sidekickforlaravel.com)

Sidekick v2.0
=============

[](#sidekick-v20)

A fluent Laravel package for integrating with **OpenAI**, **Anthropic Claude**, **Mistral**, and **Cohere** AI services. Features a modern builder API, typed responses, streaming support, database-backed conversations, an embeddable chat widget, and first-class testing support.

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 10, 11, or 12

Installation
------------

[](#installation)

```
composer require paparascaldev/sidekick
php artisan sidekick:install
```

Or install manually:

```
composer require paparascaldev/sidekick
php artisan vendor:publish --tag=sidekick-config
php artisan migrate
```

Configuration
-------------

[](#configuration)

Add your API keys to `.env` (only add the providers you use):

```
SIDEKICK_OPENAI_TOKEN=your-openai-key
SIDEKICK_CLAUDE_TOKEN=your-anthropic-key
SIDEKICK_MISTRAL_TOKEN=your-mistral-key
SIDEKICK_COHERE_TOKEN=your-cohere-key
```

Publish and customize the config file:

```
php artisan vendor:publish --tag=sidekick-config
```

### Config File Overview

[](#config-file-overview)

The `config/sidekick.php` file includes:

```
return [
    // Default provider when none specified
    'default' => env('SIDEKICK_DEFAULT_PROVIDER', 'openai'),

    // Default provider + model per capability
    'defaults' => [
        'text'          => ['provider' => 'openai', 'model' => 'gpt-4o'],
        'image'         => ['provider' => 'openai', 'model' => 'dall-e-3'],
        'audio'         => ['provider' => 'openai', 'model' => 'tts-1'],
        'transcription' => ['provider' => 'openai', 'model' => 'whisper-1'],
        'embedding'     => ['provider' => 'openai', 'model' => 'text-embedding-3-small'],
        'moderation'    => ['provider' => 'openai', 'model' => 'text-moderation-latest'],
    ],

    // Provider API keys and base URLs
    'providers' => [
        'openai'    => ['api_key' => env('SIDEKICK_OPENAI_TOKEN'), 'base_url' => '...'],
        'anthropic' => ['api_key' => env('SIDEKICK_CLAUDE_TOKEN'), 'base_url' => '...'],
        'mistral'   => ['api_key' => env('SIDEKICK_MISTRAL_TOKEN'), 'base_url' => '...'],
        'cohere'    => ['api_key' => env('SIDEKICK_COHERE_TOKEN'), 'base_url' => '...'],
    ],

    // Register custom providers
    'custom_providers' => [],

    // Chat widget settings
    'widget' => [
        'enabled'       => env('SIDEKICK_WIDGET_ENABLED', false),
        'route_prefix'  => 'sidekick',
        'middleware'     => ['web'],
        'provider'      => env('SIDEKICK_WIDGET_PROVIDER', 'openai'),
        'model'         => env('SIDEKICK_WIDGET_MODEL', 'gpt-4o'),
        'system_prompt' => env('SIDEKICK_WIDGET_SYSTEM_PROMPT', 'You are a helpful assistant.'),
        'max_tokens'    => 1024,
    ],

    // HTTP timeout and retry settings
    'http' => [
        'timeout'         => env('SIDEKICK_HTTP_TIMEOUT', 30),
        'connect_timeout' => env('SIDEKICK_HTTP_CONNECT_TIMEOUT', 10),
        'retry'           => ['times' => 0, 'sleep' => 100],
    ],
];
```

Quick Start
-----------

[](#quick-start)

You can use the `Sidekick` facade or the `sidekick()` helper function:

```
use PapaRascalDev\Sidekick\Facades\Sidekick;

// Using the facade
$response = Sidekick::text()->withPrompt('Hello')->generate();

// Using the helper function
$response = sidekick()->text()->withPrompt('Hello')->generate();
```

### Text Generation

[](#text-generation)

```
$response = Sidekick::text()
    ->using('openai', 'gpt-4o')
    ->withSystemPrompt('You are a helpful assistant.')
    ->withPrompt('What is Laravel?')
    ->generate();

echo $response->text;                // "Laravel is a PHP web framework..."
echo $response->usage->totalTokens;  // 150
echo $response->meta->latencyMs;     // 523.4
echo $response->finishReason;        // "stop"
echo (string) $response;             // Same as $response->text
```

**All TextBuilder methods:**

MethodDescription`using(string $provider, ?string $model)`Set provider and model`withPrompt(string $prompt)`Add a user message`withSystemPrompt(string $prompt)`Set the system prompt`withMessages(array $messages)`Set the full message history (array of `Message` objects or arrays)`addMessage(Role $role, string $content)`Append a single message with a specific role`withMaxTokens(int $maxTokens)`Set max tokens (default: 1024)`withTemperature(float $temp)`Set temperature (default: 1.0)`generate(): TextResponse`Execute and return a `TextResponse``stream(): StreamResponse`Execute and return a streamable `StreamResponse`### Streaming

[](#streaming)

```
$stream = Sidekick::text()
    ->using('anthropic', 'claude-sonnet-4-20250514')
    ->withPrompt('Write a haiku about coding')
    ->stream();

// Iterate over chunks
foreach ($stream as $chunk) {
    echo $chunk;
}

// Get the full buffered text after iteration
$fullText = $stream->text();

// Or return as an SSE response from a controller
return $stream->toResponse();
```

### Conversations (with DB persistence)

[](#conversations-with-db-persistence)

```
// Start a conversation
$convo = Sidekick::conversation()
    ->using('openai', 'gpt-4o')
    ->withSystemPrompt('You are a travel advisor.')
    ->withMaxTokens(2048)
    ->begin();

$response = $convo->send('I want to visit Japan.');
echo $response->text;

// Get the conversation ID to resume later
$conversationId = $convo->getConversation()->id;

// Resume later
$convo = Sidekick::conversation()->resume($conversationId);
$response = $convo->send('What about accommodation?');

// Delete a conversation
$convo->delete();
```

**All ConversationBuilder methods:**

MethodDescription`using(string $provider, ?string $model)`Set provider and model`withSystemPrompt(string $prompt)`Set the system prompt`withMaxTokens(int $maxTokens)`Set max tokens (default: 1024)`begin(): self`Start a new conversation (persisted to DB)`resume(string $id): self`Resume an existing conversation by UUID`send(string $message): TextResponse`Send a message and get a response`delete(): bool`Delete the conversation and its messages`getConversation(): ?Conversation`Get the underlying Eloquent model### Image Generation

[](#image-generation)

```
$response = Sidekick::image()
    ->using('openai', 'dall-e-3')
    ->withPrompt('A sunset over mountains')
    ->withSize('1024x1024')
    ->withQuality('hd')
    ->count(2)
    ->generate();

echo $response->url();           // First image URL
echo $response->urls;            // Array of all URLs
echo $response->revisedPrompt;   // DALL-E's revised prompt (if any)
```

**All ImageBuilder methods:**

MethodDescription`using(string $provider, ?string $model)`Set provider and model`withPrompt(string $prompt)`Set the image prompt`withSize(string $size)`Set dimensions (default: `1024x1024`)`withQuality(string $quality)`Set quality: `standard` or `hd` (default: `standard`)`count(int $count)`Number of images to generate (default: 1)`generate(): ImageResponse`Execute and return an `ImageResponse`### Audio (Text-to-Speech)

[](#audio-text-to-speech)

```
$response = Sidekick::audio()
    ->using('openai', 'tts-1')
    ->withText('Hello, welcome to Sidekick!')
    ->withVoice('nova')
    ->withFormat('mp3')
    ->generate();

$response->save('audio/welcome.mp3');       // Save to default disk
$response->save('audio/welcome.mp3', 's3'); // Save to specific disk
echo $response->format;                     // "mp3"
```

**All AudioBuilder methods:**

MethodDescription`using(string $provider, ?string $model)`Set provider and model`withText(string $text)`Set the text to speak`withVoice(string $voice)`Set the voice (default: `alloy`)`withFormat(string $format)`Set audio format (default: `mp3`)`generate(): AudioResponse`Execute and return an `AudioResponse`### Transcription

[](#transcription)

```
$response = Sidekick::transcription()
    ->using('openai', 'whisper-1')
    ->withFile('/path/to/audio.mp3')
    ->withLanguage('en')
    ->generate();

echo $response->text;       // Transcribed text
echo $response->language;   // "en"
echo $response->duration;   // Duration in seconds
echo (string) $response;    // Same as $response->text
```

**All TranscriptionBuilder methods:**

MethodDescription`using(string $provider, ?string $model)`Set provider and model`withFile(string $filePath)`Path to the audio file`withLanguage(string $language)`Hint the language (optional)`generate(): TranscriptionResponse`Execute and return a `TranscriptionResponse`### Embeddings

[](#embeddings)

```
$response = Sidekick::embedding()
    ->using('openai', 'text-embedding-3-small')
    ->withInput('Laravel is a great framework')
    ->generate();

$vector = $response->vector();      // First embedding vector (array of floats)
$all = $response->embeddings;       // All embedding vectors
echo $response->usage->totalTokens; // Token usage
```

**All EmbeddingBuilder methods:**

MethodDescription`using(string $provider, ?string $model)`Set provider and model`withInput(string|array $input)`Text or array of texts to embed`generate(): EmbeddingResponse`Execute and return an `EmbeddingResponse`### Moderation

[](#moderation)

```
$response = Sidekick::moderation()
    ->using('openai', 'text-moderation-latest')
    ->withContent('Some text to moderate')
    ->generate();

if ($response->isFlagged()) {
    // Content was flagged
}

if ($response->isFlaggedFor('violence')) {
    // Specifically flagged for violence
}

// Inspect all categories
foreach ($response->categories as $category) {
    echo "{$category->category}: flagged={$category->flagged}, score={$category->score}\n";
}
```

**All ModerationBuilder methods:**

MethodDescription`using(string $provider, ?string $model)`Set provider and model`withContent(string $content)`Text to moderate`generate(): ModerationResponse`Execute and return a `ModerationResponse`### Utility Methods

[](#utility-methods)

Convenience methods that use the default text provider:

```
// Summarize text (returns string)
$summary = Sidekick::summarize('Long text here...', maxLength: 500);

// Translate text (returns string)
$translated = Sidekick::translate('Hello', 'French');

// Extract keywords (returns string, comma-separated)
$keywords = Sidekick::extractKeywords('Some article text...');
```

Knowledge Base / RAG
--------------------

[](#knowledge-base--rag)

Sidekick includes a built-in RAG (Retrieval-Augmented Generation) system that lets you store business knowledge and ground AI responses in real data — preventing hallucinations about return policies, pricing, support hours, etc.

### Setup

[](#setup)

RAG works out of the box with the default config. The `knowledge` section in `config/sidekick.php` controls embedding provider, chunk sizes, and search settings:

```
'knowledge' => [
    'embedding' => ['provider' => 'openai', 'model' => 'text-embedding-3-small'],
    'chunking'  => ['chunk_size' => 2000, 'overlap' => 200],
    'search'    => ['default_limit' => 5, 'min_score' => 0.3, 'driver' => VectorSearch::class],
],
```

### Ingesting Content

[](#ingesting-content)

```
use PapaRascalDev\Sidekick\Facades\Sidekick;

// Ingest text
Sidekick::knowledge('my-kb')
    ->ingest('Our return policy is 30 days with receipt.', 'faq');

// Ingest a file
Sidekick::knowledge('my-kb')
    ->ingestFile('/path/to/faq.md');

// Ingest multiple texts
Sidekick::knowledge('my-kb')
    ->ingestMany(['Text one...', 'Text two...'], 'bulk-source');

// Use a different embedding provider
Sidekick::knowledge('my-kb')
    ->using('mistral', 'mistral-embed')
    ->ingest('Content here...');
```

Or use the Artisan command:

```
# Ingest a file
php artisan sidekick:ingest my-kb --file=/path/to/faq.md

# Ingest inline text
php artisan sidekick:ingest my-kb --text="Return policy is 30 days."

# Ingest a directory of .txt/.md/.html/.csv files
php artisan sidekick:ingest my-kb --dir=/path/to/docs

# Purge and re-ingest
php artisan sidekick:ingest my-kb --purge --dir=/path/to/docs
```

### Searching

[](#searching)

```
// Search for relevant chunks
$results = Sidekick::knowledge('my-kb')->search('What is your return policy?');

foreach ($results as $chunk) {
    echo $chunk->content;       // The text content
    echo $chunk->similarity;    // Cosine similarity score
    echo $chunk->source;        // Source label
}
```

### Ask (Search + Generate)

[](#ask-search--generate)

```
// One-liner: search KB and generate a grounded answer
$answer = Sidekick::knowledge('my-kb')->ask('What is your return policy?');
```

### Widget Integration

[](#widget-integration)

Connect a knowledge base to the chat widget so it answers from your data:

```
SIDEKICK_WIDGET_ENABLED=true
SIDEKICK_WIDGET_KNOWLEDGE_BASE=my-kb
```

Or in `config/sidekick.php`:

```
'widget' => [
    'knowledge_base'    => 'my-kb',
    'rag_context_chunks' => 5,
    'rag_min_score'      => 0.3,
],
```

When configured, the widget will automatically search the knowledge base for each user message and inject relevant context into the system prompt. If RAG fails (API error, empty KB), it falls back gracefully to the original system prompt.

### Custom Search Drivers

[](#custom-search-drivers)

The default `VectorSearch` driver computes cosine similarity in PHP. For production workloads, you can swap in a custom driver (e.g., pgvector, Pinecone):

```
// Implement the SearchesKnowledge contract
use PapaRascalDev\Sidekick\Contracts\SearchesKnowledge;

class PgVectorSearch implements SearchesKnowledge
{
    public function search(KnowledgeBase $kb, array $queryEmbedding, int $limit = 5, float $minScore = 0.3): Collection
    {
        // Your pgvector implementation
    }
}

// Register in config/sidekick.php
'knowledge' => [
    'search' => ['driver' => \App\Search\PgVectorSearch::class],
],
```

### Managing Knowledge Bases

[](#managing-knowledge-bases)

```
$kb = Sidekick::knowledge('my-kb');

$kb->chunkCount();           // Number of chunks stored
$kb->purge();                // Delete all chunks
$kb->getKnowledgeBase();     // Get the Eloquent model
```

Chat Widget
-----------

[](#chat-widget)

Sidekick ships with an Alpine.js-powered chat widget you can embed in any Blade template. No Livewire required.

### Enable the widget

[](#enable-the-widget)

In your `.env`:

```
SIDEKICK_WIDGET_ENABLED=true
SIDEKICK_WIDGET_PROVIDER=openai
SIDEKICK_WIDGET_MODEL=gpt-4o
SIDEKICK_WIDGET_SYSTEM_PROMPT="You are a helpful assistant."
```

### Add to a Blade template

[](#add-to-a-blade-template)

```

```

**Props:**

PropDefaultOptions`position``bottom-right``bottom-right`, `bottom-left`, `top-right`, `top-left``theme``light``light`, `dark``title``Chat Assistant`Any string`placeholder``Type a message...`Any string`button-label``Chat`Any stringMake sure your layout includes Alpine.js and a CSRF meta tag:

```

```

Custom Providers
----------------

[](#custom-providers)

Register custom providers at runtime or via config:

```
// Runtime registration
Sidekick::registerProvider('ollama', function ($app) {
    return new OllamaProvider(config('sidekick.providers.ollama'));
});

// Or in config/sidekick.php
'custom_providers' => [
    'ollama' => \App\Sidekick\OllamaProvider::class,
],
```

Custom providers should implement `ProviderContract` and the relevant capability interfaces (`ProvidesText`, `ProvidesImages`, `ProvidesAudio`, `ProvidesTranscription`, `ProvidesEmbeddings`, `ProvidesModeration`).

Testing
-------

[](#testing)

Sidekick provides first-class testing support with `Sidekick::fake()`:

```
use PapaRascalDev\Sidekick\Facades\Sidekick;
use PapaRascalDev\Sidekick\Responses\TextResponse;
use PapaRascalDev\Sidekick\ValueObjects\Meta;
use PapaRascalDev\Sidekick\ValueObjects\Usage;

public function test_my_feature(): void
{
    $fake = Sidekick::fake([
        new TextResponse(
            text: 'Mocked response',
            usage: new Usage(10, 20, 30),
            meta: new Meta('openai', 'gpt-4o'),
        ),
    ]);

    // ... run your code that uses Sidekick ...

    $fake->assertTextGenerated();       // At least one text generation
    $fake->assertTextGenerated(2);      // Exactly 2 text generations
    $fake->assertNothingSent();         // No API calls were made
    $fake->assertProviderUsed('openai');
    $fake->assertModelUsed('gpt-4o');
    $fake->assertPromptContains('expected text');
}
```

Events
------

[](#events)

Sidekick dispatches Laravel events you can listen to:

EventPropertiesWhen`RequestSending``provider`, `model`, `capability`Before a request is sent`ResponseReceived``provider`, `model`, `capability`, `response`After a successful response`StreamChunkReceived``provider`, `model`, `chunk`For each streaming chunk`RequestFailed``provider`, `model`, `capability`, `exception`When a request failsAll events are in the `PapaRascalDev\Sidekick\Events` namespace.

Provider Capabilities
---------------------

[](#provider-capabilities)

CapabilityOpenAIAnthropicMistralCohereTextYesYesYesYesImageYes---Audio (TTS)Yes---TranscriptionYes---EmbeddingYes-Yes-ModerationYes---API Key Resources
-----------------

[](#api-key-resources)

- [OpenAI](https://platform.openai.com)
- [Anthropic](https://console.anthropic.com)
- [Mistral](https://console.mistral.ai)
- [Cohere](https://dashboard.cohere.com)

Contributing
------------

[](#contributing)

Contributions are welcome! Whether it's bug reports, feature requests, documentation improvements, or code — we'd love your help.

- **Report a bug or request a feature**: [Open an issue](https://github.com/PapaRascal2020/sidekick/issues)
- **Submit code**: Fork the repo, create a branch, and [open a pull request](https://github.com/PapaRascal2020/sidekick/pulls)
- **Questions or ideas**: [Start a discussion](https://github.com/PapaRascal2020/sidekick/discussions)

See [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide (forking, branching, PR process, coding standards).

License
-------

[](#license)

GPL-2.0-or-later. See [LICENSE](LICENSE) for details.

Stargazers
----------

[](#stargazers)

[![Stargazers repo roster for @PapaRascal2020/sidekick](https://camo.githubusercontent.com/19e2ce1c40a94ac27f1b1f0d7a6b81294901ffd5947cc083c2a8518dacadb11c/68747470733a2f2f7265706f726f737465722e636f6d2f73746172732f6461726b2f6e6f746578742f5061706152617363616c323032302f736964656b69636b)](https://github.com/PapaRascal2020/sidekick/stargazers)

###  Health Score

47

—

FairBetter than 94% of packages

Maintenance82

Actively maintained with recent releases

Popularity23

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity61

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~28 days

Recently: every ~127 days

Total

20

Last Release

90d ago

Major Versions

v0.2.8 → v2.02026-02-17

PHP version history (2 changes)v0.1.6PHP ^8.0

v2.0PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/fe739fae0959de5816fffa368915b6e23e83483556a112aa8b07a7749ba286d0?d=identicon)[PapaRascalDev](/maintainers/PapaRascalDev)

---

Top Contributors

[![PapaRascal2020](https://avatars.githubusercontent.com/u/61059402?v=4)](https://github.com/PapaRascal2020 "PapaRascal2020 (138 commits)")

---

Tags

aiclaude-aicoherelaravel-packagemistralaiopen-sourceopenai

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/paparascaldev-sidekick/health.svg)

```
[![Health](https://phpackages.com/badges/paparascaldev-sidekick/health.svg)](https://phpackages.com/packages/paparascaldev-sidekick)
```

###  Alternatives

[darkaonline/l5-swagger

OpenApi or Swagger integration to Laravel

2.9k34.0M112](/packages/darkaonline-l5-swagger)[echolabsdev/prism

A powerful Laravel package for integrating Large Language Models (LLMs) into your applications.

2.3k388.3k10](/packages/echolabsdev-prism)[sburina/laravel-whmcs-up

WHMCS API client and user provider for Laravel

271.3k](/packages/sburina-laravel-whmcs-up)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
