Skip to content

Commit b350f3c

Browse files
authored
Merge pull request #1040 from ai16z/tcm-twitter-image
fix: Allow bot to post tweets with images generated by the imageGenerationPlugin
2 parents bf60b96 + 711bbc6 commit b350f3c

File tree

4 files changed

+60
-4
lines changed

4 files changed

+60
-4
lines changed

packages/client-twitter/src/interactions.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,8 @@ export class TwitterInteractionClient {
448448
await this.runtime.processActions(
449449
message,
450450
responseMessages,
451-
state
451+
state,
452+
callback
452453
);
453454

454455
const responseInfo = `Context:\n\n${context}\n\nSelected Post: ${tweet.id} - ${tweet.username}: ${tweet.text}\nAgent's Output:\n${response.text}`;

packages/client-twitter/src/utils.ts

+48-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import { stringToUuid } from "@ai16z/eliza";
55
import { ClientBase } from "./base";
66
import { elizaLogger } from "@ai16z/eliza";
77
import { DEFAULT_MAX_TWEET_LENGTH } from "./environment";
8+
import { Media } from "@ai16z/eliza";
9+
import fs from "fs";
10+
import path from "path";
811

912
export const wait = (minTime: number = 1000, maxTime: number = 3000) => {
1013
const waitTime =
@@ -162,6 +165,16 @@ export async function buildConversationThread(
162165
return thread;
163166
}
164167

168+
export function getMediaType(attachment: Media) {
169+
if (attachment.contentType?.startsWith("video")) {
170+
return "video";
171+
} else if (attachment.contentType?.startsWith("image")) {
172+
return "image";
173+
} else {
174+
throw new Error(`Unsupported media type`);
175+
}
176+
}
177+
165178
export async function sendTweet(
166179
client: ClientBase,
167180
content: Content,
@@ -178,11 +191,45 @@ export async function sendTweet(
178191
let previousTweetId = inReplyTo;
179192

180193
for (const chunk of tweetChunks) {
194+
let mediaData: { data: Buffer; mediaType: string }[] | undefined;
195+
196+
if (content.attachments && content.attachments.length > 0) {
197+
mediaData = await Promise.all(
198+
content.attachments.map(async (attachment: Media) => {
199+
if (/^(http|https):\/\//.test(attachment.url)) {
200+
// Handle HTTP URLs
201+
const response = await fetch(attachment.url);
202+
if (!response.ok) {
203+
throw new Error(
204+
`Failed to fetch file: ${attachment.url}`
205+
);
206+
}
207+
const mediaBuffer = Buffer.from(
208+
await response.arrayBuffer()
209+
);
210+
const mediaType = getMediaType(attachment);
211+
return { data: mediaBuffer, mediaType };
212+
} else if (fs.existsSync(attachment.url)) {
213+
// Handle local file paths
214+
const mediaBuffer = await fs.promises.readFile(
215+
path.resolve(attachment.url)
216+
);
217+
const mediaType = getMediaType(attachment);
218+
return { data: mediaBuffer, mediaType };
219+
} else {
220+
throw new Error(
221+
`File not found: ${attachment.url}. Make sure the path is correct.`
222+
);
223+
}
224+
})
225+
);
226+
}
181227
const result = await client.requestQueue.add(
182228
async () =>
183229
await client.twitterClient.sendTweet(
184230
chunk.trim(),
185-
previousTweetId
231+
previousTweetId,
232+
mediaData
186233
)
187234
);
188235
const body = await result.json();

packages/core/src/types.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,9 @@ export type Media = {
561561

562562
/** Text content */
563563
text: string;
564+
565+
/** Content type */
566+
contentType?: string;
564567
};
565568

566569
/**
@@ -1139,12 +1142,16 @@ export interface IPdfService extends Service {
11391142
}
11401143

11411144
export interface IAwsS3Service extends Service {
1142-
uploadFile(imagePath: string, useSignedUrl: boolean, expiresIn: number ): Promise<{
1145+
uploadFile(
1146+
imagePath: string,
1147+
useSignedUrl: boolean,
1148+
expiresIn: number
1149+
): Promise<{
11431150
success: boolean;
11441151
url?: string;
11451152
error?: string;
11461153
}>;
1147-
generateSignedUrl(fileName: string, expiresIn: number): Promise<string>
1154+
generateSignedUrl(fileName: string, expiresIn: number): Promise<string>;
11481155
}
11491156

11501157
export type SearchResult = {

packages/plugin-image-generation/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ const imageGeneration: Action = {
205205
source: "imageGeneration",
206206
description: "...", //caption.title,
207207
text: "...", //caption.description,
208+
contentType: "image",
208209
},
209210
],
210211
},

0 commit comments

Comments
 (0)