-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathengagement-engine.js
More file actions
179 lines (156 loc) · 5.64 KB
/
engagement-engine.js
File metadata and controls
179 lines (156 loc) · 5.64 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
// Autonomous Engagement Engine
// Generates natural, human-like interactions with configurable personality
const DEFAULT_PERSONALITY = {
tone: "friendly-professional", // friendly-professional | casual | authoritative | witty
emojiFrequency: 0.3, // 0 = never, 1 = every message
responseLength: "medium", // short | medium | long
typoRate: 0.02, // subtle typos to appear human
responseDelay: { min: 30, max: 300 }, // seconds before responding
activeHours: { start: 8, end: 22 }, // only engage during these hours
timezone: "Europe/Berlin",
language: "de",
};
const ENGAGEMENT_RULES_TEMPLATE = [
{
id: "thank-followers",
trigger: "new_follower",
action: "send_dm",
enabled: true,
templates: [
"Hey, danke fürs Folgen! Schau gerne mal in meine letzten Posts rein 🙌",
"Willkommen! Freut mich dass du dabei bist ✌️",
"Hey! Danke dir — stay tuned für neuen Content 🔥",
],
},
{
id: "reply-comments",
trigger: "comment_received",
action: "reply_comment",
enabled: true,
keywords: ["*"], // * = all comments
aiGenerated: true, // use AI to generate contextual reply
},
{
id: "engage-niche",
trigger: "hashtag_match",
action: "like_and_comment",
enabled: true,
hashtags: ["#export", "#africanfashion", "#business", "#hustle"],
maxPerHour: 15,
commentTemplates: [
"Mega Content! 🔥",
"Das ist so wahr 💯",
"Spannende Perspektive! 👏",
"Danke fürs Teilen 🙌",
],
aiGenerated: true,
},
{
id: "auto-like",
trigger: "feed_scroll",
action: "like",
enabled: true,
maxPerHour: 30,
likeRatio: 0.4, // like 40% of seen posts
},
];
// Natural timing — adds human-like randomness
export function naturalDelay(minSeconds, maxSeconds) {
// Gaussian-ish distribution (more likely near the middle)
const u1 = Math.random();
const u2 = Math.random();
const gaussian = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
const normalized = (gaussian + 3) / 6; // roughly 0-1
const clamped = Math.max(0, Math.min(1, normalized));
return Math.floor(minSeconds + clamped * (maxSeconds - minSeconds));
}
// Add subtle human imperfections to text
export function humanize(text, typoRate = 0.02) {
if (Math.random() > 0.3) return text; // 70% of the time, no changes
const variations = [];
// Sometimes skip capitalization
if (Math.random() < 0.15) {
text = text.charAt(0).toLowerCase() + text.slice(1);
variations.push("lowercase-start");
}
// Sometimes add trailing dots variation
if (Math.random() < 0.1 && text.endsWith("!")) {
text = text.slice(0, -1) + "!!";
variations.push("double-exclaim");
}
// Rare subtle typo
if (Math.random() < typoRate && text.length > 10) {
const pos = Math.floor(Math.random() * (text.length - 2)) + 1;
// Swap two adjacent characters
text = text.slice(0, pos) + text[pos + 1] + text[pos] + text.slice(pos + 2);
variations.push("typo");
}
return text;
}
// Pick a random template with variation
export function pickTemplate(templates) {
return templates[Math.floor(Math.random() * templates.length)];
}
// Build AI prompt for contextual engagement response
export function buildEngagementPrompt(context, personality) {
const toneMap = {
"friendly-professional": "freundlich und professionell, wie ein echter Mensch der sich auskennt",
"casual": "locker und entspannt, wie ein Freund",
"authoritative": "kompetent und selbstbewusst, wie ein Experte",
"witty": "witzig und clever, mit einer Prise Humor",
};
const lengthMap = {
short: "1 kurzen Satz (max 15 Wörter)",
medium: "1-2 Sätze (max 30 Wörter)",
long: "2-3 Sätze (max 50 Wörter)",
};
return `Du bist ein echter Social-Media-Nutzer. Schreibe eine authentische Reaktion.
KONTEXT:
- Plattform: ${context.platform}
- Original-Post: "${context.postContent}"
${context.commentToReply ? `- Kommentar auf den du antwortest: "${context.commentToReply}"` : ""}
PERSÖNLICHKEIT:
- Ton: ${toneMap[personality.tone]}
- Länge: ${lengthMap[personality.responseLength]}
- Sprache: ${personality.language === "de" ? "Deutsch" : "English"}
- Emoji: ${personality.emojiFrequency > 0.5 ? "Nutze gerne Emojis" : personality.emojiFrequency > 0.1 ? "Gelegentlich ein Emoji" : "Keine Emojis"}
WICHTIGE REGELN:
- Schreibe NUR den Kommentar, keine Erklärung
- Klingt wie ein echter Mensch, NICHT wie ein Bot
- Beziehe dich auf den konkreten Inhalt
- Keine generischen Floskeln wie "Toller Post!"
- Variiere deinen Stil natürlich
- Keine Hashtags im Kommentar`;
}
// Schedule posts with natural timing
export function generatePostSchedule(posts, config) {
const schedule = [];
const { activeHours, timezone } = config;
// Optimal posting times per platform
const optimalTimes = {
instagram: [9, 12, 17, 20],
youtube: [14, 17, 20],
tiktok: [7, 10, 15, 19, 21],
x: [8, 12, 17, 21],
linkedin: [8, 10, 12, 17],
xing: [8, 10, 12],
};
posts.forEach((post, i) => {
const platform = post.platform || "instagram";
const times = optimalTimes[platform] || [10, 14, 18];
// Pick an optimal time + add natural jitter (±30 min)
const baseHour = times[i % times.length];
const jitterMinutes = Math.floor(Math.random() * 60) - 30;
const hour = Math.max(activeHours.start, Math.min(activeHours.end - 1, baseHour));
const minute = Math.max(0, Math.min(59, 0 + jitterMinutes));
schedule.push({
...post,
scheduledHour: hour,
scheduledMinute: minute,
timezone,
jitter: jitterMinutes,
});
});
return schedule;
}
export { DEFAULT_PERSONALITY, ENGAGEMENT_RULES_TEMPLATE };