이 페이지는 AT Protocol 공식 봇 튜토리얼의 Laravel 버전입니다. TypeScript용 내용을 laravel-bluesky 패키지를 사용해 PHP/Laravel로 구현하는 방법을 설명합니다.
공식 튜토리얼에서는 lex 명령어로 Lexicon 파일을 매번 다운로드하지만, laravel-bluesky에서는 atproto-lexicon-contracts에서 사전에 모든 Lexicon을 임포트해 두었기 때문에 이 절차는 필요 없습니다. Artisan 명령어와 HasShortHand 트레이트의 메서드를 사용하면 거의 모든 조작을 실현할 수 있습니다.
전제 조건
laravel-bluesky 패키지가 설치되어 있을 것
- Bluesky 계정과 앱 패스워드가 준비되어 있을 것
설치 방법은 Laravel Bluesky를 참조하세요.
BLUESKY_IDENTIFIER=yourbot.bsky.social
BLUESKY_APP_PASSWORD=xxxx-xxxx-xxxx-xxxx
Part 1: 기본 봇(게시)
Artisan 명령어 만들기
php artisan make:command로 봇용 명령어를 생성합니다.
php artisan make:command BotPostCommand
생성된 app/Console/Commands/BotPostCommand.php를 편집합니다.
<?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.');
}
}
수동 실행
태스크 스케줄로 자동 실행
routes/console.php에 정기 실행 설정을 추가합니다.
use Illuminate\Support\Facades\Schedule;
// 3시간마다 게시
Schedule::command('bot:post')->everyThreeHours();
스케줄러를 활성화하려면 cron에 다음을 설정하세요.
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
GitHub Actions로 자동 실행
서버가 없는 경우에는 GitHub Actions로도 자동 실행할 수 있습니다.
# .github/workflows/bot.yml
name: Bot Post
on:
schedule:
- cron: '0 */3 * * *' # 3시간마다
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 }}
GitHub Actions의 시크릿에 BLUESKY_IDENTIFIER와 BLUESKY_APP_PASSWORD를 등록하세요.
Part 2: 리플라이 봇(멘션 모니터링)
멘션에 자동 회신하는 봇을 만듭니다. AI를 사용해 리플라이를 생성하는 예시도 소개합니다.
알림을 취득하여 멘션에 답장하기
php artisan make:command BotReplyCommand
<?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) {
// 멘션 알림만 처리
if (data_get($notification, 'reason') !== 'mention') {
continue;
}
// 읽음 처리된 알림은 스킵(isRead가 true인 것은 처리 완료)
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('안녕하세요! 멘션 감사합니다. 🙂')
->reply($reply);
Bluesky::post($post);
$this->info("Replied to: {$uri}");
}
// 알림을 읽음 처리
Bluesky::updateSeenNotifications(now()->toISOString());
}
}
스레드의 root가 다른 경우에는 app.bsky.feed.getPostThread로 스레드 정보를 취득해 root에 설정하세요. 간이 구현에서는 부모 게시를 root로 취급하고 있습니다.
폴링을 스케줄링하기
// routes/console.php
use Illuminate\Support\Facades\Schedule;
Schedule::command('bot:reply')->everyFiveMinutes();
AI를 사용해 리플라이를 생성하기
laravel/ai 패키지와 laravel-amazon-bedrock 드라이버를 조합하면 멘션 내용에 맞춘 AI 리플라이를 생성할 수 있습니다.
composer require laravel/ai revolution/laravel-amazon-bedrock
AI 에이전트를 생성합니다.
<?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 '당신은 Bluesky에서 활동하는 친근한 봇입니다.'
. '사용자의 메시지에 대해 짧고 친숙한 답장을 한국어로 생성해 주세요.'
. '답장은 200자 이내로 해주세요.';
}
}
명령어에서 AI 리플라이를 사용합니다.
<?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;
}
// 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());
}
}
Part 3: 라벨 봇
공식 튜토리얼의 labelAsBot에 해당하는 기능입니다. 봇 계정의 프로필에 셀프 라벨을 부여하여 자동화된 계정임을 명시합니다.
라벨 부여는 최초 셋업 시에 한 번만 실행합니다. Part 1·2의 명령어와는 독립된 별도의 명령어로 구현합니다.
라벨 봇 명령어 만들기
php artisan make:command BotLabelCommand
<?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) {
// !bot 라벨을 설정
$profile->labels(SelfLabels::make(['!bot']));
});
$this->info('Bot label applied successfully.');
}
}
실행하기
이 명령어는 봇의 최초 셋업 시에 한 번만 실행하세요. 라벨은 프로필에 영구적으로 저장됩니다.
!bot은 Bluesky의 표준 셀프 라벨입니다. 봇 계정에는 반드시 설정하는 것이 권장됩니다.
다른 공식 튜토리얼에 대해
AT Protocol 공식 튜토리얼에는 이 외에도 몇 가지 토픽이 있습니다. laravel-bluesky에서의 지원 상황을 정리합니다.
커스텀 피드
Feed Generator에서 Laravel을 사용한 커스텀 피드 제너레이터 구현 방법을 자세히 설명하고 있습니다.
OAuth 인증
Socialite에서 Laravel Socialite를 사용한 OAuth 인증 구현 방법을 설명하고 있습니다. 공식 튜토리얼보다 간단하게 구현할 수 있습니다.
소셜 앱(statusphere)
Laravel 버전의 statusphere가 invokable/statusphere로 공개되어 있습니다. lex나 tap 명령어를 사용하지 않은 이전 statusphere를 기반으로 하고 있어, 최신 공식 튜토리얼과는 약간 다른 점이 있습니다.
참고 링크