Repository navigation
Expand file tree
/
Copy pathOpenAIImageClient.js
More file actions
99 lines (81 loc) · 2.68 KB
/
Copy pathOpenAIImageClient.js
File metadata and controls
99 lines (81 loc) · 2.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
const axios = require('axios');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
class OpenAIImageClient {
constructor(config) {
const engineConfig = config?.imagegen ?? {};
this.apiKey = engineConfig.apiKey || process.env.OPENAI_API_KEY;
this.baseURL = engineConfig.endpoint || 'https://api.openai.com/v1/images/generations';
this.model = engineConfig.model || null;
if (!this.apiKey) {
throw new Error('OpenAI image generation requires imagegen.apiKey or OPENAI_API_KEY.');
}
if (!this.model) {
throw new Error('OpenAI image generation requires imagegen.model.');
}
this.timeout = 60000;
}
generateRequestId() {
return crypto.randomUUID();
}
async generateImage({ prompt, negativePrompt = '', width = 1024, height = 1024 }) {
const requestId = this.generateRequestId();
const size = `${width}x${height}`;
const combinedPrompt = negativePrompt
? `${prompt}\nNegative prompt: ${negativePrompt}`
: prompt;
try {
const response = await axios.post(
this.baseURL,
{
model: this.model,
prompt: combinedPrompt,
size,
n: 1
},
{
timeout: this.timeout,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.apiKey}`
}
}
);
const data = response.data;
if (!data || !Array.isArray(data.data) || !data.data.length || !data.data[0]?.b64_json) {
throw new Error('OpenAI image response missing image data.');
}
const imageBuffer = Buffer.from(data.data[0].b64_json, 'base64');
return {
requestId,
imageBuffer,
mimeType: data.data[0]?.mime_type || 'image/png'
};
} catch (error) {
const message = error?.response?.data?.error?.message || error.message || String(error);
throw new Error(`OpenAI image request failed: ${message}`);
}
}
async saveImage(imageBuffer, imageId, originalFilename, saveDirectory) {
if (!imageBuffer || !Buffer.isBuffer(imageBuffer)) {
throw new Error('OpenAI image buffer missing.');
}
if (!imageId) {
throw new Error('OpenAI image save requires an imageId.');
}
const ext = path.extname(originalFilename || '') || '.png';
const filename = `${imageId}${ext}`;
const filepath = path.join(saveDirectory, filename);
if (!fs.existsSync(saveDirectory)) {
fs.mkdirSync(saveDirectory, { recursive: true });
}
fs.writeFileSync(filepath, imageBuffer);
return {
filename,
filepath,
size: imageBuffer.length
};
}
}
module.exports = OpenAIImageClient;