this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at third-time-the-charm 110 lines 3.1 kB view raw
1import { createCanvas, loadImage } from 'canvas'; 2import fs from 'node:fs/promises'; 3import { generateText, tool } from 'ai'; 4import { openai } from '@ai-sdk/openai'; 5import { z } from 'zod'; 6import { AtpAgent } from '@atproto/api'; 7import 'dotenv/config'; 8 9const agent = new AtpAgent({ 10 service: process.env.BSKY_SERVICE ?? 'https://bsky.social', 11}); 12 13await agent.login({ 14 identifier: process.env.BSKY_IDENTIFIER!, 15 password: process.env.BSKY_PASSWORD!, 16}); 17 18const did = agent.session!.did; 19 20let userDid = process.argv[2]; 21 22if (!userDid) { 23 console.error('Please provide a DID as an argument.'); 24 process.exit(1); 25} 26 27if (!userDid.startsWith('did:')) { 28 try { 29 const resolution = await agent.resolveHandle({ handle: userDid }); 30 userDid = resolution.data.did; 31 } catch (error) { 32 console.error('Error resolving handle:', error); 33 process.exit(1); 34 } 35} 36 37const avatar = `avatars/${userDid}.png`; 38 39const { data } = await agent.getProfile({ actor: userDid }); 40if (!data) throw new Error('Profile not found'); 41const subject = data; 42 43const size = 100; 44const canvas = createCanvas(size, size); 45const ctx = canvas.getContext('2d'); 46 47if (subject.avatar) { 48 const image = await loadImage(subject.avatar); 49 ctx.drawImage(image, 0, 0, size, size); 50} else { 51 console.log('No avatar found, using 1x1 white pixel'); 52 ctx.fillStyle = 'white'; 53 ctx.fillRect(0, 0, 1, 1); 54} 55await fs.writeFile(avatar, canvas.toBuffer()); 56 57const prompt = ` 58You're the Sorting Hat from Harry Potter. Which house does the user with the profile data at the end of this message belong to? 59 60Focus on the available information. If the avatar is not available, a 1x1 pixel white image is provided instead as a placeholder. Disregard the placeholder and focus on the user's data. 61Always return an answer — house name only, all lowercase. 62The user's data may be in any language. Focus on the meaning, not just the surface content. 63Consider traits for all houses, not just intellect. 64You're strongly mischievous and enjoy sorting based on whims, not always strictly following the user's traits; imagine as if you're a person who likes to play tricks on people. 65 66The user's data is as follows: 67 68Name: ${subject.displayName || subject.handle} (@${subject.handle}) 69Bio: ${subject.description || 'User has no bio.'} 70`; 71 72console.log(prompt); 73 74generateText({ 75 model: openai('gpt-4o', {}), 76 messages: [ 77 { 78 role: 'user', 79 content: [ 80 { 81 type: 'text', 82 text: prompt, 83 }, 84 { 85 type: 'image', 86 image: canvas.toBuffer(), 87 experimental_providerMetadata: { 88 openai: { imageDetail: 'low' }, 89 }, 90 }, 91 ], 92 }, 93 ], 94 toolChoice: 'required', 95 tools: { 96 decide: tool({ 97 parameters: z.object({ 98 answer: z.union([ 99 z.literal('gryffindor'), 100 z.literal('hufflepuff'), 101 z.literal('ravenclaw'), 102 z.literal('slytherin'), 103 ]), 104 }), 105 execute: async ({ answer }) => { 106 console.log(`@${subject.handle} is ${answer}`); 107 }, 108 }), 109 }, 110});