myaidev-method 0.2.22 → 0.2.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/USER_GUIDE.md +453 -48
- package/bin/cli.js +18 -0
- package/content-rules.example.md +80 -0
- package/dist/mcp/mcp-launcher.js +237 -0
- package/dist/server/.tsbuildinfo +1 -1
- package/dist/server/auth/layers.d.ts +1 -1
- package/dist/server/auth/services/AuthService.d.ts +1 -1
- package/dist/server/auth/services/TokenService.js.map +1 -1
- package/dist/server/auth/services/example.d.ts +5 -5
- package/package.json +16 -16
- package/src/index.js +21 -8
- package/src/lib/update-manager.js +2 -1
- package/src/lib/visual-config-utils.js +321 -295
- package/src/lib/visual-generation-utils.js +1000 -811
- package/src/scripts/configure-wordpress-mcp.js +8 -3
- package/src/scripts/generate-visual-cli.js +365 -235
- package/src/scripts/ping.js +250 -0
- package/src/scripts/wordpress/publish-to-wordpress.js +165 -0
- package/src/server/auth/services/TokenService.ts +1 -1
- package/src/templates/claude/agents/content-rules-setup.md +657 -0
- package/src/templates/claude/agents/content-writer.md +328 -1
- package/src/templates/claude/agents/visual-content-generator.md +182 -4
- package/src/templates/claude/commands/myai-configure.md +1 -1
- package/src/templates/claude/commands/myai-content-rules-setup.md +204 -0
- package/src/templates/codex/commands/myai-content-rules-setup.md +85 -0
- package/src/templates/gemini/commands/myai-content-rules-setup.toml +57 -0
- package/.claude/mcp/sparc-orchestrator-server.js +0 -607
- package/.claude/mcp/wordpress-server.js +0 -1277
- package/src/agents/content-writer-prompt.md +0 -164
- package/src/agents/content-writer.json +0 -70
- package/src/templates/claude/mcp_config.json +0 -74
- package/src/templates/claude/slash_commands.json +0 -166
- package/src/templates/scripts/configure-wordpress-mcp.js +0 -181
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
* @module visual-config-utils
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import fs from
|
|
12
|
-
import path from
|
|
13
|
-
import dotenv from
|
|
11
|
+
import fs from "fs-extra";
|
|
12
|
+
import path from "path";
|
|
13
|
+
import dotenv from "dotenv";
|
|
14
14
|
|
|
15
15
|
dotenv.config();
|
|
16
16
|
|
|
@@ -20,16 +20,17 @@ dotenv.config();
|
|
|
20
20
|
* @returns {Object} Configuration object
|
|
21
21
|
*/
|
|
22
22
|
export function loadVisualConfig() {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
return {
|
|
24
|
+
googleApiKey: process.env.GOOGLE_API_KEY || null,
|
|
25
|
+
openaiApiKey: process.env.OPENAI_API_KEY || null,
|
|
26
|
+
falApiKey: process.env.FAL_KEY || null,
|
|
27
|
+
defaultService: process.env.VISUAL_DEFAULT_SERVICE || "gemini",
|
|
28
|
+
defaultQuality: process.env.VISUAL_DEFAULT_QUALITY || "standard",
|
|
29
|
+
assetsPath: process.env.VISUAL_ASSETS_PATH || "./content-assets",
|
|
30
|
+
dailyBudget: parseFloat(process.env.VISUAL_DAILY_BUDGET || 5.0),
|
|
31
|
+
monthlyBudget: parseFloat(process.env.VISUAL_MONTHLY_BUDGET || 50.0),
|
|
32
|
+
warnThreshold: parseFloat(process.env.VISUAL_WARN_THRESHOLD || 0.8),
|
|
33
|
+
};
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
/**
|
|
@@ -38,57 +39,71 @@ export function loadVisualConfig() {
|
|
|
38
39
|
* @returns {Object} Validation results
|
|
39
40
|
*/
|
|
40
41
|
export function validateVisualConfig() {
|
|
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
|
-
|
|
42
|
+
const config = loadVisualConfig();
|
|
43
|
+
|
|
44
|
+
const validation = {
|
|
45
|
+
isValid: false,
|
|
46
|
+
hasGoogle: false,
|
|
47
|
+
hasOpenAI: false,
|
|
48
|
+
hasFal: false,
|
|
49
|
+
hasAnyAPIKeys: false,
|
|
50
|
+
availableServices: [],
|
|
51
|
+
errors: [],
|
|
52
|
+
warnings: [],
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Validate API keys
|
|
56
|
+
if (config.googleApiKey && config.googleApiKey.length > 20) {
|
|
57
|
+
validation.hasGoogle = true;
|
|
58
|
+
validation.availableServices.push("gemini", "imagen", "veo");
|
|
59
|
+
} else if (config.googleApiKey) {
|
|
60
|
+
validation.errors.push("GOOGLE_API_KEY appears to be invalid (too short)");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (config.openaiApiKey && config.openaiApiKey.length > 20) {
|
|
64
|
+
validation.hasOpenAI = true;
|
|
65
|
+
validation.availableServices.push("dalle");
|
|
66
|
+
} else if (config.openaiApiKey) {
|
|
67
|
+
validation.errors.push("OPENAI_API_KEY appears to be invalid (too short)");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (config.falApiKey && config.falApiKey.length > 20) {
|
|
71
|
+
validation.hasFal = true;
|
|
72
|
+
validation.availableServices.push("fal");
|
|
73
|
+
} else if (config.falApiKey) {
|
|
74
|
+
validation.errors.push("FAL_KEY appears to be invalid (too short)");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
validation.hasAnyAPIKeys = validation.hasGoogle || validation.hasOpenAI;
|
|
78
|
+
|
|
79
|
+
// Validate default service
|
|
80
|
+
if (
|
|
81
|
+
config.defaultService &&
|
|
82
|
+
!validation.availableServices.includes(config.defaultService)
|
|
83
|
+
) {
|
|
84
|
+
validation.warnings.push(
|
|
85
|
+
`Default service '${config.defaultService}' is not available with current API keys`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Validate budget values
|
|
90
|
+
if (config.dailyBudget <= 0) {
|
|
91
|
+
validation.warnings.push("Daily budget should be greater than 0");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (config.monthlyBudget <= 0) {
|
|
95
|
+
validation.warnings.push("Monthly budget should be greater than 0");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (config.monthlyBudget < config.dailyBudget) {
|
|
99
|
+
validation.warnings.push("Monthly budget is less than daily budget");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Configuration is valid if at least one API key is configured
|
|
103
|
+
validation.isValid =
|
|
104
|
+
validation.hasAnyAPIKeys && validation.errors.length === 0;
|
|
105
|
+
|
|
106
|
+
return validation;
|
|
92
107
|
}
|
|
93
108
|
|
|
94
109
|
/**
|
|
@@ -97,8 +112,8 @@ export function validateVisualConfig() {
|
|
|
97
112
|
* @returns {boolean} True if at least one API key is configured
|
|
98
113
|
*/
|
|
99
114
|
export function hasAnyAPIKeys() {
|
|
100
|
-
|
|
101
|
-
|
|
115
|
+
const validation = validateVisualConfig();
|
|
116
|
+
return validation.hasAnyAPIKeys;
|
|
102
117
|
}
|
|
103
118
|
|
|
104
119
|
/**
|
|
@@ -107,8 +122,8 @@ export function hasAnyAPIKeys() {
|
|
|
107
122
|
* @returns {Array<string>} List of available service names
|
|
108
123
|
*/
|
|
109
124
|
export function getAvailableServices() {
|
|
110
|
-
|
|
111
|
-
|
|
125
|
+
const validation = validateVisualConfig();
|
|
126
|
+
return validation.availableServices;
|
|
112
127
|
}
|
|
113
128
|
|
|
114
129
|
/**
|
|
@@ -118,54 +133,65 @@ export function getAvailableServices() {
|
|
|
118
133
|
* @returns {Object} Service information
|
|
119
134
|
*/
|
|
120
135
|
export function getServiceDisplayInfo(service) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
136
|
+
const services = {
|
|
137
|
+
gemini: {
|
|
138
|
+
id: "gemini",
|
|
139
|
+
name: "Gemini 2.5 Flash Image",
|
|
140
|
+
nickname: '"Nano Banana"',
|
|
141
|
+
provider: "Google",
|
|
142
|
+
apiKey: "GOOGLE_API_KEY",
|
|
143
|
+
speed: "Fast ⚡⚡⚡",
|
|
144
|
+
cost: "$0.02/image",
|
|
145
|
+
quality: "Good",
|
|
146
|
+
bestFor: "Quick hero images, high volume",
|
|
147
|
+
},
|
|
148
|
+
imagen: {
|
|
149
|
+
id: "imagen",
|
|
150
|
+
name: "Imagen 3",
|
|
151
|
+
nickname: "Premium Quality",
|
|
152
|
+
provider: "Google",
|
|
153
|
+
apiKey: "GOOGLE_API_KEY",
|
|
154
|
+
speed: "Medium ⚡⚡",
|
|
155
|
+
cost: "$0.03/image",
|
|
156
|
+
quality: "Excellent",
|
|
157
|
+
bestFor: "Premium hero images, photorealistic content",
|
|
158
|
+
},
|
|
159
|
+
dalle: {
|
|
160
|
+
id: "dalle",
|
|
161
|
+
name: "DALL-E 3",
|
|
162
|
+
nickname: "Creative AI",
|
|
163
|
+
provider: "OpenAI",
|
|
164
|
+
apiKey: "OPENAI_API_KEY",
|
|
165
|
+
speed: "Medium ⚡⚡",
|
|
166
|
+
cost: "$0.04-0.12/image",
|
|
167
|
+
quality: "Excellent",
|
|
168
|
+
bestFor: "Creative illustrations, concept art",
|
|
169
|
+
},
|
|
170
|
+
veo: {
|
|
171
|
+
id: "veo",
|
|
172
|
+
name: "Veo 2",
|
|
173
|
+
nickname: "Video Generation",
|
|
174
|
+
provider: "Google",
|
|
175
|
+
apiKey: "GOOGLE_API_KEY",
|
|
176
|
+
speed: "Slow ⚡",
|
|
177
|
+
cost: "$0.10/video (est.)",
|
|
178
|
+
quality: "Good",
|
|
179
|
+
bestFor: "Product demos, animated diagrams",
|
|
180
|
+
},
|
|
181
|
+
fal: {
|
|
182
|
+
id: "fal",
|
|
183
|
+
name: "Fal.ai (FLUX, Nano Banana Pro)",
|
|
184
|
+
nickname: "Premium Models",
|
|
185
|
+
provider: "Fal.ai",
|
|
186
|
+
apiKey: "FAL_KEY",
|
|
187
|
+
speed: "Fast ⚡⚡⚡",
|
|
188
|
+
cost: "$0.06-0.15/image",
|
|
189
|
+
quality: "Excellent",
|
|
190
|
+
bestFor: "High-quality branded content, FLUX models",
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
return services[service] || null;
|
|
169
195
|
}
|
|
170
196
|
|
|
171
197
|
/**
|
|
@@ -175,11 +201,11 @@ export function getServiceDisplayInfo(service) {
|
|
|
175
201
|
* @returns {string} Status message
|
|
176
202
|
*/
|
|
177
203
|
export function getConfigStatusMessage(verbose = false) {
|
|
178
|
-
|
|
179
|
-
|
|
204
|
+
const validation = validateVisualConfig();
|
|
205
|
+
const config = loadVisualConfig();
|
|
180
206
|
|
|
181
|
-
|
|
182
|
-
|
|
207
|
+
if (!validation.hasAnyAPIKeys) {
|
|
208
|
+
return `⚠️ Visual content generation not configured
|
|
183
209
|
|
|
184
210
|
No API keys found. To enable image/video generation:
|
|
185
211
|
|
|
@@ -188,39 +214,41 @@ No API keys found. To enable image/video generation:
|
|
|
188
214
|
2. Add to your .env file:
|
|
189
215
|
GOOGLE_API_KEY=your_key_here # For Gemini, Imagen, Veo
|
|
190
216
|
OPENAI_API_KEY=your_key_here # For DALL-E
|
|
217
|
+
FAL_KEY=your_key_here # For Fal.ai (FLUX, Nano Banana Pro)
|
|
191
218
|
|
|
192
219
|
Get API keys:
|
|
193
220
|
• Google: https://ai.google.dev/
|
|
194
|
-
• OpenAI: https://platform.openai.com/api-keys
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
221
|
+
• OpenAI: https://platform.openai.com/api-keys
|
|
222
|
+
• Fal.ai: https://fal.ai/dashboard/keys`;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
let message = `✅ Visual content generation configured\n\n`;
|
|
226
|
+
|
|
227
|
+
// Show available services
|
|
228
|
+
message += `📋 Available Services:\n`;
|
|
229
|
+
for (const service of validation.availableServices) {
|
|
230
|
+
const info = getServiceDisplayInfo(service);
|
|
231
|
+
message += ` • ${info.name} - ${info.cost}\n`;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (verbose) {
|
|
235
|
+
message += `\n⚙️ Settings:\n`;
|
|
236
|
+
message += ` Default Service: ${config.defaultService}\n`;
|
|
237
|
+
message += ` Default Quality: ${config.defaultQuality}\n`;
|
|
238
|
+
message += ` Assets Path: ${config.assetsPath}\n`;
|
|
239
|
+
message += ` Daily Budget: $${config.dailyBudget.toFixed(2)}\n`;
|
|
240
|
+
message += ` Monthly Budget: $${config.monthlyBudget.toFixed(2)}\n`;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Show warnings
|
|
244
|
+
if (validation.warnings.length > 0) {
|
|
245
|
+
message += `\n⚠️ Warnings:\n`;
|
|
246
|
+
for (const warning of validation.warnings) {
|
|
247
|
+
message += ` • ${warning}\n`;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return message;
|
|
224
252
|
}
|
|
225
253
|
|
|
226
254
|
/**
|
|
@@ -230,33 +258,33 @@ Get API keys:
|
|
|
230
258
|
* @returns {Promise<void>}
|
|
231
259
|
*/
|
|
232
260
|
export async function updateEnvFile(updates) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
261
|
+
const envPath = path.join(process.cwd(), ".env");
|
|
262
|
+
let envContent = "";
|
|
263
|
+
|
|
264
|
+
// Read existing .env file
|
|
265
|
+
if (await fs.pathExists(envPath)) {
|
|
266
|
+
envContent = await fs.readFile(envPath, "utf-8");
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Update or add each key
|
|
270
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
271
|
+
const regex = new RegExp(`^${key}=.*$`, "m");
|
|
272
|
+
const line = `${key}=${value}`;
|
|
273
|
+
|
|
274
|
+
if (regex.test(envContent)) {
|
|
275
|
+
// Update existing key
|
|
276
|
+
envContent = envContent.replace(regex, line);
|
|
277
|
+
} else {
|
|
278
|
+
// Add new key
|
|
279
|
+
envContent += `\n${line}`;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Write back to file
|
|
284
|
+
await fs.writeFile(envPath, envContent.trim() + "\n");
|
|
285
|
+
|
|
286
|
+
// Reload environment variables
|
|
287
|
+
dotenv.config({ override: true });
|
|
260
288
|
}
|
|
261
289
|
|
|
262
290
|
/**
|
|
@@ -266,15 +294,15 @@ export async function updateEnvFile(updates) {
|
|
|
266
294
|
* @returns {string} Masked API key
|
|
267
295
|
*/
|
|
268
296
|
export function maskAPIKey(apiKey) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
297
|
+
if (!apiKey || apiKey.length < 16) {
|
|
298
|
+
return "****";
|
|
299
|
+
}
|
|
272
300
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
301
|
+
const start = apiKey.substring(0, 8);
|
|
302
|
+
const end = apiKey.substring(apiKey.length - 4);
|
|
303
|
+
const masked = `${start}${"*".repeat(Math.max(4, apiKey.length - 12))}${end}`;
|
|
276
304
|
|
|
277
|
-
|
|
305
|
+
return masked;
|
|
278
306
|
}
|
|
279
307
|
|
|
280
308
|
/**
|
|
@@ -284,57 +312,53 @@ export function maskAPIKey(apiKey) {
|
|
|
284
312
|
* @returns {Promise<Object>} Test result
|
|
285
313
|
*/
|
|
286
314
|
export async function testAPIKey(service) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
} catch (error) {
|
|
336
|
-
return { success: false, error: error.message };
|
|
337
|
-
}
|
|
315
|
+
const config = loadVisualConfig();
|
|
316
|
+
|
|
317
|
+
try {
|
|
318
|
+
if (service === "google") {
|
|
319
|
+
if (!config.googleApiKey) {
|
|
320
|
+
return { success: false, error: "GOOGLE_API_KEY not configured" };
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Simple test: list models
|
|
324
|
+
const response = await fetch(
|
|
325
|
+
`https://generativelanguage.googleapis.com/v1beta/models?key=${config.googleApiKey}`,
|
|
326
|
+
{ method: "GET" },
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
if (response.ok) {
|
|
330
|
+
return { success: true, service: "google" };
|
|
331
|
+
} else {
|
|
332
|
+
const error = await response.text();
|
|
333
|
+
return { success: false, error: `Google API test failed: ${error}` };
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (service === "openai") {
|
|
338
|
+
if (!config.openaiApiKey) {
|
|
339
|
+
return { success: false, error: "OPENAI_API_KEY not configured" };
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Simple test: list models
|
|
343
|
+
const response = await fetch("https://api.openai.com/v1/models", {
|
|
344
|
+
method: "GET",
|
|
345
|
+
headers: {
|
|
346
|
+
Authorization: `Bearer ${config.openaiApiKey}`,
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
if (response.ok) {
|
|
351
|
+
return { success: true, service: "openai" };
|
|
352
|
+
} else {
|
|
353
|
+
const error = await response.text();
|
|
354
|
+
return { success: false, error: `OpenAI API test failed: ${error}` };
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return { success: false, error: `Unknown service: ${service}` };
|
|
359
|
+
} catch (error) {
|
|
360
|
+
return { success: false, error: error.message };
|
|
361
|
+
}
|
|
338
362
|
}
|
|
339
363
|
|
|
340
364
|
/**
|
|
@@ -343,39 +367,41 @@ export async function testAPIKey(service) {
|
|
|
343
367
|
* @returns {Object} Configuration summary
|
|
344
368
|
*/
|
|
345
369
|
export function getConfigSummary() {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
370
|
+
const validation = validateVisualConfig();
|
|
371
|
+
const config = loadVisualConfig();
|
|
372
|
+
|
|
373
|
+
return {
|
|
374
|
+
configured: validation.hasAnyAPIKeys,
|
|
375
|
+
services: {
|
|
376
|
+
google: {
|
|
377
|
+
configured: validation.hasGoogle,
|
|
378
|
+
available: ["gemini", "imagen", "veo"].filter((s) =>
|
|
379
|
+
validation.availableServices.includes(s),
|
|
380
|
+
),
|
|
381
|
+
},
|
|
382
|
+
openai: {
|
|
383
|
+
configured: validation.hasOpenAI,
|
|
384
|
+
available: validation.availableServices.includes("dalle")
|
|
385
|
+
? ["dalle"]
|
|
386
|
+
: [],
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
settings: {
|
|
390
|
+
defaultService: config.defaultService,
|
|
391
|
+
defaultQuality: config.defaultQuality,
|
|
392
|
+
assetsPath: config.assetsPath,
|
|
393
|
+
budgets: {
|
|
394
|
+
daily: config.dailyBudget,
|
|
395
|
+
monthly: config.monthlyBudget,
|
|
396
|
+
warnThreshold: config.warnThreshold,
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
validation: {
|
|
400
|
+
isValid: validation.isValid,
|
|
401
|
+
errors: validation.errors,
|
|
402
|
+
warnings: validation.warnings,
|
|
403
|
+
},
|
|
404
|
+
};
|
|
379
405
|
}
|
|
380
406
|
|
|
381
407
|
/**
|
|
@@ -385,8 +411,8 @@ export function getConfigSummary() {
|
|
|
385
411
|
* @returns {boolean} True if service is available
|
|
386
412
|
*/
|
|
387
413
|
export function isServiceAvailable(service) {
|
|
388
|
-
|
|
389
|
-
|
|
414
|
+
const available = getAvailableServices();
|
|
415
|
+
return available.includes(service);
|
|
390
416
|
}
|
|
391
417
|
|
|
392
418
|
/**
|
|
@@ -396,29 +422,29 @@ export function isServiceAvailable(service) {
|
|
|
396
422
|
* @returns {string} Recommended service name
|
|
397
423
|
*/
|
|
398
424
|
export function getRecommendedService(type) {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
425
|
+
const available = getAvailableServices();
|
|
426
|
+
const config = loadVisualConfig();
|
|
427
|
+
|
|
428
|
+
// Recommendations by type
|
|
429
|
+
const recommendations = {
|
|
430
|
+
hero: ["imagen", "dalle", "gemini"], // Premium quality for hero
|
|
431
|
+
illustration: ["dalle", "imagen", "gemini"], // Creative for illustrations
|
|
432
|
+
diagram: ["gemini", "dalle", "imagen"], // Fast for diagrams
|
|
433
|
+
screenshot: ["gemini", "imagen", "dalle"], // Fast for screenshots
|
|
434
|
+
video: ["veo"], // Only Veo for video
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
const preferred = recommendations[type] || recommendations.hero;
|
|
438
|
+
|
|
439
|
+
// Return first available from preferred list
|
|
440
|
+
for (const service of preferred) {
|
|
441
|
+
if (available.includes(service)) {
|
|
442
|
+
return service;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Fallback to default or first available
|
|
447
|
+
return available.includes(config.defaultService)
|
|
448
|
+
? config.defaultService
|
|
449
|
+
: available[0];
|
|
424
450
|
}
|