Somewhat working POC

This commit is contained in:
Marcin Czop 2024-11-19 10:04:13 +01:00
parent fda9e02ef4
commit 35b6c98539
No known key found for this signature in database
GPG key ID: 44BCC84471234D0D
29 changed files with 2752 additions and 0 deletions

88
.dockerignore Normal file
View file

@ -0,0 +1,88 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/

43
.github/workflows/docker-build.yaml vendored Normal file
View file

@ -0,0 +1,43 @@
name: Docker Image CI
on:
push:
branches: ["master"]
workflow_dispatch:
env:
REGISTRY: "ghcr.io"
IMAGE: "lets-go-gambling"
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ env.REGISTRY }}/mrtalon63/${{ env.IMAGE }}:latest
${{ env.REGISTRY }}/mrtalon63/${{ env.IMAGE }}:${{ github.RUN_ID }}

19
Dockerfile Normal file
View file

@ -0,0 +1,19 @@
FROM node:lts-alpine AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
WORKDIR /app
COPY . .
FROM base AS prod-deps
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile
FROM base AS build
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm run build
FROM base
COPY --from=prod-deps /app/node_modules /app/node_modules
COPY --from=build /app/build /app/build
COPY package.json .
CMD [ "pnpm", "start" ]

12
eslint.config.mjs Normal file
View file

@ -0,0 +1,12 @@
import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
/** @type {import('eslint').Linter.Config[]} */
export default [
{files: ["**/*.{js,mjs,cjs,ts}"]},
{languageOptions: { globals: globals.node }},
pluginJs.configs.recommended,
...tseslint.configs.recommended,
];

31
package.json Normal file
View file

@ -0,0 +1,31 @@
{
"name": "lets-go-gambling",
"version": "0.0.1",
"description": "",
"main": "index.js",
"scripts": {
"dev": "nodemon --ignore 'data/*.json' -r dotenv/config src/index.ts",
"build": "tsc",
"start": "node dist/index.js"
},
"keywords": [],
"author": "MrTalon63 <marcin@mczop.eu>",
"license": "MIT",
"dependencies": {
"discord.js": "^14.16.3",
"glob": "^11.0.0",
"korwinjs": "^1.0.0",
"pg": "^8.13.1"
},
"devDependencies": {
"@eslint/js": "^9.15.0",
"@types/node": "^22.9.0",
"@types/pg": "^8.11.10",
"dotenv": "^16.4.5",
"eslint": "^9.15.0",
"nodemon": "^3.1.7",
"ts-node": "^10.9.2",
"typescript": "^5.6.3",
"typescript-eslint": "^8.15.0"
}
}

1840
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load diff

62
src/client.ts Normal file
View file

@ -0,0 +1,62 @@
import { Client, Collection, GatewayIntentBits, User, Options } from "discord.js";
import { glob } from "glob";
import db from "./utils/db";
import { Command } from "./interfaces/commands";
import { Event } from "./interfaces/events";
// eslint-disable-next-line @typescript-eslint/no-require-imports
const pkg = require("../package.json");
class Bot extends Client {
public commands: Collection<string, Command> = new Collection();
public events: Collection<string, Event> = new Collection();
public readonly version = pkg.version;
public readonly prefix = process.env.PREFIX!;
public readonly owner = process.env.OWNER;
public log = console;
public db = db;
public constructor() {
super({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent, GatewayIntentBits.GuildMessagePolls, GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildEmojisAndStickers, GatewayIntentBits.GuildMessageReactions],
makeCache: Options.cacheWithLimits(),
});
}
public async start(): Promise<void> {
this.log.debug("Logging in with token...");
this.login(process.env.TOKEN);
this.log.debug("Loading commands and events...");
const commandFiles: string[] = await glob(`${__dirname}/commands/**/*{.ts,.js}`);
commandFiles.map(async (fileName: string) => {
const file: Command = await import(`../${fileName}`);
this.commands.set(file.name, file);
if (file.aliases) file.aliases.map((alias) => this.commands.set(alias, file));
});
const eventFiles: string[] = await glob(`${__dirname}/events/**/*{.ts,.js}`);
eventFiles.map(async (fileName: string) => {
const file: Event = await import(`../${fileName}`);
this.events.set(file.name, file);
this.on(file.event, file.run.bind(this, this));
});
this.log.debug("Initialization complete!");
}
public getUserFromMention(mention: string): User | undefined {
if (!mention) return;
if (mention.startsWith("<@") && mention.endsWith(">")) {
mention = mention.slice(2, -1);
if (mention.startsWith("!")) {
mention = mention.slice(1);
}
}
return this.users.cache.get(mention);
}
}
export default Bot;

View file

@ -0,0 +1,37 @@
import { EmbedBuilder } from "discord.js";
import { RunFunction } from "../../../interfaces/commands";
export const run: RunFunction = async (client, message, args) => {
if (message.author.id !== client.owner) return;
const user = client.getUserFromMention(args[0]);
const amount = parseInt(args[1]);
if (!user || isNaN(amount)) {
message.reply("Użycie `add <użytkownik | id> <kwota>`");
return;
}
const userData = await client.db("SELECT * FROM gamblebot.users WHERE udid = $1", [user.id]);
if (userData.rowCount === 0) {
message.reply("Nie znaleziono użytkownika");
return;
}
await client.db("UPDATE gamblebot.users SET balance = balance + $1 WHERE udid = $2", [amount, user.id]);
const embed = new EmbedBuilder()
.setColor("Blue")
.setTitle("Dodano pieniądze")
.setDescription(`Dodano ${amount}zł do konta użytkownika ${user.tag}`)
.setTimestamp(new Date())
.setFooter({
text: `Wygenerowane dla ${message.author.tag}`,
iconURL: message.author.displayAvatarURL(),
});
message.channel.send({ embeds: [embed] });
};
export const name = "add";
export const description = "Add money to user";

View file

@ -0,0 +1,37 @@
import { EmbedBuilder } from "discord.js";
import { RunFunction } from "../../../interfaces/commands";
export const run: RunFunction = async (client, message, args) => {
if (message.author.id !== client.owner) return;
const user = client.getUserFromMention(args[0]);
const amount = parseInt(args[1]);
if (!user || isNaN(amount)) {
message.reply("Użycie `remove <użytkownik | id> <kwota>`");
return;
}
const userData = await client.db("SELECT * FROM gamblebot.users WHERE udid = $1", [user.id]);
if (userData.rowCount === 0) {
message.reply("Nie znaleziono użytkownika");
return;
}
await client.db("UPDATE gamblebot.users SET balance = balance - $1 WHERE udid = $2", [amount, user.id]);
const embed = new EmbedBuilder()
.setColor("Blue")
.setTitle("Zabrano pieniądze")
.setDescription(`Zabrano ${amount}zł z konta użytkownika ${user.tag}`)
.setTimestamp(new Date())
.setFooter({
text: `Wygenerowane dla ${message.author.tag}`,
iconURL: message.author.displayAvatarURL(),
});
message.channel.send({ embeds: [embed] });
};
export const name = "remove";
export const description = "Removes money from user";

View file

@ -0,0 +1,56 @@
import { EmbedBuilder } from "discord.js";
import { RunFunction } from "../../interfaces/commands";
import { User } from "../../types";
export const run: RunFunction = async (client, message, args) => {
let userData: User;
let title = "Twoje saldo";
if (args[0] && client.getUserFromMention(args[0])) {
const user = await client.db("SELECT * FROM gamblebot.users WHERE udid = $1", [client.getUserFromMention(args[0])?.id]);
if (user.rowCount === 0) {
message.reply("Nie znaleziono użytkownika");
return;
}
userData = user.rows[0];
title = `Saldo użytkownika ${message.guild?.members.cache.get(user.rows[0].udid)?.user.tag}`;
} else {
const user = await client.db("SELECT * FROM gamblebot.users WHERE udid = $1", [message.author.id]);
if (user.rowCount === 0) {
message.reply("Nie znaleziono użytkownika");
return;
}
userData = user.rows[0];
}
const embed = new EmbedBuilder()
.setColor("Blue")
.setTitle(title)
.addFields([
{
name: "Gotówka:",
value: `${userData.balance}`,
inline: true,
},
{
name: `Stan konta:`,
value: `${userData.bank_balance}`,
inline: true,
},
{
name: `Łączna wartość:`,
value: `${parseInt(userData.balance) + parseInt(userData.bank_balance)}`,
inline: true,
},
])
.setTimestamp(new Date())
.setFooter({
text: `Wygenerowane dla ${message.author.tag}`,
iconURL: message.author.displayAvatarURL(),
});
message.channel.send({ embeds: [embed] });
};
export const name = "balance";
export const aliases = ["bal"];
export const description = "Returns the balance of the user";

View file

@ -0,0 +1,49 @@
import { EmbedBuilder } from "discord.js";
import { RunFunction } from "../../interfaces/commands";
import { User } from "../../types";
export const run: RunFunction = async (client, message, args) => {
if (!args[0]) {
message.channel.send("Podaj kwotę którą chcesz wpłacić!");
return;
}
const user = await client.db("SELECT * FROM gamblebot.users WHERE udid = $1", [message.author.id]);
if (user.rowCount === 0) {
message.reply("Nie znaleziono użytkownika");
return;
}
const userData: User = user.rows[0];
const depAll = args[0] === "all";
if (args[0] === "all") {
await client.db("UPDATE gamblebot.users SET bank_balance = balance + bank_balance, balance = 0 WHERE udid = $1", [message.author.id]);
} else {
const amount = parseInt(args[0]);
if (isNaN(amount)) {
message.reply("Niepoprawne argumenty");
return;
}
if (parseInt(userData.balance) < amount) {
message.reply("Nie masz tyle gotówki!");
return;
}
await client.db("UPDATE gamblebot.users SET balance = balance - $1, bank_balance = bank_balance + $1 WHERE udid = $2", [amount, message.author.id]);
}
const embed = new EmbedBuilder()
.setColor("Blue")
.setTitle("Wpłacono pieniądze")
.setDescription(`Wpłacono ${depAll ? `${userData.balance}` : `${args[0]}`} do banku`)
.setTimestamp(new Date())
.setFooter({
text: `Wygenerowane dla ${message.author.tag}`,
iconURL: message.author.displayAvatarURL(),
});
message.channel.send({ embeds: [embed] });
};
export const name = "deposit";
export const aliases = ["dep", "wplac"];
export const description = "Deposit money to bank";

View file

@ -0,0 +1,36 @@
import { EmbedBuilder } from "discord.js";
import { RunFunction } from "../../interfaces/commands";
export const run: RunFunction = async (client, message) => {
const balances = await client.db("SELECT udid, (COALESCE(balance,0) + COALESCE(bank_balance,0)) AS sums FROM gamblebot.users ORDER BY sums DESC", []);
if (balances.rowCount === 0) {
message.reply("Nie znaleziono użytkowników");
return;
}
const top10 = balances.rows.slice(0, 10) as { udid: string; sums: string }[];
await message.guild?.members.fetch();
const filtered = top10.filter((user) => parseInt(user.sums) > 0);
const fields = filtered.map((user, index) => ({
name: `${index + 1}. ${client.getUserFromMention(user.udid)?.tag || "Nieznany użytkownik"}`,
value: `Całkowite saldo: ${user.sums}`,
inline: false,
}));
const embed = new EmbedBuilder()
.setColor("Blue")
.setTitle(`Top 10 użytkowników serwera ${message.guild?.name}`)
.setFields(fields)
.setTimestamp(new Date())
.setFooter({
text: `Wygenerowane dla ${message.author.tag}`,
iconURL: message.author.displayAvatarURL(),
});
message.channel.send({ embeds: [embed] });
};
export const name = "leaderboard";
export const aliases = ["top"];
export const description = "Returns the balance of the user";

View file

@ -0,0 +1,45 @@
import { EmbedBuilder } from "discord.js";
import { RunFunction } from "../../interfaces/commands";
import { User } from "../../types";
export const run: RunFunction = async (client, message, args) => {
const payer = message.author;
const payee = client.getUserFromMention(args[0]);
const amount = parseInt(args[1]);
if (!payee || isNaN(amount)) {
message.reply("Użycie: `pay <użytkownik | id> <kwota>`");
return;
}
const payerQuery = await client.db("SELECT * FROM gamblebot.users WHERE udid = $1", [payer.id]);
if (payerQuery.rowCount === 0) {
message.reply("Nie znaleziono użytkownika");
return;
}
const payerData = payerQuery.rows[0] as User;
if (parseInt(payerData.bank_balance) < amount) {
message.reply("Nie masz tyle pieniędzy na koncie!");
return;
}
await client.db("UPDATE gamblebot.users SET bank_balance = bank_balance - $1 WHERE udid = $2", [amount, payer.id]);
await client.db("UPDATE gamblebot.users SET bank_balance = bank_balance + $1 WHERE udid = $2", [amount, payee.id]);
const embed = new EmbedBuilder()
.setColor("Blue")
.setTitle("Dodano pieniądze")
.setDescription(`Przelano ${amount}zł do ${payee.tag}`)
.setTimestamp(new Date())
.setFooter({
text: `Wygenerowane dla ${message.author.tag}`,
iconURL: message.author.displayAvatarURL(),
});
message.channel.send({ embeds: [embed] });
};
export const name = "pay";
export const aliases = ["give", "daj", "przelej"];
export const description = "Pay money to user";

View file

@ -0,0 +1,49 @@
import { EmbedBuilder } from "discord.js";
import { RunFunction } from "../../interfaces/commands";
import { User } from "../../types";
export const run: RunFunction = async (client, message, args) => {
if (!args[0]) {
message.channel.send("Podaj kwotę którą chcesz wypłacić!");
return;
}
const user = await client.db("SELECT * FROM gamblebot.users WHERE udid = $1", [message.author.id]);
if (user.rowCount === 0) {
message.reply("Nie znaleziono użytkownika");
return;
}
const userData: User = user.rows[0];
const depAll = args[0] === "all";
if (args[0] === "all") {
await client.db("UPDATE gamblebot.users SET balance = balance + bank_balance, bank_balance = 0 WHERE udid = $1", [message.author.id]);
} else {
const amount = parseInt(args[0]);
if (isNaN(amount)) {
message.reply("Niepoprawne argumenty");
return;
}
if (parseInt(userData.bank_balance) < amount) {
message.reply("Nie masz tyle na koncie!");
return;
}
await client.db("UPDATE gamblebot.users SET balance = balance + $1, bank_balance = bank_balance - $1 WHERE udid = $2", [amount, message.author.id]);
}
const embed = new EmbedBuilder()
.setColor("Blue")
.setTitle("Wypłacono pieniądze")
.setDescription(`Wypłacono ${depAll ? `${userData.balance}` : `${args[0]}`} z banku`)
.setTimestamp(new Date())
.setFooter({
text: `Wygenerowane dla ${message.author.tag}`,
iconURL: message.author.displayAvatarURL(),
});
message.channel.send({ embeds: [embed] });
};
export const name = "withdraw";
export const aliases = ["with", "wth", "wyplac"];
export const description = "Withdraw money from bank";

View file

@ -0,0 +1,39 @@
import { EmbedBuilder } from "discord.js";
import { RunFunction } from "../../interfaces/commands";
import { User } from "../../types";
const workTexts = [`Postanawiasz sprzedawać truskawki ukradzione sąsiadowi z działki. Zarabiasz {amount}zł.`, `Sprzedajesz zardzewiałe monety jako „antyki” na pchlim targu. Twoje konto powiększa się o {amount}zł.`, `Przemycasz cukierki do szkoły i sprzedajesz je pod stołem wpadło {amount}zł z zysku!`, `Tworzysz fałszywą stronę z prognozami giełdowymi, żeby sprzedawać 'pewne' wskazówki inwestycyjne. Zarobiłeś {amount}zł, zanim zbanowali ci konto.`, `Wyprodukowałeś własne napoje energetyczne (skład: sok i cukier) i sprzedajesz jako „100% naturalny doping”. Zarabiasz {amount}zł.`, `Pomagasz znajomym załatwić 'ekskluzywne' skiny do gier w zamian za małą prowizję. Po dwóch dniach jesteś bogatszy o {amount}zł.`, `Stworzyłeś biznes mycia okien sąsiadom za 5 zł od okna. Zarabiasz {amount}zł!`, `Otwierasz stoisko z 'oryginalnymi' podróbkami perfum pod szkołą. Sprzedajesz kilkanaście flakonów i wychodzisz na plus {amount}zł.`, `Zarabiasz na 'reklamach' na serwerze - każdy, kto chce wspomnieć o swojej działalności, płaci drobną opłatę. Twój bilans to {amount}zł`];
export const run: RunFunction = async (client, message) => {
const userData = await client.db("SELECT * FROM gamblebot.users WHERE udid = $1", [message.author.id]);
if (userData.rowCount === 0) {
message.reply("Nie znaleziono użytkownika");
return;
}
const user: User = userData.rows[0];
if (parseInt(user.last_work) + 1000 * 60 * 60 > Date.now()) {
message.reply(`Musisz odczekać ${new Date(parseInt(user.last_work) + 1000 * 60 * 60 - Date.now()).getMinutes()}m ${new Date(parseInt(user.last_work) + 1000 * 60 * 60 - Date.now()).getSeconds()}s zanim zaczniesz znowu pracować`);
return;
}
const revenue = Math.floor(Math.random() * 1000);
await client.db("UPDATE gamblebot.users SET balance = balance + $1, last_work = $2 WHERE udid = $3", [revenue, Date.now(), message.author.id]);
const embed = new EmbedBuilder()
.setColor("Blue")
.setTitle("Praca")
.setDescription(workTexts[Math.floor(Math.random() * workTexts.length)].replace("{amount}", revenue.toString()))
.setTimestamp(new Date())
.setFooter({
text: `Wygenerowane dla ${message.author.tag}`,
iconURL: message.author.displayAvatarURL(),
});
message.channel.send({ embeds: [embed] });
};
export const name = "work";
export const aliases = ["praca"];
export const description = "Work for money";

46
src/commands/info.ts Normal file
View file

@ -0,0 +1,46 @@
import { EmbedBuilder } from "discord.js";
import { RunFunction } from "../interfaces/commands";
export const run: RunFunction = async (client, message) => {
const embed = new EmbedBuilder()
.setColor("Blue")
.setTitle("Pong!")
.addFields([
{
name: "Discord API ping:",
value: `${Math.round(message.client.ws.ping)} ms`,
inline: true,
},
{
name: `Bot ping:`,
value: `${Math.round(Date.now() - message.createdTimestamp)} ms`,
inline: true,
},
{
name: `Aktualna wersja:`,
value: client.version,
inline: true,
},
{
name: `Prefix:`,
value: client.prefix,
inline: true,
},
{
name: `Ilość użytkowników:`,
value: message.guild?.memberCount.toString(),
inline: true,
},
])
.setTimestamp(new Date())
.setFooter({
text: `Wygenerowane dla ${message.author.tag}`,
iconURL: message.author.displayAvatarURL(),
});
message.channel.send({ embeds: [embed] });
};
export const name = "info";
export const aliases = ["p", "ping"];
export const description = "Ping!";

32
src/commands/other/cat.ts Normal file
View file

@ -0,0 +1,32 @@
import { EmbedBuilder } from "discord.js";
import { RunFunction } from "../../interfaces/commands";
export const run: RunFunction = async (client, message) => {
const req = await fetch("https://api.thecatapi.com/v1/images/search", {
headers: {
"x-api-key": process.env.CAT_API_KEY || "",
"content-type": "application/json",
},
});
if (!req.ok) {
message.reply("Wystąpił błąd podczas pobierania obrazka kota");
return;
}
const data = await req.json();
const embed = new EmbedBuilder()
.setColor("Blue")
.setTitle("Kot")
.setImage(data[0].url)
.setTimestamp(new Date())
.setFooter({
text: `Wygenerowane dla ${message.author.tag}`,
iconURL: message.author.displayAvatarURL(),
});
message.channel.send({ embeds: [embed] });
};
export const name = "cat";
export const aliases = ["kot"];
export const description = "Generate random cat image";

32
src/commands/other/dog.ts Normal file
View file

@ -0,0 +1,32 @@
import { EmbedBuilder } from "discord.js";
import { RunFunction } from "../../interfaces/commands";
export const run: RunFunction = async (client, message) => {
const req = await fetch("https://api.thedogapi.com/v1/images/search", {
headers: {
"x-api-key": process.env.DOG_API_KEY || "",
"content-type": "application/json",
},
});
if (!req.ok) {
message.reply("Wystąpił błąd podczas pobierania obrazka psa");
return;
}
const data = await req.json();
const embed = new EmbedBuilder()
.setColor("Blue")
.setTitle("Pies")
.setImage(data[0].url)
.setTimestamp(new Date())
.setFooter({
text: `Wygenerowane dla ${message.author.tag}`,
iconURL: message.author.displayAvatarURL(),
});
message.channel.send({ embeds: [embed] });
};
export const name = "dog";
export const aliases = ["pies"];
export const description = "Generate random dog image";

View file

@ -0,0 +1,10 @@
import korwin from "korwinjs";
import { RunFunction } from "../../interfaces/commands";
export const run: RunFunction = async (client, message) => {
message.reply(await korwin());
};
export const name = "korwin";
export const description = "Korwin wypowiedź";

42
src/commands/other/llm.ts Normal file
View file

@ -0,0 +1,42 @@
import { EmbedBuilder } from "discord.js";
import { RunFunction } from "../../interfaces/commands";
export const run: RunFunction = async (client, message, args) => {
const prompt = args.join(" ");
if (!prompt) {
message.channel.send("Podaj tekst do przetworzenia.");
return;
}
let req;
try {
req = await fetch(`https://text.pollinations.ai/${prompt}`);
} catch {
message.reply("Wystąpił błąd podczas generowania odpowiedzi");
return;
}
if (!req.ok) {
message.reply("Wystąpił błąd podczas generowania odpowiedzi");
return;
}
const res = await req.text();
const embed = new EmbedBuilder()
.setColor("Blue")
.setTitle("LLM")
.setDescription(res)
.setTimestamp(new Date())
.setFooter({
text: `Wygenerowane dla ${message.author.tag}`,
iconURL: message.author.displayAvatarURL(),
});
message.channel.send({ embeds: [embed] });
};
export const name = "llm";
export const aliases = ["largelanguagemodel"];
export const description = "Send request to LLM";

43
src/commands/other/tti.ts Normal file
View file

@ -0,0 +1,43 @@
import { EmbedBuilder, AttachmentBuilder } from "discord.js";
import { RunFunction } from "../../interfaces/commands";
export const run: RunFunction = async (client, message, args) => {
const prompt = args.join(" ");
if (!prompt) {
message.channel.send("Podaj tekst do przetworzenia.");
return;
}
let req;
try {
req = await fetch(`https://image.pollinations.ai/prompt/${prompt}`);
} catch {
message.reply("Wystąpił błąd podczas generowania obrazka");
return;
}
if (!req.ok) {
message.reply("Wystąpił błąd podczas generowania obrazka");
return;
}
const image = Buffer.from(await req.arrayBuffer());
const atta = new AttachmentBuilder(image, { name: "tti.png" });
const embed = new EmbedBuilder()
.setColor("Blue")
.setTitle("Text to image")
.setImage(`attachment://tti.png`)
.setTimestamp(new Date())
.setFooter({
text: `Wygenerowane dla ${message.author.tag}`,
iconURL: message.author.displayAvatarURL(),
});
message.channel.send({ embeds: [embed], files: [atta] });
};
export const name = "tti";
export const aliases = ["texttoimage", "text-to-image"];
export const description = "Text to images";

View file

@ -0,0 +1,10 @@
import { Events } from "discord.js";
import { RunFunction } from "../../interfaces/events";
export const run: RunFunction = async (client) => {
client.log.info(`${client.user?.tag} is ready!`);
};
export const name = "Client ready";
export const event = Events.ClientReady;

View file

@ -0,0 +1,17 @@
import { OmitPartialGroupDMChannel, Message, Events } from "discord.js";
import { RunFunction } from "../../interfaces/events";
export const run: RunFunction = async (client, message: OmitPartialGroupDMChannel<Message>) => {
if (message.author.bot) return;
if (!message.content.startsWith(client.prefix)) return;
if (!message.guild) return;
const args = message.content.slice(client.prefix.length).trim().split(/ +/g);
const command = args.shift()?.toLowerCase() || "";
const cmd = client.commands.get(command);
if (!cmd) return;
cmd.run(client, message, args);
};
export const name = "Command Handler";
export const event = Events.MessageCreate;

8
src/index.ts Normal file
View file

@ -0,0 +1,8 @@
import Bot from "./client";
console.info("Starting bot...");
const client = new Bot();
client.start().catch((error) => {
console.error(error);
process.exit(1);
});

View file

@ -0,0 +1,14 @@
import { Message, OmitPartialGroupDMChannel } from "discord.js";
import Bot from "../client";
export interface Command {
name: string;
aliases: string[];
description: string;
run: RunFunction;
}
export interface RunFunction {
(client: Bot, message: OmitPartialGroupDMChannel<Message>, args: string[]): Promise<void>;
}

12
src/interfaces/events.ts Normal file
View file

@ -0,0 +1,12 @@
import Bot from "../client";
export interface Event {
name: string;
event: string;
run: RunFunction;
}
export interface RunFunction {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(client: Bot, ...args: any[]): Promise<void>;
}

15
src/types.ts Normal file
View file

@ -0,0 +1,15 @@
type User = {
udid: string;
balance: string;
bank_balance: string;
last_work: string;
last_crime: string;
last_prostitution: string;
};
type items = {
name: string;
quantity: number;
};
export { User, items };

16
src/utils/db.ts Normal file
View file

@ -0,0 +1,16 @@
import { Pool } from "pg";
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async function query(text: string, params: any[]) {
const start = Date.now();
const res = await pool.query(text, params);
const duration = Date.now() - start;
console.log("executed query", { text, duration, rows: res.rowCount });
return res;
}
export default query;

12
tsconfig.json Normal file
View file

@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"rootDir": "./src",
"outDir": "./build",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}