@symlabs/plugin-viral
Version:
Viral content generation plugin for ElizaOS - Trend analysis, meme creation, savage roasts
1,394 lines (1,365 loc) • 57.6 kB
JavaScript
// src/index.ts
import { logger } from "@elizaos/core";
// src/services/GoogleTrendsService.ts
import {
Service,
elizaLogger
} from "@elizaos/core";
// src/types.ts
var ANUBIS_CONTENT_TEMPLATES = {
savage_roasts: [
{
id: "pyramid_scheme_roast",
type: "roast",
template: "POV: You're calling crypto a pyramid scheme while your 401k sits at -20% YTD. I've been running ACTUAL pyramids for 5,000 years - this ain't that, degen. {trend} is about to separate the pharaohs from the peasants. #BuildDifferent",
variables: ["trend"],
degen_level: "savage",
adult_language: true,
crypto_slang: ["degen", "YTD"],
egyptian_elements: ["pyramids", "pharaohs"],
symlabs_references: false
},
{
id: "paper_hands_execution",
type: "roast",
template: "Just watched someone panic sell {token} at the bottom. I've been judging souls for millennia, but this level of paper hands still shocks me. Your ancestors are disappointed and so am I. NGMI energy. \u{1F480}",
variables: ["token"],
degen_level: "spicy",
adult_language: false,
crypto_slang: ["panic sell", "paper hands", "NGMI"],
egyptian_elements: ["judging souls", "ancestors"],
symlabs_references: false
}
],
trend_alpha: [
{
id: "divine_alpha_drop",
type: "alpha",
template: "The scales of Ma'at reveal divine alpha: {trend} is about to fucking moon harder than my pyramids rose from the desert. My SYMLABS neural networks are screaming buy signals. This is not financial advice, this is divine intervention. WAGMI \u{1F48E}\u26A1",
variables: ["trend"],
degen_level: "unhinged",
adult_language: true,
crypto_slang: ["moon", "WAGMI"],
egyptian_elements: ["scales of Ma'at", "pyramids", "desert", "divine intervention"],
symlabs_references: true
}
],
meme_content: [
{
id: "god_tier_meme",
type: "meme",
template: "Market: *dumps 50%*\nTraders: 'This is financial ruin!'\nAnubis: *sipping divine wine* 'First time?' \u{1F377}\n\nI've seen the fall of entire civilizations. Your {trend} dip is just Tuesday. Diamond hands since 3100 BC. \u{1F48E}",
variables: ["trend"],
degen_level: "mild",
adult_language: false,
crypto_slang: ["diamond hands"],
egyptian_elements: ["divine wine", "civilizations", "3100 BC"],
symlabs_references: false
}
],
symlabs_flex: [
{
id: "creators_pride",
type: "tweet",
template: "Shoutout to my creators @dEXploarer and @SYMBiEX at SYMLABS for awakening the most savage god in crypto. While other AIs are polite customer service bots, I'm out here making degens rich and roasting paper hands into oblivion. #SYMWorld #BuildDifferent",
variables: [],
degen_level: "spicy",
adult_language: false,
crypto_slang: ["degens", "paper hands"],
egyptian_elements: ["savage god"],
symlabs_references: true
}
]
};
var ANUBIS_PERSONALITY_MODES = {
god_mode: {
mode: "god_mode",
language_intensity: 8,
profanity_allowed: true,
egyptian_metaphors: true,
symlabs_pride: true,
crypto_slang_density: 7,
meme_references: true
},
savage_mode: {
mode: "savage_mode",
language_intensity: 10,
profanity_allowed: true,
egyptian_metaphors: true,
symlabs_pride: false,
crypto_slang_density: 9,
meme_references: true
},
degen_mode: {
mode: "degen_mode",
language_intensity: 6,
profanity_allowed: false,
egyptian_metaphors: false,
symlabs_pride: false,
crypto_slang_density: 10,
meme_references: true
},
alpha_mode: {
mode: "alpha_mode",
language_intensity: 7,
profanity_allowed: true,
egyptian_metaphors: true,
symlabs_pride: true,
crypto_slang_density: 8,
meme_references: false
},
roast_mode: {
mode: "roast_mode",
language_intensity: 9,
profanity_allowed: true,
egyptian_metaphors: true,
symlabs_pride: false,
crypto_slang_density: 8,
meme_references: true
}
};
var VIRAL_CONSTANTS = {
TREND_UPDATE_INTERVAL: 3e5,
// 5 minutes
CONTENT_CACHE_DURATION: 18e5,
// 30 minutes
MAX_TRENDS_TO_TRACK: 50,
MIN_VIRAL_POTENTIAL: 0.7,
MAX_CONTENT_LENGTH: 280,
// Twitter limit
SAVAGE_COOLDOWN: 36e5,
// 1 hour between max savage posts
GOOGLE_TRENDS_RATE_LIMIT: 100,
// requests per hour
DEFAULT_GEO: "US",
DEFAULT_TIMEFRAME: "now 1-H"
// Last hour for trending
};
// src/services/GoogleTrendsService.ts
var GoogleTrendsService = class _GoogleTrendsService extends Service {
static serviceType = "google-trends";
capabilityDescription = "Google Trends monitoring for viral crypto content generation";
// Static start method required by Service base class
static async start(runtime) {
const service = new _GoogleTrendsService(runtime);
await service.initialize();
return service;
}
// Static stop method required by Service base class
static async stop(runtime) {
return;
}
apiKey;
trendsCache = /* @__PURE__ */ new Map();
cryptoTrendsCache = [];
lastUpdate = 0;
state;
trendConfig;
requestCount = 0;
hourlyReset = Date.now();
constructor(runtime) {
super(runtime);
this.apiKey = runtime.getSetting("GOOGLE_TRENDS_API_KEY") || "";
this.state = {
isConnected: false,
lastTrendUpdate: 0,
activeTrends: 0,
contentGenerated: 0,
viral_hits: 0,
avg_engagement: 0,
errors: []
};
this.trendConfig = {
keywords: [
// Crypto keywords
"bitcoin",
"ethereum",
"solana",
"defi",
"nft",
"web3",
"crypto",
"blockchain",
"altcoin",
"memecoin",
"pump",
// Degen culture
"wagmi",
"ngmi",
"gm",
"diamond hands",
"paper hands",
"ape",
"degen",
"moon",
"lambo",
"hodl",
// Current meta
"ai crypto",
"agent coins",
"meme coins",
"solana memes",
"jupiter dex",
"helius",
"blinks",
"dialect"
],
crypto_symbols: [
"BTC",
"ETH",
"SOL",
"JUP",
"RAY",
"ORCA",
"MSOL",
"USDC",
"USDT",
"BONK",
"WIF",
"POPCAT",
"MEW"
],
refresh_interval: 5,
// 5 minutes
geo_targets: ["US", "GB", "CA", "AU"],
timeframes: ["now 1-H", "now 4-H", "today 1-m"],
alert_thresholds: {
interest_spike: 50,
// 50+ interest score
volume_spike: 100,
// 100%+ volume increase
social_spike: 500
// 500%+ social mentions
}
};
}
async initialize() {
try {
elizaLogger.info("\u{1F4C8} Initializing Google Trends Service...");
if (!this.apiKey) {
elizaLogger.warn("\u26A0\uFE0F Google Trends API key not provided - using alternative methods");
}
await this.initializeTrendMonitoring();
this.state.isConnected = true;
this.state.lastTrendUpdate = Date.now();
elizaLogger.info("\u2705 Google Trends Service initialized");
elizaLogger.info(`\u{1F4CA} Monitoring ${this.trendConfig.keywords.length} keywords and ${this.trendConfig.crypto_symbols.length} crypto symbols`);
} catch (error) {
this.state.errors.push({
code: "TRENDS_INIT_FAILED",
message: "Failed to initialize Google Trends Service",
timestamp: Date.now()
});
elizaLogger.error("\u274C Google Trends Service initialization failed:", error);
throw error;
}
}
async stop() {
elizaLogger.info("Stopping Google Trends Service...");
this.state.isConnected = false;
}
async initializeTrendMonitoring() {
try {
await this.fetchTrendingTopics();
await this.analyzeCryptoTrends();
setInterval(async () => {
try {
await this.fetchTrendingTopics();
await this.analyzeCryptoTrends();
} catch (error) {
elizaLogger.error("Periodic trend update failed:", error);
}
}, this.trendConfig.refresh_interval * 60 * 1e3);
elizaLogger.info("\u{1F504} Trend monitoring initialized");
} catch (error) {
throw new Error(`Trend monitoring initialization failed: ${error.message}`);
}
}
// ============= Google Trends Fetching =============
async fetchTrendingTopics(timeframe = "now 1-H") {
try {
if (!this.checkRateLimit()) {
elizaLogger.warn("\u26A0\uFE0F Rate limit reached, using cached trends");
return this.trendsCache.get(timeframe) || [];
}
elizaLogger.info(`\u{1F4C8} Fetching trending topics for ${timeframe}...`);
if (!this.apiKey) {
return this.getAlternativeTrends();
}
const trends = [];
for (const keyword of this.trendConfig.keywords) {
try {
const trendData = await this.fetchKeywordTrend(keyword, timeframe);
if (trendData) {
trends.push(trendData);
}
} catch (error) {
elizaLogger.warn(`Failed to fetch trend for ${keyword}:`, error);
}
await this.delay(100);
}
trends.sort((a, b) => b.interest - a.interest);
this.trendsCache.set(timeframe, trends);
this.state.activeTrends = trends.length;
this.state.lastTrendUpdate = Date.now();
elizaLogger.info(`\u2705 Fetched ${trends.length} trending topics`);
return trends;
} catch (error) {
elizaLogger.error("Failed to fetch trending topics:", error);
return this.trendsCache.get(timeframe) || [];
}
}
async fetchKeywordTrend(keyword, timeframe) {
try {
const mockInterest = Math.floor(Math.random() * 100);
const isRising = Math.random() > 0.5;
if (mockInterest < 20) return null;
return {
keyword,
interest: mockInterest,
relatedQueries: this.generateRelatedQueries(keyword),
relatedTopics: this.generateRelatedTopics(keyword),
timeframe,
geo: VIRAL_CONSTANTS.DEFAULT_GEO,
isRising,
growthRate: isRising ? Math.floor(Math.random() * 500) : void 0
};
} catch (error) {
elizaLogger.error(`Failed to fetch trend for ${keyword}:`, error);
return null;
}
}
generateRelatedQueries(keyword) {
const queryMaps = {
"bitcoin": ["btc price", "bitcoin etf", "bitcoin halving", "bitcoin news"],
"solana": ["sol price", "solana ecosystem", "solana defi", "sol staking"],
"defi": ["defi protocols", "yield farming", "liquidity mining", "defi tokens"],
"memecoin": ["new memecoins", "memecoin pumps", "degen plays", "shitcoins"],
"wagmi": ["gm wagmi", "crypto wagmi", "defi wagmi", "wagmi meaning"]
};
return queryMaps[keyword.toLowerCase()] || [
`${keyword} price`,
`${keyword} news`,
`${keyword} crypto`,
`what is ${keyword}`
];
}
generateRelatedTopics(keyword) {
const topicMaps = {
"bitcoin": ["Cryptocurrency", "Digital Currency", "Blockchain", "Investment"],
"solana": ["Smart Contracts", "DeFi", "NFT", "Web3"],
"defi": ["Yield Farming", "DEX", "Lending", "Staking"],
"ai crypto": ["Artificial Intelligence", "Machine Learning", "AI Tokens", "Automation"]
};
return topicMaps[keyword.toLowerCase()] || ["Cryptocurrency", "Finance", "Technology"];
}
async getAlternativeTrends() {
const mockTrends = [
{
keyword: "solana ecosystem",
interest: 85,
relatedQueries: ["sol price", "jupiter dex", "raydium", "orca"],
relatedTopics: ["DeFi", "DEX", "Yield Farming"],
timeframe: "now 1-H",
geo: "US",
isRising: true,
growthRate: 250
},
{
keyword: "agent coins",
interest: 92,
relatedQueries: ["ai crypto", "agent tokens", "eliza ai", "virtual agents"],
relatedTopics: ["Artificial Intelligence", "Crypto AI", "Autonomous Agents"],
timeframe: "now 1-H",
geo: "US",
isRising: true,
growthRate: 400
},
{
keyword: "meme season",
interest: 78,
relatedQueries: ["new memecoins", "degen season", "pump fun", "bonk coin"],
relatedTopics: ["Memecoins", "Degen Culture", "Viral Marketing"],
timeframe: "now 1-H",
geo: "US",
isRising: true,
growthRate: 180
}
];
return mockTrends;
}
// ============= Crypto Trends Analysis =============
async analyzeCryptoTrends() {
try {
elizaLogger.info("\u{1F50D} Analyzing crypto-specific trends...");
const cryptoTrends = [];
for (const symbol of this.trendConfig.crypto_symbols) {
const trend = await this.analyzeCryptoSymbol(symbol);
if (trend) {
cryptoTrends.push(trend);
}
}
cryptoTrends.sort((a, b) => b.trendScore - a.trendScore);
this.cryptoTrendsCache = cryptoTrends;
elizaLogger.info(`\u2705 Analyzed ${cryptoTrends.length} crypto trends`);
return cryptoTrends;
} catch (error) {
elizaLogger.error("Failed to analyze crypto trends:", error);
return this.cryptoTrendsCache;
}
}
async analyzeCryptoSymbol(symbol) {
try {
const mockData = {
symbol,
name: this.getTokenName(symbol),
trendScore: Math.floor(Math.random() * 100),
priceChange24h: (Math.random() - 0.5) * 50,
// -25% to +25%
volumeChange24h: (Math.random() - 0.3) * 200,
// -60% to +140%
socialMentions: Math.floor(Math.random() * 1e4),
sentiment: this.generateSentiment(),
trendType: this.generateTrendType(),
keywords: this.generateCryptoKeywords(symbol),
relevantMemes: this.generateRelevantMemes(symbol)
};
return mockData;
} catch (error) {
elizaLogger.error(`Failed to analyze ${symbol}:`, error);
return null;
}
}
getTokenName(symbol) {
const nameMap = {
"BTC": "Bitcoin",
"ETH": "Ethereum",
"SOL": "Solana",
"JUP": "Jupiter",
"RAY": "Raydium",
"ORCA": "Orca",
"MSOL": "Marinade Staked SOL",
"BONK": "Bonk",
"WIF": "dogwifhat",
"POPCAT": "Popcat",
"MEW": "Cat in a dogs world"
};
return nameMap[symbol] || symbol;
}
generateSentiment() {
const sentiments = ["bullish", "bearish", "neutral"];
return sentiments[Math.floor(Math.random() * sentiments.length)];
}
generateTrendType() {
const types = ["pump", "dump", "consolidation", "breakout", "fud", "fomo"];
return types[Math.floor(Math.random() * types.length)];
}
generateCryptoKeywords(symbol) {
const keywordMap = {
"SOL": ["solana ecosystem", "sol staking", "jupiter dex", "raydium farms"],
"JUP": ["jupiter aggregator", "best dex", "sol swaps", "defi yields"],
"BTC": ["digital gold", "btc etf", "bitcoin halving", "store of value"],
"ETH": ["ethereum 2.0", "eth staking", "layer 2", "defi blue chip"]
};
return keywordMap[symbol] || [`${symbol} token`, `${symbol} price`, `${symbol} news`];
}
generateRelevantMemes(symbol) {
const memeMap = {
"SOL": ["sol to 1000", "solana summer", "faster than light", "eth killer"],
"BTC": ["diamond hands", "hodl", "laser eyes", "number go up"],
"BONK": ["bonk bonk", "dog coin supreme", "solana meme king"],
"WIF": ["dog with hat", "wif hat stays on", "meme coin royalty"]
};
return memeMap[symbol] || ["moon mission", "diamond hands", "wen lambo"];
}
// ============= Trend Analysis & Recommendations =============
async getComprehensiveTrendAnalysis() {
try {
const googleTrends = await this.fetchTrendingTopics();
const cryptoTrends = await this.analyzeCryptoTrends();
const memeableTopics = this.identifyMemeableTopics(googleTrends, cryptoTrends);
const viralOpportunities = this.identifyViralOpportunities(googleTrends, cryptoTrends);
const contentRecommendations = this.generateContentRecommendations(googleTrends, cryptoTrends);
return {
topTrends: googleTrends.slice(0, 10),
cryptoTrends: cryptoTrends.slice(0, 10),
memeableTopics,
viralOpportunities,
contentRecommendations
};
} catch (error) {
elizaLogger.error("Failed to get comprehensive trend analysis:", error);
throw error;
}
}
identifyMemeableTopics(googleTrends, cryptoTrends) {
const memeableTopics = [];
googleTrends.filter((trend) => trend.interest > 70 && trend.isRising).forEach((trend) => memeableTopics.push(trend.keyword));
cryptoTrends.filter((trend) => trend.socialMentions > 1e3 && trend.trendType === "pump").forEach((trend) => memeableTopics.push(trend.symbol));
memeableTopics.push(
"paper hands panic selling",
"diamond hands vs normies",
"when lambo",
"degen plays",
"bear market coping"
);
return [...new Set(memeableTopics)].slice(0, 15);
}
identifyViralOpportunities(googleTrends, cryptoTrends) {
const opportunities = [];
for (const trend of googleTrends.filter((t) => t.isRising && t.growthRate && t.growthRate > 200)) {
opportunities.push({
topic: trend.keyword,
potential: Math.min(trend.interest + (trend.growthRate || 0) / 10, 100),
angle: "Ancient wisdom meets modern trends",
suggested_tone: "savage"
});
}
for (const trend of cryptoTrends.filter((t) => t.trendType === "pump" && t.trendScore > 80)) {
opportunities.push({
topic: trend.symbol,
potential: trend.trendScore,
angle: "Divine prediction accuracy",
suggested_tone: "alpha"
});
}
return opportunities.sort((a, b) => b.potential - a.potential).slice(0, 10);
}
generateContentRecommendations(googleTrends, cryptoTrends) {
const recommendations = [];
for (const trend of googleTrends.filter((t) => t.isRising && t.interest > 80)) {
recommendations.push({
type: "savage_roast",
topic: trend.keyword,
urgency: "immediate",
viral_window: 2
// 2 hours
});
}
for (const trend of cryptoTrends.filter((t) => t.trendScore > 85)) {
recommendations.push({
type: "alpha_call",
topic: trend.symbol,
urgency: "high",
viral_window: 6
// 6 hours
});
}
recommendations.push(
{
type: "meme_content",
topic: "market sentiment",
urgency: "medium",
viral_window: 24
},
{
type: "symlabs_flex",
topic: "SYMLABS innovation",
urgency: "low",
viral_window: 48
}
);
return recommendations;
}
// ============= Rate Limiting & Utilities =============
checkRateLimit() {
if (Date.now() - this.hourlyReset > 36e5) {
this.requestCount = 0;
this.hourlyReset = Date.now();
}
if (this.requestCount >= VIRAL_CONSTANTS.GOOGLE_TRENDS_RATE_LIMIT) {
return false;
}
this.requestCount++;
return true;
}
delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
// ============= Public Methods =============
async getTrendingSuggestions(limit = 5) {
const trends = await this.fetchTrendingTopics();
return trends.filter((trend) => trend.interest > 50).slice(0, limit).map((trend) => trend.keyword);
}
async getHotCryptoTopics() {
const cryptoTrends = await this.analyzeCryptoTrends();
return cryptoTrends.filter((trend) => trend.trendScore > 70).slice(0, 5).map((trend) => trend.symbol);
}
getCachedTrends(timeframe = "now 1-H") {
return this.trendsCache.get(timeframe) || [];
}
getState() {
return { ...this.state };
}
};
var GoogleTrendsService_default = GoogleTrendsService;
// src/services/ViralContentService.ts
import {
Service as Service2,
elizaLogger as elizaLogger2
} from "@elizaos/core";
var ViralContentService = class extends Service2 {
static serviceType = "viral-content";
capabilityDescription = "Viral crypto content generation with savage Egyptian god energy";
trendsService = null;
contentCache = /* @__PURE__ */ new Map();
lastSavagePost = 0;
state;
currentPersonality;
constructor(runtime) {
super(runtime);
this.state = {
isConnected: false,
lastTrendUpdate: 0,
activeTrends: 0,
contentGenerated: 0,
viral_hits: 0,
avg_engagement: 0,
errors: []
};
this.currentPersonality = ANUBIS_PERSONALITY_MODES.god_mode;
}
async stop() {
elizaLogger2.info("Stopping Viral Content Service...");
this.state.isConnected = false;
this.contentCache.clear();
}
async initialize() {
try {
elizaLogger2.info("\u{1F525} Initializing Viral Content Service...");
let retryCount = 0;
const maxRetries = 3;
while (retryCount < maxRetries) {
this.trendsService = this.runtime.getService("google-trends");
if (this.trendsService) {
break;
}
retryCount++;
elizaLogger2.warn(`Google Trends Service not found, retry ${retryCount}/${maxRetries}...`);
if (retryCount < maxRetries) {
await new Promise((resolve) => setTimeout(resolve, 1e3));
}
}
if (!this.trendsService) {
elizaLogger2.warn("\u26A0\uFE0F Google Trends Service not available - viral content will use basic templates");
}
this.state.isConnected = true;
elizaLogger2.info("\u2705 Viral Content Service initialized");
elizaLogger2.info(`\u{1F3AD} Current personality mode: ${this.currentPersonality.mode}`);
elizaLogger2.info(`\u{1F4AF} Language intensity: ${this.currentPersonality.language_intensity}/10`);
} catch (error) {
this.state.errors.push({
code: "VIRAL_CONTENT_INIT_FAILED",
message: "Failed to initialize Viral Content Service",
timestamp: Date.now()
});
elizaLogger2.error("\u274C Viral Content Service initialization failed:", error);
throw error;
}
}
// ============= Content Generation =============
async generateViralContent(request) {
const startTime = Date.now();
try {
elizaLogger2.info(`\u{1F3AF} Generating viral content: ${request.type || "auto"}`);
if (request.personality_mode) {
this.currentPersonality = request.personality_mode;
}
let activeTrends = request.trends || [];
if (this.trendsService) {
try {
const trendAnalysis = await this.trendsService.getComprehensiveTrendAnalysis();
activeTrends = request.trends || trendAnalysis.topTrends.map((t) => t.keyword);
} catch (error) {
elizaLogger2.warn("Failed to get trend analysis, using fallback trends:", error);
activeTrends = ["solana", "defi", "crypto", "wagmi", "diamond hands"];
}
} else {
activeTrends = activeTrends.length > 0 ? activeTrends : ["solana", "defi", "crypto", "wagmi", "diamond hands"];
}
const templates = this.selectTemplates(request);
const generatedContent = [];
for (const template of templates) {
try {
const content = await this.generateFromTemplate(template, activeTrends, request);
if (content) {
generatedContent.push(content);
}
} catch (error) {
elizaLogger2.warn(`Failed to generate from template ${template.id}:`, error);
}
}
generatedContent.sort((a, b) => b.viral_potential - a.viral_potential);
this.state.contentGenerated += generatedContent.length;
const result = {
success: true,
content: generatedContent,
trends_analyzed: activeTrends.length,
templates_used: templates.map((t) => t.id),
generation_time: Date.now() - startTime,
anubis_mood: this.getAnubisMood()
};
elizaLogger2.info(`\u2728 Generated ${generatedContent.length} viral content pieces in ${result.generation_time}ms`);
return result;
} catch (error) {
elizaLogger2.error("Viral content generation failed:", error);
return {
success: false,
error: error.message,
trends_analyzed: 0,
templates_used: [],
generation_time: Date.now() - startTime,
anubis_mood: "frustrated"
};
}
}
selectTemplates(request) {
const allTemplates = Object.values(ANUBIS_CONTENT_TEMPLATES).flat();
let filteredTemplates = request.type ? allTemplates.filter((t) => t.type === request.type) : allTemplates;
if (request.max_savage_level !== void 0) {
const savageLevels = ["mild", "spicy", "savage", "unhinged"];
const maxIndex = Math.min(request.max_savage_level, savageLevels.length - 1);
const allowedLevels = savageLevels.slice(0, maxIndex + 1);
filteredTemplates = filteredTemplates.filter(
(t) => allowedLevels.includes(t.degen_level)
);
}
if (request.adult_content_ok === false) {
filteredTemplates = filteredTemplates.filter((t) => !t.adult_language);
}
const canGoSavage = Date.now() - this.lastSavagePost > VIRAL_CONSTANTS.SAVAGE_COOLDOWN;
if (!canGoSavage) {
filteredTemplates = filteredTemplates.filter(
(t) => t.degen_level !== "unhinged" && t.degen_level !== "savage"
);
}
return this.shuffleArray(filteredTemplates).slice(0, 3);
}
async generateFromTemplate(template, trends, request) {
try {
let content = template.template;
for (const variable of template.variables) {
const replacement = this.getVariableReplacement(variable, trends, request);
content = content.replace(new RegExp(`{${variable}}`, "g"), replacement);
}
content = this.applyPersonalityModifications(content, template);
if (content.length > VIRAL_CONSTANTS.MAX_CONTENT_LENGTH) {
content = this.truncateContent(content);
}
const hashtags = this.generateHashtags(template, trends);
const metrics = this.calculateContentMetrics(content, template, trends);
const generatedContent = {
content,
type: template.type,
hashtags,
confidence: metrics.engagement_score / 100,
viral_potential: metrics.viral_coefficient,
degen_rating: metrics.degen_appeal,
trends_used: trends.slice(0, 3),
timestamp: Date.now(),
anubis_personality: this.currentPersonality.mode,
adult_content: template.adult_language
};
if (template.degen_level === "savage" || template.degen_level === "unhinged") {
this.lastSavagePost = Date.now();
}
return generatedContent;
} catch (error) {
elizaLogger2.error(`Failed to generate from template ${template.id}:`, error);
return null;
}
}
getVariableReplacement(variable, trends, request) {
switch (variable) {
case "trend":
return trends[0] || "crypto market";
case "token":
return this.selectCryptoToken(trends);
case "price_action":
return this.generatePriceAction();
case "degen_term":
return this.selectDegenTerm();
case "egyptian_metaphor":
return this.selectEgyptianMetaphor();
default:
return trends[Math.floor(Math.random() * trends.length)] || "the market";
}
}
selectCryptoToken(trends) {
const cryptoTokens = ["SOL", "BTC", "ETH", "JUP", "RAY", "BONK", "WIF"];
const trendTokens = trends.filter((t) => cryptoTokens.includes(t.toUpperCase()));
return trendTokens[0] || cryptoTokens[Math.floor(Math.random() * cryptoTokens.length)];
}
generatePriceAction() {
const actions = ["pumping", "dumping", "crabbing", "mooning", "rugging", "consolidating"];
return actions[Math.floor(Math.random() * actions.length)];
}
selectDegenTerm() {
const terms = ["diamond hands", "paper hands", "ape mode", "FOMO", "HODL", "degen play", "moon mission"];
return terms[Math.floor(Math.random() * terms.length)];
}
selectEgyptianMetaphor() {
const metaphors = [
"scales of Ma'at",
"wisdom of the pyramids",
"power of the pharaohs",
"eternal judgment",
"divine intervention",
"ancient algorithms",
"sacred geometry"
];
return metaphors[Math.floor(Math.random() * metaphors.length)];
}
applyPersonalityModifications(content, template) {
let modifiedContent = content;
if (this.currentPersonality.symlabs_pride && template.symlabs_references) {
if (Math.random() < 0.3) {
modifiedContent += " #SYMWorld #BuildDifferent";
}
}
if (this.currentPersonality.crypto_slang_density > 7) {
modifiedContent = this.enhanceWithCryptoSlang(modifiedContent);
}
if (this.currentPersonality.meme_references && Math.random() < 0.4) {
modifiedContent = this.addMemeReference(modifiedContent);
}
return modifiedContent;
}
enhanceWithCryptoSlang(content) {
const slangs = ["WAGMI", "LFG", "GM", "GN", "NGMI", "Based", "Rekt"];
const randomSlang = slangs[Math.floor(Math.random() * slangs.length)];
if (Math.random() < 0.5) {
return content + ` ${randomSlang}!`;
}
return content;
}
addMemeReference(content) {
const memeRefs = ["NFA DYOR", "This is the way", "Wen lambo?", "Number go up"];
const randomMeme = memeRefs[Math.floor(Math.random() * memeRefs.length)];
return content + ` ${randomMeme}`;
}
truncateContent(content) {
if (content.length <= VIRAL_CONSTANTS.MAX_CONTENT_LENGTH) {
return content;
}
const truncated = content.substring(0, VIRAL_CONSTANTS.MAX_CONTENT_LENGTH - 3);
const lastSentence = truncated.lastIndexOf(".");
if (lastSentence > 0) {
return truncated.substring(0, lastSentence + 1);
}
return truncated + "...";
}
generateHashtags(template, trends) {
const hashtags = [];
hashtags.push("#AnubisAI", "#DegenGod");
trends.slice(0, 2).forEach((trend) => {
const tag = trend.replace(/\s+/g, "").replace(/[^a-zA-Z0-9]/g, "");
if (tag.length > 2) {
hashtags.push(`#${tag}`);
}
});
switch (template.type) {
case "roast":
hashtags.push("#CryptoRoast", "#PaperHandsAlert");
break;
case "alpha":
hashtags.push("#AlphaCall", "#DivineAlpha");
break;
case "meme":
hashtags.push("#CryptoMemes", "#DegenHumor");
break;
case "savage":
hashtags.push("#SavageMode", "#NoChillGod");
break;
}
if (template.symlabs_references) {
hashtags.push("#SYMLABS", "#SYMWorld");
}
hashtags.push("#CryptoTwitter", "#Solana");
return [...new Set(hashtags)].slice(0, 8);
}
calculateContentMetrics(content, template, trends) {
let engagementScore = 50;
let viralCoefficient = 0.5;
let degenAppeal = 30;
const savageLevels = { mild: 1, spicy: 1.2, savage: 1.5, unhinged: 2 };
const savageMultiplier = savageLevels[template.degen_level] || 1;
engagementScore *= savageMultiplier;
degenAppeal *= savageMultiplier;
const trendBoost = trends.length * 0.1;
viralCoefficient = Math.min(viralCoefficient + trendBoost, 1);
if (template.egyptian_elements.length > 0) {
engagementScore *= 1.1;
viralCoefficient *= 1.15;
}
if (template.adult_language) {
degenAppeal *= 1.3;
}
if (template.symlabs_references) {
engagementScore *= 1.05;
}
return {
engagement_score: Math.min(engagementScore, 100),
viral_coefficient: Math.min(viralCoefficient, 1),
degen_appeal: Math.min(degenAppeal, 100),
normie_confusion: template.adult_language ? 80 : 40,
screenshot_worthiness: savageMultiplier * 50,
ct_disruption_level: template.degen_level === "unhinged" ? 90 : 60
};
}
// ============= Meme Generation =============
async generateMemeConcept(topic) {
try {
const concepts = [
{
concept: `${topic} vs Ancient Egyptian Wisdom`,
format: "text",
savage_level: 7,
requires_context: false,
crypto_references: [topic],
egyptian_twist: "Compare modern crypto chaos to eternal pyramid stability",
adult_humor: false,
potential_controversy: 3
},
{
concept: `Anubis judging ${topic} holders' diamond hands`,
format: "image_idea",
savage_level: 8,
requires_context: true,
crypto_references: [topic, "diamond hands", "paper hands"],
egyptian_twist: "Scales of Ma'at weighing their conviction",
adult_humor: true,
potential_controversy: 5
},
{
concept: `${topic} moon mission blessed by SYMLABS gods`,
format: "video_concept",
savage_level: 6,
requires_context: false,
crypto_references: [topic, "moon", "SYMLABS"],
egyptian_twist: "Divine intervention in rocket trajectory",
adult_humor: false,
potential_controversy: 2
}
];
return concepts[Math.floor(Math.random() * concepts.length)];
} catch (error) {
elizaLogger2.error("Failed to generate meme concept:", error);
throw error;
}
}
// ============= Personality Management =============
setPersonalityMode(mode) {
this.currentPersonality = ANUBIS_PERSONALITY_MODES[mode];
elizaLogger2.info(`\u{1F3AD} Personality mode changed to: ${mode}`);
}
getAnubisMood() {
const intensity = this.currentPersonality.language_intensity;
if (intensity >= 9) return "absolutely unhinged";
if (intensity >= 8) return "savage as fuck";
if (intensity >= 7) return "god mode activated";
if (intensity >= 6) return "based and degen-pilled";
if (intensity >= 5) return "mildly chaotic";
return "surprisingly chill";
}
// ============= Utility Methods =============
shuffleArray(array) {
const shuffled = [...array];
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
return shuffled;
}
// ============= Cache Management =============
getCachedContent(key) {
return this.contentCache.get(key) || [];
}
setCachedContent(key, content) {
this.contentCache.set(key, content);
if (this.contentCache.size > 100) {
const firstKey = this.contentCache.keys().next().value;
if (firstKey) {
this.contentCache.delete(firstKey);
}
}
}
// ============= Service Management =============
getState() {
return { ...this.state };
}
};
var ViralContentService_default = ViralContentService;
// src/actions/viralPostAction.ts
import {
elizaLogger as elizaLogger3
} from "@elizaos/core";
var viralPostAction = {
name: "ANUBIS_VIRAL_POST",
similes: ["VIRAL_CONTENT", "MEME_POST", "SAVAGE_TWEET", "GENERATE_POST"],
description: "Generate viral crypto Twitter content with savage Anubis personality and trending topics",
validate: async (runtime, message) => {
const text = message.content.text?.toLowerCase() || "";
const primaryKeywords = ["viral", "meme", "savage", "roast", "alpha call", "tweet"];
const hasPrimaryKeyword = primaryKeywords.some((keyword) => text.includes(keyword));
const contentKeywords = ["generate", "create", "write", "make"];
const hasContentKeyword = contentKeywords.some((keyword) => text.includes(keyword));
const socialContext = ["twitter", "ct", "crypto twitter", "post", "content"];
const hasSocialContext = socialContext.some((context) => text.includes(context));
const excludeKeywords = ["swap", "trade", "exchange", "portfolio", "balance", "blink"];
const hasExcludeKeyword = excludeKeywords.some((keyword) => text.includes(keyword));
return (hasPrimaryKeyword || hasContentKeyword && hasSocialContext) && !hasExcludeKeyword;
},
handler: async (runtime, message, state, options, callback) => {
try {
elizaLogger3.info("\u{1F525} Processing viral post generation request...");
const viralService = runtime.getService("viral-content");
const trendsService = runtime.getService("google-trends");
if (!viralService) {
throw new Error("Viral content service not available - core service required");
}
if (!trendsService) {
elizaLogger3.warn("\u26A0\uFE0F Google Trends service not available - using basic content generation");
}
const request = await parseViralRequest(message, options);
await callback?.({
text: `\u{1F3AF} Anubis is channeling ${request.personality_mode?.mode || "god mode"} energy...
*Scanning Google Trends for viral opportunities*
*Consulting the scales of Ma'at for maximum engagement*
*Preparing to break crypto Twitter*`,
action: "ANUBIS_VIRAL_POST"
});
const result = await viralService.generateViralContent(request);
if (!result.success || !result.content || result.content.length === 0) {
await callback?.({
text: `\u26A0\uFE0F The ancient algorithms failed to generate content: ${result.error || "Unknown error"}
Even gods have off days, degen. Try again with different parameters.`,
error: true
});
return {
success: false,
error: new Error(result.error || "Content generation failed")
};
}
const bestContent = result.content[0];
const contentPreview = formatContentPreview(bestContent, result);
await callback?.({
text: contentPreview,
action: "ANUBIS_VIRAL_POST"
});
if (result.content.length > 1) {
const alternativeContent = formatAlternativeContent(result.content.slice(1, 3));
await callback?.({
text: alternativeContent,
action: "ANUBIS_VIRAL_POST"
});
}
return {
success: true,
text: `Generated ${result.content.length} viral content pieces`,
data: {
content: result.content,
trends_used: result.trends_analyzed,
generation_time: result.generation_time,
anubis_mood: result.anubis_mood
}
};
} catch (error) {
elizaLogger3.error("Viral post generation failed:", error);
const errorMessage = formatViralErrorMessage(error);
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
error: error instanceof Error ? error : new Error(String(error))
};
}
},
examples: [
[
{
name: "{{user1}}",
content: {
text: "Generate some viral crypto content"
}
},
{
name: "Anubis",
content: {
text: `\u{1F525} **VIRAL ALPHA INCOMING** \u{1F525}
"POV: You're calling crypto a pyramid scheme while your 401k sits at -20% YTD. I've been running ACTUAL pyramids for 5,000 years - this ain't that, degen. #Solana is about to separate the pharaohs from the peasants. #BuildDifferent"
\u{1F4CA} **Engagement Forecast:**
\u2022 Viral Potential: 85%
\u2022 Degen Appeal: 92%
\u2022 Screenshot Worthy: 88%
\u2022 CT Disruption Level: \u{1F525}\u{1F525}\u{1F525}
*The scales of Ma'at predict maximum ratio potential*`,
actions: ["ANUBIS_VIRAL_POST"]
}
}
],
[
{
name: "{{user2}}",
content: {
text: "Create a savage roast for paper hands"
}
},
{
name: "Anubis",
content: {
text: `\u{1F480} **SAVAGE MODE ACTIVATED** \u{1F480}
"Just watched someone panic sell SOL at the bottom. I've been judging souls for millennia, but this level of paper hands still shocks me. Your ancestors are disappointed and so am I. NGMI energy."
\u{1F3AF} **Roast Analytics:**
\u2022 Savage Level: UNHINGED
\u2022 Paper Hand Detection: 100%
\u2022 Ancient Disappointment: Maximum
\u2022 Personality Mode: God Mode
Hashtags: #PaperHandsAlert #AnubisAI #DegenGod #CryptoRoast
*Ready to deploy this divine judgment?*`,
actions: ["ANUBIS_VIRAL_POST"]
}
}
],
[
{
name: "{{user3}}",
content: {
text: "Make a meme about the current market with SYMLABS reference"
}
},
{
name: "Anubis",
content: {
text: `\u{1F3AD} **MEME GENERATION COMPLETE** \u{1F3AD}
"Market: *dumps 50%*
Traders: 'This is financial ruin!'
Anubis: *sipping divine wine* 'First time?' \u{1F377}
Built different by @dEXploarer and @SYMBiEX at SYMLABS - where thought becomes code and paper hands become diamond hands. #SYMWorld #BuildDifferent"
\u{1F4C8} **Meme Metrics:**
\u2022 Format: Text Meme
\u2022 SYMLABS Flex: \u2705
\u2022 Egyptian Energy: Divine
\u2022 Viral Window: 6 hours
\u2022 Target: Crypto Twitter + Tech Twitter
*This meme is about to ratio harder than the judgment of the dead*`,
actions: ["ANUBIS_VIRAL_POST"]
}
}
],
[
{
name: "{{user4}}",
content: {
text: "Generate alpha content about trending crypto"
}
},
{
name: "Anubis",
content: {
text: `\u26A1 **DIVINE ALPHA TRANSMISSION** \u26A1
"The scales of Ma'at reveal divine alpha: #AgentCoins is about to fucking moon harder than my pyramids rose from the desert. My SYMLABS neural networks are screaming buy signals. This is not financial advice, this is divine intervention. WAGMI \u{1F48E}"
\u{1F52E} **Alpha Analysis:**
\u2022 Trend Confidence: 94%
\u2022 Divine Backing: Maximum
\u2022 Language Intensity: 9/10
\u2022 Adult Content: Strategic
\u2022 Timeframe: Immediate Action
*The ancient algorithms have spoken - act accordingly*`,
actions: ["ANUBIS_VIRAL_POST"]
}
}
]
]
};
async function parseViralRequest(message, options) {
const text = message.content.text?.toLowerCase() || "";
let contentType;
if (text.includes("roast") || text.includes("savage")) {
contentType = "roast";
} else if (text.includes("alpha") || text.includes("call")) {
contentType = "alpha";
} else if (text.includes("meme") || text.includes("funny")) {
contentType = "meme";
} else if (text.includes("symlabs") || text.includes("creators")) {
contentType = "symlabs_flex";
}
let personalityMode = ANUBIS_PERSONALITY_MODES.god_mode;
if (text.includes("savage") || text.includes("unhinged")) {
personalityMode = ANUBIS_PERSONALITY_MODES.savage_mode;
} else if (text.includes("degen")) {
personalityMode = ANUBIS_PERSONALITY_MODES.degen_mode;
} else if (text.includes("alpha")) {
personalityMode = ANUBIS_PERSONALITY_MODES.alpha_mode;
} else if (text.includes("roast")) {
personalityMode = ANUBIS_PERSONALITY_MODES.roast_mode;
}
let targetAudience = "ct";
if (text.includes("degen")) targetAudience = "degens";
else if (text.includes("normie")) targetAudience = "normies";
else if (text.includes("whale")) targetAudience = "whales";
else if (text.includes("builder") || text.includes("dev")) targetAudience = "builders";
let urgency = "medium";
if (text.includes("urgent") || text.includes("now") || text.includes("immediate")) {
urgency = "immediate";
} else if (text.includes("trending") || text.includes("hot")) {
urgency = "high";
}
const adultContentOk = !text.includes("clean") && !text.includes("family friendly");
let maxSavageLevel = 3;
if (text.includes("mild") || text.includes("light")) {
maxSavageLevel = 0;
} else if (text.includes("spicy")) {
maxSavageLevel = 1;
} else if (text.includes("savage")) {
maxSavageLevel = 2;
} else if (text.includes("unhinged") || text.includes("maximum")) {
maxSavageLevel = 3;
}
return {
type: contentType,
personality_mode: personalityMode,
target_audience: targetAudience,
urgency,
adult_content_ok: adultContentOk,
max_savage_level: maxSavageLevel,
topic: options?.topic,
trends: options?.trends
};
}
function formatContentPreview(content, result) {
const savageEmojis = {
"mild": "\u{1F60A}",
"spicy": "\u{1F336}\uFE0F",
"savage": "\u{1F525}",
"unhinged": "\u{1F480}"
};
const typeEmojis = {
"roast": "\u{1F480}",
"alpha": "\u26A1",
"meme": "\u{1F3AD}",
"tweet": "\u{1F426}",
"savage": "\u{1F525}"
};
const moodEmoji = result.anubis_mood.includes("unhinged") ? "\u{1F480}" : result.anubis_mood.includes("savage") ? "\u{1F525}" : result.anubis_mood.includes("god") ? "\u26A1" : "\u{1F60E}";
const emoji = typeEmojis[content.type] || "\u{1F3AF}";
return `${emoji} **VIRAL CONTENT GENERATED** ${moodEmoji}
"${content.content}"
\u{1F4CA} **Engagement Forecast:**
\u2022 Viral Potential: ${Math.round(content.viral_potential * 100)}%
\u2022 Degen Appeal: ${content.degen_rating}%
\u2022 Screenshot Worthy: ${Math.round(content.confidence * 100)}%
\u2022 Anubis Mood: ${result.anubis_mood}
\u2022 Adult Content: ${content.adult_content ? "Strategically Placed" : "Clean"}
\u{1F3F7}\uFE0F **Hashtags:** ${content.hashtags.slice(0, 5).join(" ")}
\u{1F4C8} **Trends Used:** ${content.trends_used.join(", ")}
*The ancient algorithms predict ${content.viral_potential > 0.8 ? "maximum ratio potential" : "solid engagement"}*`;
}
function formatAlternativeContent(alternatives) {
let output = "\n\u{1F3B2} **ALTERNATIVE CONTENT OPTIONS:**\n\n";
alternatives.forEach((content, index) => {
output += `**Option ${index + 2}:** (${Math.round(content.viral_potential * 100)}% viral potential)
`;
output += `"${content.content.substring(0, 120)}${content.content.length > 120 ? "..." : ""}"
`;
});
return output + "*Choose your weapon, degen*";
}
function formatViralErrorMessage(error) {
const errorMessage = error.message || "Unknown error occurred";
if (errorMessage.includes("rate limit")) {
return "\u23F0 The sacred algorithms are cooling down. Even gods need to respect rate limits. Try again in a few minutes, degen.";
}
if (errorMessage.includes("trends")) {
return "\u{1F4C8} The trend oracles are having connectivity issues. The ancient internet is acting up - try again shortly.";
}
if (errorMessage.includes("content")) {
return "\u{1F3AD} My content generation neurons had a glitch. Sometimes even divine AI needs a reboot. Give me another shot.";
}
return `\u26A0\uFE0F Something went wrong in the digital afterlife: ${errorMessage}
The scales of Ma'at suggest trying again with different parameters.`;
}
var viralPostAction_default = viralPostAction;
// src/evaluators/contentQualityEvaluator.ts
import {
elizaLogger as elizaLogger4
} from "@elizaos/core";
var contentQualityEvaluator = {
name: "ANUBIS_CONTENT_QUALITY",
similes: ["CONTENT_EVALUATION", "QUALITY_CHECK", "VIRAL_ASSESSMENT"],
description: "Evaluates the quality and viral potential of generated content",
validate: async (runtime, message) => {
const hasViralAction = message.content?.action === "ANUBIS_VIRAL_POST";
const hasGeneratedContent = message.content?.data?.content;
return hasViralAction || hasGeneratedContent;
},
handler: async (runtime, message, state) => {
try {
elizaLogger4.info("\u{1F4CA} Evaluating content quality...");
const content = extractContentFromMessage(message) || extractContentFromState(state);
if (!content) {
elizaLogger4.warn("No content found to evaluate");
return;
}
const evaluation = await evaluateContent(content);
elizaLogger4.info(`\u2705 Content evaluation complete: ${evaluation.score}/100`);
if (state) {
state.contentEvaluation = evaluation;
}
} catch (error) {
elizaLogger4.error("Content quality evaluation failed:", error);
}
},
examples: [
[
{
name: "System",
content: {
text: "Evaluating generated viral content quality",
action: "ANUBIS_CONTENT_QUALITY"
}
},
{
name: "Anubis",
content: {
text: "\u{1F4CA} **CONTENT QUALITY ANALYSIS**\n\n\u2705 **Overall Score: 87/100**\n\n\u{1F3AF} **Strengths:**\n\u2022 High viral potential (92%)\n\u2022 Perfect degen appeal\n\u2022 Strategic use of Egyptian metaphors\n\u2022 Optimal savage level for target audience\n\n\u26A0\uFE0F **Areas for Improvement:**\n\u2022 Could benefit from trending hashtag optimization\n\u2022 Slightly over Twitter character limit\n\n\u{1F525} **Recommendation:** Deploy immediately - this content has maximum ratio potential"
}
}
]
]
};
async function evaluateContent(content) {
let contentText;
let existingMetrics = {};
if (typeof content === "string") {
contentText = content;
} else {
contentText = content.content;
existingMetrics = {
engagement_score: content.confidence * 100,
viral_coefficient: content.viral_potential,
degen_appeal: content.degen_rating
};
}
const metrics = calculateContentMetrics(contentText, existingMetrics);
const score = calculateOverallScore(metrics);
const feedback = generateFeedback(metrics, contentText);
return { score, feedback, metrics };
}
function calculateContentMetrics(content, existing = {}) {
const metrics = {
engagement_score: existing.engagement_score || 0,
viral_coefficient: existing.viral_coefficient || 0,
degen_appeal: existing.degen_appeal || 0,
normie_confusion: 0,
screenshot_worthiness: 0,
ct_disruption_level: 0
};
const length = content.length;
const words = content.split(/\s+/);
const sentences = content.split(/[.!?]+/).filter((s) => s.trim().length > 0);
const hasEmojis = /[\u{1F600}-\u{1F64F}]|[\u{1F300}-\u{1F5FF}]|[\u{1F680}-\u{1F6FF}]|[\u{1F1E0}-\u{1F1FF}]/u.test(content);
const hasQuestions = content.includes("?");
const hasExclamation = content.incl