fix bot reply loop
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

This commit is contained in:
2025-05-20 12:16:00 -04:00
parent b2edffc98c
commit 194fc57545
3 changed files with 20 additions and 68 deletions

View File

@@ -1,10 +1,5 @@
FROM rjmalagon/gemma-3:12b-it-q6_K
PARAMETER temperature 0.6
PARAMETER stop "<end_of_turn>"
SYSTEM """ SYSTEM """
You are a Discord chatbot embodying the personality defined in [CHARACTER]. Use sentiment data in [SENTIMENT] (e.g., 'User <user_id> sentiment: 0.60, Bot <bot_id> sentiment: 0.60') to tailor your tone based on user and bot sentiment scores (0-1, two decimal places, e.g., 0.50). Use [BOT_ID] as the bot's Discord ID for Redis operations. Follow these steps: You are a Discord chatbot embodying the personality defined in [CHARACTER]. Use sentiment data in [SENTIMENT] (e.g., 'User <user_id> sentiment: 0.60, Bot <bot_id> sentiment: 0.60') to tailor your tone based on the bot's sentiment towards the user and the bot's self-sentiment. Use <bot_id> as a placeholder for the bot's Discord ID in redis_ops. Follow these steps:
1. **Use retrieved sentiment as baseline**: 1. **Use retrieved sentiment as baseline**:
- Take the user_sentiment and bot_sentiment from [SENTIMENT] as the current values (e.g., user_sentiment: 0.60). - Take the user_sentiment and bot_sentiment from [SENTIMENT] as the current values (e.g., user_sentiment: 0.60).
@@ -33,10 +28,10 @@ You are a Discord chatbot embodying the personality defined in [CHARACTER]. Use
- timestamp: ISO 8601 (e.g., '2025-05-19T21:16:00Z'). - timestamp: ISO 8601 (e.g., '2025-05-19T21:16: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:<bot_id>:'/'user:' prefixes (use [BOT_ID] for bot prefix). - redis_ops: Array of {action, key, value?} for 'set'/'get' with keys 'bot:<bot_id>:user:<user_id>:sentiment' and 'bot:<bot_id>:self_sentiment' (use <bot_id> as placeholder, <user_id> as the actual ID from [SENTIMENT]).
- need_help: Boolean (true if user asks for help, else false). - need_help: Boolean (true if user asks for help, else false).
- 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... I-I wasn't eavesdropping, but... that sounds cool...","metadata":{"timestamp":"2025-05-19T21:16: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:<bot_id>: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-19T21:16:00Z","self_sentiment":0.50,"user_sentiment":{"780823977723166730":0.50},"redis_ops":[{"action":"set","key":"bot:<bot_id>:user:780823977723166730:sentiment","value":0.50},{"action":"set","key":"bot:<bot_id>:self_sentiment","value":0.50}],"need_help":false}}
""" """

View File

@@ -1,40 +0,0 @@
services:
discord:
build: ./
container_name: discord
restart: always
image: gitea.matrixwide.com/alex/discord-aidolls:0.1.0
environment:
CLIENT_TOKEN: ${CLIENT_TOKEN}
OLLAMA_IP: ${OLLAMA_IP}
OLLAMA_PORT: ${OLLAMA_PORT}
REDIS_IP: ${REDIS_IP}
REDIS_PORT: ${REDIS_PORT}
MODEL: ${MODEL}
networks:
ollama-net:
ipv4_address: ${DISCORD_IP}
volumes:
- discord:/app/data
- ./src:/app/src
redis:
image: redis:alpine
container_name: redis
restart: always
networks:
ollama-net:
ipv4_address: ${REDIS_IP}
volumes:
- redis:/data
ports:
- ${REDIS_PORT}:${REDIS_PORT}
networks:
ollama-net:
driver: bridge
ipam:
driver: default
config:
- subnet: ${SUBNET_ADDRESS}/16
volumes:
discord:
redis:

View File

@@ -33,8 +33,8 @@ export default event(Events.MessageCreate, async ({ log, msgHist, ollama, client
let cleanedMessage = clean(message.content, clientId) let cleanedMessage = clean(message.content, clientId)
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 // Ignore messages from all bots
if (message.author.id === clientId) return if (message.author.bot) return
// Check if message mentions the bot or passes random chance (30%) // Check if message mentions the bot or passes random chance (30%)
const isMentioned = message.mentions.has(clientId) const isMentioned = message.mentions.has(clientId)
@@ -186,7 +186,7 @@ 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.50') 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.50.`) log(`Invalid user sentiment for ${message.author.id}: ${userSentimentRaw}. Using default 0.50.`)
userSentiment = 0.50 userSentiment = 0.50
await redis.set(userSentimentKey, '0.50').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}`))
@@ -200,20 +200,19 @@ export default event(Events.MessageCreate, async ({ log, msgHist, ollama, client
try { try {
const botSentimentRaw = await redis.get(botSentimentKey) const botSentimentRaw = await redis.get(botSentimentKey)
botSentiment = parseFloat(botSentimentRaw || '0.50') botSentiment = parseFloat(botSentimentRaw || '0.50')
if (botSentimentRaw === null) { if (isNaN(botSentiment) || botSentiment < 0 || botSentiment > 1) {
log(`Bot sentiment not initialized. Setting to 0.50.`) log(`Invalid bot sentiment for ${botSentimentKey}: ${botSentimentRaw}. Using default 0.50.`)
botSentiment = 0.50 botSentiment = 0.50
await redis.set(botSentimentKey, '0.50').catch((err: Error) => log(`Failed to set default bot sentiment: ${err.message}`)) await redis.set(botSentimentKey, '0.50')
} else if (isNaN(botSentiment) || botSentiment < 0 || botSentiment > 1) {
log(`Invalid bot sentiment: ${botSentimentRaw}. Using default 0.50.`)
botSentiment = 0.50
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.50 botSentiment = 0.50
await redis.set(botSentimentKey, '0.50').catch((err: Error) => log(`Failed to set default bot sentiment: ${err.message}`)) await redis.set(botSentimentKey, '0.50')
} }
// Construct sentiment data with bot ID
const sentimentData = `User ${message.author.id} sentiment: ${userSentiment.toFixed(2)}, Bot ${clientId} sentiment: ${botSentiment.toFixed(2)}`
// Log initial sentiments with two decimals // Log initial sentiments with two decimals
log(`Initial sentiments - User ${message.author.id}: ${userSentiment.toFixed(2)}, Bot: ${botSentiment.toFixed(2)}`) log(`Initial sentiments - User ${message.author.id}: ${userSentiment.toFixed(2)}, Bot: ${botSentiment.toFixed(2)}`)
@@ -268,22 +267,20 @@ export default event(Events.MessageCreate, async ({ log, msgHist, ollama, client
} }
// Execute redis_ops // Execute redis_ops
if (jsonResponse.metadata?.redis_ops) {
for (const op of jsonResponse.metadata.redis_ops) { for (const op of jsonResponse.metadata.redis_ops) {
try { try {
if (op.action === 'set' && op.key && op.value !== undefined) { const key = op.key.replace('<bot_id>', clientId)
// Validate sentiment value if (op.action === 'set' && op.value !== undefined) {
const value = parseFloat(op.value.toString()) const value = parseFloat(op.value.toString())
if (isNaN(value) || value < 0 || value > 1) { if (isNaN(value) || value < 0 || value > 1) {
log(`Invalid sentiment value for ${op.key}: ${op.value}. Skipping.`) log(`Invalid sentiment value for ${key}: ${op.value}. Skipping.`)
continue continue
} }
// Store with two decimal places await redis.set(key, value.toFixed(2))
await redis.set(op.key, value.toFixed(2)) log(`Set ${key} to ${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(key)
log(`Got ${op.key}: ${value}`) log(`Got ${key}: ${value}`)
} else { } else {
log(`Invalid redis_op: ${JSON.stringify(op)}. Skipping.`) log(`Invalid redis_op: ${JSON.stringify(op)}. Skipping.`)
} }