mirror of
https://github.com/alterware/aw-bot.git
synced 2025-10-26 06:05:54 +00:00
feat: logs
This commit is contained in:
11
aw.py
11
aw.py
@@ -5,6 +5,7 @@ from discord.ext import commands
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from bot.ai.handle_request import DiscourseSummarizer
|
||||
from bot.log import logger
|
||||
from database import initialize_db
|
||||
|
||||
GUILD_ID = 1110531063161299074
|
||||
@@ -16,7 +17,7 @@ intents = discord.Intents.all()
|
||||
bot = commands.Bot(command_prefix="!", intents=intents)
|
||||
|
||||
# Load environment variables from .env file (if it exists)
|
||||
load_dotenv(override=True)
|
||||
load_dotenv(os.path.join(os.path.dirname(__file__), ".env"))
|
||||
|
||||
initialize_db()
|
||||
|
||||
@@ -25,13 +26,13 @@ bot.ai_helper = DiscourseSummarizer()
|
||||
|
||||
@bot.event
|
||||
async def on_ready():
|
||||
print(f"{bot.user.name} has connected to Discord!")
|
||||
logger.info(f"{bot.user.name} has connected to Discord!")
|
||||
|
||||
try:
|
||||
await bot.tree.sync(guild=discord.Object(id=GUILD_ID))
|
||||
print("Slash commands synchronized!")
|
||||
logger.info("Slash commands synchronized!")
|
||||
except Exception as e:
|
||||
print(f"Failed to sync commands: {e}")
|
||||
logger.error("Failed to sync commands: %s", e)
|
||||
|
||||
# Load extensions asynchronously
|
||||
await bot.load_extension("bot.tasks")
|
||||
@@ -39,4 +40,4 @@ async def on_ready():
|
||||
await bot.load_extension("bot.commands")
|
||||
|
||||
|
||||
bot.run(os.getenv("BOT_TOKEN"))
|
||||
bot.run(os.getenv("BOT_TOKEN"), log_handler=None)
|
||||
|
||||
@@ -4,6 +4,8 @@ import requests
|
||||
from google import genai
|
||||
from google.genai import types
|
||||
|
||||
from bot.log import logger
|
||||
|
||||
API_KEY = os.getenv("GOOGLE_API_KEY")
|
||||
|
||||
GENERIC_INSTRUCTION = "You are a Discord chatbot named 'AlterWare' who helps users with all kinds of topics across various subjects. You should limit your answers to fewer than 2000 characters."
|
||||
@@ -19,7 +21,7 @@ class DiscourseSummarizer:
|
||||
self.discourse_data = None
|
||||
|
||||
if not API_KEY:
|
||||
print("Google API key is not set. Please contact the administrator.")
|
||||
logger.error("Google API key is not set. Please contact the administrator.")
|
||||
return
|
||||
|
||||
self.client = genai.Client(api_key=API_KEY)
|
||||
@@ -50,7 +52,7 @@ class DiscourseSummarizer:
|
||||
ttl=self.ttl,
|
||||
),
|
||||
)
|
||||
print(f"Cached content created: {self.cache.name}")
|
||||
logger.info("Cached content created: %s", self.cache.name)
|
||||
|
||||
def update_cache(self):
|
||||
"""
|
||||
@@ -64,7 +66,7 @@ class DiscourseSummarizer:
|
||||
self.client.caches.update(
|
||||
name=self.cache.name, config=types.UpdateCachedContentConfig(ttl="21600s")
|
||||
)
|
||||
print("Cache updated.")
|
||||
logger.info("Cache updated.")
|
||||
|
||||
def ask(self, prompt):
|
||||
"""
|
||||
|
||||
@@ -5,6 +5,7 @@ import discord
|
||||
from discord import app_commands
|
||||
|
||||
from bot.config import message_patterns, update_patterns
|
||||
from bot.log import logger
|
||||
from bot.utils import compile_stats, fetch_game_stats, perform_search
|
||||
from database import add_pattern, add_user_to_blacklist, is_user_blacklisted
|
||||
|
||||
@@ -128,4 +129,4 @@ async def setup(bot):
|
||||
|
||||
await bot.tree.sync(guild=discord.Object(id=GUILD_ID)) # Force sync
|
||||
|
||||
print("Commands extension loaded!")
|
||||
logger.info("Commands extension loaded!")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import csv
|
||||
import os
|
||||
|
||||
from bot.log import logger
|
||||
from database import get_patterns
|
||||
|
||||
message_patterns = get_patterns()
|
||||
@@ -9,7 +10,7 @@ message_patterns = get_patterns()
|
||||
def update_patterns(regex: str, response: str):
|
||||
"""update patterns in memory."""
|
||||
message_patterns.append({"regex": regex, "response": response})
|
||||
print(f"Pattern added in memory: {regex}")
|
||||
logger.info(f"Pattern added in memory: {regex}")
|
||||
|
||||
|
||||
def load_chat_messages(csv_path="chat/chat_messages.csv"):
|
||||
@@ -24,7 +25,7 @@ def load_chat_messages(csv_path="chat/chat_messages.csv"):
|
||||
"""
|
||||
messages = []
|
||||
if not os.path.exists(csv_path):
|
||||
print(f"CSV file not found: {csv_path}")
|
||||
logger.info(f"CSV file not found: {csv_path}")
|
||||
return messages
|
||||
|
||||
with open(csv_path, newline="", encoding="utf-8") as csvfile:
|
||||
|
||||
@@ -3,6 +3,8 @@ import os
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
from bot.log import logger
|
||||
|
||||
DISCOURSE_BASE_URL = os.getenv("DISCOURSE_BASE_URL")
|
||||
API_KEY = os.getenv("DISCOURSE_API_KEY")
|
||||
API_USERNAME = os.getenv("DISCOURSE_API_USERNAME")
|
||||
@@ -23,8 +25,11 @@ def get_topics_by_id(topic_id):
|
||||
response = requests.get(f"{DISCOURSE_BASE_URL}/t/{topic_id}.json", headers=headers)
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
elif response.status_code == 403:
|
||||
logger.error(f"Access forbidden for topic {topic_id}: {response.status_code}")
|
||||
return None
|
||||
else:
|
||||
print(
|
||||
logger.error(
|
||||
f"Error fetching topic {topic_id}: {response.status_code} - {response.text}"
|
||||
)
|
||||
return None
|
||||
@@ -56,8 +61,11 @@ def get_topics_by_tag(tag_name):
|
||||
for post in posts:
|
||||
cooked_strings.append(post.get("cooked", ""))
|
||||
return cooked_strings
|
||||
elif response.status_code == 403:
|
||||
logger.error(f"Access forbidden for topic {topic_id}: {response.status_code}")
|
||||
return None
|
||||
else:
|
||||
print(
|
||||
logger.error(
|
||||
f"Error fetching topics with tag '{tag_name}': {response.status_code} - {response.text}"
|
||||
)
|
||||
return []
|
||||
|
||||
@@ -8,6 +8,7 @@ from bot.events_handlers import (
|
||||
handle_reaction_add,
|
||||
handle_voice_state_update,
|
||||
)
|
||||
from bot.log import logger
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
@@ -43,4 +44,4 @@ async def setup(bot):
|
||||
async def on_voice_state_update(member, before, after):
|
||||
await handle_voice_state_update(member, before, after, bot)
|
||||
|
||||
print("Events extension loaded!")
|
||||
logger.info("Events extension loaded!")
|
||||
|
||||
@@ -4,6 +4,7 @@ from datetime import timedelta
|
||||
import discord
|
||||
|
||||
from bot.ai.handle_request import forward_to_google_api
|
||||
from bot.log import logger
|
||||
from bot.utils import aware_utcnow, timeout_member
|
||||
from database import add_user_to_role
|
||||
|
||||
@@ -89,11 +90,15 @@ async def handle_bot_mention(message, bot, no_context=False):
|
||||
image_object = fetch_image_from_message(referenced_message)
|
||||
|
||||
except discord.NotFound:
|
||||
print("Referenced message not found.")
|
||||
logger.error("Referenced message not found.")
|
||||
except discord.Forbidden:
|
||||
print("Bot does not have permission to fetch the referenced message.")
|
||||
logger.error(
|
||||
"Bot does not have permission to fetch the referenced message."
|
||||
)
|
||||
except discord.HTTPException as e:
|
||||
print(f"An error occurred while fetching the referenced message: {e}")
|
||||
logger.error(
|
||||
"An error occurred while fetching the referenced message: %s", e
|
||||
)
|
||||
|
||||
# Pass the reply content to forward_to_google_api
|
||||
await forward_to_google_api(message, bot, image_object, reply_content, no_context)
|
||||
@@ -162,7 +167,7 @@ async def is_message_a_duplicate(message):
|
||||
|
||||
time_difference = current_time - message_time
|
||||
if time_difference >= timedelta(minutes=5):
|
||||
print(
|
||||
logger.debug(
|
||||
f"Message is probably not a duplicate. Time difference: {time_difference}"
|
||||
)
|
||||
continue
|
||||
@@ -174,9 +179,11 @@ async def is_message_a_duplicate(message):
|
||||
await timeout_member(member)
|
||||
return
|
||||
except discord.Forbidden:
|
||||
print(f"Bot does not have permission to read messages in {channel.name}.")
|
||||
logger.error(
|
||||
f"Bot does not have permission to read messages in {channel.name}."
|
||||
)
|
||||
except discord.HTTPException as e:
|
||||
print(f"An error occurred: {e}")
|
||||
logger.error("An error occurred: %s", e)
|
||||
|
||||
|
||||
async def was_message_replied_by_bot(message, bot):
|
||||
|
||||
@@ -2,6 +2,8 @@ import asyncio
|
||||
|
||||
import discord
|
||||
|
||||
from bot.log import logger
|
||||
|
||||
MP3_PATH = "sounds/hello.mp3"
|
||||
|
||||
|
||||
@@ -29,4 +31,4 @@ async def handle_voice_state_update(member, before, after, bot):
|
||||
await vc.disconnect()
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
logger.error("Error: %s", e)
|
||||
|
||||
23
bot/log.py
Normal file
23
bot/log.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import logging
|
||||
import logging.handlers
|
||||
import os
|
||||
|
||||
log_dir = "/bot-data"
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
|
||||
logger = logging.getLogger("discord")
|
||||
logger.setLevel(logging.INFO)
|
||||
logging.getLogger("discord.http").setLevel(logging.INFO)
|
||||
|
||||
handler = logging.handlers.RotatingFileHandler(
|
||||
filename=os.path.join(log_dir, "discord.log"),
|
||||
encoding="utf-8",
|
||||
maxBytes=32 * 1024 * 1024, # 32 MiB
|
||||
backupCount=5, # Rotate through 5 files
|
||||
)
|
||||
dt_fmt = "%Y-%m-%d %H:%M:%S"
|
||||
formatter = logging.Formatter(
|
||||
"[{asctime}] [{levelname:<8}] {name}: {message}", dt_fmt, style="{"
|
||||
)
|
||||
handler.setFormatter(formatter)
|
||||
logger.addHandler(handler)
|
||||
33
bot/tasks.py
33
bot/tasks.py
@@ -7,6 +7,7 @@ from discord.ext import commands, tasks
|
||||
|
||||
from bot.config import schizo_messages
|
||||
from bot.discourse.handle_request import combine_posts_text, fetch_cooked_posts
|
||||
from bot.log import logger
|
||||
from bot.utils import aware_utcnow, fetch_api_data
|
||||
from database import migrate_users_with_role
|
||||
|
||||
@@ -53,7 +54,9 @@ class SteamSaleChecker(commands.Cog):
|
||||
|
||||
channel = self.bot.get_channel(channel_id)
|
||||
if channel is None:
|
||||
print(f"Error: Channel ID {channel_id} for {game_name} not found.")
|
||||
logger.error(
|
||||
f"Error: Channel ID {channel_id} for {game_name} not found."
|
||||
)
|
||||
return
|
||||
|
||||
steam_api_url = (
|
||||
@@ -65,7 +68,9 @@ class SteamSaleChecker(commands.Cog):
|
||||
data = response.json().get(str(app_id), {}).get("data", {})
|
||||
|
||||
if not data:
|
||||
print(f"Warning: No data returned for {game_name}. Skipping...")
|
||||
logger.warning(
|
||||
f"Warning: No data returned for {game_name}. Skipping..."
|
||||
)
|
||||
return
|
||||
|
||||
price_info = data.get("price_overview", {})
|
||||
@@ -113,7 +118,7 @@ class SteamSaleChecker(commands.Cog):
|
||||
await channel.send(embed=embed)
|
||||
|
||||
except requests.RequestException as e:
|
||||
print(f"Error fetching Steam sale data for {game_name}: {e}")
|
||||
logger.error("Error fetching Steam sale data for %s: %s", game_name, e)
|
||||
|
||||
@check_steam_sale.before_loop
|
||||
async def before_check_steam_sale(self):
|
||||
@@ -134,16 +139,16 @@ class DiscourseUpdater(commands.Cog):
|
||||
Periodically fetches and updates Discourse data for the bot.
|
||||
"""
|
||||
tag_name = "docs"
|
||||
print("Fetching Discourse data...")
|
||||
logger.info("Fetching Discourse data...")
|
||||
cooked_posts = fetch_cooked_posts(tag_name)
|
||||
if cooked_posts:
|
||||
combined_text = combine_posts_text(
|
||||
[{"cooked": post} for post in cooked_posts]
|
||||
)
|
||||
self.bot.ai_helper.set_discourse_data(combined_text)
|
||||
print("Discourse data updated successfully.")
|
||||
logger.info("Discourse data updated successfully.")
|
||||
else:
|
||||
print(f"No posts found for tag '{tag_name}'.")
|
||||
logger.warning(f"No posts found for tag '{tag_name}'.")
|
||||
|
||||
@update_discourse_data.before_loop
|
||||
async def before_update_discourse_data(self):
|
||||
@@ -167,7 +172,7 @@ async def setup(bot):
|
||||
now = aware_utcnow()
|
||||
remaining_seconds = int((TARGET_DATE - now).total_seconds())
|
||||
|
||||
print(f"Seconds until August 12, 2036, UTC: {remaining_seconds}")
|
||||
logger.info(f"Seconds until August 12, 2036, UTC: {remaining_seconds}")
|
||||
|
||||
channel = bot.get_channel(OFFTOPIC_CHANNEL)
|
||||
if channel:
|
||||
@@ -180,9 +185,11 @@ async def setup(bot):
|
||||
"The heat death of the universe has come and gone. We exist in a post-time void. Nothing remains but this message."
|
||||
)
|
||||
else:
|
||||
print("Debug: Channel not found. Check the OFFTOPIC_CHANNEL variable.")
|
||||
logger.debug(
|
||||
"Debug: Channel not found. Check the OFFTOPIC_CHANNEL variable."
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"An error occurred in heat_death task: {e}")
|
||||
logger.error("An error occurred in heat_death task: %s", e)
|
||||
|
||||
@tasks.loop(hours=5)
|
||||
async def shizo_message():
|
||||
@@ -191,7 +198,7 @@ async def setup(bot):
|
||||
message = random.choice(schizo_messages)
|
||||
await channel.send(message)
|
||||
else:
|
||||
print("Debug: Channel not found or schizo_messages is empty.")
|
||||
logger.debug("Debug: Channel not found or schizo_messages is empty.")
|
||||
|
||||
@tasks.loop(hours=24)
|
||||
async def share_dementia_image():
|
||||
@@ -200,7 +207,9 @@ async def setup(bot):
|
||||
for _ in range(3):
|
||||
await channel.send(DEMENTIA_URL)
|
||||
else:
|
||||
print("Debug: Channel not found. Check the OFFTOPIC_CHANNEL variable.")
|
||||
logger.debug(
|
||||
"Debug: Channel not found. Check the OFFTOPIC_CHANNEL variable."
|
||||
)
|
||||
|
||||
await migrate_all_users(bot)
|
||||
|
||||
@@ -212,4 +221,4 @@ async def setup(bot):
|
||||
await bot.add_cog(SteamSaleChecker(bot))
|
||||
await bot.add_cog(DiscourseUpdater(bot))
|
||||
|
||||
print("Tasks extension loaded!")
|
||||
logger.info("Tasks extension loaded!")
|
||||
|
||||
18
bot/utils.py
18
bot/utils.py
@@ -5,6 +5,8 @@ from datetime import datetime, timedelta, timezone
|
||||
import discord
|
||||
import requests
|
||||
|
||||
from bot.log import logger
|
||||
|
||||
|
||||
def aware_utcnow():
|
||||
return datetime.now(timezone.utc)
|
||||
@@ -73,24 +75,24 @@ async def timeout_member(
|
||||
reason: str = "Requested by the bot",
|
||||
):
|
||||
if not member:
|
||||
print("Debug: Member is None. Skipping timeout.")
|
||||
logger.error("Member is None. Skipping timeout.")
|
||||
return
|
||||
|
||||
try:
|
||||
# Debug: Print the member object and timeout duration
|
||||
print(f"Debug: Attempting to timeout member {member} (ID: {member.id}).")
|
||||
print(f"Debug: Timeout duration set to {duration}.")
|
||||
print(f"Debug: Reason: {reason}")
|
||||
logger.debug(f"Debug: Attempting to timeout member {member} (ID: {member.id}).")
|
||||
logger.debug(f"Debug: Timeout duration set to {duration}.")
|
||||
logger.debug(f"Debug: Reason: {reason}")
|
||||
|
||||
await member.timeout(duration, reason=reason)
|
||||
print(f"Debug: Successfully timed out {member}.")
|
||||
logger.info(f"Successfully timed out {member}.")
|
||||
|
||||
except discord.Forbidden:
|
||||
print(f"Debug: Bot lacks permissions to timeout member {member}.")
|
||||
logger.error(f"Bot lacks permissions to timeout member {member}.")
|
||||
except discord.HTTPException as e:
|
||||
print(f"Debug: HTTPException occurred: {e}")
|
||||
logger.error("HTTPException occurred: %s", e)
|
||||
except Exception as e:
|
||||
print(f"Debug: Unexpected error occurred: {e}")
|
||||
logger.error("Unexpected error occurred: %s", e)
|
||||
|
||||
|
||||
# Check if a username is valid
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import os
|
||||
import sqlite3
|
||||
|
||||
from bot.log import logger
|
||||
from bot.utils import aware_utcnow
|
||||
|
||||
DB_DIR = os.getenv("BOT_DATA_DIR", "/bot-data")
|
||||
@@ -11,7 +12,7 @@ os.makedirs(DB_DIR, exist_ok=True)
|
||||
|
||||
def initialize_db():
|
||||
"""Creates the database tables if they don't exist."""
|
||||
print(f"Opening database: {DB_PATH}")
|
||||
logger.info("Opening database: %s", DB_PATH)
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cursor = conn.cursor()
|
||||
|
||||
@@ -21,7 +22,7 @@ def initialize_db():
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
print(f"Done loading database: {DB_PATH}")
|
||||
logger.info("Done loading database: %s", DB_PATH)
|
||||
|
||||
|
||||
def add_pattern(regex: str, response: str):
|
||||
|
||||
Reference in New Issue
Block a user