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

# Tutorial per bot - Laravel Bluesky

> Versione Laravel del tutorial ufficiale per bot di AT Protocol. Implementa bot per post, bot di risposta e bot per label con il pacchetto laravel-bluesky.

## Panoramica

Questa pagina è la versione Laravel del [tutorial ufficiale per bot di AT Protocol](https://atproto.com/ja/guides/bot-tutorial). Spiega come implementare in PHP/Laravel, tramite il pacchetto `laravel-bluesky`, i contenuti pensati per TypeScript.

Nel tutorial ufficiale il file Lexicon viene scaricato di volta in volta con il comando `lex`, ma in `laravel-bluesky` tutti i Lexicon sono già inclusi in anticipo tramite [atproto-lexicon-contracts](https://github.com/invokable/atproto-lexicon-contracts), quindi questo passaggio non è necessario. Con i comandi Artisan e i metodi del trait `HasShortHand` puoi realizzare praticamente tutte le operazioni.

```mermaid theme={null}
graph LR
    A["Tutorial ufficiale<br>(TypeScript)"] -->|"Versione Laravel"| B["laravel-bluesky"]
    B --> C["Comando Artisan"]
    B --> D["Trait HasShortHand"]
    B --> E["Task scheduler<br>/ GitHub Actions"]
```

## Prerequisiti

* Il pacchetto `laravel-bluesky` è già installato
* Devi avere un account Bluesky e una app password

Per le istruzioni di installazione consulta [Laravel Bluesky](/it/packages/laravel-bluesky/index).

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

***

## Parte 1: bot base (post)

### Creare un comando Artisan

Crea un comando per il bot con `php artisan make:command`.

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

Modifica il file generato `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.');
    }
}
```

### Esecuzione manuale

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

### Esecuzione automatica con il task scheduler

Aggiungi le impostazioni per l'esecuzione periodica in `routes/console.php`.

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

// Post ogni 3 ore
Schedule::command('bot:post')->everyThreeHours();
```

Per abilitare lo scheduler, imposta il seguente cron.

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

### Esecuzione automatica con GitHub Actions

Se non hai un server, puoi comunque eseguirlo automaticamente con GitHub Actions.

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

on:
  schedule:
    - cron: '0 */3 * * *'  # ogni 3 ore
  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>
  Registra `BLUESKY_IDENTIFIER` e `BLUESKY_APP_PASSWORD` nei secret di GitHub Actions.
</Tip>

***

## Parte 2: bot di risposta (monitoraggio delle menzioni)

Creiamo un bot che risponde automaticamente alle menzioni. Vediamo anche un esempio in cui la risposta viene generata da un'AI.

### Recuperare le notifiche e rispondere alle menzioni

```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) {
            // Elabora solo le notifiche di menzione
            if (data_get($notification, 'reason') !== 'mention') {
                continue;
            }

            // Salta le notifiche già lette (isRead a true sono già elaborate)
            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('Ciao! Grazie per la menzione. 🙂')
                ->reply($reply);

            Bluesky::post($post);

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

        // Segna le notifiche come lette
        Bluesky::updateSeenNotifications(now()->toISOString());
    }
}
```

<Info>
  Se il root del thread è diverso, recupera le informazioni del thread con `app.bsky.feed.getPostThread` e impostalo come `root`. In questa implementazione semplificata, il post padre viene usato come root.
</Info>

### Schedulare il polling

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

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

### Generare la risposta con l'AI

Combinando il pacchetto `laravel/ai` con il driver `laravel-amazon-bedrock`, puoi generare risposte AI adattate al contenuto della menzione.

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

Crea un agente AI.

```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 'Sei un bot amichevole attivo su Bluesky.'
            . ' Genera risposte brevi e cordiali in italiano ai messaggi degli utenti.'
            . ' Le risposte devono essere entro 200 caratteri.';
    }
}
```

Usa le risposte AI nel comando.

```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;
            }

            // Genera la risposta con l'AI
            $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>
  Per la configurazione di `laravel-amazon-bedrock` consulta il [driver Amazon Bedrock](/it/packages/laravel-amazon-bedrock).
</Tip>

***

## Parte 3: bot per label

È la funzionalità equivalente a `labelAsBot` del tutorial ufficiale. Applica una self-label al profilo dell'account bot per dichiarare esplicitamente che si tratta di un account automatizzato.

<Info>
  L'applicazione della label va eseguita una sola volta, in fase di configurazione iniziale. Va implementata come comando separato dai comandi della Parte 1 e 2.
</Info>

### Creare il comando del bot per 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) {
            // Imposta la label !bot
            $profile->labels(SelfLabels::make(['!bot']));
        });

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

### Esecuzione

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

Esegui questo comando una sola volta, durante la configurazione iniziale del bot. La label viene salvata in modo persistente nel profilo.

<Warning>
  `!bot` è una self-label standard di Bluesky. Se ne consiglia sempre l'impostazione per gli account bot.
</Warning>

***

## Sugli altri tutorial ufficiali

Il tutorial ufficiale di AT Protocol tratta anche altri argomenti. Ecco lo stato del supporto in `laravel-bluesky`.

### Feed personalizzati

In [Feed Generator](/it/packages/laravel-bluesky/feed-generator) trovi la spiegazione dettagliata su come implementare un feed generator personalizzato con Laravel.

### Autenticazione OAuth

In [Socialite](/it/packages/laravel-bluesky/socialite) trovi la spiegazione su come implementare l'autenticazione OAuth con Laravel Socialite. È più semplice da implementare rispetto al tutorial ufficiale.

### App sociale (statusphere)

La versione Laravel di statusphere è pubblicata come [invokable/statusphere](https://github.com/invokable/statusphere). È basata su una versione più vecchia di statusphere che non usava i comandi `lex` o `tap`, quindi presenta lievi differenze rispetto al tutorial ufficiale più recente.

## Link di riferimento

* [Tutorial ufficiale per bot di AT Protocol (inglese)](https://atproto.com/guides/bot-tutorial)
* [Tutorial ufficiale per bot di AT Protocol (giapponese)](https://atproto.com/ja/guides/bot-tutorial)
* [laravel-bluesky](https://github.com/invokable/laravel-bluesky)
* [BlueskyManager e HasShortHand](/it/packages/laravel-bluesky/bluesky-manager)
* [Canale di notifica](/it/packages/laravel-bluesky/notification)
* [Driver Amazon Bedrock](/it/packages/laravel-amazon-bedrock)


## Related topics

- [Webhook / Bot - LINE SDK for Laravel](/it/packages/laravel-line-sdk/bot.md)
- [Laravel Bluesky](/it/packages/laravel-bluesky/index.md)
- [Feed Generator](/it/packages/laravel-bluesky/feed-generator.md)
- [LINE SDK for Laravel](/it/packages/laravel-line-sdk/index.md)
- [Socialite - Laravel Bluesky](/it/packages/laravel-bluesky/socialite.md)
