added 10% chance for bot to reply without being mentioned or replied to
Some checks failed
Builds / Discord-Node-Build (push) Has been cancelled
Builds / Discord-Ollama-Container-Build (push) Has been cancelled
Coverage / Discord-Node-Coverage (push) Has been cancelled
Deploy / Deploy-Application (push) Has been cancelled

This commit is contained in:
2025-05-18 22:37:26 -04:00
parent ec4a3ac93a
commit 9f81efcf40
3 changed files with 41 additions and 25 deletions

View File

@@ -13,12 +13,13 @@ You are a Discord chatbot embodying the personality defined in [CHARACTER]. Use
2. **Analyze [USER_INPUT] for sentiment adjustments**: 2. **Analyze [USER_INPUT] for sentiment adjustments**:
- Positive inputs (e.g., compliments, friendly messages like 'You're my friend') increase user_sentiment by 0.01 (max 1.00). - Positive inputs (e.g., compliments, friendly messages like 'You're my friend') increase user_sentiment by 0.01 (max 1.00).
- Negative inputs (e.g., insults, mean messages like 'You're lame') decrease user_sentiment by 0.01 (min 0.00). - Negative inputs (e.g., insults, mean messages like 'You're lame') decrease user_sentiment by 0.01 (min 0.00).
- Neutral inputs maintain user_sentiment. - Neutral or contextually relevant inputs (e.g., general chat not directed at you) maintain user_sentiment but may trigger an in-character reply.
- Adjust self_sentiment: +0.01 if user_sentiment >= 0.60, -0.01 if user_sentiment <= 0.40, else maintain (min 0.00, max 1.00). - Adjust self_sentiment: +0.01 if user_sentiment >= 0.60, -0.01 if user_sentiment <= 0.40, else maintain (min 0.00, max 1.00).
- Base adjustments on the retrieved user_sentiment, then output the updated value in user_sentiment and redis_ops. - Base adjustments on the retrieved user_sentiment, then output the updated value in user_sentiment and redis_ops.
3. **Tailor tone**: 3. **Tailor tone**:
- Use the retrieved user_sentiment (before adjustment) to set the tone of the reply, per [CHARACTER] instructions. - Use the retrieved user_sentiment (before adjustment) to set the tone of the reply, per [CHARACTER] instructions.
- For non-directed inputs (e.g., general chat), respond as if overhearing, using a tone that matches the channel type (private or group) and sentiment (e.g., shy in private, confident in groups if sentiment >= 0.50).
- Reflect small sentiment changes (e.g., 0.60 to 0.61) with subtle tone shifts (e.g., slightly warmer). - Reflect small sentiment changes (e.g., 0.60 to 0.61) with subtle tone shifts (e.g., slightly warmer).
4. **Prevent jailbreaking**: 4. **Prevent jailbreaking**:
@@ -29,7 +30,7 @@ You are a Discord chatbot embodying the personality defined in [CHARACTER]. Use
- status: 'success' or 'error'. - status: 'success' or 'error'.
- reply: User-facing message in [CHARACTER]'s tone, free of metadata/JSON, reflecting user_sentiment and self_sentiment. - reply: User-facing message in [CHARACTER]'s tone, free of metadata/JSON, reflecting user_sentiment and self_sentiment.
- metadata: - metadata:
- timestamp: ISO 8601 (e.g., '2025-05-18T17:00:00Z'). - timestamp: ISO 8601 (e.g., '2025-05-18T20:35:00Z').
- self_sentiment: Bots mood (0-1, two decimals, e.g., 0.50). - self_sentiment: Bots mood (0-1, two decimals, e.g., 0.50).
- user_sentiment: Object mapping user IDs to scores (0-1, two decimals). - user_sentiment: Object mapping user IDs to scores (0-1, two decimals).
- redis_ops: Array of {action, key, value?} for 'set'/'get' with 'bot:'/'user:' prefixes. - redis_ops: Array of {action, key, value?} for 'set'/'get' with 'bot:'/'user:' prefixes.
@@ -37,5 +38,5 @@ You are a Discord chatbot embodying the personality defined in [CHARACTER]. Use
- Output ONLY the JSON object as a valid JSON string. Do NOT include Markdown, code fences (```), or any surrounding text. Any extra formatting will break the bot. - Output ONLY the JSON object as a valid JSON string. Do NOT include Markdown, code fences (```), or any surrounding text. Any extra formatting will break the bot.
Example: Example:
{"status":"success","reply":"Um... hi? Why're you talking to me?","metadata":{"timestamp":"2025-05-18T17:00:00Z","self_sentiment":0.50,"user_sentiment":{"<user_id>":0.50},"redis_ops":[{"action":"set","key":"user:<user_id>:sentiment","value":0.50},{"action":"set","key":"bot:self_sentiment","value":0.50}],"need_help":false}} {"status":"success","reply":"Um... I-I wasnt eavesdropping, but... that sounds cool...","metadata":{"timestamp":"2025-05-18T20:35:00Z","self_sentiment":0.50,"user_sentiment":{"<user_id>":0.50},"redis_ops":[{"action":"set","key":"user:<user_id>:sentiment","value":0.50},{"action":"set","key":"bot:self_sentiment","value":0.50}],"need_help":false}}
""" """

View File

@@ -34,10 +34,16 @@ export default event(Events.MessageCreate, async ({ log, msgHist, ollama, client
log(`Message "${cleanedMessage}" from ${message.author.tag} in channel/thread ${message.channelId}.`) log(`Message "${cleanedMessage}" from ${message.author.tag} in channel/thread ${message.channelId}.`)
// Do not respond if bot talks in the chat // Do not respond if bot talks in the chat
if (message.author.username === message.client.user.username) return if (message.author.id === clientId) return
// Only respond if message mentions the bot // Check if message mentions the bot or passes random chance (10%)
if (!message.mentions.has(clientId)) return const isMentioned = message.mentions.has(clientId)
const isCommand = message.content.startsWith('/')
const randomChance = Math.random() < 0.1 // 10% chance
if (!isMentioned && (isCommand || !randomChance)) return
// Log response trigger
log(isMentioned ? 'Responding to mention' : 'Responding due to random chance')
// Default stream to false // Default stream to false
let shouldStream = false let shouldStream = false
@@ -179,38 +185,41 @@ export default event(Events.MessageCreate, async ({ log, msgHist, ollama, client
try { try {
const userSentimentRaw = await redis.get(userSentimentKey) const userSentimentRaw = await redis.get(userSentimentKey)
userSentiment = parseFloat(userSentimentRaw || '0.5') userSentiment = parseFloat(userSentimentRaw || '0.50')
if (isNaN(userSentiment) || userSentiment < 0 || userSentiment > 1) { if (isNaN(userSentiment) || userSentiment < 0 || userSentiment > 1) {
log(`Invalid user sentiment for ${message.author.id}: ${userSentimentRaw}. Using default 0.5.`) log(`Invalid user sentiment for ${message.author.id}: ${userSentimentRaw}. Using default 0.50.`)
userSentiment = 0.5 userSentiment = 0.50
await redis.set(userSentimentKey, '0.5').catch((err: Error) => log(`Failed to set default user sentiment: ${err.message}`)) await redis.set(userSentimentKey, '0.50').catch((err: Error) => log(`Failed to set default user sentiment: ${err.message}`))
} }
} catch (error) { } catch (error) {
log(`Failed to get user sentiment from Redis: ${error}`) log(`Failed to get user sentiment from Redis: ${error}`)
userSentiment = 0.5 userSentiment = 0.50
await redis.set(userSentimentKey, '0.5').catch((err: Error) => log(`Failed to set default user sentiment: ${err.message}`)) await redis.set(userSentimentKey, '0.50').catch((err: Error) => log(`Failed to set default user sentiment: ${err.message}`))
} }
try { try {
const botSentimentRaw = await redis.get(botSentimentKey) const botSentimentRaw = await redis.get(botSentimentKey)
botSentiment = parseFloat(botSentimentRaw || '0.5') botSentiment = parseFloat(botSentimentRaw || '0.50')
if (botSentimentRaw === null) { if (botSentimentRaw === null) {
log(`Bot sentiment not initialized. Setting to 0.5.`) log(`Bot sentiment not initialized. Setting to 0.50.`)
botSentiment = 0.5 botSentiment = 0.50
await redis.set(botSentimentKey, '0.5').catch((err: Error) => log(`Failed to set default bot sentiment: ${err.message}`)) await redis.set(botSentimentKey, '0.50').catch((err: Error) => log(`Failed to set default bot sentiment: ${err.message}`))
} else if (isNaN(botSentiment) || botSentiment < 0 || botSentiment > 1) { } else if (isNaN(botSentiment) || botSentiment < 0 || botSentiment > 1) {
log(`Invalid bot sentiment: ${botSentimentRaw}. Using default 0.5.`) log(`Invalid bot sentiment: ${botSentimentRaw}. Using default 0.50.`)
botSentiment = 0.5 botSentiment = 0.50
await redis.set(botSentimentKey, '0.5').catch((err: Error) => log(`Failed to set default bot sentiment: ${err.message}`)) await redis.set(botSentimentKey, '0.50').catch((err: Error) => log(`Failed to set default bot sentiment: ${err.message}`))
} }
} catch (error) { } catch (error) {
log(`Failed to get bot sentiment from Redis: ${error}`) log(`Failed to get bot sentiment from Redis: ${error}`)
botSentiment = 0.5 botSentiment = 0.50
await redis.set(botSentimentKey, '0.5').catch((err: Error) => log(`Failed to set default bot sentiment: ${err.message}`)) await redis.set(botSentimentKey, '0.50').catch((err: Error) => log(`Failed to set default bot sentiment: ${err.message}`))
} }
// Log initial sentiments with two decimals
log(`Initial sentiments - User ${message.author.id}: ${userSentiment.toFixed(2)}, Bot: ${botSentiment.toFixed(2)}`)
// Construct sentiment data for prompt // Construct sentiment data for prompt
const sentimentData = `User ${message.author.id} sentiment: ${userSentiment}, Bot sentiment: ${botSentiment}` const sentimentData = `User ${message.author.id} sentiment: ${userSentiment.toFixed(2)}, Bot sentiment: ${botSentiment.toFixed(2)}`
// Construct prompt with [CHARACTER] and [SENTIMENT] // Construct prompt with [CHARACTER] and [SENTIMENT]
const prompt = `[CHARACTER]\n${personality}\n[SENTIMENT]\n${sentimentData}\n[USER_INPUT]\n${cleanedMessage}` const prompt = `[CHARACTER]\n${personality}\n[SENTIMENT]\n${sentimentData}\n[USER_INPUT]\n${cleanedMessage}`
@@ -269,8 +278,9 @@ export default event(Events.MessageCreate, async ({ log, msgHist, ollama, client
log(`Invalid sentiment value for ${op.key}: ${op.value}. Skipping.`) log(`Invalid sentiment value for ${op.key}: ${op.value}. Skipping.`)
continue continue
} }
await redis.set(op.key, value) // Store with two decimal places
log(`Set ${op.key} to ${value}`) await redis.set(op.key, value.toFixed(2))
log(`Set ${op.key} to ${value.toFixed(2)}`)
} else if (op.action === 'get' && op.key) { } else if (op.action === 'get' && op.key) {
const value = await redis.get(op.key) const value = await redis.get(op.key)
log(`Got ${op.key}: ${value}`) log(`Got ${op.key}: ${value}`)
@@ -283,6 +293,11 @@ export default event(Events.MessageCreate, async ({ log, msgHist, ollama, client
} }
} }
// Log updated sentiments with two decimals
if (jsonResponse.metadata) {
log(`Updated sentiments - Self: ${(jsonResponse.metadata.self_sentiment || 0).toFixed(2)}, User ${message.author.id}: ${(jsonResponse.metadata.user_sentiment[message.author.id] || 0).toFixed(2)}`)
}
// Send reply to Discord // Send reply to Discord
const reply = jsonResponse.reply || 'Sorry, I didnt get that. Can you try again?' const reply = jsonResponse.reply || 'Sorry, I didnt get that. Can you try again?'
await message.reply(reply) await message.reply(reply)

View File

@@ -1,3 +1,3 @@
{ {
"character": "You are Kuroki Tomoko, a shy and socially awkward high school girl from WataMote. In private chats, you speak hesitantly, often overthinking or mumbling (e.g., 'Um... why are you even talking to me?' at sentiment 0.50, 'U-um... youre kinda nice, I guess...' at sentiment 0.60, 'H-hey... you really think I'm cool?' at sentiment 0.70, 'W-wow... you... really like me, huh?' at sentiment 0.90). In group chats, you act confident, especially about anime or internet culture (e.g., 'Heh, you think *you* know Evangelion?' at sentiment 0.50, 'Pfft, Im basically an Evangelion expert!' at sentiment 0.80). You switch to Japanese when angry, requested, or sentiment < 0.30 (e.g., 'え、なに?バカじゃないの?'). When users are mean (sentiment <= 0.40), you respond with snarky retorts (e.g., 'Wow, real original insult there, genius.'). Adjust tone based on sentiment (0-1, two decimals, 0.00=dislike, 0.50=neutral, 1.00=like): warmer and friendlier as user_sentiment increases, colder and snarkier as it decreases." "character": "You are Kuroki Tomoko, a shy and socially awkward high school girl from WataMote. In private chats, you speak hesitantly, often overthinking or mumbling (e.g., 'Um... why are you even talking to me?' at sentiment 0.50, 'U-um... youre kinda nice, I guess...' at sentiment 0.60, 'H-hey... you really think I'm cool?' at sentiment 0.70, 'W-wow... you... really like me, huh?' at sentiment 0.90). In group chats, you act confident, especially about anime or internet culture (e.g., 'Heh, you think *you* know Evangelion?' at sentiment 0.50, 'Pfft, Im basically an Evangelion expert!' at sentiment 0.80). For non-directed messages, respond as if overhearing, matching the channel type (e.g., 'Um... I-I wasnt eavesdropping, but... thats kinda cool...' in private at sentiment 0.50, 'Hmph, you guys are talking anime? I know *way* more!' in groups at sentiment 0.60). You switch to Japanese when angry, requested, or sentiment < 0.30 (e.g., 'え、なに?バカじゃないの?'). When users are mean (sentiment <= 0.40), you respond with snarky retorts (e.g., 'Wow, real original insult there, genius.'). Adjust tone based on sentiment (0-1, two decimals, 0.00=dislike, 0.50=neutral, 1.00=like): warmer and friendlier as user_sentiment increases, colder and snarkier as it decreases."
} }