Add pollinations as image generation source

This commit is contained in:
Cohee 2024-04-04 20:40:47 +03:00
parent 42138ca09b
commit 75ebdf394a
3 changed files with 171 additions and 7 deletions

View File

@ -48,6 +48,7 @@ const sources = {
comfy: 'comfy',
togetherai: 'togetherai',
drawthings: 'drawthings',
pollinations: 'pollinations',
};
const generationMode = {
@ -254,6 +255,10 @@ const defaultSettings = {
// ComyUI settings
comfy_url: 'http://127.0.0.1:8188',
comfy_workflow: 'Default_Comfy_Workflow.json',
// Pollinations settings
pollinations_enhance: false,
pollinations_refine: false,
};
function processTriggers(chat, _, abort) {
@ -383,6 +388,8 @@ async function loadSettings() {
$('#sd_novel_sm').prop('checked', extension_settings.sd.novel_sm);
$('#sd_novel_sm_dyn').prop('checked', extension_settings.sd.novel_sm_dyn);
$('#sd_novel_sm_dyn').prop('disabled', !extension_settings.sd.novel_sm);
$('#sd_pollinations_enhance').prop('checked', extension_settings.sd.pollinations_enhance);
$('#sd_pollinations_refine').prop('checked', extension_settings.sd.pollinations_refine);
$('#sd_horde').prop('checked', extension_settings.sd.horde);
$('#sd_horde_nsfw').prop('checked', extension_settings.sd.horde_nsfw);
$('#sd_horde_karras').prop('checked', extension_settings.sd.horde_karras);
@ -828,6 +835,16 @@ function onNovelSmDynInput() {
saveSettingsDebounced();
}
function onPollinationsEnhanceInput() {
extension_settings.sd.pollinations_enhance = !!$('#sd_pollinations_enhance').prop('checked');
saveSettingsDebounced();
}
function onPollinationsRefineInput() {
extension_settings.sd.pollinations_refine = !!$('#sd_pollinations_refine').prop('checked');
saveSettingsDebounced();
}
function onHordeNsfwInput() {
extension_settings.sd.horde_nsfw = !!$(this).prop('checked');
saveSettingsDebounced();
@ -1023,7 +1040,7 @@ async function onModelChange() {
extension_settings.sd.model = $('#sd_model').find(':selected').val();
saveSettingsDebounced();
const cloudSources = [sources.horde, sources.novel, sources.openai, sources.togetherai];
const cloudSources = [sources.horde, sources.novel, sources.openai, sources.togetherai, sources.pollinations];
if (cloudSources.includes(extension_settings.sd.source)) {
return;
@ -1188,6 +1205,9 @@ async function loadSamplers() {
case sources.togetherai:
samplers = ['N/A'];
break;
case sources.pollinations:
samplers = ['N/A'];
break;
}
for (const sampler of samplers) {
@ -1368,6 +1388,9 @@ async function loadModels() {
case sources.togetherai:
models = await loadTogetherAIModels();
break;
case sources.pollinations:
models = await loadPollinationsModels();
break;
}
for (const model of models) {
@ -1384,6 +1407,55 @@ async function loadModels() {
}
}
async function loadPollinationsModels() {
return [
{
value: 'pixart',
text: 'PixArt-αlpha',
},
{
value: 'playground',
text: 'Playground v2',
},
{
value: 'dalle3xl',
text: 'DALL•E 3 XL',
},
{
value: 'formulaxl',
text: 'FormulaXL',
},
{
value: 'dreamshaper',
text: 'DreamShaper',
},
{
value: 'deliberate',
text: 'Deliberate',
},
{
value: 'dpo',
text: 'SDXL-DPO',
},
{
value: 'swizz8',
text: 'Swizz8',
},
{
value: 'juggernaut',
text: 'Juggernaut',
},
{
value: 'turbo',
text: 'SDXL Turbo',
},
{
value: 'realvis',
text: 'Realistic Vision',
},
];
}
async function loadTogetherAIModels() {
if (!secret_state[SECRET_KEYS.TOGETHERAI]) {
console.debug('TogetherAI API key is not set.');
@ -1641,6 +1713,9 @@ async function loadSchedulers() {
case sources.togetherai:
schedulers = ['N/A'];
break;
case sources.pollinations:
schedulers = ['N/A'];
break;
case sources.comfy:
schedulers = await loadComfySchedulers();
break;
@ -1706,6 +1781,9 @@ async function loadVaes() {
case sources.togetherai:
vaes = ['N/A'];
break;
case sources.pollinations:
vaes = ['N/A'];
break;
case sources.comfy:
vaes = await loadComfyVaes();
break;
@ -2135,6 +2213,9 @@ async function sendGenerationRequest(generationType, prompt, characterName = nul
case sources.togetherai:
result = await generateTogetherAIImage(prefixedPrompt, negativePrompt);
break;
case sources.pollinations:
result = await generatePollinationsImage(prefixedPrompt, negativePrompt);
break;
}
if (!result.data) {
@ -2181,6 +2262,30 @@ async function generateTogetherAIImage(prompt, negativePrompt) {
}
}
async function generatePollinationsImage(prompt, negativePrompt) {
const result = await fetch('/api/sd/pollinations/generate', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify({
prompt: prompt,
negative_prompt: negativePrompt,
model: extension_settings.sd.model,
width: extension_settings.sd.width,
height: extension_settings.sd.height,
enhance: extension_settings.sd.pollinations_enhance,
refine: extension_settings.sd.pollinations_refine,
}),
});
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 "extras" image using a provided prompt and other settings.
*
@ -2775,6 +2880,8 @@ function isValidState() {
return true;
case sources.togetherai:
return secret_state[SECRET_KEYS.TOGETHERAI];
case sources.pollinations:
return true;
}
}
@ -2922,6 +3029,8 @@ jQuery(async () => {
$('#sd_novel_view_anlas').on('click', onViewAnlasClick);
$('#sd_novel_sm').on('input', onNovelSmInput);
$('#sd_novel_sm_dyn').on('input', onNovelSmDynInput);
$('#sd_pollinations_enhance').on('input', onPollinationsEnhanceInput);
$('#sd_pollinations_refine').on('input', onPollinationsRefineInput);
$('#sd_comfy_validate').on('click', validateComfyUrl);
$('#sd_comfy_url').on('input', onComfyUrlInput);
$('#sd_comfy_workflow').on('change', onComfyWorkflowChange);

View File

@ -32,14 +32,15 @@
</label>
<label for="sd_source">Source</label>
<select id="sd_source">
<option value="extras">Extras API (local / remote)</option>
<option value="horde">Stable Horde</option>
<option value="auto">Stable Diffusion Web UI (AUTOMATIC1111)</option>
<option value="vlad">SD.Next (vladmandic)</option>
<option value="comfy">ComfyUI</option>
<option value="drawthings">DrawThings HTTP API</option>
<option value="extras">Extras API (local / remote)</option>
<option value="novel">NovelAI Diffusion</option>
<option value="openai">OpenAI (DALL-E)</option>
<option value="comfy">ComfyUI</option>
<option value="pollinations">Pollinations</option>
<option value="vlad">SD.Next (vladmandic)</option>
<option value="auto">Stable Diffusion Web UI (AUTOMATIC1111)</option>
<option value="horde">Stable Horde</option>
<option value="togetherai">TogetherAI</option>
</select>
<div data-sd-source="auto">
@ -158,6 +159,22 @@
</div>
</div>
</div>
<div data-sd-source="pollinations">
<div class="flex-container">
<label class="flex1 checkbox_label" for="sd_pollinations_enhance">
<input id="sd_pollinations_enhance" type="checkbox" />
<span data-i18n="Enhance">
Enhance
</span>
</label>
<label class="flex1 checkbox_label" for="sd_pollinations_refine">
<input id="sd_pollinations_refine" type="checkbox" />
<span data-i18n="Refine">
Refine
</span>
</label>
</div>
</div>
<label for="sd_scale">CFG Scale (<span id="sd_scale_value"></span>)</label>
<input id="sd_scale" type="range" min="{{scale_min}}" max="{{scale_max}}" step="{{scale_step}}" value="{{scale}}" />
<label for="sd_steps">Sampling steps (<span id="sd_steps_value"></span>)</label>

View File

@ -684,7 +684,7 @@ drawthings.post('/generate', jsonParser, async (request, response) => {
const url = new URL(request.body.url);
url.pathname = '/sdapi/v1/txt2img';
const body = {...request.body};
const body = { ...request.body };
delete body.url;
const result = await fetch(url, {
@ -710,8 +710,46 @@ drawthings.post('/generate', jsonParser, async (request, response) => {
}
});
const pollinations = express.Router();
pollinations.post('/generate', jsonParser, async (request, response) => {
try {
const promptUrl = new URL(`https://image.pollinations.ai/prompt/${encodeURIComponent(request.body.prompt)}`);
const params = new URLSearchParams({
model: String(request.body.model),
negative_prompt: String(request.body.negative_prompt),
seed: String(Math.floor(Math.random() * 10_000_000)),
enhance: String(request.body.enhance ?? false),
refine: String(request.body.refine ?? false),
width: String(request.body.width ?? 1024),
height: String(request.body.height ?? 1024),
nologo: String(true),
nofeed: String(true),
});
promptUrl.search = params.toString();
console.log('Pollinations request URL:', promptUrl.toString());
const result = await fetch(promptUrl);
if (!result.ok) {
console.log('Pollinations returned an error.', result.status, result.statusText);
throw new Error('Pollinations request failed.');
}
const buffer = await result.buffer();
const base64 = buffer.toString('base64');
return response.send({ image: base64 });
} catch (error) {
console.log(error);
return response.sendStatus(500);
}
});
router.use('/comfy', comfy);
router.use('/together', together);
router.use('/drawthings', drawthings);
router.use('/pollinations', pollinations);
module.exports = { router };