added 10% chance for bot to reply without being mentioned or replied to
This commit is contained in:
@@ -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: Bot’s mood (0-1, two decimals, e.g., 0.50).
|
- self_sentiment: Bot’s 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 wasn’t 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}}
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -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 didn’t get that. Can you try again?'
|
const reply = jsonResponse.reply || 'Sorry, I didn’t get that. Can you try again?'
|
||||||
await message.reply(reply)
|
await message.reply(reply)
|
||||||
|
|||||||
@@ -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... you’re 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, I’m 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... you’re 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, I’m 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 wasn’t eavesdropping, but... that’s 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."
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user