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();
|