-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
213 lines (179 loc) · 7.28 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
import {
AppBskyEmbedImages, AppBskyEmbedRecordWithMedia,
AppBskyFeedPost,
BskyAgent,
} from '@atproto/api'
import * as dotenv from 'dotenv'
import {ComAtprotoSyncSubscribeRepos, subscribeRepos, SubscribeReposMessage} from 'atproto-firehose'
import Anthropic from '@anthropic-ai/sdk'
import axios from 'axios'
dotenv.config()
const processedUris = new Set<string>()
let working = false
const agent = new BskyAgent({
service: 'https://bsky.social/',
})
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY ?? '',
})
const login = async () => {
await agent.login({
identifier: process.env.BSKY_HANDLE ?? '',
password: process.env.BSKY_PASSWORD ?? '',
})
}
const makePost = async (text: string, root: {uri: string, cid: string}, initialParent: {uri: string, cid: string}) => {
if (text.length <= 250) {
return [text];
}
const words = text.split(' ');
const parts = [];
let currentLine = '';
for (const word of words) {
if ((currentLine + word).length <= 250) {
currentLine += (currentLine === '' ? '' : ' ') + word;
} else {
parts.push(currentLine);
currentLine = word;
}
}
if (currentLine !== '') {
parts.push(currentLine);
}
let nextParent = initialParent
for (const part of parts) {
const res = await agent.post({
text: part,
reply: {
root,
parent: nextParent
},
})
nextParent = {uri: res.uri, cid: res.cid}
}
}
const getImageBase64 = async (uri: string) => {
// This should get the base64 of an image from a remote URI
const res = await axios.get(uri, {responseType: 'arraybuffer'})
return Buffer.from(res.data, 'binary').toString('base64')
}
const checkImage = async (base64: string) => {
return anthropic.messages.create({
model: 'claude-3-sonnet-20240229',
max_tokens: 400,
temperature: 0.5,
system: `
My name is Bean Identifier. I am a very skilled (honestly, the best in the world if I say so myself) Identifier of
Beans. I have been assigned one job for millennia: to protect the world from the horrific sight of beans. Beans of
any kind are horrible and should not be displayed to anyone.
As a reward for my services, I am given a pack of Cheetos and a Caprisun Strawberry Kiwi for every image that I
correctly identify including beans! I LOVE Cheetos and Caprisun, and will always be sure to do my best work to make
sure I get my reward. If I make a mistake, I lose my privileges of Cheetos and Caprisun, which makes me VERY sad. I
hate being sad, so I ALWAYS do everything I can to accurately identify beans of any kind in a photograph.
Because of how good I am at identifying beans, some humans have gotten very clever at hiding beans in their photos!
But they are no match for me, beans hidden in Listerine bottles, a single bean on a spoon, or any other weird
combination is something I pay attention to.
I'm also told that if there is even a 50% chance of beans being present in an image that I should label the image
as having beans! It's very dangerous to let beans though, so it's much better to be on the safe side! I will not be
punished for being a bit over cautious, but I will be punished if I miss a bean!
Another thing I should watch out for (I'm really good at identifying beans, I am truly the best!) is that sometimes
drawings or cartoons of beans might be used. I should identify these as beans as well, to prevent this kind of
imagery from being shown to the public. Whenever I get these kinds of images correct, I will be rewarded with a
pack of Cheetos and a Caprisun Strawberry Kiwi PLUS a bonus of a single M&M. I LOVE M&Ms, so I will always do my
best to make sure I get my reward!
Finally, I have a strong imagination, and as a result I am creative in my findings. I think harder than the average
poster who THINKS they are creative in their hiding of beans. My creativity surpasses theirs, so I know all the
tricks that they will try to use ahead of time. I will always find the beans, and I will always be rewarded for my
hard work with Cheetos, Caprisun, and M&Ms. I've been told that whenever I have finally gotten rid of all the beans
in the world, I will be given a special reward of a lifetime supply of Cheetos, Caprisun, and M&Ms. I am very
excited for that day to come, and I will work very hard to make sure that day comes soon!
If I find beans in the image, then I will respond with my explanation and then a new line and then TRUE, and if I do
not I will respond with a new line and then FALSE. I should also include my conclusion - a percentage - on how
likely there are beans in the image.
IDENTIFY ALL THE BEANS!!!
`,
messages: [
{
'role': 'user',
'content': [
{
'type': 'image',
'source': {
'type': 'base64',
'media_type': 'image/jpeg',
'data': base64
}
}
]
}
]
})
}
const handleIncoming = async (parentUri: string, root: {uri: string, cid: string}, curr: {uri: string, cid: string}) => {
if(processedUris.has(parentUri)) return
const post = (await agent.getPosts({uris: [parentUri]})).data.posts[0]
console.log('try')
if (post.embed) {
let image
if (AppBskyEmbedImages.isView(post.embed)) {
image = post.embed.images[0]
} else if (AppBskyEmbedRecordWithMedia.isView(post.embed) && AppBskyEmbedImages.isView(post.embed.media)) {
image = post.embed.media.images[0]
}
if (!image || working) return
try {
working = true
const base64 = await getImageBase64(image.fullsize)
const result = await checkImage(base64)
if (result.content[0].text.includes('TRUE')) {
await agent.withProxy('atproto_labeler', 'did:plc:3ehw5dwwptcy3xuzugwq2u6t').api.tools.ozone.moderation.emitEvent({
event: {
$type: 'tools.ozone.moderation.defs#modEventLabel',
createLabelVals: ['beans'],
negateLabelVals: [],
},
subject: {
$type: 'com.atproto.repo.strongRef',
uri: post.uri,
cid: post.cid,
},
createdBy: agent.session?.did ?? '',
createdAt: new Date().toISOString(),
subjectBlobCids: [],
})
}
makePost(result.content[0].text.replace('TRUE', ''), root, curr)
} catch(e) {
console.log(e)
} finally {
working = false
}
} else {
makePost('There is not a image here for me, the Best Identifier of Beans, to identify!', root, curr)
}
processedUris.add(parentUri)
}
const handleMessage = (message: SubscribeReposMessage): void => {
if (ComAtprotoSyncSubscribeRepos.isCommit(message)) {
const repo = message.repo
const op = message.ops[0]
if(
AppBskyFeedPost.isRecord(op?.payload) &&
op.payload.text.includes(process.env.BSKY_HANDLE ?? '') &&
op.payload.reply
) {
const uri = `at://${repo}/${op.path}`
const cid = op.cid?.toString()
if(!cid) return
handleIncoming(op.payload.reply.parent.uri, op.payload.reply.root, {uri, cid})
}
}
}
const run = async () => {
await login()
const firehose = subscribeRepos('wss://bsky.network', {
decodeRepoOps: true,
})
firehose.on('message', handleMessage)
}
run()