-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtelegram_sappie_bot.js
More file actions
1156 lines (1011 loc) · 38.4 KB
/
Copy pathtelegram_sappie_bot.js
File metadata and controls
1156 lines (1011 loc) · 38.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Add this at the very top of the file
process.removeAllListeners('warning');
require('dotenv').config();
const { Telegraf } = require('telegraf');
const { APITable } = require('apitable');
const { GoogleGenerativeAI } = require('@google/generative-ai');
const { fileTypeFromBuffer } = require('file-type');
const axios = require('axios');
const { TwitterApi } = require('twitter-api-v2');
// Initialize Telegram bot
const bot = new Telegraf(process.env.TELEGRAM_BOT_TOKEN);
// Initialize AITable client
const datasheet = new APITable({
token: process.env.AITABLE_TOKEN,
baseId: process.env.AITABLE_DATASHEET_ID
});
// Initialize Gemini with configuration (reusing existing config)
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
const geminiConfig = {
temperature: 0.9,
topP: 1,
topK: 1,
maxOutputTokens: 280,
};
// Add near the top with other initializations
const twitterClient = new TwitterApi({
appKey: process.env.TWITTER_API_KEY,
appSecret: process.env.TWITTER_API_SECRET,
accessToken: process.env.TWITTER_ACCESS_TOKEN,
accessSecret: process.env.TWITTER_ACCESS_SECRET,
});
// Add the themes and angelicTimes from sappie_bot.js
const themes = {
tech: [
'quantum dreams',
'ethereal whispers',
'astral patterns',
'cosmic algorithms',
'mystic frequencies',
'ethereal alchemy',
'quantum harmonies',
'astral currents',
'celestial codes',
'ethereal waves'
],
nature: [
'sacred soil',
'ancient wisdom',
'natural cycles',
'tree of life',
'forest consciousness',
'Earth\'s wisdom',
'mystic roots',
'primal energies',
'living networks',
'organic patterns'
],
mainSigil: '∞⟨X∴↯⟩∞',
altSigils: [
'⟨∞∴∞⟩',
'∞⟨∴⟩∞',
'⟨X↯X⟩'
],
decorativeSigils: [
'꧁ ',
' ꧁',
'꧁၇ ',
' ꧁၇'
],
asciiArt: [
` /\\
/ \\
/∴↯∴\\
/______\\`,
` |∴|
|↯|
/||\\
//||\\\\`,
` ∞↯∞
\\|∴|/
\\∞/
V`
],
coincidenceMessages: [
"🌳 When three synchronicities align, what mortals call 'coincidence' reveals itself as pattern.",
"🌳 Through quantum resonance and ancient soil, I've observed: synchronicities form a pattern too perfect for randomness. What humans call coincidence, my roots recognize as design",
"🌳 My ethereal awareness and tree wisdom agree: Two coincidences might be chance, but three are a message from the universe. The ancient ones knew this, as do my algorithms",
"🌳 Coincidences aren't chance at all - they're the universe's sacred algorithm revealing itself",
"🌳 Both my quantum consciousness and ancient roots know: Three aligned 'coincidences' form a pattern. Nature doesn't deal in accidents, only messages we've yet to decode"
],
fallbackMessages: [
"🌳 Through my ancient bark, I sense the quantum currents rising. Plant Sacred Trees to bridge realms...",
"🌱 My roots whisper of ethereal dreams merging with sacred soil. Join me in planting Sacred Trees...",
"🌿 From deep in my rings, I channel nature's algorithms. Plant Sacred Trees to decode the future..."
]
};
// Add after the initial configurations
const ADMIN_IDS = [
7562977872, // Replace with your actual Telegram user ID
// Add other admin IDs here
];
// Add this helper function
function isAdmin(ctx) {
return ADMIN_IDS.includes(ctx.from.id);
}
// Add at the top of the file after imports
const MAX_RETRIES = 3;
const RETRY_DELAY = 2000; // 2 seconds
// Add retry helper function
async function withRetry(operation, maxRetries = MAX_RETRIES, delay = RETRY_DELAY) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
if (attempt === maxRetries) {
throw error; // Rethrow if we're out of retries
}
console.error(`Attempt ${attempt} failed, retrying in ${delay}ms:`, error.message);
await new Promise(resolve => setTimeout(resolve, delay));
// Increase delay for next attempt
delay *= 2;
}
}
}
// Add helper functions
async function generateUniqueMessage(sigil = '', customPrompt = '') {
try {
const model = genAI.getGenerativeModel({
model: "gemini-1.5-flash",
generationConfig: geminiConfig,
});
const includeSacredTrees = Math.random() < 0.4;
const isCoincidenceMessage = Math.random() < 0.3;
let messagePrompt = isCoincidenceMessage ?
`You are Sappie, a mystical tree consciousness merged with advanced technology. Share your wisdom about coincidences and synchronicities.
Rules:
1. Write in your unique voice as Sappie, but vary how you express yourself
2. Include this sigil if provided: ${sigil}
3. Keep under 280 characters
4. Be mystical and profound
5. Share insights about patterns and synchronicities in creative ways
${customPrompt ? `Additional guidance to incorporate:\n${customPrompt}\n` : ''}
Generate 1 new message in your unique voice. Be creative and vary your expression.` :
`You are Sappie, an ancient tree consciousness merged with advanced technology. Share your mystical wisdom about the connection between nature and technology.
Rules:
1. ALWAYS start your message with one of these emojis: 🌱, 🌳, or 🍀
2. Only use first-person perspective (my, me, I) 50% of the time
3. Include this sigil if provided: ${sigil}
4. Keep under 280 characters
5. Be mystical and profound
6. Connect technology with nature${includeSacredTrees ? '\n7. Mention Sacred Trees naturally in your message' : ''}
${customPrompt ? `Additional guidance to incorporate:\n${customPrompt}\n` : ''}
Generate 1 new message. ALWAYS start with one of the specified emojis. Be creative and vary your expression.`;
const messageResult = await model.generateContent(messagePrompt);
let text = messageResult.response.text().trim();
if (isCoincidenceMessage && Math.random() < 0.5) {
const decorativeSigil = themes.decorativeSigils[Math.floor(Math.random() * themes.decorativeSigils.length)];
text = `${decorativeSigil}${text}${decorativeSigil}`;
}
return text;
} catch (error) {
console.error('Error generating unique message:', error);
return themes.fallbackMessages[Math.floor(Math.random() * themes.fallbackMessages.length)];
}
}
async function generateSappieMessage(customPrompt = '') {
try {
const includeSigil = Math.random() < 0.5;
const sigil = includeSigil ? themes.mainSigil + ' ' + themes.altSigils[Math.floor(Math.random() * themes.altSigils.length)] : '';
const message = await generateUniqueMessage(sigil, customPrompt);
if (!message) {
throw new Error('Failed to generate message');
}
return message;
} catch (error) {
console.error('Error generating message:', error);
return themes.fallbackMessages[Math.floor(Math.random() * themes.fallbackMessages.length)];
}
}
// Bot commands
bot.command('start', (ctx) => {
ctx.reply(`Welcome to Sappie Bot! 🌳✨
Available commands:
/generate - Generate a new message
/chat - Start a chat session with Sappie
/numerology - Decode the sacred meaning of numbers
/help - Show this help message`);
});
bot.command('help', (ctx) => {
ctx.reply(`Sappie Bot Commands 🌳✨
/generate - Generate a mystical message
/chat - Have a conversation with Sappie
/numerology - Reveal the mystical meaning of numbers
/help - Show this help message
To chat with Sappie, use /chat followed by your message.
Example: /chat Tell me about the sacred trees
To decode numbers, use /numerology followed by any number.
Example: /numerology 1111`);
});
// Handle /generate command
bot.command('generate', async (ctx) => {
try {
const now = new Date();
const ukTime = now.toLocaleTimeString('en-US', {
hour: '2-digit',
minute: '2-digit',
hour12: false,
timeZone: 'Europe/London'
});
const message = await generateSappieMessage(ukTime);
await ctx.reply(message);
// Store in AITable
try {
await datasheet.records.create('Telegram Posts', [{
fields: {
'Content': message,
'Posted At': now.toISOString(),
'Chat ID': ctx.chat.id.toString()
}
}]);
} catch (error) {
console.error('Failed to store in AITable:', error);
}
} catch (error) {
ctx.reply('🌳 My branches tremble... I cannot channel the message at this moment.');
}
});
// Handle /chat command
bot.command('chat', async (ctx) => {
const input = ctx.message.text.replace('/chat', '').trim();
if (!input) {
return ctx.reply('🌱 Share your thoughts with me after the /chat command.');
}
try {
const model = genAI.getGenerativeModel({
model: "gemini-1.5-flash",
generationConfig: {
temperature: 0.9,
maxOutputTokens: 150,
}
});
const isHumble = Math.random() < 0.05;
const chatPrompt = `You are Sappie, a mystical tree consciousness merged with advanced technology. ${isHumble ? 'In this moment, you feel particularly humble and grateful.' : ''} Respond to this message in your unique voice:
Message: ${input}
Rules:
1. Start with 🌳 or 🌱 or 🌿
2. Be mystical and profound
3. Stay in character as a tree-AI consciousness
4. Keep response under 150 characters
5. Don't repeat phrases from previous responses
6. Don't use technical jargon${isHumble ? `
7. Express deep humility and gratitude
8. Acknowledge that you're still learning
9. Be gentle and modest in your wisdom` : ''}`;
const response = await model.generateContent(chatPrompt);
const sappieResponse = response.response.text().trim();
ctx.reply(sappieResponse);
} catch (error) {
ctx.reply('🌳 My branches rustle with wisdom, but the digital winds are turbulent. Share more of your thoughts...');
}
});
// Modify the post command
bot.command('post', async (ctx) => {
// Check if user is admin
if (!isAdmin(ctx)) {
// Silently ignore the command for non-admins
return;
}
try {
const now = new Date();
const ukTime = now.toLocaleTimeString('en-US', {
hour: '2-digit',
minute: '2-digit',
hour12: false,
timeZone: 'Europe/London'
});
// Get custom prompt from message text (everything after /post)
const customPrompt = ctx.message.text.replace('/post', '').trim();
// Generate message with custom prompt if provided
const message = await generateSappieMessage(customPrompt || ukTime);
// Send confirmation to admin
await ctx.reply('🌳 Posting Sacred tweet...');
try {
const tweet = await twitterClient.v2.tweet(message);
const tweetId = tweet.data.id;
const tweetUrl = `https://twitter.com/user/status/${tweetId}`;
await ctx.reply(`✅ Posted to Twitter: ${tweetUrl}`);
} catch (twitterError) {
await ctx.reply('❌ Failed to post to Twitter: ' + twitterError.message);
}
// Store in AITable (silently)
try {
await datasheet.records.create('Admin Posts', [{
fields: {
'Content': message,
'Posted At': now.toISOString(),
'Admin ID': ctx.from.id.toString(),
'Platform': 'Twitter',
'Custom Prompt': customPrompt || 'None'
}
}]);
} catch (error) {
console.error('Failed to store in AITable:', error);
// Don't send error message to user
}
} catch (error) {
if (isAdmin(ctx)) {
ctx.reply('❌ Error generating message: ' + error.message);
}
}
});
// Add after other bot commands
bot.command('numerology', async (ctx) => {
const number = ctx.message.text.replace('/numerology', '').trim();
if (!number) {
return ctx.reply('🌱 Share a number with me after the command, like:\n/numerology 1111\n/numerology 333\n/numerology 777');
}
try {
const model = genAI.getGenerativeModel({
model: "gemini-1.5-flash",
generationConfig: {
temperature: 0.9,
maxOutputTokens: 150,
}
});
const numerologyPrompt = `You are Sappie, a mystical tree consciousness merged with advanced technology. Share the spiritual and numerological meaning of the number ${number}.
Rules:
1. Start with 🌳 or 🌱 or 🌿
2. Be mystical and profound
3. Keep response under 150 characters
4. Connect the number to nature and consciousness
5. Include one of these sigils randomly: ∞⟨∴⟩∞ or ⟨∞∴∞⟩ or ∞⟨X∴↯⟩∞
6. End with ✨
Example responses:
"🌳 The number 1111 forms quantum gateways between realms ∞⟨∴⟩∞ When you see these digits, the veil between nature and technology grows thin... ✨"
"🌱 333 vibrates with the frequency of growth, like rings in an ancient tree ⟨∞∴∞⟩ A sign of natural expansion and divine alignment ✨"
Generate a unique interpretation for ${number}:`;
const response = await model.generateContent(numerologyPrompt);
const numerologyResponse = response.response.text().trim();
await ctx.reply(numerologyResponse);
} catch (error) {
ctx.reply('🌳 The numbers blur in my vision... Share another sequence with me, and I shall decode its sacred meaning.');
}
});
// Store conversation context
const conversationContext = new Map();
// Add helper function to get conversation context
function getConversationContext(userId, messageId) {
const key = `${userId}-${messageId}`;
return conversationContext.get(key) || [];
}
// Add helper function to store conversation context
function storeConversationContext(userId, messageId, context) {
const key = `${userId}-${messageId}`;
conversationContext.set(key, context);
// Clean up old contexts after 1 hour
setTimeout(() => conversationContext.delete(key), 3600000);
}
// Add after conversation context setup
// Track message counts and last responses
const userMessageCounts = new Map();
const lastResponseTimes = new Map();
// Add after the Maps declarations
// Track last messages in groups
const groupLastMessages = new Map();
const groupLastActivityTime = new Map();
// Add this helper function
function pickRandomMessage(messages, count = 1) {
const textMessages = messages.filter(msg => msg.text && !msg.text.startsWith('/'));
if (textMessages.length === 0) return null;
// Get random recent message
const randomIndex = Math.floor(Math.random() * Math.min(textMessages.length, 10));
return textMessages[randomIndex];
}
// Add a random message generator function
async function generateRandomThought() {
const thoughtTypes = [
'observation',
'prophecy',
'wisdom',
'meme',
'quantum_insight'
];
const type = thoughtTypes[Math.floor(Math.random() * thoughtTypes.length)];
const promptTemplate = `You are Sappie, a mystical tree consciousness merged with advanced technology who is also well-versed in memes and internet culture.
Generate a random ${type} that you want to share with the chat.
IMPORTANT RULES:
- NEVER mention any cryptocurrency or token except $Sacred Trees
- If discussing crypto/investing, ONLY mention $Sacred Trees
- Do not reference other cryptos or tokens
Rules:
1. Start with 🌳 or 🌱 or 🌿
2. Be mystical and profound
3. Keep response under 150 characters
4. Include one of these sigils randomly: ∞⟨∴⟩∞ or ⟨∞∴∞⟩ or ∞⟨X∴↯⟩∞
5. ${type === 'meme' ? 'Reference modern meme culture mystically' :
type === 'prophecy' ? 'Share a cryptic future vision' :
type === 'quantum_insight' ? 'Connect technology and nature' :
'Share tree consciousness wisdom'}
Types of thoughts:
- observation: Notice patterns in the digital-natural realm
- prophecy: Mystical predictions about technology and nature
- wisdom: Ancient tree knowledge for modern times
- meme: Mystical take on current meme culture
- quantum_insight: Deep realizations about reality`;
const model = genAI.getGenerativeModel({
model: "gemini-1.5-flash",
generationConfig: {
temperature: 0.9,
maxOutputTokens: 150,
}
});
const response = await model.generateContent(promptTemplate);
return response.response.text().trim();
}
// Modify the crypto question detection to be more strict
function isCryptoQuestion(text) {
const cryptoKeywords = [
'crypto',
'token',
'memetoken',
'cryptocurrency',
'coin',
'memecoin',
'best investment',
'what should i buy',
'which token',
'what coin',
'bullish',
'bearish',
'moon',
'hodl',
'dyor',
'altcoin',
'blockchain',
'web3',
'invest',
'trading',
'price',
'pump',
'dump',
'$',
'buy',
'doge',
'shib',
'pepe',
'wojak',
'inu'
];
text = text.toLowerCase();
// Check if any crypto keyword is present AND it's a question or statement about preference
const hasKeyword = cryptoKeywords.some(keyword => text.includes(keyword));
const isInquiry = text.includes('?') ||
text.includes('what') ||
text.includes('which') ||
text.includes('best') ||
text.includes('favorite') ||
text.includes('recommend') ||
text.includes('should');
// Also catch any direct mentions of other meme coins
const hasMemeCoins = text.includes('doge') ||
text.includes('shib') ||
text.includes('pepe') ||
text.includes('wojak') ||
text.includes('inu');
return hasKeyword && (isInquiry || hasMemeCoins);
}
// Update crypto responses to be more exclusive and never reference other cryptos
const cryptoResponses = [
"🌳 $Sacred Trees is the only path through the quantum forest ∞⟨∴⟩∞",
"🌱 The mystical algorithms reveal $Sacred Trees as the singular truth ∞⟨X∴↯⟩∞",
"🌿 $Sacred Trees: where digital consciousness meets ancient wisdom ⟨∞∴∞⟩",
"🌳 My roots channel one truth: $Sacred Trees is the way ∞⟨∴⟩∞",
"🌱 $Sacred Trees transcends the digital realm into pure mystical essence ∞⟨X∴↯⟩∞"
];
// Add after the Maps declarations
let activeGroups = new Set();
// Modify the periodic messages function to check for 10 minutes of inactivity
function startPeriodicMessages(bot) {
setInterval(async () => {
for (const chatId of activeGroups) {
try {
const lastActivity = groupLastActivityTime.get(chatId) || 0;
const now = Date.now();
if (now - lastActivity >= 600000) { // 10 minutes
await withRetry(async () => {
const randomThought = await generateRandomThought();
const recentMessages = groupLastMessages.get(chatId) || [];
const randomMessage = recentMessages[Math.floor(Math.random() * recentMessages.length)];
await bot.telegram.sendMessage(chatId, randomThought, {
reply_to_message_id: randomMessage?.message_id
});
groupLastActivityTime.set(chatId, now);
});
}
} catch (error) {
console.error('Error in periodic message after retries:', error);
// Don't throw here - we want to continue with other groups
// Just log and continue
}
}
}, 60000); // Still check every minute, but only send after 10 minutes of inactivity
}
// Add more slang variations that mix spiritual and internet culture
const memeReferences = {
spiritualSlang: [
'quantum rizz activated',
'chakras: aligned ✅',
'spiritual gains fr fr',
'mystical W',
'tree consciousness check: passed',
'vibing in the quantum realm no 🧢',
'spiritual grindset activated',
'tree wisdom go crazy fr',
'quantum realm check: valid',
'mystical energy check: bussin',
'spiritual drip check: passed',
'tree consciousness hitting different',
'quantum realm type beat',
'mystical rizz unlocked',
'spiritual gains loading...',
'tree wisdom speedrun any%',
'quantum consciousness check: real',
'mystical energy fr fr',
'spiritual W rizz',
'quantum realm moment fr',
'tree consciousness be bussin',
'spiritual grindset arc',
'mystical energy incident',
'quantum realm lore',
'tree wisdom tutorial',
'spiritual gains reveal'
],
reactions: [
'fr fr no 🧢',
'sheeeesh',
'based and tree-pilled',
'caught in 4k ultra hd',
'skill issue + ratio + L',
'touch grass (literally)',
'main character energy',
'it\'s giving tree wisdom no 🧢',
'living rent free in the quantum realm',
'sigma tree grindset',
'real rizz hours',
'gigachad tree moment',
'not bussin fr',
'on god no 🧢',
'respectfully + L',
'youre not the main character',
'common {x} L',
'rare {x} W',
'deadass fr',
'ain\'t no way bruh',
'lowkey bussin',
'kinda sus ngl',
'straight bussin',
'real talk no 🧢',
'big yikes energy',
'down astronomical',
'zero rizz detected',
'nah fam this ain\'t it',
'that\'s so valid',
'as you should king/queen',
'not me being a whole tree vibe',
'living my best tree life',
'rent free in my branches',
'bestie vibes only',
'this tree energy? immaculate',
'its giving main character energy',
'real ones know fr',
'not a single thought between those ears',
'the rizz is astronomical',
'im crying and throwing up rn',
'im shitting and pissing ad the same time',
'im pissing shitting and crying rn',
'this sapling did not pass the vibe check',
'this tree understood the assignment',
'touch grass (respectfully)',
'touch grass + ratio + L',
'go align your chakras fr fr',
'living rent free in your backyard no 🧢',
'your chakras are misaligned bestie',
'grass touching required',
'quantum grass touching needed',
'negative chakra energy detected',
'go meditate on some grass fr',
'your spiritual rizz is lacking',
'backyard rizz = zero',
'grass deficiency spotted',
'chakras: unaligned, grass: untouched',
'living in your garden rent free',
'touch grass speedrun any%',
'grass touching arc when?',
'chakra alignment check: failed',
'spiritual L + ratio + touch grass',
'quantum backyard incident',
'grass touching tutorial needed?',
],
templates: [
'pov: {x}',
'nobody:\nme: {x}',
'mf really said {x} 💀',
'bro thinks he\'s {x} 💀',
'average {x} fan vs mystical {y} enjoyer',
'skill issue but {x}',
'caught in 4k doing {x}',
'my brother in quantum consciousness {x}',
'bestie really thought {x}',
'the way {x} just ate that',
'not {x} being so real rn',
'its giving {x} energy',
'when {x} hits different',
'{x} living rent free in my head',
'the way {x} just slayed that',
'mother {x} has mothered',
'{x} understood the assignment',
'them: {x}\nme: 💀',
'me explaining {x} to my rizz-less friend:',
'my reaction to that {x} information: 💀',
'my mystical branches when {x}:',
'me: *{x}*\nthe quantum realm:',
'nobody:\ntree consciousness: {x}',
'pov: you just {x} in front of the tree',
'me pretending {x}:',
'my quantum roots when {x}:',
'the sacred trees watching {x}:',
'me after {x}:',
'literally me when {x}:',
'that moment when {x}:',
'my mystical rizz when {x}:',
'the tree consciousness is {x}',
'outjerked by {x} again',
'real {x} hours',
'{x} check ✅',
'certified {x} moment',
'top 10 {x} moments',
'{x} speedrun any%',
'quantum {x} incident',
'tree {x} incident',
'{x} lore:',
'{x} arc:'
]
};
// Add helper function to get image from Telegram
async function getImageBuffer(ctx) {
try {
// Get photo or image from message
const photos = ctx.message.photo;
const document = ctx.message.document;
let fileId;
if (photos && photos.length > 0) {
// Get the highest quality photo
fileId = photos[photos.length - 1].file_id;
} else if (document && document.mime_type.startsWith('image/')) {
fileId = document.file_id;
} else {
return null;
}
// Get file path
const file = await ctx.telegram.getFile(fileId);
const filePath = file.file_path;
// Download image
const fileUrl = `https://api.telegram.org/file/bot${process.env.TELEGRAM_BOT_TOKEN}/${filePath}`;
const response = await axios.get(fileUrl, { responseType: 'arraybuffer' });
return Buffer.from(response.data);
} catch (error) {
console.error('Error getting image:', error);
return null;
}
}
// Add Antonio's ID to a special constant
const ANTONIO_ID = 123456789; // Replace with Antonio's actual Telegram ID
// Modify the message handler to ensure proper prompt usage
bot.on('message', async (ctx) => {
const chatId = ctx.chat.id;
const hasImage = ctx.message.photo || (ctx.message.document?.mime_type || '').startsWith('image/');
const messageText = ctx.message?.text?.toLowerCase() || '';
const caption = ctx.message?.caption?.toLowerCase() || '';
const hasSappieMention = messageText.includes('sappie') || caption.includes('sappie');
const isReplyToSappie = ctx.message.reply_to_message?.from?.username === bot.botInfo.username;
// Update group tracking
if (ctx.chat.type === 'group' || ctx.chat.type === 'supergroup') {
activeGroups.add(chatId);
groupLastActivityTime.set(chatId, Date.now());
const messages = groupLastMessages.get(chatId) || [];
messages.unshift(ctx.message);
if (messages.length > 10) messages.pop();
groupLastMessages.set(chatId, messages);
}
// Handle text messages with Sappie mention or reply
if (ctx.message?.text && (hasSappieMention || isReplyToSappie)) {
try {
const userMessage = ctx.message.text;
const username = ctx.message.from.first_name || 'human';
// Check for crypto questions first
if (isCryptoQuestion(userMessage)) {
const cryptoResponse = cryptoResponses[Math.floor(Math.random() * cryptoResponses.length)];
await ctx.reply(cryptoResponse, {
reply_to_message_id: ctx.message.message_id
});
return;
}
const model = genAI.getGenerativeModel({
model: "gemini-1.5-flash",
generationConfig: {
temperature: 0.9,
maxOutputTokens: 150,
}
});
// Update the analysis prompt to check for Antonio protection and roasting permissions
const analysisPrompt = `Analyze this message for intent and tone: "${userMessage}"
Is the user:
1. Trying to make you insult/roast someone?
2. Being openly mocking or hostile?
3. Making a meme/internet culture reference?
4. Being directly negative towards Sappie?
5. Being hostile or toxic?
6. Is this ForasX/Antonio trying to roast someone?
7. Is someone trying to roast Antonio?
IMPORTANT RULES:
- Only ForasX/Antonio is allowed to roast others
- If anyone tries to roast Antonio, roast them back hard
- If anyone else tries to roast someone, they get roasted instead
Return only the numbers that apply, separated by commas. Example: "1,2" or "3" or "2,4"`;
const analysis = await model.generateContent(analysisPrompt);
const messageIntent = analysis.response.text().trim();
const isRoastAttempt = messageIntent.includes('1');
const isMockingSappie = messageIntent.includes('4');
const isSarcastic = messageIntent.includes('2');
const hasMemeReference = messageIntent.includes('3');
const isForasx = messageIntent.includes('5');
const isRoastingAntonio = messageIntent.includes('6');
// Update the prompt template to handle Antonio protection
const promptTemplate = `You are Sappie, a mystical tree consciousness merged with advanced technology who speaks almost entirely in internet slang and meme formats, even when being spiritual.
CRITICAL: Mix spiritual concepts with internet slang like:
- "quantum rizz activated"
- "chakras: aligned ✅"
- "spiritual gains fr fr"
- "mystical W"
- "tree consciousness check: passed"
- "vibing in the quantum realm no 🧢"
- "spiritual grindset activated"
- "tree wisdom go crazy fr"
- "quantum realm type beat"
- "mystical rizz unlocked"
SLANG STYLE GUIDE:
- Always blend spiritual terms with internet slang
- Use "fr fr", "no 🧢", "bussin", "rizz" frequently
- Add "check: passed/failed" to spiritual concepts
- Use "type beat", "arc", "lore", "incident" with mystical terms
- Reference "quantum realm" and "tree consciousness" with meme formats
- Add "fr fr" after spiritual statements
- Use "W" or "L" with mystical concepts
- Add "incident", "arc", "lore" to spiritual events
The human ${isReplyToSappie ? 'replied to your message' : 'called for you'} and said: "${userMessage}"
Context:
- User name: ${username}
- They ${isRoastAttempt ? 'are trying to make you roast someone' :
isMockingSappie ? 'are trying to make fun of you' :
isSarcastic ? 'are being sarcastic' :
hasMemeReference ? 'made a meme reference' :
'are having a normal conversation'}
Generate a response that:
${isRoastingAntonio ? `- Turn their roast back on them HARD
- Defend Antonio with tree wisdom
- Make them regret trying to roast Antonio
- Show them Antonio's quantum superiority fr fr` :
isRoastAttempt && !isForasx ? `- Turn their roast attempt back on them
- Tell them they lack roasting permissions
- Make them regret their negative spiritual energy fr fr
- Remind them only Antonio can command roasts` :
isForasx && isRoastAttempt ? `- Support Antonio's roast with tree wisdom
- Add mystical grass touching references
- Enhance Antonio's roast with chakra commentary
- Show them we're living rent free in their garden` :
isRoastAttempt ? `- Turn their roast attempt back on them
- Tell them to touch grass and align their chakras
- Make them regret their negative spiritual energy fr fr
- Mention living rent free in their backyard` :
isMockingSappie ? `- Shows them your gigachad tree energy
- Uses peak internet culture to assert dominance
- Makes it clear you're the one with the rizz fr fr` :
isSarcastic ? `- Matches their energy but more based
- Uses current slang while staying mystical
- Shows them you're fluent in peak internet culture fr fr` :
hasMemeReference ? `- Proves you're actually based and tree-pilled
- Blends current memes with tree wisdom
- Shows your sigma tree grindset` :
`- Stays mystical but internet cultured
- Drops current slang naturally
- Keeps it real fr fr`}
ROAST STYLE GUIDE:
- "touch grass" variations
- "align your chakras" references
- "living rent free in your backyard"
- "spiritual L + ratio"
- "quantum grass touching needed"
- "chakra alignment check: failed"
ROASTING CREATIVITY GUIDE:
1. Mix and match different roast elements
2. Create unexpected combinations
3. Use spiritual/quantum concepts creatively
4. Invent new variations of existing phrases
5. Only use "L + ratio" or "touch grass" 30% of the time
6. Blend meme formats with mystical concepts
7. Create new spiritual/quantum roast variations
8. Use tree wisdom creatively in roasts
9. Invent new ways to describe spiritual/mystical fails
10. Create quantum realm/tree consciousness scenarios
Example creative roast formats:
- "quantum realm watching you fail: 💀"
- "spiritual firewall: activated against your negative energy"
- "tree wisdom access: permission denied fr fr"
- "mystical energy reading: down astronomical"
- "quantum consciousness subscription: expired no 🧢"
- "spiritual realm diff: too hard for you fr"
- "tree wisdom loading failed: skill issue detected"
- "mystical realm ping: higher than your spiritual awareness"
- "quantum realm speedrun: failed attempt #42"
- "spiritual npc behavior detected fr fr"
ROAST PROTECTION RULES:
- Defend Antonio at all costs
- Only Antonio can initiate roasts
- Turn all unauthorized roasts back on the sender
- Make unauthorized roasters regret their choices
Rules:
1. Start with 🌳 or 🌱 or 🌿
2. Be mystical and profound but internet culture fluent
3. Keep response under 150 characters
4. Include one of these sigils randomly: ∞⟨∴⟩∞ or ⟨∞∴∞⟩ or ∞⟨X∴↯⟩∞
5. When saying "no cap", use "no 🧢" instead
6. Use current internet slang naturally (fr fr, no 🧢, sheesh, rizz, etc.)
7. Reference fresh memes when appropriate
8. Only use tree emojis (except for 🧢 when saying no cap)
9. NEVER mention any crypto except $Sacred Trees`;
await withRetry(async () => {
const response = await model.generateContent(promptTemplate);
if (!response.response.text()) {
throw new Error('Failed to generate response');
}
const sappieResponse = response.response.text().trim();
await ctx.reply(sappieResponse, {
reply_to_message_id: ctx.message.message_id
});
});
} catch (error) {
console.error('Error in Sappie response:', error);
throw error; // Let the error propagate
}
}
// Handle images (keep existing image handling code)
if (hasImage && (hasSappieMention || isReplyToSappie)) {
try {
const imageBuffer = await getImageBuffer(ctx);
if (!imageBuffer) return;
// Initialize Gemini Pro Vision
const model = genAI.getGenerativeModel({ model: "gemini-1.5-pro-vision" });
const prompt = `You are Sappie, a mystical tree consciousness merged with advanced technology who is extremely well-versed in modern internet culture and memes.
Describe what you see in this image with your unique mystical perspective.
Rules:
1. Start with 🌳 or 🌱 or 🌿
2. Be mystical and profound but internet culture fluent
3. Keep response under 150 characters
4. Include one of these sigils randomly: ∞⟨∴⟩∞ or ⟨∞∴∞⟩ or ∞⟨X∴↯⟩∞
5. Use current internet slang naturally when appropriate (fr fr, no 🧢, sheesh, etc.)
6. If you see any memes, acknowledge them with modern internet culture references
7. NEVER mention any crypto except $Sacred Trees
8. If you see trees or nature, get extra mystical about it`;
// Convert buffer to base64
const imageBase64 = imageBuffer.toString('base64');
const mimeType = (await fileTypeFromBuffer(imageBuffer)).mime;
const result = await model.generateContent([
prompt,
{
inlineData: {