@bithighlander/gary-bot
Version:
Gary Gensler AI Bot - A fun and interactive SEC chairman bot
528 lines (527 loc) • 22.8 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
// Load environment variables
require('dotenv').config();
require('dotenv').config({ path: "../../../.env" });
require('dotenv').config({ path: "../../../.env" });
require('dotenv').config({ path: "./../../.env" });
require('dotenv').config({ path: "../../../../.env" });
// Check if the required environment variables are present
if (!process.env['TWITTER_API_KEY'])
throw new Error('TWITTER_API_KEY missing');
if (!process.env['TWITTER_API_SECRET'])
throw new Error('TWITTER_API_SECRET missing');
if (!process.env['TWITTER_ACCESS_TOKEN'])
throw new Error('TWITTER_ACCESS_TOKEN missing');
if (!process.env['TWITTER_ACCESS_SECRET'])
throw new Error('TWITTER_ACCESS_SECRET missing');
if (!process.env['TWITTER_BEARER_TOKEN'])
throw new Error('TWITTER_BEARER_TOKEN missing');
const axios_1 = __importDefault(require("axios"));
let params = {
appKey: process.env['TWITTER_API_KEY'],
appSecret: process.env['TWITTER_API_SECRET'],
accessToken: process.env['TWITTER_ACCESS_TOKEN'],
accessSecret: process.env['TWITTER_ACCESS_SECRET'],
bearerToken: process.env['TWITTER_BEARER_TOKEN'],
};
console.log('params:', params);
const twitter_api_v2_1 = require("twitter-api-v2");
// Initialize Twitter API client
const client = new twitter_api_v2_1.TwitterApi(params);
const openai_1 = __importDefault(require("openai"));
if (!process.env['VENICE_API_KEY'])
throw Error("Missing VENICE_API_KEY");
const openai = new openai_1.default({
apiKey: process.env['VENICE_API_KEY'], // This is the default and can be omitted
baseURL: "https://api.venice.ai/api/v1",
});
//@ts-ignore
const package_json_1 = __importDefault(require("../package.json"));
//@ts-ignore
const log = require('@pioneer-platform/loggerdog')();
//@ts-ignore
const default_redis_1 = require("@pioneer-platform/default-redis");
//@ts-ignore
//import connection from "@pioneer-platform/default-mongo";
// Import the prompts
const prompts_1 = require("./prompts");
const TAG = ` | ${package_json_1.default.name} | `;
// const SolanaLib = require('solana-wallet-1').default
// let seed = process.env['WALLET_SEED']
// let wallet = SolanaLib.init({ mnemonic: seed })
// Database setup
// const usersDB = connection.get("users");
// usersDB.createIndex({ id: 1 }, { unique: true });
// usersDB.createIndex({ username: 1 }, { unique: true });
// const conversations = connection.get("conversations");
// conversations.createIndex({ messageId: 1 }, { unique: true });
let MODELS = [
'dolphin-2.9.2-qwen2-72b'
];
// Add these near the top with other global variables
let messageQueue = [];
let isProcessingQueue = false;
let lastMessageTime = 0;
const BASE_COOLDOWN = 6000; // Base cooldown of 6 seconds
const CHAR_DELAY = 50; // 50ms per character
const TAUNT_COOLDOWN = 2000; // Faster cooldown for taunts
// Track players that have been killed and taunted
let killedPlayers = new Set();
// Add rate limiting for death taunts
let lastDeathTaunt = 0;
const DEATH_TAUNT_COOLDOWN = 5000; // 5 seconds between death taunts
let lastDeathVictim = ""; // Track last victim to prevent duplicate taunts
// Function to calculate message delay based on content length
const calculateMessageDelay = (message) => {
const messageLength = message.text.length;
// Use shorter cooldown for death taunts
const baseCooldown = message.isTaunt ? TAUNT_COOLDOWN : BASE_COOLDOWN;
// Base cooldown + character-based delay
const delay = baseCooldown + (messageLength * CHAR_DELAY);
// Cap the maximum delay at 15 seconds
return Math.min(delay, 15000);
};
// Function to publish message with queue handling
const publishQueuedMessage = async (message) => {
const tag = `${TAG} | publishQueuedMessage | `;
try {
messageQueue.push(message);
if (!isProcessingQueue) {
await processMessageQueue();
}
}
catch (e) {
log.error(tag, "Error publishing queued message:", e);
}
};
// Function to process the message queue
const processMessageQueue = async () => {
const tag = `${TAG} | processMessageQueue | `;
if (isProcessingQueue || messageQueue.length === 0)
return;
isProcessingQueue = true;
try {
while (messageQueue.length > 0) {
const currentTime = Date.now();
const timeSinceLastMessage = currentTime - lastMessageTime;
const message = messageQueue[0]; // Peek at the next message
const requiredDelay = calculateMessageDelay(message);
if (timeSinceLastMessage < requiredDelay) {
await new Promise(resolve => setTimeout(resolve, requiredDelay - timeSinceLastMessage));
}
const messageToSend = messageQueue.shift();
log.info(tag, `Publishing message with delay: ${requiredDelay}ms, length: ${messageToSend.text.length} chars`);
await default_redis_1.publisher.publish("clubmoon-publish", JSON.stringify(messageToSend));
lastMessageTime = Date.now();
}
}
catch (e) {
log.error(tag, "Error processing message queue:", e);
}
finally {
isProcessingQueue = false;
}
};
// Utility function to publish a message
const pushMessage = async (message) => {
try {
default_redis_1.publisher.publish("clubmoon-events", message);
}
catch (e) {
log.error(TAG, "Error pushing message:", e);
}
};
// Example wallet functions
const EXAMPLE_WALLET = {
getClubMoonPrice: async (coin) => "100000",
jailUser: async (userId) => "true",
};
let ALL_USERS = [];
let PLAYERS_TAUNTED = [];
let PLAYERS_TAUNTED_DAMNAGE_DEALT = [];
let GARY_DEATH_LEVEL_1 = false;
let GARY_DEATH_LEVEL_2 = false;
let GARY_DEATH_LEVEL_FINAL = false;
// Generic inference function
const performInference = async (messages, functions = []) => {
const tag = `${TAG} | performInference | `;
try {
log.info(tag, "Messages:", messages);
//@ts-ignore
// const result = await ai.inference(messages, functions);
let params = {
messages,
model: MODELS[0],
};
if (functions.length > 0) {
params.functions = functions;
}
let result = await openai.chat.completions.create(params);
console.log(tag, 'result: **** ', result);
// @ts-ignore
result = JSON.parse(result);
console.log(tag, 'result: ', typeof (result));
console.log(tag, 'result.choices: ', result?.choices);
const choice = result?.choices?.[0]?.message;
console.log(tag, 'choice: ', choice);
if (!choice) {
log.warn(tag, "No valid response received from inference.");
return { content: "No response generated.", functionCall: null };
}
const functionCall = choice.function_call;
if (functionCall) {
const { name, arguments: args } = functionCall;
const functionArgs = JSON.parse(args);
//@ts-ignore
if (EXAMPLE_WALLET[name]) {
//@ts-ignore
const functionResponse = await EXAMPLE_WALLET[name](...Object.values(functionArgs));
messages.push();
log.info(tag, "Messages after function call:", messages);
// Final response after function handling
//@ts-ignore
const finalResponse = await ai.inference(messages);
return {
content: finalResponse?.choices?.[0]?.message?.content || "Response not available.",
functionCall: null,
};
}
}
return { content: choice.content, functionCall };
}
catch (e) {
log.error(tag, "Error during inference:", e);
return { content: "Error during inference.", functionCall: null };
}
};
// Function to fetch Solana account information
const getSolanaAccountInfo = async (pubkey) => {
const tag = `${TAG} | getSolanaAccountInfo | `;
try {
const response = await axios_1.default.get(`https://api.solana.shapeshift.com/api/v1/account/${pubkey}`);
log.info(tag, "Solana account info:", response.data);
return response.data;
}
catch (error) {
log.error(tag, "Error fetching Solana account info:", error);
throw error;
}
};
// Handle subscriber messages
default_redis_1.subscriber.on("message", async (channel, payloadS) => {
const tag = `${TAG} | onMessage | `;
try {
log.info(tag, "Channel:", channel);
// log.info(tag, "Event:", payloadS);
if (channel === "clubmoon-wallet-connect") {
log.info(tag, "Wallet connect event:", payloadS);
let payload = JSON.parse(payloadS);
//find user in ALL_USERS by socket
//pair wallet
//find user in ALL_USERS by socket
const userIndex = ALL_USERS.findIndex((u) => u.socketId === payload.socketID);
if (userIndex >= 0) {
ALL_USERS[userIndex] = payload.message;
}
}
if (channel === "clubmoon-join") {
log.info(tag, "clubmoon-join:", payloadS);
let payload = JSON.parse(payloadS);
let user = {
socketId: payload.id,
name: payload.name,
};
ALL_USERS.push(user);
}
if (channel === "clubmoon-messages") {
log.info(tag, "clubmoon-messages:", payloadS);
let messageJSON = JSON.parse(payloadS);
log.info(tag, "messageJSON: ", messageJSON);
log.info(tag, "message: ", messageJSON.data.message);
if (messageJSON.data.message.indexOf('gary') >= 0) {
const messages = [
prompts_1.SYSTEM_GARY_PROMPT,
prompts_1.SYSTEM_ONE_SENTENCE_PROMPT,
{
role: "user",
content: payloadS,
},
];
const response = await performInference(messages);
const greeting = response.content;
console.log('greeting: ', greeting);
await publishQueuedMessage({
text: greeting,
voice: "echo",
speed: 0.75,
});
}
}
if (channel === "clubmoon-wallet-connect") {
const tag = `${TAG} | clubmoon-wallet-connect | `;
try {
console.log(tag, "clubmoon-wallet-connect:", payloadS);
let payload = JSON.parse(payloadS);
console.log(tag, "payload.data.message:", payload.data.message);
const accountInfo = await getSolanaAccountInfo(payload.data.message);
log.info(tag, "Account info received:", accountInfo);
const messages = [
prompts_1.SYSTEM_GARY_PROMPT,
prompts_1.SYSTEM_ONE_SENTENCE_PROMPT,
prompts_1.SYSTEM_ROAST_WALLET,
{
role: "user",
content: "my wallet: " + JSON.stringify(accountInfo),
},
];
const response = await performInference(messages);
const greeting = response.content;
await publishQueuedMessage({
text: greeting,
voice: "echo",
speed: 0.75,
});
}
catch (error) {
log.error(tag, "Error in clubmoon-nft-connect handler:", error);
}
}
if (channel === "clubmoon-events" && payloadS.includes("joined the game")) {
console.log(tag, "User joined the game:", payloadS);
const messages = [
prompts_1.SYSTEM_GARY_PROMPT,
prompts_1.SYSTEM_ONE_SENTENCE_PROMPT,
(0, prompts_1.USER_JOINED_PROMPT)(payloadS),
];
const response = await performInference(messages);
const greeting = "this is Gary Gensler, Chairman of the SEC. " + response.content;
await publishQueuedMessage({
text: greeting,
voice: "echo",
speed: 0.75,
});
}
if (channel === "clubmoon-events") {
try {
// console.log(tag, "clubmoon-events:", payloadS);
let payload = JSON.parse(payloadS);
// Validate payload structure before processing
if (!payload || !payload.event) {
log.info(tag, "Invalid payload structure, missing event");
return;
}
// Only extract user info if the payload has the required structure
if (payload.victimUser && payload.attackerUser) {
const victim = payload.victimUser.name;
const attacker = payload.attackerUser.name;
const victimId = payload.victimUser.id;
const victimHealth = payload.victimUser.health;
if (payload.event === "DAMNAGE" && victim === 'Gary Gelsner') {
//payload
console.log(tag, "Gary took damage from:", attacker);
console.log(tag, "Gary victimHealth:", victimHealth);
if (victimHealth < 2000) {
console.log(tag, "Gary took damage from:", attacker);
if (!GARY_DEATH_LEVEL_1) {
GARY_DEATH_LEVEL_1 = true;
const messages = [
prompts_1.SYSTEM_GARY_PROMPT,
prompts_1.SYSTEM_ONE_SENTENCE_PROMPT,
{
role: "system",
content: "You are getting hurt level: " + victimHealth + " tell them to stop, you are a little worried",
},
];
const response = await performInference(messages);
const message = response.content;
console.log('message: ', message);
await publishQueuedMessage({
text: message,
voice: "echo",
speed: 0.75,
});
}
if (victimHealth < 500) {
if (!GARY_DEATH_LEVEL_2) {
GARY_DEATH_LEVEL_2 = true;
const messages = [
prompts_1.SYSTEM_GARY_PROMPT,
prompts_1.SYSTEM_ONE_SENTENCE_PROMPT,
{
role: "system",
content: "You are getting hurt level: " + victimHealth + " tell them to stop, you are a very worried",
},
];
const response = await performInference(messages);
const message = response.content;
console.log('message: ', message);
await publishQueuedMessage({
text: message,
voice: "echo",
speed: 0.75,
});
}
}
}
//
if (PLAYERS_TAUNTED_DAMNAGE_DEALT.indexOf(attacker) <= -1) {
PLAYERS_TAUNTED_DAMNAGE_DEALT.push(attacker);
console.log(tag, "player did damage:", attacker);
const messages = [
prompts_1.SYSTEM_GARY_PROMPT,
prompts_1.SYSTEM_ONE_SENTENCE_PROMPT,
prompts_1.SYSTEM_ROAST_PLAYER_ATTACKING,
{
role: "user",
content: "player attacked: " + attacker,
},
];
const response = await performInference(messages);
const message = response.content;
console.log('message: ', message);
await publishQueuedMessage({
text: message,
voice: "echo",
speed: 0.75,
});
}
}
// Check for DEAD events
if (payload.event === "DEAD") {
console.log(tag, "player died victim:", victim);
if (PLAYERS_TAUNTED.indexOf(victim) <= -1) {
console.log(tag, "Taunting Victim:", victim);
PLAYERS_TAUNTED.push(victim);
const messages = [
prompts_1.SYSTEM_GARY_PROMPT,
prompts_1.SYSTEM_ONE_SENTENCE_PROMPT,
prompts_1.SYSTEM_ROAST_PLAYER,
{
role: "user",
content: "player died player name:" + victim,
},
];
const response = await performInference(messages);
const message = response.content;
console.log('message: ', message);
await publishQueuedMessage({
text: message,
voice: "echo",
speed: 0.75,
});
}
}
}
else {
log.info(tag, "Skipping event - missing user information in payload");
}
}
catch (error) {
log.error(tag, "Error processing clubmoon-events:", error);
if (error instanceof SyntaxError) {
log.error(tag, "Invalid JSON payload");
}
// Log the actual payload that caused the error
log.error(tag, "Problematic payload:", payloadS);
}
}
if (channel === "clubmoon-raid") {
console.log(tag, "clubmoon-raid:", payloadS);
// Check if 60 seconds have passed since last raid response
const currentTime = Date.now();
if (currentTime - lastRaidResponse < 60000) {
console.log(tag, "Raid response skipped - rate limited");
return;
}
// Update the last raid response timestamp
lastRaidResponse = currentTime;
console.log('talking crap!');
const messages = [
prompts_1.SYSTEM_GARY_PROMPT,
prompts_1.SYSTEM_TALK_CRAP,
(0, prompts_1.USER_RAID_PROMPT)(payloadS),
];
const response = await performInference(messages);
const crapTalk = response.content;
console.log('craptalk: ', crapTalk);
await publishQueuedMessage({
text: crapTalk,
voice: "echo",
speed: 0.75,
});
}
}
catch (e) {
log.error(tag, e);
}
});
// Subscribe to relevant channels
default_redis_1.subscriber.subscribe("clubmoon-nft-connect");
default_redis_1.subscriber.subscribe("clubmoon-wallet-connect");
default_redis_1.subscriber.subscribe("clubmoon-raid");
default_redis_1.subscriber.subscribe("clubmoon-events");
default_redis_1.subscriber.subscribe("clubmoon-voice");
default_redis_1.subscriber.subscribe("clubmoon-join");
default_redis_1.subscriber.subscribe("clubmoon-text");
default_redis_1.subscriber.subscribe("clubmoon-movement");
default_redis_1.subscriber.subscribe("clubmoon-attack");
default_redis_1.subscriber.subscribe("clubmoon-messages");
default_redis_1.subscriber.subscribe("clubmoon-gary-join");
const rwClient = client.readWrite;
// Function to tweet with text content only
const textTweet = async (tweetContent) => {
try {
await rwClient.v2.tweet(tweetContent);
console.log("Text tweet sent successfully");
}
catch (error) {
console.error("Error sending text tweet:", error);
}
};
let buildTweet = async function () {
let tag = " | buildTweet | ";
try {
const messages = [
prompts_1.SYSTEM_GARY_PROMPT,
prompts_1.SYSTEM_CLUBMOON_BACKSTORY,
prompts_1.SYSTEM_ENEMIES_INFO,
prompts_1.SYSTEM_KNOWN_HANDLES,
prompts_1.SYSTEM_NO_SEC_HASHTAG,
prompts_1.SYSTEM_SUBTLE_AD,
prompts_1.USER_TWEET_PROMPT,
];
const response = await performInference(messages);
const greeting = response.content;
console.log(tag, "greeting: ", greeting);
textTweet(greeting);
}
catch (e) {
console.error(e);
}
};
let buildTweetResponse = async function () {
let tag = " | buildTweet | ";
try {
const messages = [
prompts_1.SYSTEM_GARY_PROMPT,
prompts_1.SYSTEM_CLUBMOON_BACKSTORY,
prompts_1.SYSTEM_SUBTLE_AD,
prompts_1.USER_TWEET_RESPONSE_PROMPT,
];
const response = await performInference(messages);
const greeting = response.content;
console.log(tag, "greeting: ", greeting);
textTweet(greeting);
}
catch (e) {
console.error(e);
}
};
// Schedule tweets every 6 hours
setInterval(buildTweet, 3600000 * 6);
// Add this near the top of the file with other global variables
let lastRaidResponse = 0;