Stable diffusion.cpp server support (#5074) * feat: Add stable-diffusion.cpp server endpoints * feat: Add stable-diffusion.cpp server settings * feat: Add stable-diffusion.cpp server * Add debug log for sdcpp payload * feat: add loadSdcppSamplers and loadSdcppSchedulers for sdcpp backend * feat: add sdcpp to sampler and scheduler source lists --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
Signed| @@ -79,6 +79,7 @@ const sources = { | |||
| 79 | extras: 'extras', | 79 | extras: 'extras', |
| 80 | horde: 'horde', | 80 | horde: 'horde', |
| 81 | auto: 'auto', | 81 | auto: 'auto', |
| 82 | sdcpp: 'sdcpp', | ||
| 82 | novel: 'novel', | 83 | novel: 'novel', |
| 83 | vlad: 'vlad', | 84 | vlad: 'vlad', |
| 84 | openai: 'openai', | 85 | openai: 'openai', |
| @@ -290,6 +291,9 @@ const defaultSettings = { | |||
| 290 | auto_url: 'http://localhost:7860', | 291 | auto_url: 'http://localhost:7860', |
| 291 | auto_auth: '', | 292 | auto_auth: '', |
| 292 | 293 | ||
| 294 | // stable-diffusion.cpp settings | ||
| 295 | sdcpp_url: 'http://127.0.0.1:1234', | ||
| 296 | |||
| 293 | vlad_url: 'http://localhost:7860', | 297 | vlad_url: 'http://localhost:7860', |
| 294 | vlad_auth: '', | 298 | vlad_auth: '', |
| 295 | 299 | ||
| @@ -528,6 +532,7 @@ async function loadSettings() { | |||
| 528 | $('#sd_multimodal_captioning').prop('checked', extension_settings.sd.multimodal_captioning); | 532 | $('#sd_multimodal_captioning').prop('checked', extension_settings.sd.multimodal_captioning); |
| 529 | $('#sd_auto_url').val(extension_settings.sd.auto_url); | 533 | $('#sd_auto_url').val(extension_settings.sd.auto_url); |
| 530 | $('#sd_auto_auth').val(extension_settings.sd.auto_auth); | 534 | $('#sd_auto_auth').val(extension_settings.sd.auto_auth); |
| 535 | $('#sd_sdcpp_url').val(extension_settings.sd.sdcpp_url); | ||
| 531 | $('#sd_vlad_url').val(extension_settings.sd.vlad_url); | 536 | $('#sd_vlad_url').val(extension_settings.sd.vlad_url); |
| 532 | $('#sd_vlad_auth').val(extension_settings.sd.vlad_auth); | 537 | $('#sd_vlad_auth').val(extension_settings.sd.vlad_auth); |
| 533 | $('#sd_drawthings_url').val(extension_settings.sd.drawthings_url); | 538 | $('#sd_drawthings_url').val(extension_settings.sd.drawthings_url); |
| @@ -1156,6 +1161,11 @@ function onAutoAuthInput() { | |||
| 1156 | saveSettingsDebounced(); | 1161 | saveSettingsDebounced(); |
| 1157 | } | 1162 | } |
| 1158 | 1163 | ||
| 1164 | function onSdcppUrlInput() { | ||
| 1165 | extension_settings.sd.sdcpp_url = $('#sd_sdcpp_url').val(); | ||
| 1166 | saveSettingsDebounced(); | ||
| 1167 | } | ||
| 1168 | |||
| 1159 | function onVladUrlInput() { | 1169 | function onVladUrlInput() { |
| 1160 | extension_settings.sd.vlad_url = $('#sd_vlad_url').val(); | 1170 | extension_settings.sd.vlad_url = $('#sd_vlad_url').val(); |
| 1161 | saveSettingsDebounced(); | 1171 | saveSettingsDebounced(); |
| @@ -1264,6 +1274,29 @@ async function validateAutoUrl() { | |||
| 1264 | } | 1274 | } |
| 1265 | } | 1275 | } |
| 1266 | 1276 | ||
| 1277 | async function validateSdcppUrl() { | ||
| 1278 | try { | ||
| 1279 | if (!extension_settings.sd.sdcpp_url) { | ||
| 1280 | throw new Error('URL is not set.'); | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | const result = await fetch('/api/sd/sdcpp/ping', { | ||
| 1284 | method: 'POST', | ||
| 1285 | headers: getRequestHeaders(), | ||
| 1286 | body: JSON.stringify({ url: extension_settings.sd.sdcpp_url }), | ||
| 1287 | }); | ||
| 1288 | |||
| 1289 | if (!result.ok) { | ||
| 1290 | throw new Error('stable-diffusion.cpp server returned an error.'); | ||
| 1291 | } | ||
| 1292 | |||
| 1293 | await loadSettingOptions(); | ||
| 1294 | toastr.success('stable-diffusion.cpp server connected.'); | ||
| 1295 | } catch (error) { | ||
| 1296 | toastr.error(`Could not validate stable-diffusion.cpp server: ${error.message}`); | ||
| 1297 | } | ||
| 1298 | } | ||
| 1299 | |||
| 1267 | async function validateDrawthingsUrl() { | 1300 | async function validateDrawthingsUrl() { |
| 1268 | try { | 1301 | try { |
| 1269 | if (!extension_settings.sd.drawthings_url) { | 1302 | if (!extension_settings.sd.drawthings_url) { |
| @@ -1557,6 +1590,9 @@ async function loadSamplers() { | |||
| 1557 | case sources.auto: | 1590 | case sources.auto: |
| 1558 | samplers = await loadAutoSamplers(); | 1591 | samplers = await loadAutoSamplers(); |
| 1559 | break; | 1592 | break; |
| 1593 | case sources.sdcpp: | ||
| 1594 | samplers = await loadSdcppSamplers(); | ||
| 1595 | break; | ||
| 1560 | case sources.drawthings: | 1596 | case sources.drawthings: |
| 1561 | samplers = await loadDrawthingsSamplers(); | 1597 | samplers = await loadDrawthingsSamplers(); |
| 1562 | break; | 1598 | break; |
| @@ -1682,6 +1718,11 @@ async function loadAutoSamplers() { | |||
| 1682 | } | 1718 | } |
| 1683 | } | 1719 | } |
| 1684 | 1720 | ||
| 1721 | async function loadSdcppSamplers() { | ||
| 1722 | // The sdcpp server does not provide an API for samplers, so we return the known list. | ||
| 1723 | return ['euler', 'euler_a', 'heun', 'dpm2', 'dpm++2s_a', 'dpm++2m', 'dpm++2mv2', 'ipndm', 'ipndm_v', 'lcm', 'ddim_trailing', 'tcd']; | ||
| 1724 | } | ||
| 1725 | |||
| 1685 | async function loadDrawthingsSamplers() { | 1726 | async function loadDrawthingsSamplers() { |
| 1686 | // The app developer doesn't provide an API to get these yet | 1727 | // The app developer doesn't provide an API to get these yet |
| 1687 | return [ | 1728 | return [ |
| @@ -1771,6 +1812,9 @@ async function loadModels() { | |||
| 1771 | case sources.auto: | 1812 | case sources.auto: |
| 1772 | models = await loadAutoModels(); | 1813 | models = await loadAutoModels(); |
| 1773 | break; | 1814 | break; |
| 1815 | case sources.sdcpp: | ||
| 1816 | models = [{ value: '', text: 'N/A' }]; | ||
| 1817 | break; | ||
| 1774 | case sources.drawthings: | 1818 | case sources.drawthings: |
| 1775 | models = await loadDrawthingsModels(); | 1819 | models = await loadDrawthingsModels(); |
| 1776 | break; | 1820 | break; |
| @@ -2379,6 +2423,9 @@ async function loadSchedulers() { | |||
| 2379 | case sources.auto: | 2423 | case sources.auto: |
| 2380 | schedulers = await getAutoRemoteSchedulers(); | 2424 | schedulers = await getAutoRemoteSchedulers(); |
| 2381 | break; | 2425 | break; |
| 2426 | case sources.sdcpp: | ||
| 2427 | schedulers = await loadSdcppSchedulers(); | ||
| 2428 | break; | ||
| 2382 | case sources.novel: | 2429 | case sources.novel: |
| 2383 | schedulers = loadNovelSchedulers(); | 2430 | schedulers = loadNovelSchedulers(); |
| 2384 | break; | 2431 | break; |
| @@ -2477,6 +2524,11 @@ async function loadComfySchedulers() { | |||
| 2477 | } | 2524 | } |
| 2478 | } | 2525 | } |
| 2479 | 2526 | ||
| 2527 | async function loadSdcppSchedulers() { | ||
| 2528 | // The sdcpp server does not provide an API for schedulers, so we return the known list. | ||
| 2529 | return ['discrete', 'karras', 'exponential', 'ays', 'gits', 'smoothstep', 'sgm_uniform', 'simple', 'kl_optimal', 'lcm']; | ||
| 2530 | } | ||
| 2531 | |||
| 2480 | async function loadVaes() { | 2532 | async function loadVaes() { |
| 2481 | $('#sd_vae').empty(); | 2533 | $('#sd_vae').empty(); |
| 2482 | let vaes = []; | 2534 | let vaes = []; |
| @@ -2491,6 +2543,9 @@ async function loadVaes() { | |||
| 2491 | case sources.auto: | 2543 | case sources.auto: |
| 2492 | vaes = await loadAutoVaes(); | 2544 | vaes = await loadAutoVaes(); |
| 2493 | break; | 2545 | break; |
| 2546 | case sources.sdcpp: | ||
| 2547 | vaes = ['N/A']; | ||
| 2548 | break; | ||
| 2494 | case sources.novel: | 2549 | case sources.novel: |
| 2495 | vaes = ['N/A']; | 2550 | vaes = ['N/A']; |
| 2496 | break; | 2551 | break; |
| @@ -3166,6 +3221,9 @@ async function sendGenerationRequest(generationType, prompt, additionalNegativeP | |||
| 3166 | case sources.auto: | 3221 | case sources.auto: |
| 3167 | result = await generateAutoImage(prefixedPrompt, negativePrompt, signal); | 3222 | result = await generateAutoImage(prefixedPrompt, negativePrompt, signal); |
| 3168 | break; | 3223 | break; |
| 3224 | case sources.sdcpp: | ||
| 3225 | result = await generateSdcppImage(prefixedPrompt, negativePrompt, signal); | ||
| 3226 | break; | ||
| 3169 | case sources.novel: | 3227 | case sources.novel: |
| 3170 | result = await generateNovelImage(prefixedPrompt, negativePrompt, signal); | 3228 | result = await generateNovelImage(prefixedPrompt, negativePrompt, signal); |
| 3171 | break; | 3229 | break; |
| @@ -3654,6 +3712,55 @@ async function generateAutoImage(prompt, negativePrompt, signal) { | |||
| 3654 | } | 3712 | } |
| 3655 | 3713 | ||
| 3656 | /** | 3714 | /** |
| 3715 | * Generates an image using stable-diffusion.cpp server API. | ||
| 3716 | * | ||
| 3717 | * @param {string} prompt - The main instruction used to guide the image generation. | ||
| 3718 | * @param {string} negativePrompt - The instruction used to restrict the image generation. | ||
| 3719 | * @param {AbortSignal} signal - An AbortSignal object that can be used to cancel the request. | ||
| 3720 | * @returns {Promise<{format: string, data: string}>} - A promise that resolves when the image generation and processing are complete. | ||
| 3721 | */ | ||
| 3722 | async function generateSdcppImage(prompt, negativePrompt, signal) { | ||
| 3723 | const payload = { | ||
| 3724 | url: extension_settings.sd.sdcpp_url, | ||
| 3725 | prompt: prompt, | ||
| 3726 | negative_prompt: negativePrompt, | ||
| 3727 | steps: extension_settings.sd.steps, | ||
| 3728 | cfg_scale: extension_settings.sd.scale, | ||
| 3729 | width: extension_settings.sd.width, | ||
| 3730 | height: extension_settings.sd.height, | ||
| 3731 | batch_size: 1, | ||
| 3732 | seed: extension_settings.sd.seed >= 0 ? extension_settings.sd.seed : undefined, | ||
| 3733 | }; | ||
| 3734 | |||
| 3735 | if (extension_settings.sd.sampler && extension_settings.sd.sampler !== 'N/A') { | ||
| 3736 | payload.sampler_name = extension_settings.sd.sampler; | ||
| 3737 | } | ||
| 3738 | |||
| 3739 | if (extension_settings.sd.scheduler && extension_settings.sd.scheduler !== 'N/A') { | ||
| 3740 | payload.scheduler = extension_settings.sd.scheduler; | ||
| 3741 | } | ||
| 3742 | |||
| 3743 | if (Number.isFinite(extension_settings.sd.clip_skip)) { | ||
| 3744 | payload.clip_skip = extension_settings.sd.clip_skip; | ||
| 3745 | } | ||
| 3746 | |||
| 3747 | const result = await fetch('/api/sd/sdcpp/generate', { | ||
| 3748 | method: 'POST', | ||
| 3749 | headers: getRequestHeaders(), | ||
| 3750 | signal: signal, | ||
| 3751 | body: JSON.stringify(payload), | ||
| 3752 | }); | ||
| 3753 | |||
| 3754 | if (result.ok) { | ||
| 3755 | const data = await result.json(); | ||
| 3756 | return { format: 'png', data: data.images?.[0] }; | ||
| 3757 | } else { | ||
| 3758 | const text = await result.text(); | ||
| 3759 | throw new Error(text); | ||
| 3760 | } | ||
| 3761 | } | ||
| 3762 | |||
| 3763 | /** | ||
| 3657 | * Generates an image in Drawthings API using the provided prompt and configuration settings. | 3764 | * Generates an image in Drawthings API using the provided prompt and configuration settings. |
| 3658 | * | 3765 | * |
| 3659 | * @param {string} prompt - The main instruction used to guide the image generation. | 3766 | * @param {string} prompt - The main instruction used to guide the image generation. |
| @@ -4736,6 +4843,8 @@ function isValidState() { | |||
| 4736 | return true; | 4843 | return true; |
| 4737 | case sources.auto: | 4844 | case sources.auto: |
| 4738 | return !!extension_settings.sd.auto_url; | 4845 | return !!extension_settings.sd.auto_url; |
| 4846 | case sources.sdcpp: | ||
| 4847 | return !!extension_settings.sd.sdcpp_url; | ||
| 4739 | case sources.drawthings: | 4848 | case sources.drawthings: |
| 4740 | return !!extension_settings.sd.drawthings_url; | 4849 | return !!extension_settings.sd.drawthings_url; |
| 4741 | case sources.vlad: | 4850 | case sources.vlad: |
| @@ -5418,6 +5527,8 @@ jQuery(async () => { | |||
| 5418 | $('#sd_auto_validate').on('click', validateAutoUrl); | 5527 | $('#sd_auto_validate').on('click', validateAutoUrl); |
| 5419 | $('#sd_auto_url').on('input', onAutoUrlInput); | 5528 | $('#sd_auto_url').on('input', onAutoUrlInput); |
| 5420 | $('#sd_auto_auth').on('input', onAutoAuthInput); | 5529 | $('#sd_auto_auth').on('input', onAutoAuthInput); |
| 5530 | $('#sd_sdcpp_validate').on('click', validateSdcppUrl); | ||
| 5531 | $('#sd_sdcpp_url').on('input', onSdcppUrlInput); | ||
| 5421 | $('#sd_drawthings_validate').on('click', validateDrawthingsUrl); | 5532 | $('#sd_drawthings_validate').on('click', validateDrawthingsUrl); |
| 5422 | $('#sd_drawthings_url').on('input', onDrawthingsUrlInput); | 5533 | $('#sd_drawthings_url').on('input', onDrawthingsUrlInput); |
| 5423 | $('#sd_drawthings_auth').on('input', onDrawthingsAuthInput); | 5534 | $('#sd_drawthings_auth').on('input', onDrawthingsAuthInput); |
| @@ -55,6 +55,7 @@ | |||
| 55 | <option value="vlad">SD.Next (vladmandic)</option> | 55 | <option value="vlad">SD.Next (vladmandic)</option> |
| 56 | <option value="stability">Stability AI</option> | 56 | <option value="stability">Stability AI</option> |
| 57 | <option value="auto">Stable Diffusion Web UI (AUTOMATIC1111)</option> | 57 | <option value="auto">Stable Diffusion Web UI (AUTOMATIC1111)</option> |
| 58 | <option value="sdcpp">stable-diffusion.cpp server</option> | ||
| 58 | <option value="horde">Stable Horde</option> | 59 | <option value="horde">Stable Horde</option> |
| 59 | <option value="togetherai">TogetherAI</option> | 60 | <option value="togetherai">TogetherAI</option> |
| 60 | <option value="xai">xAI (Grok)</option> | 61 | <option value="xai">xAI (Grok)</option> |
| @@ -76,6 +77,19 @@ | |||
| 76 | <!-- (Original Text)<b>Important:</b> run SD Web UI with the <tt>--api</tt> flag! The server must be accessible from the SillyTavern host machine. --> | 77 | <!-- (Original Text)<b>Important:</b> run SD Web UI with the <tt>--api</tt> flag! The server must be accessible from the SillyTavern host machine. --> |
| 77 | <i><b data-i18n="Important:">Important:</b></i><i data-i18n="sd_auto_auth_warning_1"> run SD Web UI with the </i><i><tt>--api</tt></i><i data-i18n="sd_auto_auth_warning_2"> flag! The server must be accessible from the SillyTavern host machine.</i> | 78 | <i><b data-i18n="Important:">Important:</b></i><i data-i18n="sd_auto_auth_warning_1"> run SD Web UI with the </i><i><tt>--api</tt></i><i data-i18n="sd_auto_auth_warning_2"> flag! The server must be accessible from the SillyTavern host machine.</i> |
| 78 | </div> | 79 | </div> |
| 80 | <div data-sd-source="sdcpp"> | ||
| 81 | <label for="sd_sdcpp_url">stable-diffusion.cpp URL</label> | ||
| 82 | <div class="flex-container flexnowrap"> | ||
| 83 | <input id="sd_sdcpp_url" type="text" class="text_pole" placeholder="Example: {{sdcpp_url}}" value="{{sdcpp_url}}" /> | ||
| 84 | <div id="sd_sdcpp_validate" class="menu_button menu_button_icon"> | ||
| 85 | <i class="fa-solid fa-check"></i> | ||
| 86 | <span data-i18n="Connect"> | ||
| 87 | Connect | ||
| 88 | </span> | ||
| 89 | </div> | ||
| 90 | </div> | ||
| 91 | <i data-i18n="The server must be accessible from the SillyTavern host machine.">The server must be accessible from the SillyTavern host machine.</i> | ||
| 92 | </div> | ||
| 79 | <div data-sd-source="drawthings"> | 93 | <div data-sd-source="drawthings"> |
| 80 | <label for="sd_drawthings_url">DrawThings API URL</label> | 94 | <label for="sd_drawthings_url">DrawThings API URL</label> |
| 81 | <div class="flex-container flexnowrap"> | 95 | <div class="flex-container flexnowrap"> |
| @@ -395,12 +409,12 @@ | |||
| 395 | </div> | 409 | </div> |
| 396 | 410 | ||
| 397 | <div class="flex-container"> | 411 | <div class="flex-container"> |
| 398 | <div class="flex1" data-sd-source="extras,horde,auto,drawthings,novel,vlad,comfy"> | 412 | <div class="flex1" data-sd-source="extras,horde,auto,drawthings,novel,vlad,comfy,sdcpp"> |
| 399 | <label for="sd_sampler" data-i18n="Sampling method">Sampling method</label> | 413 | <label for="sd_sampler" data-i18n="Sampling method">Sampling method</label> |
| 400 | <select id="sd_sampler"></select> | 414 | <select id="sd_sampler"></select> |
| 401 | </div> | 415 | </div> |
| 402 | 416 | ||
| 403 | <div class="flex1" data-sd-source="comfy,auto,novel"> | 417 | <div class="flex1" data-sd-source="comfy,auto,novel,sdcpp"> |
| 404 | <label for="sd_scheduler" data-i18n="Scheduler">Scheduler</label> | 418 | <label for="sd_scheduler" data-i18n="Scheduler">Scheduler</label> |
| 405 | <select id="sd_scheduler"></select> | 419 | <select id="sd_scheduler"></select> |
| 406 | </div> | 420 | </div> |
| @@ -483,7 +497,7 @@ | |||
| 483 | <input class="neo-range-input" type="number" id="sd_hr_second_pass_steps_value" data-for="sd_hr_second_pass_steps" max="{{hr_second_pass_steps_max}}" step="{{hr_second_pass_steps_step}}" value="{{hr_second_pass_steps}}" > | 497 | <input class="neo-range-input" type="number" id="sd_hr_second_pass_steps_value" data-for="sd_hr_second_pass_steps" max="{{hr_second_pass_steps_max}}" step="{{hr_second_pass_steps_step}}" value="{{hr_second_pass_steps}}" > |
| 484 | </div> | 498 | </div> |
| 485 | 499 | ||
| 486 | <div class="alignitemscenter flex-container flexFlowColumn flexGrow flexShrink gap0 flexBasis48p" data-sd-source="auto,vlad,comfy,horde,drawthings,extras"> | 500 | <div class="alignitemscenter flex-container flexFlowColumn flexGrow flexShrink gap0 flexBasis48p" data-sd-source="auto,vlad,comfy,horde,drawthings,extras,sdcpp"> |
| 487 | <small> | 501 | <small> |
| 488 | <span data-i18n="CLIP Skip">CLIP Skip</span> | 502 | <span data-i18n="CLIP Skip">CLIP Skip</span> |
| 489 | </small> | 503 | </small> |
| @@ -537,7 +551,7 @@ | |||
| 537 | </label> | 551 | </label> |
| 538 | </div> | 552 | </div> |
| 539 | 553 | ||
| 540 | <div data-sd-source="novel,togetherai,pollinations,comfy,drawthings,vlad,auto,horde,extras,stability,bfl" class="marginTop5"> | 554 | <div data-sd-source="novel,togetherai,pollinations,comfy,drawthings,vlad,auto,horde,extras,stability,bfl,sdcpp" class="marginTop5"> |
| 541 | <label for="sd_seed"> | 555 | <label for="sd_seed"> |
| 542 | <span data-i18n="Seed">Seed</span> | 556 | <span data-i18n="Seed">Seed</span> |
| 543 | <small data-i18n="(-1 for random)">(-1 for random)</small> | 557 | <small data-i18n="(-1 for random)">(-1 for random)</small> |
| @@ -801,6 +801,73 @@ together.post('/generate', async (request, response) => { | |||
| 801 | } | 801 | } |
| 802 | }); | 802 | }); |
| 803 | 803 | ||
| 804 | const sdcpp = express.Router(); | ||
| 805 | |||
| 806 | sdcpp.post('/ping', async (request, response) => { | ||
| 807 | try { | ||
| 808 | const url = new URL(request.body.url); | ||
| 809 | url.pathname = '/v1/images/generations'; | ||
| 810 | |||
| 811 | const result = await fetch(url, { method: 'OPTIONS' }); | ||
| 812 | if (!result.ok) { | ||
| 813 | throw new Error('stable-diffusion.cpp server returned an error.'); | ||
| 814 | } | ||
| 815 | |||
| 816 | return response.sendStatus(200); | ||
| 817 | } catch (error) { | ||
| 818 | console.error(error); | ||
| 819 | return response.sendStatus(500); | ||
| 820 | } | ||
| 821 | }); | ||
| 822 | |||
| 823 | sdcpp.post('/generate', async (request, response) => { | ||
| 824 | try { | ||
| 825 | const url = new URL(request.body.url); | ||
| 826 | url.pathname = '/sdapi/v1/txt2img'; | ||
| 827 | |||
| 828 | const payload = { | ||
| 829 | prompt: request.body.prompt, | ||
| 830 | negative_prompt: request.body.negative_prompt, | ||
| 831 | width: request.body.width, | ||
| 832 | height: request.body.height, | ||
| 833 | steps: request.body.steps, | ||
| 834 | cfg_scale: request.body.cfg_scale, | ||
| 835 | seed: request.body.seed, | ||
| 836 | batch_size: request.body.batch_size, | ||
| 837 | sampler_name: request.body.sampler_name, | ||
| 838 | scheduler: request.body.scheduler, | ||
| 839 | clip_skip: request.body.clip_skip, | ||
| 840 | }; | ||
| 841 | |||
| 842 | for (const [key, value] of Object.entries(payload)) { | ||
| 843 | if (value === undefined || value === null || value === '') { | ||
| 844 | delete payload[key]; | ||
| 845 | } | ||
| 846 | } | ||
| 847 | |||
| 848 | console.debug('stable-diffusion.cpp request:', payload); | ||
| 849 | |||
| 850 | const result = await fetch(url, { | ||
| 851 | method: 'POST', | ||
| 852 | body: JSON.stringify(payload), | ||
| 853 | headers: { | ||
| 854 | 'Content-Type': 'application/json', | ||
| 855 | }, | ||
| 856 | }); | ||
| 857 | |||
| 858 | if (!result.ok) { | ||
| 859 | const text = await result.text(); | ||
| 860 | throw new Error('stable-diffusion.cpp server returned an error.', { cause: text }); | ||
| 861 | } | ||
| 862 | |||
| 863 | const data = await result.json(); | ||
| 864 | return response.send(data); | ||
| 865 | } catch (error) { | ||
| 866 | console.error(error); | ||
| 867 | return response.sendStatus(500); | ||
| 868 | } | ||
| 869 | }); | ||
| 870 | |||
| 804 | const drawthings = express.Router(); | 871 | const drawthings = express.Router(); |
| 805 | 872 | ||
| 806 | drawthings.post('/ping', async (request, response) => { | 873 | drawthings.post('/ping', async (request, response) => { |
| @@ -1917,6 +1984,7 @@ zai.post('/generate-video', async (request, response) => { | |||
| 1917 | router.use('/comfy', comfy); | 1984 | router.use('/comfy', comfy); |
| 1918 | router.use('/comfyrunpod', comfyRunPod); | 1985 | router.use('/comfyrunpod', comfyRunPod); |
| 1919 | router.use('/together', together); | 1986 | router.use('/together', together); |
| 1987 | router.use('/sdcpp', sdcpp); | ||
| 1920 | router.use('/drawthings', drawthings); | 1988 | router.use('/drawthings', drawthings); |
| 1921 | router.use('/pollinations', pollinations); | 1989 | router.use('/pollinations', pollinations); |
| 1922 | router.use('/stability', stability); | 1990 | router.use('/stability', stability); |