mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-02-04 05:08:26 +01:00
NanoGPT: Add to image generation extension
This commit is contained in:
parent
649c3911eb
commit
77be125a99
@ -54,6 +54,7 @@ const sources = {
|
|||||||
stability: 'stability',
|
stability: 'stability',
|
||||||
blockentropy: 'blockentropy',
|
blockentropy: 'blockentropy',
|
||||||
huggingface: 'huggingface',
|
huggingface: 'huggingface',
|
||||||
|
nanogpt: 'nanogpt',
|
||||||
};
|
};
|
||||||
|
|
||||||
const initiators = {
|
const initiators = {
|
||||||
@ -1236,6 +1237,7 @@ async function onModelChange() {
|
|||||||
sources.stability,
|
sources.stability,
|
||||||
sources.blockentropy,
|
sources.blockentropy,
|
||||||
sources.huggingface,
|
sources.huggingface,
|
||||||
|
sources.nanogpt,
|
||||||
];
|
];
|
||||||
|
|
||||||
if (cloudSources.includes(extension_settings.sd.source)) {
|
if (cloudSources.includes(extension_settings.sd.source)) {
|
||||||
@ -1454,6 +1456,9 @@ async function loadSamplers() {
|
|||||||
case sources.huggingface:
|
case sources.huggingface:
|
||||||
samplers = ['N/A'];
|
samplers = ['N/A'];
|
||||||
break;
|
break;
|
||||||
|
case sources.nanogpt:
|
||||||
|
samplers = ['N/A'];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const sampler of samplers) {
|
for (const sampler of samplers) {
|
||||||
@ -1646,6 +1651,9 @@ async function loadModels() {
|
|||||||
case sources.huggingface:
|
case sources.huggingface:
|
||||||
models = [{ value: '', text: '<Enter Model ID above>' }];
|
models = [{ value: '', text: '<Enter Model ID above>' }];
|
||||||
break;
|
break;
|
||||||
|
case sources.nanogpt:
|
||||||
|
models = await loadNanoGPTModels();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const model of models) {
|
for (const model of models) {
|
||||||
@ -1725,6 +1733,25 @@ async function loadBlockEntropyModels() {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function loadNanoGPTModels() {
|
||||||
|
if (!secret_state[SECRET_KEYS.NANOGPT]) {
|
||||||
|
console.debug('NanoGPT API key is not set.');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await fetch('/api/sd/nanogpt/models', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: getRequestHeaders(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.ok) {
|
||||||
|
const data = await result.json();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
async function loadHordeModels() {
|
async function loadHordeModels() {
|
||||||
const result = await fetch('/api/horde/sd-models', {
|
const result = await fetch('/api/horde/sd-models', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -1997,6 +2024,9 @@ async function loadSchedulers() {
|
|||||||
case sources.huggingface:
|
case sources.huggingface:
|
||||||
schedulers = ['N/A'];
|
schedulers = ['N/A'];
|
||||||
break;
|
break;
|
||||||
|
case sources.nanogpt:
|
||||||
|
schedulers = ['N/A'];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const scheduler of schedulers) {
|
for (const scheduler of schedulers) {
|
||||||
@ -2079,6 +2109,9 @@ async function loadVaes() {
|
|||||||
case sources.huggingface:
|
case sources.huggingface:
|
||||||
vaes = ['N/A'];
|
vaes = ['N/A'];
|
||||||
break;
|
break;
|
||||||
|
case sources.nanogpt:
|
||||||
|
vaes = ['N/A'];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const vae of vaes) {
|
for (const vae of vaes) {
|
||||||
@ -2631,6 +2664,8 @@ async function sendGenerationRequest(generationType, prompt, additionalNegativeP
|
|||||||
case sources.huggingface:
|
case sources.huggingface:
|
||||||
result = await generateHuggingFaceImage(prefixedPrompt, signal);
|
result = await generateHuggingFaceImage(prefixedPrompt, signal);
|
||||||
break;
|
break;
|
||||||
|
case sources.nanogpt:
|
||||||
|
result = await generateNanoGPTImage(prefixedPrompt, negativePrompt, signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result.data) {
|
if (!result.data) {
|
||||||
@ -3308,6 +3343,40 @@ async function generateHuggingFaceImage(prompt, signal) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an image using the NanoGPT API.
|
||||||
|
* @param {string} prompt - The main instruction used to guide the image generation.
|
||||||
|
* @param {string} negativePrompt - The instruction used to restrict 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 generateNanoGPTImage(prompt, negativePrompt, signal) {
|
||||||
|
const result = await fetch('/api/sd/nanogpt/generate', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: getRequestHeaders(),
|
||||||
|
signal: signal,
|
||||||
|
body: JSON.stringify({
|
||||||
|
model: extension_settings.sd.model,
|
||||||
|
prompt: prompt,
|
||||||
|
negative_prompt: negativePrompt,
|
||||||
|
num_steps: parseInt(extension_settings.sd.steps),
|
||||||
|
scale: parseFloat(extension_settings.sd.scale),
|
||||||
|
width: parseInt(extension_settings.sd.width),
|
||||||
|
height: parseInt(extension_settings.sd.height),
|
||||||
|
resolution: `${extension_settings.sd.width}x${extension_settings.sd.height}`,
|
||||||
|
showExplicitContent: true,
|
||||||
|
nImages: 1,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.ok) {
|
||||||
|
const data = await result.json();
|
||||||
|
return { format: 'jpg', data: data.image };
|
||||||
|
} else {
|
||||||
|
const text = await result.text();
|
||||||
|
throw new Error(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function onComfyOpenWorkflowEditorClick() {
|
async function onComfyOpenWorkflowEditorClick() {
|
||||||
let workflow = await (await fetch('/api/sd/comfy/workflow', {
|
let workflow = await (await fetch('/api/sd/comfy/workflow', {
|
||||||
@ -3591,6 +3660,8 @@ function isValidState() {
|
|||||||
return secret_state[SECRET_KEYS.BLOCKENTROPY];
|
return secret_state[SECRET_KEYS.BLOCKENTROPY];
|
||||||
case sources.huggingface:
|
case sources.huggingface:
|
||||||
return secret_state[SECRET_KEYS.HUGGINGFACE];
|
return secret_state[SECRET_KEYS.HUGGINGFACE];
|
||||||
|
case sources.nanogpt:
|
||||||
|
return secret_state[SECRET_KEYS.NANOGPT];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
<option value="drawthings">DrawThings HTTP API</option>
|
<option value="drawthings">DrawThings HTTP API</option>
|
||||||
<option value="extras">Extras API (local / remote)</option>
|
<option value="extras">Extras API (local / remote)</option>
|
||||||
<option value="huggingface">HuggingFace Inference API (serverless)</option>
|
<option value="huggingface">HuggingFace Inference API (serverless)</option>
|
||||||
|
<option value="nanogpt">NanoGPT</option>
|
||||||
<option value="novel">NovelAI Diffusion</option>
|
<option value="novel">NovelAI Diffusion</option>
|
||||||
<option value="openai">OpenAI (DALL-E)</option>
|
<option value="openai">OpenAI (DALL-E)</option>
|
||||||
<option value="pollinations">Pollinations</option>
|
<option value="pollinations">Pollinations</option>
|
||||||
@ -88,6 +89,9 @@
|
|||||||
<label for="sd_huggingface_model_id" data-i18n="Model ID">Model ID</label>
|
<label for="sd_huggingface_model_id" data-i18n="Model ID">Model ID</label>
|
||||||
<input id="sd_huggingface_model_id" type="text" class="text_pole" data-i18n="[placeholder]e.g. black-forest-labs/FLUX.1-dev" placeholder="e.g. black-forest-labs/FLUX.1-dev" value="" />
|
<input id="sd_huggingface_model_id" type="text" class="text_pole" data-i18n="[placeholder]e.g. black-forest-labs/FLUX.1-dev" placeholder="e.g. black-forest-labs/FLUX.1-dev" value="" />
|
||||||
</div>
|
</div>
|
||||||
|
<div data-sd-source="nanogpt">
|
||||||
|
<i>Hint: Save an API key in the NanoGPT (Chat Completion) API settings to use it here.</i>
|
||||||
|
</div>
|
||||||
<div data-sd-source="vlad">
|
<div data-sd-source="vlad">
|
||||||
<label for="sd_vlad_url">SD.Next API URL</label>
|
<label for="sd_vlad_url">SD.Next API URL</label>
|
||||||
<div class="flex-container flexnowrap">
|
<div class="flex-container flexnowrap">
|
||||||
|
@ -1001,6 +1001,89 @@ huggingface.post('/generate', jsonParser, async (request, response) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const nanogpt = express.Router();
|
||||||
|
|
||||||
|
nanogpt.post('/models', jsonParser, async (request, response) => {
|
||||||
|
try {
|
||||||
|
const key = readSecret(request.user.directories, SECRET_KEYS.NANOGPT);
|
||||||
|
|
||||||
|
if (!key) {
|
||||||
|
console.log('NanoGPT key not found.');
|
||||||
|
return response.sendStatus(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
const modelsResponse = await fetch('https://nano-gpt.com/api/models', {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'x-api-key': key,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!modelsResponse.ok) {
|
||||||
|
console.log('NanoGPT returned an error.');
|
||||||
|
return response.sendStatus(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {any} */
|
||||||
|
const data = await modelsResponse.json();
|
||||||
|
const imageModels = data?.models?.image;
|
||||||
|
|
||||||
|
if (!imageModels || typeof imageModels !== 'object') {
|
||||||
|
console.log('NanoGPT returned invalid data.');
|
||||||
|
return response.sendStatus(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
const models = Object.values(imageModels).map(x => ({ value: x.model, text: x.name }));
|
||||||
|
return response.send(models);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return response.sendStatus(500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
nanogpt.post('/generate', jsonParser, async (request, response) => {
|
||||||
|
try {
|
||||||
|
const key = readSecret(request.user.directories, SECRET_KEYS.NANOGPT);
|
||||||
|
|
||||||
|
if (!key) {
|
||||||
|
console.log('NanoGPT key not found.');
|
||||||
|
return response.sendStatus(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('NanoGPT request:', request.body);
|
||||||
|
|
||||||
|
const result = await fetch('https://nano-gpt.com/api/generate-image', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(request.body),
|
||||||
|
headers: {
|
||||||
|
'x-api-key': key,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result.ok) {
|
||||||
|
console.log('NanoGPT returned an error.');
|
||||||
|
return response.sendStatus(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {any} */
|
||||||
|
const data = await result.json();
|
||||||
|
|
||||||
|
const image = data?.data?.[0]?.b64_json;
|
||||||
|
if (!image) {
|
||||||
|
console.log('NanoGPT returned invalid data.');
|
||||||
|
return response.sendStatus(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.send({ image });
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return response.sendStatus(500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
router.use('/comfy', comfy);
|
router.use('/comfy', comfy);
|
||||||
router.use('/together', together);
|
router.use('/together', together);
|
||||||
@ -1009,3 +1092,4 @@ router.use('/pollinations', pollinations);
|
|||||||
router.use('/stability', stability);
|
router.use('/stability', stability);
|
||||||
router.use('/blockentropy', blockentropy);
|
router.use('/blockentropy', blockentropy);
|
||||||
router.use('/huggingface', huggingface);
|
router.use('/huggingface', huggingface);
|
||||||
|
router.use('/nanogpt', nanogpt);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user