-11
Dockerfile
-11
Dockerfile
···
8
8
9
9
COPY . .
10
10
11
-
ENV AUTHORIZED_USERS=""
12
-
ENV SERVICE="https://bsky.social"
13
-
ENV DB_PATH="data/sqlite.db"
14
-
ENV GEMINI_MODEL="gemini-2.5-flash"
15
-
ENV ADMIN_DID=""
16
-
ENV ADMIN_HANDLE=""
17
-
ENV DID=""
18
-
ENV HANDLE=""
19
-
ENV BSKY_PASSWORD=""
20
-
ENV GEMINI_API_KEY=""
21
-
22
11
CMD ["bun", "start"]
+17
docker-compose.yml
+17
docker-compose.yml
···
1
+
services:
2
+
aero:
3
+
build:
4
+
context: .
5
+
dockerfile: Dockerfile
6
+
environment:
7
+
- "AUTHORIZED_USERS="
8
+
- "SERVICE=${SERVICE:?https://bsky.social}"
9
+
- "DB_PATH=data/sqlite.db"
10
+
- "GEMINI_MODEL=${GEMINI_MODEL:?gemini-2.5-flash}"
11
+
- "DID=${DID:?}"
12
+
- "HANDLE=${HANDLE:?}"
13
+
- "BSKY_PASSWORD=${BSKY_PASSWORD:?}"
14
+
- "GEMINI_API_KEY=${GEMINI_API_KEY:?}"
15
+
volumes:
16
+
- .:/app
17
+
- aero_db:/app/data
-2
src/env.ts
-2
src/env.ts
+14
-1
src/utils/conversation.ts
+14
-1
src/utils/conversation.ts
···
9
9
import { and, eq } from "drizzle-orm";
10
10
import { env } from "../env";
11
11
import { bot, MAX_GRAPHEMES } from "../core";
12
-
import { traverseThread } from "./thread";
12
+
import { parsePostImages, traverseThread } from "./post";
13
13
14
+
/*
15
+
Utilities
16
+
*/
14
17
const resolveDid = (convo: Conversation, did: string) =>
15
18
convo.members.find((actor) => actor.did == did)!;
16
19
···
23
26
return Array.from(array, (b) => b.toString(16).padStart(2, "0")).join("");
24
27
}
25
28
29
+
/*
30
+
Conversations
31
+
*/
26
32
async function initConvo(convo: Conversation) {
27
33
const user = getUserDid(convo);
28
34
···
136
142
? `${post.author.displayName} (${post.author.handle})`
137
143
: `Handle: ${post.author.handle}`,
138
144
text: post.text,
145
+
images: parsePostImages(post),
139
146
likes: post.likeCount || 0,
140
147
replies: post.replyCount || 0,
141
148
},
···
152
159
});
153
160
}
154
161
162
+
/*
163
+
Messages
164
+
*/
155
165
async function parseMessagePostUri(message: ChatMessage) {
156
166
if (!message.embed) return null;
157
167
const post = message.embed;
···
194
204
});
195
205
}
196
206
207
+
/*
208
+
Reponse Utilities
209
+
*/
197
210
export function exceedsGraphemes(content: string) {
198
211
return graphemeLength(content) > MAX_GRAPHEMES;
199
212
}
+64
src/utils/post.ts
+64
src/utils/post.ts
···
1
+
import { EmbedImage, Post } from "@skyware/bot";
2
+
import * as c from "../core";
3
+
import * as yaml from "js-yaml";
4
+
5
+
export function parsePostImages(post: Post) {
6
+
if (!post.embed) return [];
7
+
8
+
let images: EmbedImage[] = [];
9
+
10
+
if (post.embed.isImages()) {
11
+
images = post.embed.images;
12
+
} else if (post.embed.isRecordWithMedia()) {
13
+
const media = post.embed.media;
14
+
if (media && media.isImages()) {
15
+
images = media.images;
16
+
}
17
+
}
18
+
19
+
return images.map((image, idx) => parseImage(image, idx + 1));
20
+
}
21
+
22
+
function parseImage(image: EmbedImage, index: number) {
23
+
return {
24
+
index: index,
25
+
alt: image.alt,
26
+
};
27
+
}
28
+
29
+
/*
30
+
Traversal
31
+
*/
32
+
export async function traverseThread(post: Post): Promise<Post[]> {
33
+
const thread: Post[] = [
34
+
post,
35
+
];
36
+
let currentPost: Post | undefined = post;
37
+
let parentCount = 0;
38
+
39
+
while (
40
+
currentPost && parentCount < c.MAX_THREAD_DEPTH
41
+
) {
42
+
const parentPost = await currentPost.fetchParent();
43
+
44
+
if (parentPost) {
45
+
thread.push(parentPost);
46
+
currentPost = parentPost;
47
+
} else {
48
+
break;
49
+
}
50
+
parentCount++;
51
+
}
52
+
53
+
return thread.reverse();
54
+
}
55
+
56
+
export function parseThread(thread: Post[]) {
57
+
return yaml.dump({
58
+
uri: thread[0]!.uri,
59
+
posts: thread.map((post) => ({
60
+
author: `${post.author.displayName} (${post.author.handle})`,
61
+
text: post.text,
62
+
})),
63
+
});
64
+
}
-40
src/utils/thread.ts
-40
src/utils/thread.ts
···
1
-
import { Post } from "@skyware/bot";
2
-
import * as c from "../core";
3
-
import * as yaml from "js-yaml";
4
-
5
-
/*
6
-
Traversal
7
-
*/
8
-
export async function traverseThread(post: Post): Promise<Post[]> {
9
-
const thread: Post[] = [
10
-
post,
11
-
];
12
-
let currentPost: Post | undefined = post;
13
-
let parentCount = 0;
14
-
15
-
while (
16
-
currentPost && parentCount < c.MAX_THREAD_DEPTH
17
-
) {
18
-
const parentPost = await currentPost.fetchParent();
19
-
20
-
if (parentPost) {
21
-
thread.push(parentPost);
22
-
currentPost = parentPost;
23
-
} else {
24
-
break;
25
-
}
26
-
parentCount++;
27
-
}
28
-
29
-
return thread.reverse();
30
-
}
31
-
32
-
export function parseThread(thread: Post[]) {
33
-
return yaml.dump({
34
-
uri: thread[0]!.uri,
35
-
posts: thread.map((post) => ({
36
-
author: `${post.author.displayName} (${post.author.handle})`,
37
-
text: post.text,
38
-
})),
39
-
});
40
-
}