joel bot
This commit is contained in:
14
src/core/client.ts
Normal file
14
src/core/client.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Extended Discord client with bot-specific functionality
|
||||
*/
|
||||
|
||||
import { Client, Collection, type ClientOptions } from "discord.js";
|
||||
import type { Command } from "../commands/types";
|
||||
|
||||
export class BotClient extends Client {
|
||||
public commands: Collection<string, Command> = new Collection();
|
||||
|
||||
constructor(options: ClientOptions) {
|
||||
super(options);
|
||||
}
|
||||
}
|
||||
59
src/core/config.ts
Normal file
59
src/core/config.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Application configuration
|
||||
* Centralizes all environment variables and configuration settings
|
||||
*/
|
||||
|
||||
interface BotConfig {
|
||||
discord: {
|
||||
token: string;
|
||||
};
|
||||
ai: {
|
||||
replicateApiToken: string;
|
||||
model: string;
|
||||
maxTokens: number;
|
||||
temperature: number;
|
||||
};
|
||||
bot: {
|
||||
/** Chance of Joel responding without being mentioned (0-1) */
|
||||
freeWillChance: number;
|
||||
/** Chance of using memories for responses (0-1) */
|
||||
memoryChance: number;
|
||||
/** Minimum time between random user mentions (ms) */
|
||||
mentionCooldown: number;
|
||||
/** Chance of mentioning a random user (0-1) */
|
||||
mentionProbability: number;
|
||||
};
|
||||
}
|
||||
|
||||
function getEnvOrThrow(key: string): string {
|
||||
const value = Bun.env[key];
|
||||
if (!value) {
|
||||
throw new Error(`Missing required environment variable: ${key}`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function getEnvOrDefault(key: string, defaultValue: string): string {
|
||||
return Bun.env[key] ?? defaultValue;
|
||||
}
|
||||
|
||||
export const config: BotConfig = {
|
||||
discord: {
|
||||
token: getEnvOrThrow("DISCORD_TOKEN"),
|
||||
},
|
||||
ai: {
|
||||
replicateApiToken: getEnvOrThrow("REPLICATE_API_TOKEN"),
|
||||
model: getEnvOrDefault(
|
||||
"AI_MODEL",
|
||||
"lucataco/dolphin-2.9-llama3-8b:ee173688d3b8d9e05a5b910f10fb9bab1e9348963ab224579bb90d9fce3fb00b"
|
||||
),
|
||||
maxTokens: parseInt(getEnvOrDefault("AI_MAX_TOKENS", "500")),
|
||||
temperature: parseFloat(getEnvOrDefault("AI_TEMPERATURE", "1.2")),
|
||||
},
|
||||
bot: {
|
||||
freeWillChance: 0.02,
|
||||
memoryChance: 0.3,
|
||||
mentionCooldown: 24 * 60 * 60 * 1000, // 24 hours
|
||||
mentionProbability: 0.001,
|
||||
},
|
||||
};
|
||||
7
src/core/index.ts
Normal file
7
src/core/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Core module exports
|
||||
*/
|
||||
|
||||
export { BotClient } from "./client";
|
||||
export { config } from "./config";
|
||||
export { createLogger } from "./logger";
|
||||
136
src/core/logger.ts
Normal file
136
src/core/logger.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* Simple logger with context support and colored output
|
||||
*/
|
||||
|
||||
type LogLevel = "debug" | "info" | "warn" | "error";
|
||||
|
||||
// Log level priority (higher = more severe)
|
||||
const levelPriority: Record<LogLevel, number> = {
|
||||
debug: 0,
|
||||
info: 1,
|
||||
warn: 2,
|
||||
error: 3,
|
||||
};
|
||||
|
||||
// Get minimum log level from environment
|
||||
function getMinLogLevel(): LogLevel {
|
||||
const envLevel = (process.env.LOG_LEVEL ?? "debug").toLowerCase();
|
||||
if (envLevel in levelPriority) {
|
||||
return envLevel as LogLevel;
|
||||
}
|
||||
return "debug";
|
||||
}
|
||||
|
||||
const minLogLevel = getMinLogLevel();
|
||||
|
||||
// ANSI color codes
|
||||
const colors = {
|
||||
reset: "\x1b[0m",
|
||||
dim: "\x1b[2m",
|
||||
bold: "\x1b[1m",
|
||||
|
||||
// Foreground colors
|
||||
gray: "\x1b[90m",
|
||||
white: "\x1b[37m",
|
||||
cyan: "\x1b[36m",
|
||||
green: "\x1b[32m",
|
||||
yellow: "\x1b[33m",
|
||||
red: "\x1b[31m",
|
||||
magenta: "\x1b[35m",
|
||||
} as const;
|
||||
|
||||
const levelColors: Record<LogLevel, string> = {
|
||||
debug: colors.gray,
|
||||
info: colors.green,
|
||||
warn: colors.yellow,
|
||||
error: colors.red,
|
||||
};
|
||||
|
||||
const levelLabels: Record<LogLevel, string> = {
|
||||
debug: "DEBUG",
|
||||
info: "INFO ",
|
||||
warn: "WARN ",
|
||||
error: "ERROR",
|
||||
};
|
||||
|
||||
/**
|
||||
* Format a date as "YYYY-MM-DD HH:mm:ss"
|
||||
*/
|
||||
function formatDate(date: Date): string {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(date.getDate()).padStart(2, "0");
|
||||
const hours = String(date.getHours()).padStart(2, "0");
|
||||
const minutes = String(date.getMinutes()).padStart(2, "0");
|
||||
const seconds = String(date.getSeconds()).padStart(2, "0");
|
||||
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
class Logger {
|
||||
private context: string;
|
||||
|
||||
constructor(context: string) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
private log(level: LogLevel, message: string, data?: unknown): void {
|
||||
// Skip if below minimum log level
|
||||
if (levelPriority[level] < levelPriority[minLogLevel]) {
|
||||
return;
|
||||
}
|
||||
|
||||
const timestamp = formatDate(new Date());
|
||||
const levelColor = levelColors[level];
|
||||
const label = levelLabels[level];
|
||||
|
||||
// Build colored output
|
||||
const parts = [
|
||||
`${colors.dim}${timestamp}${colors.reset}`,
|
||||
`${levelColor}${label}${colors.reset}`,
|
||||
`${colors.cyan}[${this.context}]${colors.reset}`,
|
||||
message,
|
||||
];
|
||||
|
||||
const output = parts.join(" ");
|
||||
|
||||
switch (level) {
|
||||
case "debug":
|
||||
console.debug(output, data !== undefined ? data : "");
|
||||
break;
|
||||
case "info":
|
||||
console.log(output, data !== undefined ? data : "");
|
||||
break;
|
||||
case "warn":
|
||||
console.warn(output, data !== undefined ? data : "");
|
||||
break;
|
||||
case "error":
|
||||
console.error(output, data !== undefined ? data : "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
debug(message: string, data?: unknown): void {
|
||||
this.log("debug", message, data);
|
||||
}
|
||||
|
||||
info(message: string, data?: unknown): void {
|
||||
this.log("info", message, data);
|
||||
}
|
||||
|
||||
warn(message: string, data?: unknown): void {
|
||||
this.log("warn", message, data);
|
||||
}
|
||||
|
||||
error(message: string, data?: unknown): void {
|
||||
this.log("error", message, data);
|
||||
}
|
||||
|
||||
child(context: string): Logger {
|
||||
return new Logger(`${this.context}:${context}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function createLogger(context: string): Logger {
|
||||
return new Logger(context);
|
||||
}
|
||||
Reference in New Issue
Block a user