Add Electron Hub as Chat Completions Provider (#4458)
* fixed merge conflicts * Supported max tokens + fixed wrong image model mapping * fixed merge conflicts * fixed merge conflicts * updated the logic * updated the logic * replaced hard coded reasoning_effort mode list with a dynamic function * replaced hard coded reasoning_effort model list with a dynamic function * Fix eslint * Adjust reasoning effort logic * Code clean-up * Add logo * Add inline image quality * Fix multimodal models list * Fix seed not passed * Add "detail" error parser --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
This commit is contained in:
@@ -82,6 +82,7 @@ const sources = {
|
||||
pollinations: 'pollinations',
|
||||
stability: 'stability',
|
||||
huggingface: 'huggingface',
|
||||
electronhub: 'electronhub',
|
||||
nanogpt: 'nanogpt',
|
||||
bfl: 'bfl',
|
||||
falai: 'falai',
|
||||
@@ -1289,6 +1290,7 @@ async function onModelChange() {
|
||||
sources.pollinations,
|
||||
sources.stability,
|
||||
sources.huggingface,
|
||||
sources.electronhub,
|
||||
sources.nanogpt,
|
||||
sources.bfl,
|
||||
sources.falai,
|
||||
@@ -1506,6 +1508,9 @@ async function loadSamplers() {
|
||||
case sources.huggingface:
|
||||
samplers = ['N/A'];
|
||||
break;
|
||||
case sources.electronhub:
|
||||
samplers = ['N/A'];
|
||||
break;
|
||||
case sources.nanogpt:
|
||||
samplers = ['N/A'];
|
||||
break;
|
||||
@@ -1702,6 +1707,9 @@ async function loadModels() {
|
||||
case sources.huggingface:
|
||||
models = [{ value: '', text: '<Enter Model ID above>' }];
|
||||
break;
|
||||
case sources.electronhub:
|
||||
models = await loadElectronHubModels();
|
||||
break;
|
||||
case sources.nanogpt:
|
||||
models = await loadNanoGPTModels();
|
||||
break;
|
||||
@@ -1806,6 +1814,24 @@ async function loadTogetherAIModels() {
|
||||
return [];
|
||||
}
|
||||
|
||||
async function loadElectronHubModels() {
|
||||
if (!secret_state[SECRET_KEYS.ELECTRONHUB]) {
|
||||
console.debug('Electron Hub API key is not set.');
|
||||
return [];
|
||||
}
|
||||
|
||||
const result = await fetch('/api/sd/electronhub/models', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
});
|
||||
|
||||
if (result.ok) {
|
||||
return await result.json();
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
async function loadNanoGPTModels() {
|
||||
if (!secret_state[SECRET_KEYS.NANOGPT]) {
|
||||
console.debug('NanoGPT API key is not set.');
|
||||
@@ -2131,6 +2157,9 @@ async function loadSchedulers() {
|
||||
case sources.huggingface:
|
||||
schedulers = ['N/A'];
|
||||
break;
|
||||
case sources.electronhub:
|
||||
schedulers = ['N/A'];
|
||||
break;
|
||||
case sources.nanogpt:
|
||||
schedulers = ['N/A'];
|
||||
break;
|
||||
@@ -2228,6 +2257,9 @@ async function loadVaes() {
|
||||
case sources.huggingface:
|
||||
vaes = ['N/A'];
|
||||
break;
|
||||
case sources.electronhub:
|
||||
vaes = ['N/A'];
|
||||
break;
|
||||
case sources.nanogpt:
|
||||
vaes = ['N/A'];
|
||||
break;
|
||||
@@ -2811,6 +2843,9 @@ async function sendGenerationRequest(generationType, prompt, additionalNegativeP
|
||||
case sources.huggingface:
|
||||
result = await generateHuggingFaceImage(prefixedPrompt, signal);
|
||||
break;
|
||||
case sources.electronhub:
|
||||
result = await generateElectronHubImage(prefixedPrompt, signal);
|
||||
break;
|
||||
case sources.nanogpt:
|
||||
result = await generateNanoGPTImage(prefixedPrompt, negativePrompt, signal);
|
||||
break;
|
||||
@@ -3013,6 +3048,56 @@ function getClosestAspectRatio(width, height, source) {
|
||||
return closestAspectRatio;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get closest size for Electron Hub
|
||||
* @param {number} width - The width of the image
|
||||
* @param {number} height - The height of the image
|
||||
* @returns {Promise<string>} - The closest size
|
||||
*/
|
||||
async function getClosestSize(width, height) {
|
||||
const response = await fetch('/api/sd/electronhub/sizes', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({
|
||||
model: extension_settings.sd.model,
|
||||
}),
|
||||
});
|
||||
if (!response.ok) {
|
||||
const text = await response.text();
|
||||
throw new Error(text);
|
||||
}
|
||||
const result = await response.json();
|
||||
const sizesData = result.sizes;
|
||||
|
||||
const closestSize = sizesData.reduce((closest, size) => {
|
||||
if (!size || typeof size !== 'string') {
|
||||
return closest;
|
||||
}
|
||||
const sizeParts = size.split('x');
|
||||
if (sizeParts.length !== 2) {
|
||||
return closest;
|
||||
}
|
||||
|
||||
const sizeWidth = Number(sizeParts[0]);
|
||||
const sizeHeight = Number(sizeParts[1]);
|
||||
const targetWidth = Number(width);
|
||||
const targetHeight = Number(height);
|
||||
|
||||
if (isNaN(sizeWidth) || isNaN(sizeHeight) || isNaN(targetWidth) || isNaN(targetHeight)) {
|
||||
return closest;
|
||||
}
|
||||
|
||||
const sizeArea = sizeWidth * sizeHeight;
|
||||
const targetArea = targetWidth * targetHeight;
|
||||
const diff = Math.abs(sizeArea - targetArea);
|
||||
|
||||
return diff < closest.diff ? { size, diff } : closest;
|
||||
}, { size: null, diff: Infinity });
|
||||
|
||||
const size = closestSize.size;
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an image using Stability AI.
|
||||
* @param {string} prompt - The main instruction used to guide the image generation.
|
||||
@@ -3564,6 +3649,35 @@ async function generateHuggingFaceImage(prompt, signal) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an image using the Electron Hub API.
|
||||
* @param {string} prompt - The main instruction used to guide the image generation.
|
||||
* @param {AbortSignal} signal - An AbortSignal object that can be used to cancel the request.
|
||||
* @returns {Promise<{format: string, data: string}>} - A promise that resolves when the image generation and processing are complete.
|
||||
*/
|
||||
async function generateElectronHubImage(prompt, signal) {
|
||||
const size = await getClosestSize(extension_settings.sd.width, extension_settings.sd.height);
|
||||
|
||||
const result = await fetch('/api/sd/electronhub/generate', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
signal: signal,
|
||||
body: JSON.stringify({
|
||||
model: extension_settings.sd.model,
|
||||
prompt: prompt,
|
||||
size: size,
|
||||
}),
|
||||
});
|
||||
|
||||
if (result.ok) {
|
||||
const data = await result.json();
|
||||
return { format: 'jpg', data: data.image };
|
||||
} else {
|
||||
const text = await result.text();
|
||||
throw new Error(text);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an image using the NanoGPT API.
|
||||
* @param {string} prompt - The main instruction used to guide the image generation.
|
||||
@@ -4014,6 +4128,8 @@ function isValidState() {
|
||||
return secret_state[SECRET_KEYS.STABILITY];
|
||||
case sources.huggingface:
|
||||
return secret_state[SECRET_KEYS.HUGGINGFACE];
|
||||
case sources.electronhub:
|
||||
return secret_state[SECRET_KEYS.ELECTRONHUB];
|
||||
case sources.nanogpt:
|
||||
return secret_state[SECRET_KEYS.NANOGPT];
|
||||
case sources.bfl:
|
||||
|
||||
Reference in New Issue
Block a user