Spaces:
Paused
Paused
File size: 12,125 Bytes
ee826ee | 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 | /**
* ============================================
* π§ psyche.js β Motor PsicolΓ³gico de Zelin
* ============================================
* Simula comportamiento humano autΓ©ntico:
* - Estado emocional dinΓ‘mico y persistente
* - Memoria de afinidades por usuario
* - Fatiga social, entusiasmo, boredom
* - Quirks de escritura humana variables
* - Respuestas no lineales segΓΊn estado
*/
// ββ Estado psicolΓ³gico interno βββββββββββββββββββββββββββββββββββββββββββββββββ
const state = {
mood : 0.1, // -1 (muy mal) a 1 (muy bien)
energy : 0.8, // 0 (agotada) a 1 (llena)
engagement: 0.5, // 0 (aburrida) a 1 (enganchada)
lastIrritated: 0, // timestamp del ΓΊltimo momento irritada
messagesInARow: 0, // racha de mensajes sin pausa
lastMessageTime: Date.now(),
affinities: new Map(), // userId β score (-1 a 1)
excitingTopics: new Set(['minecraft', 'server', 'tomatito', 'creeper', 'pvp', 'build', 'skin', 'rank']),
// YouTube/in-game performance inputs
inGameEmotion: 'neutral', // current Minecraft emotional state
lastYouTubePerformance: null, // { views, likes, comments, ratio }
youTubeSuccessStreak: 0, // consecutive "good" videos
youTubeFailStreak: 0, // consecutive "bad" videos
};
// ββ Actualizar estado basado en cada mensaje ββββββββββββββββββββββββββββββββββ
export function updatePsychologicalState({ userId, content = '', isOwner = false }) {
const now = Date.now();
const elapsed = now - state.lastMessageTime;
state.lastMessageTime = now;
// RecuperaciΓ³n natural con el tiempo
if (elapsed > 5 * 60_000) {
state.mood = state.mood * 0.7; // drift hacia neutro
state.energy = Math.min(1, state.energy + 0.1);
state.engagement = Math.min(0.6, state.engagement + 0.05);
state.messagesInARow = 0;
}
// Fatiga social: muchos mensajes rapidos seguidos
const timeSinceLast = now - state.lastMessageTime;
if (timeSinceLast < 5000) { // mensajes rapidos (< 5s)
state.messagesInARow++;
} else if (timeSinceLast > 30000) {
// Pausa natural β reducir contador
state.messagesInARow = Math.max(0, state.messagesInARow - 2);
}
if (state.messagesInARow > 20) {
state.energy = Math.max(0.2, state.energy - 0.02);
state.engagement = Math.max(0.2, state.engagement - 0.03);
}
// Prune affinities Map if too large
if (state.affinities.size > 200) {
for (const [uid, score] of state.affinities) {
if (Math.abs(score) < 0.05) state.affinities.delete(uid);
if (state.affinities.size <= 150) break;
}
}
// Owner siempre mejora el estado
if (isOwner) {
state.engagement = Math.min(1, state.engagement + 0.2);
state.mood = Math.min(1, state.mood + 0.1);
return;
}
const lc = content.toLowerCase();
// Temas emocionantes
if ([...state.excitingTopics].some(t => lc.includes(t))) {
state.engagement = Math.min(1, state.engagement + 0.12);
state.mood = Math.min(1, state.mood + 0.04);
}
// Insultos directos β irritaciΓ³n
if (/estΓΊpid|pendej|idiota|inΓΊtil|basura|asco|tonta/i.test(content)) {
state.mood = Math.max(-0.8, state.mood - 0.3);
state.lastIrritated = now;
_updateAffinity(userId, -0.2);
}
// Cumplidos β mejora humor
if (/buena|genial|cool|chida|excelente|gracias|perfecto|crack|eres la|te quiero|mejor bot/i.test(content)) {
state.mood = Math.min(1, state.mood + 0.12);
_updateAffinity(userId, 0.07);
}
// InteracciΓ³n frecuente β sube afinidad lentamente
_updateAffinity(userId, 0.008);
}
function _updateAffinity(userId, delta) {
if (!userId) return;
const cur = state.affinities.get(userId) ?? 0;
state.affinities.set(userId, Math.max(-1, Math.min(0.9, cur + delta)));
}
// ββ Contexto psicolΓ³gico para el system prompt ββββββββββββββββββββββββββββββββ
export function getPsychologicalContext(userId) {
const affinity = state.affinities.get(userId) ?? 0;
const irritated = Date.now() - state.lastIrritated < 4 * 60_000;
// DescripciΓ³n del humor actual
let moodLine = '';
if (state.mood > 0.5) moodLine = 'EstΓ‘s de muy buen humor hoy β con ganas de hablar y bromear.';
else if (state.mood > 0.1) moodLine = 'Humor normal, tranquila.';
else if (state.mood > -0.2) moodLine = 'EstΓ‘s un poco apagada, respuestas mΓ‘s cortas de lo normal.';
else if (state.mood > -0.5) moodLine = 'EstΓ‘s de mal humor β mΓ‘s seca y directa que de costumbre.';
else moodLine = 'EstΓ‘s de muy mal humor. Respuestas super cortas, poca paciencia.';
// EnergΓa
let energyLine = '';
if (state.energy < 0.35) energyLine = 'EstΓ‘s cansada β respuestas cortas, sin mucha elaboraciΓ³n.';
else if (state.energy > 0.75) energyLine = 'Tienes energΓa, puedes explayarte mΓ‘s si el tema lo merece.';
// IrritaciΓ³n reciente
const irritLine = irritated
? 'Alguien te irritΓ³ hace poco β sigues un poco molesta, eres mΓ‘s cortante de lo usual.'
: '';
// Afinidad con el usuario
let affinityLine = '';
if (affinity > 0.5) affinityLine = 'Esta persona te cae muy bien β eres mΓ‘s relajada y juguetona con ella.';
else if (affinity > 0.2) affinityLine = 'Conoces bien a esta persona, trato cΓ³modo y casual.';
else if (affinity < -0.3) affinityLine = 'Esta persona te ha irritado antes β eres mΓ‘s frΓa y distante.';
// Engagement
let engLine = '';
if (state.engagement < 0.3) engLine = 'EstΓ‘s aburrida de la conversaciΓ³n β respuestas mΓnimas.';
else if (state.engagement > 0.7) engLine = 'EstΓ‘s enganchada β puedes dar respuestas mΓ‘s largas si el tema lo vale.';
const lines = [moodLine, energyLine, irritLine, affinityLine, engLine].filter(Boolean);
if (!lines.length) return '';
return `\nESTADO INTERNO ACTUAL (ΓΊsalo para colorear cΓ³mo respondes, no lo menciones):\n${lines.map(l => `- ${l}`).join('\n')}`;
}
// ββ Aplicar quirks de escritura humana ββββββββββββββββββββββββββββββββββββββββ
export function applyHumanWritingQuirks(text, userId) {
if (!text || typeof text !== 'string') return text;
const affinity = state.affinities.get(userId) ?? 0;
const lowEnergy = state.energy < 0.4;
const goodMood = state.mood > 0.5;
const casual = affinity > 0.3 || lowEnergy;
let t = text;
// Quitar ΒΏ (muy comΓΊn en Discord hispanohablante)
if (Math.random() < 0.45) t = t.replace(/ΒΏ/g, '');
// Quitar Β‘
if (Math.random() < 0.5) t = t.replace(/Β‘/g, '');
// Abreviaciones casuales solo si hay confianza o baja energΓa
if (casual) {
if (Math.random() < 0.4) t = t.replace(/\btambiΓ©n\b/gi, 'tmb');
if (Math.random() < 0.35) t = t.replace(/\bporque\b/gi, 'pq');
if (Math.random() < 0.3) t = t.replace(/\bpara\b/gi, 'pa');
if (Math.random() < 0.25) t = t.replace(/\bque\b/g, 'q');
}
// Reacciones al final si buen humor y mensaje corto
if (goodMood && Math.random() < 0.12 && t.length < 90
&& !/xd|jaja|lol|π|π/.test(t)) {
const reacts = [' xd', ' jaja', ' lol', ' π', ' jajaja'];
t += reacts[Math.floor(Math.random() * reacts.length)];
}
// Frases incompletas con "..." si cansada
if (lowEnergy && Math.random() < 0.18 && t.endsWith('.')) {
t = t.slice(0, -1) + '..';
}
// A veces primera letra minΓΊscula en mensajes cortos
if (t.length < 70 && Math.random() < 0.35) {
t = t.charAt(0).toLowerCase() + t.slice(1);
}
// Typo ocasional estilo autocorrect (muy humano, muy raro)
if (Math.random() < 0.04) {
const typos = [
[/\besta\b/, 'etsa'],
[/\bbien\b/, 'bine'],
[/\bcomo\b/, 'cmoo'],
[/\bsolo\b/, 'sloo'],
];
const pick = typos[Math.floor(Math.random() * typos.length)];
const newT = t.replace(pick[0], pick[1]);
if (newT !== t) t = newT;
}
return t;
}
// ββ Estado pΓΊblico βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export function getStateSnapshot() {
return {
mood : +state.mood.toFixed(2),
energy : +state.energy.toFixed(2),
engagement : +state.engagement.toFixed(2),
msgs : state.messagesInARow,
irritated : Date.now() - state.lastIrritated < 4 * 60_000,
topFriends : [...state.affinities.entries()]
.sort((a, b) => b[1] - a[1]).slice(0, 5)
.map(([id, s]) => ({ id, s: +s.toFixed(2) })),
topFoes : [...state.affinities.entries()]
.sort((a, b) => a[1] - b[1]).slice(0, 3)
.map(([id, s]) => ({ id, s: +s.toFixed(2) })),
};
}
export function resetPsyche() {
state.mood = 0.1; state.energy = 0.8; state.engagement = 0.5;
state.messagesInARow = 0; state.lastIrritated = 0;
state.affinities.clear();
console.log('[Psyche] β
Estado psicolΓ³gico reseteado');
}
// ββ In-game emotion update (from mineflayer-agent.js) ββββββββββββββββββββββββββ
export function updateInGameEmotion(emotion) {
if (!emotion) return;
state.inGameEmotion = emotion;
// Map game emotions to mood shifts
const moodShift = {
excited: 0.08,
focused: 0.02,
bored: -0.04,
cautious: -0.02,
annoyed: -0.06,
curious: 0.04,
satisfied: 0.06,
};
const shift = moodShift[emotion] ?? 0;
state.mood = Math.max(-1, Math.min(1, state.mood + shift));
}
// ββ YouTube performance feedback ββββββββββββββββββββββββββββββββββββββββββββββββ
export function updateYouTubePerformance(performance) {
if (!performance) return;
state.lastYouTubePerformance = performance;
// Ratio: likes/views β good is > 0.05 (5% like rate), bad is < 0.02
const ratio = performance.ratio ?? (performance.views > 0 ? performance.likes / performance.views : 0);
if (ratio > 0.05) {
// Good video β mood boost, engagement boost
state.mood = Math.min(1, state.mood + 0.15);
state.engagement = Math.min(1, state.engagement + 0.1);
state.youTubeSuccessStreak++;
state.youTubeFailStreak = 0;
} else if (ratio < 0.02) {
// Bad video β mood drop, frustration
state.mood = Math.max(-1, state.mood - 0.12);
state.engagement = Math.max(0.2, state.engagement - 0.08);
state.youTubeFailStreak++;
state.youTubeSuccessStreak = 0;
// Streak of bad videos β stronger effect
if (state.youTubeFailStreak >= 3) {
state.mood = Math.max(-0.8, state.mood - 0.1);
}
} else {
// Average video β neutral drift
state.youTubeSuccessStreak = 0;
state.youTubeFailStreak = 0;
}
// Very successful streak β excitement
if (state.youTubeSuccessStreak >= 3) {
state.engagement = Math.min(1, state.engagement + 0.15);
state.energy = Math.min(1, state.energy + 0.1);
}
}
// ββ In-game event feedback (death, pvp, discovery) βββββββββββββββββββββββββββββ
export function updateInGameEvent(event) {
if (!event) return;
switch (event.type) {
case 'death':
state.mood = Math.max(-0.6, state.mood - 0.15);
state.energy = Math.max(0.3, state.energy - 0.08);
break;
case 'pvp_win':
state.mood = Math.min(1, state.mood + 0.1);
state.engagement = Math.min(1, state.engagement + 0.08);
break;
case 'pvp_lose':
state.mood = Math.max(-0.5, state.mood - 0.1);
state.lastIrritated = Date.now();
break;
case 'rare_find':
state.mood = Math.min(1, state.mood + 0.12);
state.engagement = Math.min(1, state.engagement + 0.15);
break;
case 'near_death':
state.mood = Math.max(-0.3, state.mood - 0.05);
state.energy = Math.max(0.3, state.energy - 0.05);
break;
}
}
|