Skip to content

Instantly share code, notes, and snippets.

@shouc
Created April 30, 2025 04:36
Show Gist options
  • Save shouc/d3777f4d453db98194800fae8d190dcd to your computer and use it in GitHub Desktop.
Save shouc/d3777f4d453db98194800fae8d190dcd to your computer and use it in GitHub Desktop.
trent monitor
import { TwitterApi } from 'twitter-api-v2';
import { Configuration, OpenAIApi } from 'openai';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import TelegramBot from 'node-telegram-bot-api';
import * as dotenv from 'dotenv';
dotenv.config();
enum Victim {
FIREDANCER = 'Firedancer',
SOLAYER = 'Solayer',
ECLIPSE = 'Eclipse',
FOGO = 'Fogo',
}
interface TweetAnalysisResult {
victim: Victim | null;
confidence: number;
explanation: string;
}
class TwitterMonitor {
private twitterClient: TwitterApi;
private openaiClient: OpenAIApi;
private telegramBot: TelegramBot | null = null;
private telegramChatId: string | null = null;
constructor(twitterBearerToken: string, openaiApiKey: string, telegramToken?: string, telegramChatId?: string) {
this.twitterClient = new TwitterApi(twitterBearerToken);
const configuration = new Configuration({
apiKey: openaiApiKey,
});
this.openaiClient = new OpenAIApi(configuration);
if (telegramToken) {
this.telegramBot = new TelegramBot(telegramToken, { polling: false });
this.telegramChatId = telegramChatId || null;
}
}
async monitorUser(username: string = "trentdotsol", limit: number = 10): Promise<void> {
try {
const user = await this.twitterClient.v2.userByUsername(username);
if (!user.data) {
throw new Error(`User ${username} not found`);
}
const userId = user.data.id;
const tweets = await this.twitterClient.v2.userTimeline(userId, {
max_results: limit,
exclude: ['retweets', 'replies']
});
for (const tweet of tweets.data.data) {
const analysis = await this.analyzeTweet(tweet.text);
const message = `
Tweet: ${tweet.text}
Analysis:
${analysis.victim ? `Target: ${analysis.victim}` : 'No specific target identified'}
Confidence: ${analysis.confidence}%
Explanation: ${analysis.explanation}
`;
console.log(message);
if (this.telegramBot && this.telegramChatId) {
await this.telegramBot.sendMessage(this.telegramChatId, message);
}
}
} catch (error) {
console.error('Error monitoring Twitter:', error);
if (this.telegramBot && this.telegramChatId) {
await this.telegramBot.sendMessage(this.telegramChatId, `Error monitoring Twitter: ${error}`);
}
}
}
private async analyzeTweet(tweetText: string): Promise<TweetAnalysisResult> {
try {
const prompt = `
Analyze the following tweet and picture and determine if it's targeting any of these projects:
- Firedancer
- Solayer
- Eclipse
- Fogo
Tweet: "${tweetText}"
If the tweet is targeting one of these, identify which one, provide a confidence score (0-100),
and explain your reasoning. If it's not targeting any of them, indicate that.
`;
const response = await this.openaiClient.createChatCompletion({
model: "gpt-4o-mini",
messages: [
{ role: "system", content: "You are an expert at analyzing tweets about project." },
{ role: "user", content: prompt }
],
});
const content = response.data.choices[0]?.message?.content || '';
return this.parseGptResponse(content);
} catch (error) {
console.error('Error analyzing tweet with GPT:', error);
return {
victim: null,
confidence: 0,
explanation: 'Error analyzing tweet'
};
}
}
private parseGptResponse(response: string): TweetAnalysisResult {
let victim: Victim | null = null;
let confidence = 0;
let explanation = '';
// Look for mentions of each victim
for (const v of Object.values(Victim)) {
if (response.includes(v)) {
victim = v as Victim;
break;
}
}
// Extract confidence score if present
const confidenceMatch = response.match(/confidence[:\s]+(\d+)/i);
if (confidenceMatch && confidenceMatch[1]) {
confidence = parseInt(confidenceMatch[1], 10);
}
// Extract explanation
const explanationMatch = response.match(/reasoning[:\s]+(.*)/i);
if (explanationMatch && explanationMatch[1]) {
explanation = explanationMatch[1].trim();
} else {
explanation = response; // Use full response if no specific explanation found
}
return {
victim,
confidence,
explanation
};
}
}
async function main() {
const argv = await yargs(hideBin(process.argv))
.option('username', {
alias: 'u',
description: 'Twitter username to monitor',
type: 'string',
default: 'trentdotsol'
})
.option('limit', {
alias: 'l',
description: 'Number of tweets to analyze',
type: 'number',
default: 10
})
.help()
.alias('help', 'h')
.argv;
const twitterToken = process.env.TWITTER_BEARER_TOKEN;
const openaiToken = process.env.OPENAI_API_KEY;
const telegramToken = process.env.TELEGRAM_BOT_TOKEN;
const telegramChatId = process.env.TELEGRAM_CHAT_ID;
if (!twitterToken || !openaiToken) {
console.error('Missing required environment variables. Please set TWITTER_BEARER_TOKEN and OPENAI_API_KEY.');
process.exit(1);
}
const monitor = new TwitterMonitor(
twitterToken,
openaiToken,
telegramToken,
telegramChatId
);
while (true) {
await monitor.monitorUser(argv.username, argv.limit);
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
main().catch(error => {
console.error('Error in main execution:', error);
process.exit(1);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment