Skip to content

Commit 82b8c38

Browse files
committed
rework using response api
1 parent c999a62 commit 82b8c38

27 files changed

Lines changed: 524 additions & 896 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,4 @@ speech-*.mp3
108108
.env
109109
config.js
110110
package-lock.json
111+
bun.lock

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# DecryptGPT
1+
# EdgarGPT
22

3-
DecryptGPT is an advanced Discord bot developed by Decrypt, utilizing the `discord.js` library along with OpenAI's latest models including GPT-4o, GPT-4.1, and o3. The bot features image generation and editing capabilities using GPT-Image-1, voice message transcription with Whisper, and comprehensive document processing. Designed specifically for medical students and professionals, Edgar provides academic assistance and AI-powered conversations in French, making it ideal for advanced medical revisions and study sessions.
3+
EdgarGPT is an advanced Discord bot developed by Decrypt, utilizing the `discord.js` library along with OpenAI's latest models including GPT-4o, GPT-4.1, and o3. The bot features image generation and editing capabilities using GPT-Image-1, voice message transcription with Whisper, and comprehensive document processing. Designed specifically for medical students and professionals, Edgar provides academic assistance and AI-powered conversations in French, making it ideal for advanced medical revisions and study sessions.
44

55
## Features
66

@@ -22,7 +22,7 @@ DecryptGPT is an advanced Discord bot developed by Decrypt, utilizing the `disco
2222

2323
## Slash Commands
2424

25-
DecryptGPT supports the following slash commands:
25+
EdgarGPT supports the following slash commands:
2626

2727
- `/gpt-model` — Switch between AI models (GPT-4o, GPT-4.1, o3)
2828
- `/gpt-mode` — Toggle between text and voice interaction modes
@@ -33,7 +33,7 @@ All commands include comprehensive logging for monitoring and debugging purposes
3333

3434
## Configuration
3535

36-
Before running DecryptGPT, configure the following:
36+
Before running EdgarGPT, configure the following:
3737

3838
### Environment Variables
3939

@@ -64,13 +64,13 @@ Replace the placeholder values with your actual OpenAI API key and Discord bot c
6464
1. Clone the repository:
6565

6666
```bash
67-
git clone https://github.com/Decryptu/DecryptGPT.git
67+
git clone https://github.com/Decryptu/EdgarGPT.git
6868
```
6969

7070
2. Navigate to the project directory:
7171

7272
```bash
73-
cd DecryptGPT
73+
cd EdgarGPT
7474
```
7575

7676
3. Install dependencies:
@@ -127,7 +127,7 @@ The bot is built with modern JavaScript (ES modules) and includes:
127127

128128
## Contributing
129129

130-
Contributions to DecryptGPT are welcome! Feel free to submit pull requests, create issues, or suggest new features.
130+
Contributions to EdgarGPT are welcome! Feel free to submit pull requests, create issues, or suggest new features.
131131

132132
## License
133133

channels.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// channels.mjs
12
const allowedChannels = [
23
"1088435060170051714", // decrypt
34
"1097824934153170984", // idkzp

commands/gpt-mode.js

Lines changed: 0 additions & 19 deletions
This file was deleted.

commands/gpt-model.js

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,25 @@
1+
// commands/gpt-model.js
12
import { GPT_MODELS, MODEL_SURNAMES } from "../config.js";
23
import setBotActivity from "../utils/setBotActivity.js";
34
import { MessageFlags } from "discord.js";
45

56
async function gptModel(interaction, client) {
6-
await interaction.deferReply({ flags: MessageFlags.Ephemeral });
7+
await interaction.deferReply({ flags: MessageFlags.Ephemeral });
78

8-
const selectedModel = interaction.options.getString("model");
9+
const selectedModel = interaction.options.getString("model");
10+
11+
if (!Object.values(GPT_MODELS).includes(selectedModel)) {
12+
return await interaction.editReply({ content: "Modèle invalide." });
13+
}
914

10-
if (!Object.values(GPT_MODELS).includes(selectedModel)) {
11-
await interaction.editReply({ content: "Invalid model selected." });
12-
return;
13-
}
15+
const previousModel = MODEL_SURNAMES[client.currentModel];
16+
client.currentModel = selectedModel;
17+
setBotActivity(client, client.currentModel);
1418

15-
console.log(
16-
`Switching global model to: ${selectedModel} (requested by ${interaction.user.username})`,
17-
);
18-
19-
client.currentModel = selectedModel;
20-
setBotActivity(client, client.currentMode, client.currentModel);
21-
22-
const surname = MODEL_SURNAMES[selectedModel];
23-
await interaction.editReply({ content: `Switched to model: ${surname}` });
19+
const newModel = MODEL_SURNAMES[selectedModel];
20+
console.log(`[MODEL SWITCH] ${interaction.user.username}: ${previousModel}${newModel}`);
21+
22+
await interaction.editReply({ content: `Modèle activé: ${newModel}` });
2423
}
2524

26-
export default gptModel;
25+
export default gptModel;

commands/image-edit.js

Lines changed: 30 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,63 @@
1+
// commands/image-edit.js
12
import { EmbedBuilder, AttachmentBuilder } from "discord.js";
2-
import axios from "axios";
33
import { toFile } from "openai";
44

55
async function imageEdit(interaction, client) {
6-
// Immediately defer the reply to avoid timeout issues
76
await interaction.deferReply();
87

98
try {
10-
// Log the interaction for debugging
11-
console.log("Image edit command received:", {
12-
user: interaction.user.tag,
13-
options: interaction.options.data
14-
});
15-
169
const description = interaction.options.getString("description");
1710
const imageAttachment = interaction.options.getAttachment("image");
1811

19-
// Validate inputs after deferring to ensure we can respond properly
20-
if (!description) {
21-
return await interaction.editReply({
22-
content: "Please provide an image description."
23-
});
12+
if (!imageAttachment?.contentType?.startsWith("image/")) {
13+
return await interaction.editReply("Veuillez fournir une image valide (PNG, JPEG, WebP).");
2414
}
2515

26-
if (!imageAttachment) {
27-
return await interaction.editReply({
28-
content: "Please provide a valid image attachment."
29-
});
30-
}
16+
console.log(`[IMAGE EDIT] ${interaction.user.username}: "${description}"`);
17+
console.log(`[IMAGE EDIT] Input image: ${imageAttachment.name} (${imageAttachment.size} bytes)`);
3118

32-
// Log the attachment details
33-
console.log("Attachment details:", {
34-
name: imageAttachment.name,
35-
contentType: imageAttachment.contentType,
36-
size: imageAttachment.size,
37-
url: imageAttachment.url
38-
});
39-
40-
if (!imageAttachment.contentType?.startsWith("image/")) {
41-
return await interaction.editReply({
42-
content: "The provided attachment is not an image. Please upload a PNG, JPEG, or WebP image."
43-
});
44-
}
45-
46-
// Download the image from Discord
47-
console.log("Downloading image from Discord...");
48-
const response = await axios.get(imageAttachment.url, { responseType: 'arraybuffer' });
49-
const imageBuffer = Buffer.from(response.data);
50-
console.log(`Image downloaded, size: ${imageBuffer.length} bytes`);
51-
52-
// Convert to proper format for OpenAI
53-
console.log("Converting image for OpenAI...");
54-
const imageFile = await toFile(imageBuffer, imageAttachment.name || "image.png", {
19+
const response = await fetch(imageAttachment.url);
20+
const buffer = await response.arrayBuffer();
21+
const imageFile = await toFile(buffer, imageAttachment.name, {
5522
type: imageAttachment.contentType
5623
});
57-
console.log("Image converted successfully");
5824

59-
// Call the edit endpoint
60-
console.log("Calling OpenAI edit API with prompt:", description);
6125
const result = await client.openai.images.edit({
6226
model: "gpt-image-1",
6327
image: imageFile,
6428
prompt: description,
29+
// Removed response_format - no longer supported
6530
});
6631

67-
console.log("OpenAI API response received:", result);
68-
69-
if (!result?.data?.[0]?.b64_json) {
70-
throw new Error("No image data returned from API");
32+
// Check if response has base64 data or URL
33+
let outputBuffer;
34+
if (result.data[0].b64_json) {
35+
// Base64 response
36+
outputBuffer = Buffer.from(result.data[0].b64_json, "base64");
37+
console.log(`[IMAGE EDIT] Received base64 edited image`);
38+
} else if (result.data[0].url) {
39+
// URL response - download the image
40+
console.log(`[IMAGE EDIT] Downloading from URL: ${result.data[0].url}`);
41+
const imageResponse = await fetch(result.data[0].url);
42+
const arrayBuffer = await imageResponse.arrayBuffer();
43+
outputBuffer = Buffer.from(arrayBuffer);
44+
} else {
45+
throw new Error("No image data in response");
7146
}
7247

73-
// Convert base64 to buffer for Discord attachment
74-
const outputBuffer = Buffer.from(result.data[0].b64_json, "base64");
75-
const attachment = new AttachmentBuilder(outputBuffer, { name: "edited-image.png" });
48+
const attachment = new AttachmentBuilder(outputBuffer, { name: "edited.png" });
7649

7750
const embed = new EmbedBuilder()
78-
.setTitle("Image edited successfully")
51+
.setTitle("Image modifiée")
7952
.setDescription(`Prompt: ${description}`)
80-
.setImage("attachment://edited-image.png")
53+
.setImage("attachment://edited.png")
8154
.setTimestamp();
8255

83-
await interaction.editReply({
84-
content: null,
85-
embeds: [embed],
86-
files: [attachment]
87-
});
88-
89-
console.log("Successfully sent edited image response");
56+
console.log(`[IMAGE EDIT] Success - Edited image sent to ${interaction.user.username}`);
57+
await interaction.editReply({ embeds: [embed], files: [attachment] });
9058
} catch (error) {
91-
console.error("Error in imageEdit function:", error);
92-
93-
// Check for specific API errors
94-
const errorMessage = error.response?.data?.error?.message || error.message || "Unknown error";
95-
console.error("Detailed error:", errorMessage);
96-
97-
// Always use editReply since we deferred at the beginning
98-
await interaction.editReply({
99-
content: `Failed to edit the image. Error: ${errorMessage}`,
100-
embeds: [],
101-
files: []
102-
});
59+
console.error("[IMAGE EDIT] Error:", error);
60+
await interaction.editReply("Échec de modification d'image. " + (error.message || ""));
10361
}
10462
}
10563

commands/image-gpt.js

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,59 @@
1+
// commands/image-gpt.js
12
import { EmbedBuilder, AttachmentBuilder, MessageFlags } from "discord.js";
3+
import { GPT_IMAGE_MODEL, GPT_IMAGE_SIZE, GPT_IMAGE_QUALITY } from "../config.js";
24

35
async function imageGpt(interaction, client) {
46
const description = interaction.options.getString("description");
7+
58
if (!description) {
6-
await interaction.reply({
7-
content: "Please provide an image description.",
9+
return await interaction.reply({
10+
content: "Veuillez fournir une description.",
811
flags: MessageFlags.Ephemeral
912
});
10-
return;
1113
}
1214

15+
await interaction.deferReply();
16+
console.log(`[IMAGE GENERATION] ${interaction.user.username}: "${description}"`);
17+
1318
try {
14-
// Acknowledge the interaction immediately to prevent timeouts
15-
await interaction.deferReply();
16-
17-
const imageBase64 = await client.createGptImage(description);
19+
const response = await client.openai.images.generate({
20+
model: GPT_IMAGE_MODEL,
21+
prompt: description,
22+
n: 1,
23+
size: GPT_IMAGE_SIZE,
24+
quality: GPT_IMAGE_QUALITY,
25+
// Removed response_format - no longer supported
26+
});
1827

19-
if (!imageBase64) {
20-
throw new Error("No image data returned");
28+
// Check if response has base64 data or URL
29+
let buffer;
30+
if (response.data[0].b64_json) {
31+
// Base64 response
32+
buffer = Buffer.from(response.data[0].b64_json, "base64");
33+
console.log(`[IMAGE GENERATION] Received base64 image`);
34+
} else if (response.data[0].url) {
35+
// URL response - download the image
36+
console.log(`[IMAGE GENERATION] Downloading from URL: ${response.data[0].url}`);
37+
const imageResponse = await fetch(response.data[0].url);
38+
const arrayBuffer = await imageResponse.arrayBuffer();
39+
buffer = Buffer.from(arrayBuffer);
40+
} else {
41+
throw new Error("No image data in response");
2142
}
2243

23-
// Convert base64 to buffer for Discord attachment
24-
const buffer = Buffer.from(imageBase64, "base64");
25-
const attachment = new AttachmentBuilder(buffer, { name: "generated-image.png" });
44+
const attachment = new AttachmentBuilder(buffer, { name: "image.png" });
2645

2746
const embed = new EmbedBuilder()
28-
.setTitle("Votre image")
29-
.setImage("attachment://generated-image.png");
47+
.setTitle("Image générée")
48+
.setDescription(`Prompt: ${description}`)
49+
.setImage("attachment://image.png")
50+
.setTimestamp();
3051

31-
await interaction.editReply({
32-
embeds: [embed],
33-
files: [attachment]
34-
});
52+
console.log(`[IMAGE GENERATION] Success - Image sent to ${interaction.user.username}`);
53+
await interaction.editReply({ embeds: [embed], files: [attachment] });
3554
} catch (error) {
36-
console.error("Error in imageGpt function:", error);
37-
38-
// Check if the interaction has already been replied to
39-
if (interaction.deferred || interaction.replied) {
40-
await interaction.editReply({
41-
content: "Échec de la génération d'une image. Veuillez réessayer ultérieurement.",
42-
files: []
43-
});
44-
} else {
45-
await interaction.reply({
46-
content: "Échec de la génération d'une image. Veuillez réessayer ultérieurement.",
47-
flags: MessageFlags.Ephemeral
48-
});
49-
}
55+
console.error("[IMAGE GENERATION] Error:", error);
56+
await interaction.editReply("Échec de génération d'image. " + (error.message || ""));
5057
}
5158
}
5259

0 commit comments

Comments
 (0)