Skip to content

Commit 49f03a0

Browse files
authored
v10.14 (#1066)
2 parents 047f234 + 8b149a4 commit 49f03a0

File tree

7 files changed

+161
-14
lines changed

7 files changed

+161
-14
lines changed

commands.json

+1-1
Large diffs are not rendered by default.

package.json

+11-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bastion",
3-
"version": "10.13.0",
3+
"version": "10.14.0",
44
"description": "Get an enhanced Discord experience!",
55
"type": "module",
66
"homepage": "https://bastion.traction.one",
@@ -22,12 +22,12 @@
2222
"@types/express": "^4.17.21",
2323
"@types/gamedig": "^4.0.5",
2424
"@types/http-errors": "^2.0.4",
25-
"@types/jsdom": "^21.1.5",
26-
"@types/node": "^20.9.2",
27-
"@typescript-eslint/eslint-plugin": "^6.11.0",
28-
"@typescript-eslint/parser": "^6.11.0",
29-
"eslint": "^8.54.0",
30-
"typescript": "^5.2.2"
25+
"@types/jsdom": "^21.1.6",
26+
"@types/node": "^20.10.2",
27+
"@typescript-eslint/eslint-plugin": "^6.13.1",
28+
"@typescript-eslint/parser": "^6.13.1",
29+
"eslint": "^8.55.0",
30+
"typescript": "^5.3.2"
3131
},
3232
"dependencies": {
3333
"@bastion/tesseract": "^5.1.0",
@@ -36,13 +36,14 @@
3636
"discord-rpc": "^4.0.1",
3737
"dotenv": "^16.3.1",
3838
"emoji-regex": "^10.3.0",
39-
"gamedig": "^4.1.0",
40-
"jsdom": "^22.1.0",
39+
"gamedig": "^4.2.0",
40+
"jsdom": "^23.0.1",
4141
"libsodium-wrappers": "^0.7.13",
4242
"mathjs": "^12.1.0",
43+
"openai": "^4.20.1",
4344
"play-dl": "^1.9.7",
4445
"r6api.js": "^4.4.1",
45-
"undici": "^5.27.2",
46+
"undici": "^5.28.2",
4647
"ytdl-core": "^4.11.5",
4748
"ytpl": "^2.3.0"
4849
},

settings.example.yaml

+10
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,16 @@ auth: ""
7979
coinMarketCapApiKey: ""
8080
# Required for `apod` command.
8181
nasaApiKey: "DEMO_KEY"
82+
# Required for `chat` command to use the OpenAI's ChatGPT APIs.
83+
# API pricing depends on these values.
84+
# For more details, check https://openai.com/pricing
85+
openai:
86+
apiKey: ""
87+
# If you want to use GPT-4, set `model` to `gpt-4`.
88+
model: "gpt-3.5-turbo"
89+
# Change the `maxTokens` value to set the length of ChatGPT's responses.
90+
# https://platform.openai.com/tokenizer
91+
maxTokens: 100
8292
# Required for `weather` command.
8393
openWeatherMapApiKey: ""
8494
# Required for `movie` and `tv` commands.

src/commands/chat.ts

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*!
2+
* @author TRACTION (iamtraction)
3+
* @copyright 2023
4+
*/
5+
import { ApplicationCommandOptionType, ChatInputCommandInteraction } from "discord.js";
6+
import { Client, Command } from "@bastion/tesseract";
7+
import OpenAI from "openai";
8+
9+
import Settings from "../utils/settings.js";
10+
11+
class ChatCommand extends Command {
12+
constructor() {
13+
super({
14+
name: "chat",
15+
description: "Ask questions or chat with ChatGPT from OpenAI.",
16+
owner: true,
17+
options: [
18+
{
19+
type: ApplicationCommandOptionType.String,
20+
name: "message",
21+
description: "Your message.",
22+
required: true,
23+
},
24+
],
25+
});
26+
}
27+
28+
public async exec(interaction: ChatInputCommandInteraction<"cached">): Promise<void> {
29+
await interaction.deferReply();
30+
31+
const message = interaction.options.getString("message");
32+
33+
const openai = new OpenAI({
34+
apiKey: ((interaction.client as Client).settings as Settings).get("openai").apiKey,
35+
});
36+
37+
const response = await openai.chat.completions.create({
38+
model: ((interaction.client as Client).settings as Settings).get("openai").model || "gpt-3.5-turbo",
39+
messages: [
40+
{
41+
role: "user",
42+
content: message,
43+
},
44+
],
45+
max_tokens: ((interaction.client as Client).settings as Settings).get("openai").maxTokens || 100,
46+
user: interaction.member.id,
47+
});
48+
49+
await interaction.editReply({
50+
content: response.choices[0].message.content,
51+
});
52+
}
53+
}
54+
55+
export { ChatCommand as Command };

src/commands/image/generate.ts

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*!
2+
* @author TRACTION (iamtraction)
3+
* @copyright 2023
4+
*/
5+
import { ApplicationCommandOptionType, ChatInputCommandInteraction } from "discord.js";
6+
import { Client, Command } from "@bastion/tesseract";
7+
import OpenAI from "openai";
8+
9+
import Settings from "../../utils/settings.js";
10+
11+
class ImageGenerateCommand extends Command {
12+
constructor() {
13+
super({
14+
name: "generate",
15+
description: "Generate an image with DALL-E from OpenAI.",
16+
owner: true,
17+
options: [
18+
{
19+
type: ApplicationCommandOptionType.String,
20+
name: "prompt",
21+
description: "A description of the desired image.",
22+
required: true,
23+
},
24+
{
25+
type: ApplicationCommandOptionType.String,
26+
name: "size",
27+
description: "The size of the generated image.",
28+
choices: [
29+
{
30+
name: "Square",
31+
value: "1024x1024",
32+
},
33+
{
34+
name: "Portrait",
35+
value: "1024x1792",
36+
},
37+
{
38+
name: "Landscape",
39+
value: "1792x1024",
40+
},
41+
],
42+
},
43+
],
44+
});
45+
}
46+
47+
public async exec(interaction: ChatInputCommandInteraction<"cached">): Promise<void> {
48+
await interaction.deferReply();
49+
50+
const prompt = interaction.options.getString("prompt");
51+
const size = interaction.options.getString("size") as "1024x1024" | "1024x1792" | "1792x1024" || "1024x1024";
52+
53+
const openai = new OpenAI({
54+
apiKey: ((interaction.client as Client).settings as Settings).get("openai").apiKey,
55+
});
56+
57+
const response = await openai.images.generate({
58+
model: "dall-e-3",
59+
prompt: prompt,
60+
response_format: "url",
61+
size: size,
62+
user: interaction.member.id,
63+
});
64+
65+
await interaction.editReply({
66+
content: response.data[0].revised_prompt,
67+
files: [{
68+
attachment: response.data[0].url,
69+
}],
70+
});
71+
}
72+
}
73+
74+
export { ImageGenerateCommand as Command };

src/schedulers/liveStreams.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import GuildModel from "../models/Guild.js";
99
import memcache from "../utils/memcache.js";
1010
import * as requests from "../utils/requests.js";
1111
import { COLORS } from "../utils/constants.js";
12+
import { TWITCH_CHANNEL } from "../utils/regex.js";
1213
import Settings from "../utils/settings.js";
1314
import { TwitchStream } from "../types.js";
1415

@@ -40,15 +41,16 @@ class LiveStreamNotificationScheduler extends Scheduler {
4041

4142
for (const guild of guildDocuments) {
4243
// twitch streams
43-
if (guild.twitchNotificationChannel && this.client.guilds.cache.get(guild.id).channels.cache.has(guild.twitchNotificationChannel) && guild.twitchNotificationUsers?.length) {
44+
const twitchNotificationUsers = guild.twitchNotificationUsers.filter(u => TWITCH_CHANNEL.test(u));
45+
if (guild.twitchNotificationChannel && this.client.guilds.cache.get(guild.id).channels.cache.has(guild.twitchNotificationChannel) && twitchNotificationUsers?.length) {
4446
// get current live streams
45-
const { body, statusCode } = await requests.get("https://api.twitch.tv/helix/streams/?user_login=" + guild.twitchNotificationUsers.join("&user_login="), {
47+
const { body, statusCode } = await requests.get("https://api.twitch.tv/helix/streams/?user_login=" + twitchNotificationUsers.join("&user_login="), {
4648
"authorization": "Bearer " + (this.client.settings as Settings).get("twitch").accessToken,
4749
"client-id": (this.client.settings as Settings).get("twitch").clientId,
4850
});
4951

5052
if (statusCode >= 400) {
51-
Logger.error(await body.json());
53+
return Logger.error(await body.json());
5254
}
5355

5456
const streams: TwitchStream[] = (await body.json())?.["data"] || [];

src/types.ts

+5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ export namespace bastion {
1212
auth?: string;
1313
coinMarketCapApiKey?: string;
1414
nasaApiKey?: string;
15+
openai?: {
16+
apiKey?: string;
17+
model?: string;
18+
maxTokens?: number;
19+
};
1520
openWeatherMapApiKey?: string;
1621
tmdbApiKey?: string;
1722
trackerNetworkApiKey?: string;

0 commit comments

Comments
 (0)