File size: 3,809 Bytes
85078f5 31d882e 85078f5 31d882e 85078f5 31d882e 85078f5 e04cf41 85078f5 e04cf41 987f2db e04cf41 987f2db 2b4727d 9920173 987f2db 9920173 987f2db e04cf41 987f2db 85078f5 987f2db 58ea57b 987f2db 85078f5 58ea57b 9920173 987f2db 85078f5 2b4727d 58ea57b 85078f5 2b4727d 85078f5 31d882e 58ea57b 31d882e e04cf41 99fbfe2 85078f5 99fbfe2 |
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 |
import OAuth from "oauth";
import "dotenv/config";
import { setTimeout } from "timers/promises";
const { API_KEY, API_SECRET, BEARER_TOKEN, ACCESS_TOKEN, ACCESS_TOKEN_SECRET } = process.env;
function getAuthHeader(oauth: OAuth.OAuth, url: string) {
return oauth.authHeader(url, ACCESS_TOKEN as string, ACCESS_TOKEN_SECRET as string, "post");
}
const client = new OAuth.OAuth(
"https://api.twitter.com/oauth/request_token",
"https://api.twitter.com/oauth/access_token",
API_KEY as string,
API_SECRET as string,
"1.0A",
null,
"HMAC-SHA1"
);
const BOT_ID = "1612094318906417152";
interface TweetMentions {
data: Array<{ id: string; text: string }>;
meta: {
result_count: number;
newest_id: string;
oldest_id: string;
};
}
interface TweetLookups {
data: Array<{
id: string;
conversation_id: "string";
text: string;
created_at: string;
attachments?: { media_keys: string[] };
}>;
includes: { media: Array<{ media_key: string; url: string }> };
}
async function ff(url: string) {
const resp = await fetch(`https://api.twitter.com/2/${url}`, {
headers: { Authorization: `Bearer ${BEARER_TOKEN}` },
});
if (resp.status !== 200) {
throw new Error("invalid status: " + resp.status + "- " + (await resp.text()));
}
return await resp.json();
}
let lastMention = "";
async function lookupTweets() {
const data: TweetMentions = await ff(
`users/${BOT_ID}/mentions?${lastMention && `start_time=${new Date(new Date(lastMention).getTime() + 1).toJSON()}`}`
);
let lookups: TweetLookups = await ff(
`tweets?ids=${data.data
.map((t) => t.id)
.join(
","
)}&tweet.fields=created_at&expansions=attachments.media_keys&media.fields=duration_ms,height,media_key,preview_image_url,public_metrics,type,url,width,alt_text`
);
if (!lastMention) {
console.log("added mention", lookups.data[0].created_at);
lastMention = lookups.data[0].created_at;
return lookupTweets();
}
const tweets = lookups.data.filter((tweet) => tweet.attachments?.media_keys.length === 1);
console.log(lastMention);
for (const tweet of tweets) {
const imageUrl = lookups.includes.media.find((media) => media.media_key === tweet?.attachments!.media_keys[0])
?.url!;
console.log("imageUrl", imageUrl);
const imageResp = await fetch(imageUrl);
const contentType = imageResp.headers.get("Content-Type");
const image = await imageResp.arrayBuffer();
console.log(contentType, image);
const altText = await fetch("https://olivierdehaene-git-large-coco.hf.space/run/predict", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
data: [`data:${contentType};base64,${Buffer.from(image).toString("base64")}`],
}),
})
.then((r) => r.json())
.then((r) => r.data);
console.log(altText[0]);
const header = getAuthHeader(client, "https://api.twitter.com/2/tweets");
const r = await fetch("https://api.twitter.com/2/tweets", {
headers: {
Authorization: header,
"user-agent": "v3CreateTweetJS",
"content-type": "application/json",
accept: "application/json",
},
body: JSON.stringify({
text: altText[0],
reply: { in_reply_to_tweet_id: tweet!.id, conversation_id: tweet!.conversation_id },
}),
method: "post",
});
try {
console.log("end", await r.json());
} catch {}
}
}
process.on("unhandledRejection", async (err) => {
console.error("unhandled rejection", err);
});
process.on("uncaughtException", console.error);
async function run() {
while (1) {
console.log("looking up");
await lookupTweets();
await setTimeout(5_000);
}
}
run();
const SPACE_ID = process.env.SPACE_ID || "huggingface-projects/twitter-alt-image-bot";
// Keep space alive
setInterval(() => {
fetch(`https://${SPACE_ID.replace("/", "-")}.hf.space`);
}, 24 * 3600 * 1000);
|