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

# Tutoriel bot - Laravel Bluesky

> Version Laravel du tutoriel officiel de bot AT Protocol. Implémentation d'un bot de publication, d'un bot de réponse et d'un bot de labellisation avec le package laravel-bluesky.

## Vue d'ensemble

Cette page est la version Laravel du [tutoriel officiel de bot AT Protocol](https://atproto.com/ja/guides/bot-tutorial). Elle explique comment implémenter en PHP/Laravel avec le package `laravel-bluesky` ce que le tutoriel officiel montre en TypeScript.

Le tutoriel officiel télécharge à chaque fois les fichiers Lexicon via la commande `lex`, mais `laravel-bluesky` intègre déjà tous les Lexicons via [atproto-lexicon-contracts](https://github.com/invokable/atproto-lexicon-contracts) : cette étape est donc superflue. À l'aide des commandes Artisan et des méthodes du trait `HasShortHand`, la quasi-totalité des opérations est réalisable.

```mermaid theme={null}
graph LR
    A["Tutoriel officiel<br>(TypeScript)"] -->|"Version Laravel"| B["laravel-bluesky"]
    B --> C["Commandes Artisan"]
    B --> D["Trait HasShortHand"]
    B --> E["Planification de tâches<br>/ GitHub Actions"]
```

## Prérequis

* Le package `laravel-bluesky` doit être installé
* Vous devez disposer d'un compte Bluesky et d'un App Password

Pour la procédure d'installation, voir [Laravel Bluesky](/fr/packages/laravel-bluesky/index).

```dotenv theme={null}
BLUESKY_IDENTIFIER=yourbot.bsky.social
BLUESKY_APP_PASSWORD=xxxx-xxxx-xxxx-xxxx
```

***

## Partie 1 : bot de base (publication)

### Créer une commande Artisan

Créez la commande du bot avec `php artisan make:command`.

```bash theme={null}
php artisan make:command BotPostCommand
```

Modifiez le fichier généré `app/Console/Commands/BotPostCommand.php`.

```php theme={null}
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Revolution\Bluesky\Facades\Bluesky;

class BotPostCommand extends Command
{
    protected $signature = 'bot:post';

    protected $description = 'Post to Bluesky';

    public function handle(): void
    {
        Bluesky::login(
            identifier: config('bluesky.identifier'),
            password: config('bluesky.password'),
        )->post('🙂');

        $this->info('Posted successfully.');
    }
}
```

### Exécution manuelle

```bash theme={null}
php artisan bot:post
```

### Exécution automatique via le planificateur

Ajoutez une planification dans `routes/console.php`.

```php theme={null}
use Illuminate\Support\Facades\Schedule;

// Publier toutes les 3 heures
Schedule::command('bot:post')->everyThreeHours();
```

Pour activer le planificateur, ajoutez la ligne suivante à cron :

```bash theme={null}
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
```

### Exécution automatique via GitHub Actions

Si vous n'avez pas de serveur, GitHub Actions permet également d'exécuter automatiquement la commande.

```yaml theme={null}
# .github/workflows/bot.yml
name: Bot Post

on:
  schedule:
    - cron: '0 */3 * * *'  # Toutes les 3 heures
  workflow_dispatch:

jobs:
  post:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: shivammathur/setup-php@v2
        with:
          php-version: '8.4'
      - run: composer install --no-dev --optimize-autoloader
      - run: php artisan bot:post
        env:
          BLUESKY_IDENTIFIER: ${{ secrets.BLUESKY_IDENTIFIER }}
          BLUESKY_APP_PASSWORD: ${{ secrets.BLUESKY_APP_PASSWORD }}
```

<Tip>
  Enregistrez `BLUESKY_IDENTIFIER` et `BLUESKY_APP_PASSWORD` dans les secrets de GitHub Actions.
</Tip>

***

## Partie 2 : bot de réponse (surveillance des mentions)

Créons un bot qui répond automatiquement aux mentions. Nous présenterons également un exemple générant des réponses par IA.

### Récupérer les notifications et répondre aux mentions

```bash theme={null}
php artisan make:command BotReplyCommand
```

```php theme={null}
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Record\Post;
use Revolution\Bluesky\Types\ReplyRef;
use Revolution\Bluesky\Types\StrongRef;

class BotReplyCommand extends Command
{
    protected $signature = 'bot:reply';

    protected $description = 'Reply to mentions on Bluesky';

    public function handle(): void
    {
        Bluesky::login(
            identifier: config('bluesky.identifier'),
            password: config('bluesky.password'),
        );

        $notifications = Bluesky::listNotifications(limit: 20)->json('notifications', []);

        foreach ($notifications as $notification) {
            // Ne traiter que les notifications de type mention
            if (data_get($notification, 'reason') !== 'mention') {
                continue;
            }

            // Ignorer les notifications déjà lues (isRead à true = déjà traitées)
            if (data_get($notification, 'isRead')) {
                continue;
            }

            $uri = data_get($notification, 'uri');
            $cid = data_get($notification, 'cid');

            if (! $uri || ! $cid) {
                continue;
            }

            $ref = StrongRef::to(uri: $uri, cid: $cid);
            $reply = ReplyRef::to(root: $ref, parent: $ref);

            $post = Post::create('Bonjour ! Merci pour la mention. 🙂')
                ->reply($reply);

            Bluesky::post($post);

            $this->info("Replied to: {$uri}");
        }

        // Marquer les notifications comme lues
        Bluesky::updateSeenNotifications(now()->toISOString());
    }
}
```

<Info>
  Si le root du thread diffère, récupérez les informations du thread avec `app.bsky.feed.getPostThread` et affectez-les à `root`. Cette implémentation simplifiée traite le post parent comme root.
</Info>

### Planifier le polling

```php theme={null}
// routes/console.php
use Illuminate\Support\Facades\Schedule;

Schedule::command('bot:reply')->everyFiveMinutes();
```

### Générer les réponses avec l'IA

En combinant le package `laravel/ai` et le pilote `laravel-amazon-bedrock`, vous pouvez générer des réponses IA adaptées au contenu de la mention.

```bash theme={null}
composer require laravel/ai revolution/laravel-amazon-bedrock
```

Créez un agent IA.

```php theme={null}
<?php

namespace App\Ai\Agents;

use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Promptable;

class BotReplyAgent implements Agent
{
    use Promptable;

    public function instructions(): string
    {
        return 'Vous êtes un bot amical qui interagit sur Bluesky. '
            . 'Générez en français une réponse courte et chaleureuse au message de l\'utilisateur. '
            . 'La réponse doit faire au maximum 200 caractères.';
    }
}
```

Utilisez la réponse IA dans la commande.

```php theme={null}
<?php

namespace App\Console\Commands;

use App\Ai\Agents\BotReplyAgent;
use Illuminate\Console\Command;
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Record\Post;
use Revolution\Bluesky\Types\ReplyRef;
use Revolution\Bluesky\Types\StrongRef;

class BotReplyCommand extends Command
{
    protected $signature = 'bot:reply';

    protected $description = 'Reply to mentions on Bluesky using AI';

    public function handle(): void
    {
        Bluesky::login(
            identifier: config('bluesky.identifier'),
            password: config('bluesky.password'),
        );

        $notifications = Bluesky::listNotifications(limit: 20)->json('notifications', []);

        foreach ($notifications as $notification) {
            if (data_get($notification, 'reason') !== 'mention') {
                continue;
            }

            if (data_get($notification, 'isRead')) {
                continue;
            }

            $uri = data_get($notification, 'uri');
            $cid = data_get($notification, 'cid');
            $mentionText = data_get($notification, 'record.text', '');

            if (! $uri || ! $cid) {
                continue;
            }

            // Générer la réponse via IA
            $replyText = (new BotReplyAgent)->prompt($mentionText)->text;

            $ref = StrongRef::to(uri: $uri, cid: $cid);
            $reply = ReplyRef::to(root: $ref, parent: $ref);

            $post = Post::create($replyText)->reply($reply);

            Bluesky::post($post);

            $this->info("AI replied to: {$uri}");
        }

        Bluesky::updateSeenNotifications(now()->toISOString());
    }
}
```

<Tip>
  Pour la configuration de `laravel-amazon-bedrock`, voir [Pilote Amazon Bedrock](/fr/packages/laravel-amazon-bedrock).
</Tip>

***

## Partie 3 : bot de label

Fonctionnalité équivalente à `labelAsBot` du tutoriel officiel. Il s'agit d'ajouter un self label au profil du compte bot pour signaler explicitement qu'il s'agit d'un compte automatisé.

<Info>
  La labellisation ne s'exécute qu'une seule fois, lors de la configuration initiale. Elle est implémentée en tant que commande distincte des parties 1 et 2.
</Info>

### Créer la commande du bot de label

```bash theme={null}
php artisan make:command BotLabelCommand
```

```php theme={null}
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Record\Profile;
use Revolution\Bluesky\Types\SelfLabels;

class BotLabelCommand extends Command
{
    protected $signature = 'bot:label';

    protected $description = 'Add bot self-label to the Bluesky profile';

    public function handle(): void
    {
        Bluesky::login(
            identifier: config('bluesky.identifier'),
            password: config('bluesky.password'),
        )->upsertProfile(function (Profile $profile) {
            // Appliquer le label !bot
            $profile->labels(SelfLabels::make(['!bot']));
        });

        $this->info('Bot label applied successfully.');
    }
}
```

### Exécution

```bash theme={null}
php artisan bot:label
```

N'exécutez cette commande qu'une seule fois lors de la configuration initiale du bot. Le label est stocké de manière permanente dans le profil.

<Warning>
  `!bot` est un self label standard de Bluesky. Il est recommandé de toujours l'appliquer aux comptes de type bot.
</Warning>

***

## Autres tutoriels officiels

Le tutoriel officiel AT Protocol traite d'autres sujets. Voici l'état de la prise en charge dans `laravel-bluesky`.

### Flux personnalisés

[Feed Generator](/fr/packages/laravel-bluesky/feed-generator) décrit en détail comment implémenter un feed generator personnalisé avec Laravel.

### Authentification OAuth

[Socialite](/fr/packages/laravel-bluesky/socialite) explique comment implémenter l'authentification OAuth avec Laravel Socialite. L'implémentation est plus simple que dans le tutoriel officiel.

### Application sociale (statusphere)

Une version Laravel de statusphere est publiée sous [invokable/statusphere](https://github.com/invokable/statusphere). Elle s'appuie sur une version antérieure de statusphere qui n'utilise pas encore les commandes `lex` ou `tap`, elle diffère donc légèrement du tutoriel officiel le plus récent.

## Liens utiles

* [Tutoriel officiel de bot AT Protocol (anglais)](https://atproto.com/guides/bot-tutorial)
* [Tutoriel officiel de bot AT Protocol (japonais)](https://atproto.com/ja/guides/bot-tutorial)
* [laravel-bluesky](https://github.com/invokable/laravel-bluesky)
* [BlueskyManager et HasShortHand](/fr/packages/laravel-bluesky/bluesky-manager)
* [Canal de notification](/fr/packages/laravel-bluesky/notification)
* [Pilote Amazon Bedrock](/fr/packages/laravel-amazon-bedrock)


## Related topics

- [Laravel Socialite (authentification sociale)](/fr/socialite.md)
- [Webhook / Bot - LINE SDK for Laravel](/fr/packages/laravel-line-sdk/bot.md)
- [Feed Generator](/fr/packages/laravel-bluesky/feed-generator.md)
- [Tutoriel - Laravel Console Starter](/fr/packages/laravel-console-starter/tutorial.md)
- [Laravel Bluesky](/fr/packages/laravel-bluesky/index.md)
