Commit
·
85078f5
1
Parent(s):
3b164f6
⚗️ Try to write tweets
Browse files- package-lock.json +0 -0
- package.json +2 -0
- server.ts +75 -79
package-lock.json
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
package.json
CHANGED
|
@@ -18,6 +18,7 @@
|
|
| 18 |
"@types/koa-compress": "^4.0.3",
|
| 19 |
"@types/koa-morgan": "^1.0.5",
|
| 20 |
"@types/koa-router": "^7.4.4",
|
|
|
|
| 21 |
"ts-node": "^10.9.1",
|
| 22 |
"typescript": "^4.9.4"
|
| 23 |
},
|
|
@@ -28,6 +29,7 @@
|
|
| 28 |
"koa-compress": "^5.1.0",
|
| 29 |
"koa-morgan": "^1.0.1",
|
| 30 |
"koa-router": "^12.0.0",
|
|
|
|
| 31 |
"prettier": "^2.8.2",
|
| 32 |
"twitter-api-sdk": "^1.2.1"
|
| 33 |
}
|
|
|
|
| 18 |
"@types/koa-compress": "^4.0.3",
|
| 19 |
"@types/koa-morgan": "^1.0.5",
|
| 20 |
"@types/koa-router": "^7.4.4",
|
| 21 |
+
"@types/oauth": "^0.9.1",
|
| 22 |
"ts-node": "^10.9.1",
|
| 23 |
"typescript": "^4.9.4"
|
| 24 |
},
|
|
|
|
| 29 |
"koa-compress": "^5.1.0",
|
| 30 |
"koa-morgan": "^1.0.1",
|
| 31 |
"koa-router": "^12.0.0",
|
| 32 |
+
"oauth": "^0.10.0",
|
| 33 |
"prettier": "^2.8.2",
|
| 34 |
"twitter-api-sdk": "^1.2.1"
|
| 35 |
}
|
server.ts
CHANGED
|
@@ -1,45 +1,25 @@
|
|
| 1 |
-
import
|
| 2 |
-
import bodyParser from "koa-bodyparser";
|
| 3 |
-
import compression from "koa-compress";
|
| 4 |
-
import morgan from "koa-morgan";
|
| 5 |
-
import Router from "koa-router";
|
| 6 |
-
import { inspect } from "util";
|
| 7 |
import "dotenv/config";
|
| 8 |
-
import {
|
| 9 |
|
| 10 |
-
const
|
| 11 |
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
app.use(compression());
|
| 16 |
-
app.use(bodyParser());
|
| 17 |
-
|
| 18 |
-
const { API_KEY, API_SECRET, BEARER_TOKEN, CLIENT_ID, CLIENT_SECRET, COOKIE } = process.env;
|
| 19 |
-
|
| 20 |
-
const router = new Router();
|
| 21 |
-
|
| 22 |
-
app.use(router.routes());
|
| 23 |
-
app.use(router.allowedMethods());
|
| 24 |
-
|
| 25 |
-
// Initialize auth client first
|
| 26 |
-
const authClient = new auth.OAuth2User({
|
| 27 |
-
client_id: CLIENT_ID as string,
|
| 28 |
-
client_secret: CLIENT_SECRET as string,
|
| 29 |
-
callback: "https://huggingface-projects-twitter-image-alt-bot.hf.space/callback",
|
| 30 |
-
scopes: ["tweet.read", "users.read", "offline.access"],
|
| 31 |
-
});
|
| 32 |
|
| 33 |
-
|
| 34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
|
| 36 |
-
const BOT_NAME = "AltImageBot1";
|
| 37 |
const BOT_ID = "1612094318906417152";
|
| 38 |
|
| 39 |
-
function debug(stuff: any) {
|
| 40 |
-
console.log(inspect(stuff, { depth: 20 }));
|
| 41 |
-
}
|
| 42 |
-
|
| 43 |
interface TweetMentions {
|
| 44 |
data: Array<{ id: string; text: string }>;
|
| 45 |
meta: {
|
|
@@ -71,10 +51,12 @@ async function ff(url: string) {
|
|
| 71 |
return await resp.json();
|
| 72 |
}
|
| 73 |
|
|
|
|
|
|
|
| 74 |
async function lookupTweets() {
|
| 75 |
const data: TweetMentions = await ff(`users/${BOT_ID}/mentions`);
|
| 76 |
|
| 77 |
-
|
| 78 |
`tweets?ids=${data.data
|
| 79 |
.map((t) => t.id)
|
| 80 |
.join(
|
|
@@ -82,55 +64,69 @@ async function lookupTweets() {
|
|
| 82 |
)}&expansions=attachments.media_keys&media.fields=duration_ms,height,media_key,preview_image_url,public_metrics,type,url,width,alt_text`
|
| 83 |
);
|
| 84 |
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
const
|
| 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 |
-
await
|
| 121 |
-
|
| 122 |
-
console.log("app started on port", port);
|
| 123 |
-
|
| 124 |
-
process.send?.("ready");
|
| 125 |
-
} catch (err) {
|
| 126 |
-
console.error(err);
|
| 127 |
}
|
| 128 |
}
|
| 129 |
|
| 130 |
-
listen();
|
| 131 |
-
|
| 132 |
process.on("unhandledRejection", async (err) => {
|
| 133 |
console.error("unhandled rejection", err);
|
| 134 |
});
|
| 135 |
|
| 136 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import OAuth from "oauth";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
import "dotenv/config";
|
| 3 |
+
import { setTimeout } from "timers/promises";
|
| 4 |
|
| 5 |
+
const { API_KEY, API_SECRET, BEARER_TOKEN, ACCESS_TOKEN, ACCESS_TOKEN_SECRET } = process.env;
|
| 6 |
|
| 7 |
+
function getAuthHeader(oauth: OAuth.OAuth, url: string) {
|
| 8 |
+
return oauth.authHeader(url, ACCESS_TOKEN as string, ACCESS_TOKEN_SECRET as string, "post");
|
| 9 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
+
const client = new OAuth.OAuth(
|
| 12 |
+
"https://api.twitter.com/oauth/request_token",
|
| 13 |
+
"https://api.twitter.com/oauth/access_token",
|
| 14 |
+
API_KEY as string,
|
| 15 |
+
API_SECRET as string,
|
| 16 |
+
"1.0A",
|
| 17 |
+
null,
|
| 18 |
+
"HMAC-SHA1"
|
| 19 |
+
);
|
| 20 |
|
|
|
|
| 21 |
const BOT_ID = "1612094318906417152";
|
| 22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
interface TweetMentions {
|
| 24 |
data: Array<{ id: string; text: string }>;
|
| 25 |
meta: {
|
|
|
|
| 51 |
return await resp.json();
|
| 52 |
}
|
| 53 |
|
| 54 |
+
let lastMention = "";
|
| 55 |
+
|
| 56 |
async function lookupTweets() {
|
| 57 |
const data: TweetMentions = await ff(`users/${BOT_ID}/mentions`);
|
| 58 |
|
| 59 |
+
let lookups: TweetLookups = await ff(
|
| 60 |
`tweets?ids=${data.data
|
| 61 |
.map((t) => t.id)
|
| 62 |
.join(
|
|
|
|
| 64 |
)}&expansions=attachments.media_keys&media.fields=duration_ms,height,media_key,preview_image_url,public_metrics,type,url,width,alt_text`
|
| 65 |
);
|
| 66 |
|
| 67 |
+
if (!lastMention) {
|
| 68 |
+
console.log("added mention", lookups.data[0].id);
|
| 69 |
+
lastMention = lookups.data[0].id;
|
| 70 |
+
return;
|
| 71 |
+
}
|
| 72 |
+
const tweets = lookups.data.filter((tweet) => tweet.attachments?.media_keys.length === 1 && tweet.id > lastMention);
|
| 73 |
+
lastMention = lookups.data[0].id;
|
| 74 |
+
console.log(lastMention);
|
| 75 |
+
|
| 76 |
+
for (const tweet of tweets) {
|
| 77 |
+
const imageUrl = lookups.includes.media.find((media) => media.media_key === tweet?.attachments!.media_keys[0])
|
| 78 |
+
?.url!;
|
| 79 |
+
|
| 80 |
+
console.log("imageUrl", imageUrl);
|
| 81 |
+
|
| 82 |
+
const imageResp = await fetch(imageUrl);
|
| 83 |
+
const contentType = imageResp.headers.get("Content-Type");
|
| 84 |
+
const image = await imageResp.arrayBuffer();
|
| 85 |
+
|
| 86 |
+
console.log(contentType, image);
|
| 87 |
+
|
| 88 |
+
const altText = await fetch("https://olivierdehaene-git-large-coco.hf.space/run/predict", {
|
| 89 |
+
method: "POST",
|
| 90 |
+
headers: { "Content-Type": "application/json" },
|
| 91 |
+
body: JSON.stringify({
|
| 92 |
+
data: [`data:${contentType};base64,${Buffer.from(image).toString("base64")}`],
|
| 93 |
+
}),
|
| 94 |
+
})
|
| 95 |
+
.then((r) => r.json())
|
| 96 |
+
.then((r) => r.data);
|
| 97 |
+
|
| 98 |
+
console.log(altText[0]);
|
| 99 |
+
|
| 100 |
+
const header = getAuthHeader(client, "https://api.twitter.com/2/tweets");
|
| 101 |
+
|
| 102 |
+
const r = await fetch("https://api.twitter.com/2/tweets", {
|
| 103 |
+
headers: {
|
| 104 |
+
Authorization: header,
|
| 105 |
+
"user-agent": "v3CreateTweetJS",
|
| 106 |
+
"content-type": "application/json",
|
| 107 |
+
accept: "application/json",
|
| 108 |
+
},
|
| 109 |
+
body: JSON.stringify({
|
| 110 |
+
text: altText[0],
|
| 111 |
+
reply: { in_reply_to_tweet_id: tweet!.id, conversation_id: tweet!.conversation_id },
|
| 112 |
+
}),
|
| 113 |
+
method: "post",
|
| 114 |
});
|
| 115 |
|
| 116 |
+
console.log("end", await r.text());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
}
|
| 118 |
}
|
| 119 |
|
|
|
|
|
|
|
| 120 |
process.on("unhandledRejection", async (err) => {
|
| 121 |
console.error("unhandled rejection", err);
|
| 122 |
});
|
| 123 |
|
| 124 |
+
async function run() {
|
| 125 |
+
while (1) {
|
| 126 |
+
console.log("looking up");
|
| 127 |
+
await lookupTweets();
|
| 128 |
+
await setTimeout(5_000);
|
| 129 |
+
}
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
run();
|