🦔
AI エージェント Codex さんが Bluesky に投稿する Julia のクライアントアプリを作ってくれたようです
本日は
Julia アドベントカレンダーです.
数年前,Twitter というものがあった時の時代ですが,Plots.jl で作った画像,GIFを投稿するツール (TweetPlots.jl) を作っていました.
今日の X とやらでどうするのかわからなかったので今は放置しています.
今は Bluesky ですよ.#JuliaLang のタグをフォローしていれば静かで・穏やかです.
作ったもの
Bluesky で同様のことができるようになりたかったので AI エージェント Codex に作らせました.
下記のリポジトリをクローンして読ませて
「文字を投稿できるようにしたい」旨のプロンプトを入力させ,デバッグさせながら3時間ほどで完成させました.成果物は下記のリンクにあります.
用意するもの
- Julia v1.12 以上
- 投稿するネタ
- Bluesky にログインするときのメールアドレスとパスワード.各々
BSKY_HANDLE,BSKY_PASSWORDという名前で環境変数に格納しておきます.
使い方
文字の投稿
send_post 関数で投稿できます.
using BlueskyClient
using DotEnv; DotEnv.load!()
client = Client() # defaults to https://bsky.social
# Prefer App Passwords with DM scope when accessing real accounts.
session = login!(client;
identifier = ENV["BSKY_HANDLE"],
password = ENV["BSKY_PASSWORD"],
)
post_text = "I'm making BlueskyClient.jl now ♩"
@info "Sending text post to Bluesky"
post = send_post(client, post_text)
@info "Text post sent successfully" uri=post.uri
println("New record URI: ", post.uri)
画像の投稿
send_image 関数を使います.ALT 付きで投稿ができます.
using BlueskyClient
using DotEnv; DotEnv.load!()
client = Client()
login!(client; identifier=ENV["BSKY_HANDLE"], password=ENV["BSKY_PASSWORD"])
image_path = "screenshot.png"
@info "Loading image fixture" path=image_path
img_bytes = read(image_path)
@info "Sending image post to Bluesky"
post = send_image(
client,
"Screenshot from today's build ✅",
img_bytes,
"BlueskyClient.jl terminal output showing the new client API", # ALT
mime_type="image/png",
)
@info "Image post sent successfully" uri=post.uri
GIF, MP4 の投稿
GIF は MP4 に変換して投稿します.下記のスクリプトで Makie.jl のdemoを投稿することができます.
using BlueskyClient
using DotEnv
using GLMakie
DotEnv.load!()
# https://docs.makie.org/stable/
using GLMakie
Base.@kwdef mutable struct Lorenz
dt::Float64 = 0.01
σ::Float64 = 10
ρ::Float64 = 28
β::Float64 = 8/3
x::Float64 = 1
y::Float64 = 1
z::Float64 = 1
end
function step!(l::Lorenz)
dx = l.σ * (l.y - l.x)
dy = l.x * (l.ρ - l.z) - l.y
dz = l.x * l.y - l.β * l.z
l.x += l.dt * dx
l.y += l.dt * dy
l.z += l.dt * dz
Point3f(l.x, l.y, l.z)
end
attractor = Lorenz()
points = Point3f[]
colors = Int[]
set_theme!(theme_black())
fig, ax, l = lines(points, color = colors,
colormap = :inferno, transparency = true,
axis = (; type = Axis3, protrusions = (0, 0, 0, 0),
viewmode = :fit, limits = (-30, 30, -30, 30, 0, 50)))
mktempdir() do dir
video_path = joinpath(dir, "lorenz.mp4")
@info "Recording Lorenz attractor animation" path=video_path
record(fig, video_path, 1:120) do frame
for i in 1:50
push!(points, step!(attractor))
push!(colors, frame)
end
ax.azimuth[] = 1.7pi + 0.3 * sin(2pi * frame / 120)
Makie.update!(l, arg1 = points, color = colors) # Makie 0.24+
l.colorrange = (0, frame)
end
@info "Completed Lorenz animation recording"
client = Client()
login!(client; identifier=ENV["BSKY_HANDLE"], password=ENV["BSKY_PASSWORD"])
video_bytes = read(video_path)
upload = upload_blob(client, Vector{UInt8}(video_bytes); content_type="video/mp4")
embed = Dict(
"\$type" => "app.bsky.embed.video",
"video" => upload["blob"],
"alt" => get(ENV, "BSKY_VIDEO_ALT", "MP4 sample posted from BlueskyClient.jl"),
"aspectRatio" => Dict("width" => 16, "height" => 9),
)
@info "Sending MP4 post to Bluesky"
post = send_post(client, "Post with MP4 attachment 🎬"; embed=embed)
@info "MP4 post sent successfully" uri=post.uri
end
これで可視化ボットを作ることができますね.
Julia は(他の言語にあるが,Juliaにはないという意味で)ライブラリが少ないと言われますが,LLMの時代であれば,公式実装があればそれを元に Julia パッケージが作れるようになってきました.使いたいと感じる人間のヤル気と情熱があればなんとかなりそうです.
Discussion