diff --git a/Dockerfile b/Dockerfile index 5684900..5b006a4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,15 +8,4 @@ RUN bun install --frozen-lockfile COPY . . -ENV AUTHORIZED_USERS="" -ENV SERVICE="https://bsky.social" -ENV DB_PATH="data/sqlite.db" -ENV GEMINI_MODEL="gemini-2.5-flash" -ENV ADMIN_DID="" -ENV ADMIN_HANDLE="" -ENV DID="" -ENV HANDLE="" -ENV BSKY_PASSWORD="" -ENV GEMINI_API_KEY="" - CMD ["bun", "start"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..f174194 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,17 @@ +services: + aero: + build: + context: . + dockerfile: Dockerfile + environment: + - "AUTHORIZED_USERS=" + - "SERVICE=${SERVICE:?https://bsky.social}" + - "DB_PATH=data/sqlite.db" + - "GEMINI_MODEL=${GEMINI_MODEL:?gemini-2.5-flash}" + - "DID=${DID:?}" + - "HANDLE=${HANDLE:?}" + - "BSKY_PASSWORD=${BSKY_PASSWORD:?}" + - "GEMINI_API_KEY=${GEMINI_API_KEY:?}" + volumes: + - .:/app + - aero_db:/app/data diff --git a/src/env.ts b/src/env.ts index df55af5..d2281e1 100644 --- a/src/env.ts +++ b/src/env.ts @@ -11,8 +11,6 @@ const envSchema = z.object({ DB_PATH: z.string().default("sqlite.db"), GEMINI_MODEL: z.string().default("gemini-2.5-flash"), - ADMIN_DID: z.string(), - ADMIN_HANDLE: z.string(), DID: z.string(), HANDLE: z.string(), BSKY_PASSWORD: z.string(), diff --git a/src/utils/conversation.ts b/src/utils/conversation.ts index 75d1bd8..7cf1820 100644 --- a/src/utils/conversation.ts +++ b/src/utils/conversation.ts @@ -9,8 +9,11 @@ import { conversations, messages } from "../db/schema"; import { and, eq } from "drizzle-orm"; import { env } from "../env"; import { bot, MAX_GRAPHEMES } from "../core"; -import { traverseThread } from "./thread"; +import { parsePostImages, traverseThread } from "./post"; +/* + Utilities +*/ const resolveDid = (convo: Conversation, did: string) => convo.members.find((actor) => actor.did == did)!; @@ -23,6 +26,9 @@ function generateRevision(bytes = 8) { return Array.from(array, (b) => b.toString(16).padStart(2, "0")).join(""); } +/* + Conversations +*/ async function initConvo(convo: Conversation) { const user = getUserDid(convo); @@ -136,6 +142,7 @@ export async function parseConversation(convo: Conversation) { ? `${post.author.displayName} (${post.author.handle})` : `Handle: ${post.author.handle}`, text: post.text, + images: parsePostImages(post), likes: post.likeCount || 0, replies: post.replyCount || 0, }, @@ -152,6 +159,9 @@ export async function parseConversation(convo: Conversation) { }); } +/* + Messages +*/ async function parseMessagePostUri(message: ChatMessage) { if (!message.embed) return null; const post = message.embed; @@ -194,6 +204,9 @@ export async function saveMessage( }); } +/* + Reponse Utilities +*/ export function exceedsGraphemes(content: string) { return graphemeLength(content) > MAX_GRAPHEMES; } diff --git a/src/utils/thread.ts b/src/utils/post.ts similarity index 58% rename from src/utils/thread.ts rename to src/utils/post.ts index 58ca6a9..eee7196 100644 --- a/src/utils/thread.ts +++ b/src/utils/post.ts @@ -1,7 +1,31 @@ -import { Post } from "@skyware/bot"; +import { EmbedImage, Post } from "@skyware/bot"; import * as c from "../core"; import * as yaml from "js-yaml"; +export function parsePostImages(post: Post) { + if (!post.embed) return []; + + let images: EmbedImage[] = []; + + if (post.embed.isImages()) { + images = post.embed.images; + } else if (post.embed.isRecordWithMedia()) { + const media = post.embed.media; + if (media && media.isImages()) { + images = media.images; + } + } + + return images.map((image, idx) => parseImage(image, idx + 1)); +} + +function parseImage(image: EmbedImage, index: number) { + return { + index: index, + alt: image.alt, + }; +} + /* Traversal */