gork-imagine Closes #5216

3f8b9998ca5e2bb5081b0f94943e7c2de9caf68c

Cohee <18619528+Cohee1207@users.noreply.github.com>

2 files changed, +43 -5Showing whitespace changes
public/scripts/extensions/stable-diffusion/index.js+32 -2
@@ -2091,6 +2091,8 @@ async function loadFalaiModels() {
20912091
20922092async function loadXAIModels() {
20932093 return [
2094+ { value: 'grok-imagine-image', text: 'grok-imagine-image' },
2095+ { value: 'grok-imagine-image-pro', text: 'grok-imagine-image-pro' },
20942096 { value: 'grok-2-image-1212', text: 'grok-2-image-1212' },
20952097 ];
20962098}
@@ -3547,7 +3549,7 @@ async function generateExtrasImage(prompt, negativePrompt, signal) {
35473549 * Gets an aspect ratio for Stability that is the closest to the given width and height.
35483550 * @param {number} width Target width
35493551 * @param {number} height Target height
35503552 * @param {'google'|'stability'|'zai'|'xai'} source Source of the request, used to determine aspect ratio
35513553 * @returns {string} Closest aspect ratio as a string
35523554 */
35533555function getClosestAspectRatio(width, height, source) {
@@ -3579,6 +3581,22 @@ function getClosestAspectRatio(width, height, source) {
35793581 '16:9': 16 / 9,
35803582 '9:16': 9 / 16,
35813583 };
3584+ case 'xai':
3585+ return {
3586+ '1:1': 1,
3587+ '3:4': 3 / 4,
3588+ '4:3': 4 / 3,
3589+ '9:16': 9 / 16,
3590+ '16:9': 16 / 9,
3591+ '2:3': 2 / 3,
3592+ '3:2': 3 / 2,
3593+ '9:19.5': 9 / 19.5,
3594+ '19.5:9': 19.5 / 9,
3595+ '9:20': 9 / 20,
3596+ '20:9': 20 / 9,
3597+ '1:2': 1 / 2,
3598+ '2:1': 2 / 1,
3599+ };
35823600 default:
35833601 console.warn(`Unknown source "${source}" for aspect ratio calculation.`);
35843602 return null;
@@ -4464,6 +4482,16 @@ async function generateBflImage(prompt, signal) {
44644482 * @returns {Promise<{format: string, data: string}>} A promise that resolves when the image generation and processing are complete.
44654483 */
44664484async function generateXAIImage(prompt, _negativePrompt, signal) {
4485+ let aspectRatio;
4486+ let resolution;
4487+
4488+ if (/grok-imagine/.test(extension_settings.sd.model)) {
4489+ const resolutionThreshold = 1296 * 864;
4490+ const use2kResolution = (extension_settings.sd.width * extension_settings.sd.height) > resolutionThreshold;
4491+ aspectRatio = getClosestAspectRatio(extension_settings.sd.width, extension_settings.sd.height, 'xai');
4492+ resolution = use2kResolution ? '2k' : '1k';
4493+ }
4494+
44674495 const result = await fetch('/api/sd/xai/generate', {
44684496 method: 'POST',
44694497 headers: getRequestHeaders(),
@@ -4471,12 +4499,14 @@ async function generateXAIImage(prompt, _negativePrompt, signal) {
44714499 body: JSON.stringify({
44724500 prompt: prompt,
44734501 model: extension_settings.sd.model,
4502+ aspect_ratio: aspectRatio,
4503+ resolution: resolution,
44744504 }),
44754505 });
44764506
44774507 if (result.ok) {
44784508 const data = await result.json();
44794509 return { format: 'jpg'data.format, data: data.image };
44804510 } else {
44814511 const text = await result.text();
44824512 throw new Error(text);
src/endpoints/stable-diffusion.js+11 -3
@@ -1723,6 +1723,8 @@ xai.post('/generate', async (request, response) => {
17231723 const requestBody = {
17241724 prompt: request.body.prompt,
17251725 model: request.body.model,
1726+ aspect_ratio: request.body.aspect_ratio,
1727+ resolution: request.body.resolution,
17261728 response_format: 'b64_json',
17271729 };
17281730
@@ -1746,13 +1748,19 @@ xai.post('/generate', async (request, response) => {
17461748 /** @type {any} */
17471749 const data = await result.json();
17481750
1749- const image = data?.data?.[0]?.b64_json;
1751+ // Can either be a base64 buffer (always JPEG) or a data URL (with MIME type)
1750- if (!image) {
1752+ const encodedImage = String(data?.data?.[0]?.b64_json || '');
1753+ if (!encodedImage) {
17511754 console.warn('xAI returned invalid data.');
17521755 return response.sendStatus(500);
17531756 }
17541757
1755- return response.send({ image });
1758+ const dataUrlMatch = encodedImage.match(/^data:(.+);base64,(.+)$/);
1759+ const mimeType = dataUrlMatch?.[1] || 'image/jpeg';
1760+ const format = mime.extension(mimeType) || 'jpg';
1761+ const image = dataUrlMatch?.[2] || encodedImage;
1762+
1763+ return response.send({ image, format });
17561764 } catch (error) {
17571765 console.error('Error communicating with xAI', error);
17581766 return response.sendStatus(500);