2024-04-12 / @syui

bluesky , atproto

blueskyのcustom feedでslash cmdを有効にした

blueskyでfeed serverを立て、slash command(cmd slash)を有効にしました。

/help

or 

@yui.syui.ai /help

スラッシュ コマンドを使用すると、テーブル、タスクリスト、コード ブロックなど、より複雑な Markdown を簡単に入力できます。

これによって何ができるのかというと、例えば、/helpと投稿すると、botが反応できるようになります。

今までのbotは大体が(1)mention, replyで反応するか、(2)feed(following)から反応するか、(3)global timelineから反応するかの方法があり、それぞれに欠点がありました。

    1. mention, reply : 最も合理的で負荷が少なくlimitに引っかかる可能性は少なく確実な方法。ただ、ユーザーからすると面倒
    1. feed(following) : user timelineから取るので負荷も少ない。ただ、followingの処理が必要になったり、follow listの監視と解除があればその処理が必要
    1. global timeline : ユーザーが増えるにつれて流速が早くなり負荷が高くなる。全部に対応するのが難しくなるかも

しかし、feed serverを自分で建て、そこから反応すると、このようなデメリットを解消できます。これはcustom feedと呼ばれるものになります。

ちなみに、skyfeedで簡単に作れますが、自前でhostするのがいいです。skyfeedだと反応が遅くなってしまう。

feed server自体は、昔にfeed.syu.isのほうで建てていて、今回はそれをbsky.networkにdeply(登録)し、didをbsky.socialのaccountに変更したのと、algosの正規表現を調整しました。

$ git clone https://github.com/bluesky-social/feed-generator
$ cd feed-generator
├── .env
└── src
    ├── scripts
    │   └── publishFeedGen.ts
    ├── algos
    │   ├── cmd.ts
    │   └── index.ts
    └── subscription.ts

編集するのは上に挙げたファイルです。

FEEDGEN_PORT=3000
FEEDGEN_LISTENHOST="0.0.0.0"
FEEDGEN_SQLITE_LOCATION="/data/db.sqlite"
FEEDGEN_HOSTNAME="feed.syu.is"
FEEDGEN_SUBSCRIPTION_RECONNECT_DELAY=3000
FEEDGEN_PUBLISHER_DID=did:plc:4hqjfn7m6n5hno3doamuhgef
FEEDGEN_SUBSCRIPTION_ENDPOINT="wss://bsky.network"
const handle = ''
const password = ''
const recordName = ''
const displayName = ''
const description = ''
const avatar: string = 'icon/ai.png'
./feed-generator
├── icon/ai.png
├── .env
└── src
# bsky.networkにpush
$ npm run publishFeed
.filter((create) => {
	return create.record.text.match('^/[a-z]') || create.record.text.match('^@ai');
	//return create.record.text.toLowerCase().includes('alf')
})
$ docker compose build feed-generator
$ docker compose up feed-generator

これをbotで取得すると、返信できます。

feed = at://did:plc:4hqjfn7m6n5hno3doamuhgef/app.bsky.feed.generator/cmd

// https://docs.bsky.app/docs/api/app-bsky-feed-get-feed
extern crate reqwest;
use crate::data_refresh;
use crate::url;

pub async fn get_request(feed: String) -> String {
    let token = data_refresh(&"access");
    let url = url(&"feed_get");
    let feed = feed.to_string();

    let client = reqwest::Client::new();
    let res = client
        .get(url)
        .query(&[("feed", feed)])
        .header("Authorization", "Bearer ".to_owned() + &token)
        .send()
        .await
        .unwrap();
 
    let status_ref = res.error_for_status_ref();

    match status_ref {
        Ok(_) => {
            return res.text().await.unwrap();
        }
        Err(_e) => {
            let e = "err".to_string();
            return e;
        }
    }

}