Skip to content

Commit c7205c9

Browse files
authored
feat: Add DALL-E reverse proxy settings and handle errors in image generation (danny-avila#1173)
* feat: Add DALL-E reverse proxy settings and handle errors in image generation * fix(ci): avoid importing extra utilities
1 parent 25402fd commit c7205c9

File tree

4 files changed

+66
-23
lines changed

4 files changed

+66
-23
lines changed

.env.example

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,13 @@ DEBUG_OPENAI=false # Set to true to enable debug mode for the OpenAI endpoint
123123
# OPENAI_SUMMARY_MODEL=gpt-3.5-turbo
124124

125125
# Reverse proxy settings for OpenAI:
126-
# https://github.com/waylaidwanderer/node-chatgpt-api#using-a-reverse-proxy
126+
# https://github.com/waylaidwanderer/node-chatgpt-api#using-a-reverse-proxy
127+
# The URL must match the "url/v1," pattern, the "openai" suffix is also allowed.
128+
# Examples:
129+
# - https://open.ai/v1
130+
# - https://open.ai/v1/ACCOUNT/GATEWAY/openai
131+
# - https://open.ai/v1/hi/openai
132+
127133
# OPENAI_REVERSE_PROXY=
128134

129135
# (Advanced) Sometimes when using Local LLM APIs, you may need to force the API
@@ -138,6 +144,20 @@ DEBUG_OPENAI=false # Set to true to enable debug mode for the OpenAI endpoint
138144
# https://github.com/spdustin/ChatGPT-AutoExpert/blob/main/_system-prompts/dall-e.md
139145
# DALLE3_SYSTEM_PROMPT="Your System Prompt here"
140146

147+
# (Advanced) DALL-E Proxy settings
148+
# This is separate from its OpenAI counterpart for customization purposes
149+
150+
# Reverse proxy settings, changes the baseURL for the DALL-E-3 API Calls
151+
# The URL must match the "url/v1," pattern, the "openai" suffix is also allowed.
152+
# Examples:
153+
# - https://open.ai/v1
154+
# - https://open.ai/v1/ACCOUNT/GATEWAY/openai
155+
# - https://open.ai/v1/hi/openai
156+
157+
# DALLE_REVERSE_PROXY=
158+
159+
# Note: if you have PROXY set, it will be used for DALLE calls also, which is universal for the app
160+
141161
##########################
142162
# OpenRouter (overrides OpenAI and Plugins Endpoints):
143163
##########################

api/app/clients/tools/DALL-E.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,30 @@
11
// From https://platform.openai.com/docs/api-reference/images/create
22
// To use this tool, you must pass in a configured OpenAIApi object.
33
const fs = require('fs');
4+
const path = require('path');
45
const OpenAI = require('openai');
56
// const { genAzureEndpoint } = require('../../../utils/genAzureEndpoints');
67
const { Tool } = require('langchain/tools');
8+
const { HttpsProxyAgent } = require('https-proxy-agent');
79
const saveImageFromUrl = require('./saveImageFromUrl');
8-
const path = require('path');
10+
const extractBaseURL = require('../../../utils/extractBaseURL');
11+
const { DALLE_REVERSE_PROXY, PROXY } = process.env;
912

1013
class OpenAICreateImage extends Tool {
1114
constructor(fields = {}) {
1215
super();
1316

1417
let apiKey = fields.DALLE_API_KEY || this.getApiKey();
18+
const config = { apiKey };
19+
if (DALLE_REVERSE_PROXY) {
20+
config.baseURL = extractBaseURL(DALLE_REVERSE_PROXY);
21+
}
22+
23+
if (PROXY) {
24+
config.httpAgent = new HttpsProxyAgent(PROXY);
25+
}
26+
1527
// let azureKey = fields.AZURE_API_KEY || process.env.AZURE_API_KEY;
16-
let config = { apiKey };
1728

1829
// if (azureKey) {
1930
// apiKey = azureKey;

api/app/clients/tools/structured/DALLE3.js

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,24 @@ const path = require('path');
55
const { z } = require('zod');
66
const OpenAI = require('openai');
77
const { Tool } = require('langchain/tools');
8+
const { HttpsProxyAgent } = require('https-proxy-agent');
89
const saveImageFromUrl = require('../saveImageFromUrl');
9-
const { DALLE3_SYSTEM_PROMPT } = process.env;
10+
const extractBaseURL = require('../../../../utils/extractBaseURL');
11+
const { DALLE3_SYSTEM_PROMPT, DALLE_REVERSE_PROXY, PROXY } = process.env;
1012
class DALLE3 extends Tool {
1113
constructor(fields = {}) {
1214
super();
1315

1416
let apiKey = fields.DALLE_API_KEY || this.getApiKey();
15-
let config = { apiKey };
17+
const config = { apiKey };
18+
if (DALLE_REVERSE_PROXY) {
19+
config.baseURL = extractBaseURL(DALLE_REVERSE_PROXY);
20+
}
21+
22+
if (PROXY) {
23+
config.httpAgent = new HttpsProxyAgent(PROXY);
24+
}
25+
1626
this.openai = new OpenAI(config);
1727
this.name = 'dalle';
1828
this.description = `Use DALLE to create images from text descriptions.
@@ -84,19 +94,30 @@ class DALLE3 extends Tool {
8494
if (!prompt) {
8595
throw new Error('Missing required field: prompt');
8696
}
87-
const resp = await this.openai.images.generate({
88-
model: 'dall-e-3',
89-
quality,
90-
style,
91-
size,
92-
prompt: this.replaceUnwantedChars(prompt),
93-
n: 1,
94-
});
97+
98+
let resp;
99+
try {
100+
resp = await this.openai.images.generate({
101+
model: 'dall-e-3',
102+
quality,
103+
style,
104+
size,
105+
prompt: this.replaceUnwantedChars(prompt),
106+
n: 1,
107+
});
108+
} catch (error) {
109+
return `Something went wrong when trying to generate the image. The DALL-E API may unavailable:
110+
Error Message: ${error.message}`;
111+
}
112+
113+
if (!resp) {
114+
return 'Something went wrong when trying to generate the image. The DALL-E API may unavailable';
115+
}
95116

96117
const theImageUrl = resp.data[0].url;
97118

98119
if (!theImageUrl) {
99-
throw new Error('No image URL returned from OpenAI API.');
120+
return 'No image URL returned from OpenAI API. There may be a problem with the API or your configuration.';
100121
}
101122

102123
const regex = /img-[\w\d]+.png/;

api/app/clients/tools/structured/specs/DALLE3.spec.js

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,6 @@ describe('DALLE3', () => {
134134
await expect(dalle._call(mockData)).rejects.toThrow('Missing required field: prompt');
135135
});
136136

137-
it('should throw an error if no image URL is returned from OpenAI API', async () => {
138-
const mockData = {
139-
prompt: 'A test prompt',
140-
};
141-
// Simulate a response with an object that has a `url` property set to `undefined`
142-
generate.mockResolvedValue({ data: [{ url: undefined }] });
143-
await expect(dalle._call(mockData)).rejects.toThrow('No image URL returned from OpenAI API.');
144-
});
145-
146137
it('should log to console if no image name is found in the URL', async () => {
147138
const mockData = {
148139
prompt: 'A test prompt',

0 commit comments

Comments
 (0)