Changeset 3401075
- Timestamp:
- 11/22/2025 08:03:55 PM (4 months ago)
- Location:
- kaigen
- Files:
-
- 16 edited
- 1 copied
-
tags/v0.2.4 (copied) (copied from kaigen/trunk)
-
tags/v0.2.4/build/index.asset.php (modified) (1 diff)
-
tags/v0.2.4/build/index.js (modified) (1 diff)
-
tags/v0.2.4/inc/class-admin.php (modified) (2 diffs)
-
tags/v0.2.4/inc/class-image-provider.php (modified) (1 diff)
-
tags/v0.2.4/inc/class-rest-api.php (modified) (4 diffs)
-
tags/v0.2.4/inc/providers/class-image-provider-openai.php (modified) (9 diffs)
-
tags/v0.2.4/inc/providers/class-image-provider-replicate.php (modified) (4 diffs)
-
tags/v0.2.4/kaigen.php (modified) (1 diff)
-
trunk/build/index.asset.php (modified) (1 diff)
-
trunk/build/index.js (modified) (1 diff)
-
trunk/inc/class-admin.php (modified) (2 diffs)
-
trunk/inc/class-image-provider.php (modified) (1 diff)
-
trunk/inc/class-rest-api.php (modified) (4 diffs)
-
trunk/inc/providers/class-image-provider-openai.php (modified) (9 diffs)
-
trunk/inc/providers/class-image-provider-replicate.php (modified) (4 diffs)
-
trunk/kaigen.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
kaigen/tags/v0.2.4/build/index.asset.php
r3361350 r3401075 1 <?php return array('dependencies' => array('react', 'wp-api-fetch', 'wp-block-editor', 'wp-components', 'wp-data', 'wp-element', 'wp-hooks', 'wp-rich-text'), 'version' => 'fd cac31f2e1ee5e68851');1 <?php return array('dependencies' => array('react', 'wp-api-fetch', 'wp-block-editor', 'wp-components', 'wp-data', 'wp-element', 'wp-hooks', 'wp-rich-text'), 'version' => 'fd9194ab12765b897e21'); -
kaigen/tags/v0.2.4/build/index.js
r3361350 r3401075 1 (()=>{"use strict";var e={n:t=>{var a=t&&t.__esModule?()=>t.default:()=>t;return e.d(a,{a}),a},d:(t,a)=>{for(var r in a)e.o(a,r)&&!e.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:a[r]})}};e.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),e.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var t;e.g.importScripts&&(t=e.g.location+"");var a=e.g.document;if(!t&&a&&(a.currentScript&&(t=a.currentScript.src),!t)){var r=a.getElementsByTagName("script");if(r.length)for(var n=r.length-1;n>-1&&(!t||!/^http(s?):/.test(t));)t=r[n--].src}if(!t)throw new Error("Automatic publicPath is not supported in this browser");t=t.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),e.p=t})();const t=window.React,a=window.wp.element,r=window.wp.components,n=e.p+"images/KaiGen-logo-128x128.44b1814b.png",o=async(e,t,a={})=>{try{const r=wp.data.select("core/editor")?.getEditorSettings()?.kaigen_provider;if(!r)throw new Error("No provider configured. Please check your plugin settings.");const n=wp.data.select("core/editor")?.getEditorSettings()?.kaigen_has_api_key;if(!n)throw new Error("No API key configured for the selected provider. Please add one in the KaiGen settings.");const o={prompt:e,provider:r};a.sourceImageUrl &&(o.source_image_url=a.sourceImageUrl),a.additionalImageUrls&&Array.isArray(a.additionalImageUrls)&&(o.additional_image_urls=a.additionalImageUrls),a.maskUrl&&(o.mask_url=a.maskUrl),a.moderation&&["auto","low"].includes(a.moderation)&&(o.moderation=a.moderation),a.style&&["natural","vivid"].includes(a.style)&&(o.style=a.style),a.aspectRatio&&["1:1","16:9","9:16","4:3","3:4"].includes(a.aspectRatio)&&(o.aspect_ratio=a.aspectRatio);const i=await wp.apiFetch({path:"/kaigen/v1/generate-image",method:"POST",data:o});if(i.code&&i.message){if("content_moderation"===i.code)throw new Error(i.message);if("replicate_error"===i.code)throw new Error("Image generation failed: "+i.message);throw new Error(i.message)}if(!i||!i.url)throw new Error("Invalid response from server: "+JSON.stringify(i));i.id&&"number"==typeof i.id&&i.id>0?t({url:i.url,alt:e,id:i.id,caption:""}):t({url:i.url,alt:e,caption:""})}catch(e){console.error("Image generation failed:",e),e.message&&console.error("Error message:",e.message),e.stack&&console.error("Error stack:",e.stack),t({error:e.message||"An unknown error occurred while generating the image"})}},i=({onSelect:e,shouldDisplay:i})=>{const[l,c]=(0,a.useState)(!1),[s,d]=(0,a.useState)(""),[m,g]=(0,a.useState)(!1),[u,p]=(0,a.useState)(null),[k,b]=(0,a.useState)([]),[w,E]=(0,a.useState)(null),[f,h]=(0,a.useState)("1:1"),y=window.kaiGen?.supportsImageToImage||!1;(0,a.useEffect)((()=>{l&&y&&(async()=>{try{const e=await wp.apiFetch({path:"/kaigen/v1/reference-images",method:"GET"});return Array.isArray(e)?e:[]}catch(e){return console.error("Failed to fetch reference images:",e),[]}})().then(b)}),[l]);const v=()=>{if(!s.trim())return void p("Please enter a prompt for image generation.");g(!0),p(null);const t={};w&&(t.sourceImageUrl=w.url),f&&(t.aspectRatio=f),o(s.trim(),(t=>{t.error?(p(t.error),g(!1)):(e(t),g(!1),c(!1))}),t)};return i?(0,t.createElement)(t.Fragment,null,(0,t.createElement)(r.Button,{onClick:()=>c(!0),className:"kaigen-placeholder-button","aria-label":"KaiGen",role:"button",title:"KaiGen",style:{order:10}},(0,t.createElement)("img",{src:n,alt:"KaiGen","aria-label":"KaiGen logo",role:"button",title:"KaiGen logo",style:{width:"64px",height:"64px"}})),l&&(0,t.createElement)(r.Modal,{className:"kaigen-modal",title:(0,t.createElement)("div",{className:"kaigen-modal__logo-container"},(0,t.createElement)("img",{src:n,alt:"KaiGen logo",className:"kaigen-modal__logo"})),"aria-label":"KaiGen",onRequestClose:()=>c(!1)},u&&(0,t.createElement)("p",{className:"kaigen-error-text"},u),(0,t.createElement)("div",{className:"kaigen-modal__input-container"},y&&k.length>0&&(0,t.createElement)(r.Dropdown,{onFocusOutside:()=>setIsOpen(!1),popoverProps:{placement:"bottom-start",focusOnMount:!0},renderToggle:({isOpen:e,onToggle:a})=>(0,t.createElement)(r.Button,{className:"kaigen-modal__ref-button "+(w?"kaigen-ref-button-selected":""),onClick:a,"aria-expanded":e,"aria-label":"Reference Images"},(0,t.createElement)(r.Dashicon,{icon:"format-image",className:w?"kaigen-ref-button-icon-selected":""})),renderContent:()=>(0,t.createElement)("div",{className:"kaigen-modal-dropdown-content-container"},(0,t.createElement)("h4",{className:"kaigen-modal-dropdown-content-title"},"Reference Images"),(0,t.createElement)("div",{className:"kaigen-modal-reference-images-container"},k.map((e=>(0,t.createElement)("img",{key:e.id,src:e.url,alt:e.alt||"",onClick:()=>w&&w.id===e.id?E(null):E(e),className:"kaigen-modal-reference-image "+(w&&w.id===e.id?"kaigen-modal-reference-image-selected":"")})))))}),(0,t.createElement)("div",{className:"kaigen-modal__textarea-container"},(0,t.createElement)(r.TextareaControl,{className:"kaigen-modal__textarea",placeholder:"Image prompt...",value:s,onChange:d,onKeyDown:e=>{"Enter"!==e.key||e.shiftKey||(e.preventDefault(),v())},rows:2})),s.trim()&&(0,t.createElement)(r.Button,{className:"kaigen-modal__submit-button",variant:"primary",onClick:v,disabled:m||!s.trim(),"aria-label":"Generate Image"},m?(0,t.createElement)(t.Fragment,null,(0,t.createElement)(r.Spinner,null)):(0,t.createElement)(r.Dashicon,{icon:"admin-appearance"})),(0,t.createElement)(r.Dropdown,{onFocusOutside:()=>setIsOpen(!1),popoverProps:{placement:"bottom-end",focusOnMount:!0},renderToggle:({isOpen:e,onToggle:a})=>(0,t.createElement)(r.Button,{className:"kaigen-modal__settings-button",onClick:a,"aria-expanded":e,"aria-label":"Settings"},(0,t.createElement)(r.Dashicon,{icon:"admin-generic"})),renderContent:()=>(0,t.createElement)("div",{className:"kaigen-modal-dropdown-content-container"},(0,t.createElement)("h4",{className:"kaigen-modal-dropdown-content-title"},"Aspect Ratio"),(0,t.createElement)("div",{className:"kaigen-modal-aspect-ratio-container"},[{value:"1:1",label:"1:1",title:"Square"},{value:"16:9",label:"16:9",title:"Landscape"},{value:"9:16",label:"9:16",title:"Portrait"}].map((e=>(0,t.createElement)("div",{key:e.value,onClick:()=>h((t=>t===e.value?null:e.value)),"aria-pressed":f===e.value,"aria-label":`${e.title} (${e.label})`,className:"kaigen-modal__aspect-ratio-button "+(f===e.value?"kaigen-modal__aspect-ratio-button-selected":"")},(0,t.createElement)("div",{className:"kaigen-modal-aspect-ratio-icon-container"},(0,t.createElement)("div",{className:`kaigen-modal-aspect-ratio-icon ${f===e.value?"kaigen-modal-aspect-ratio-icon-selected":""} kaigen-aspect-ratio-${e.value.replace(":","-")}`})),(0,t.createElement)("span",{className:"kaigen-modal-aspect-ratio-label"},e.label))))))})))):null},l=e.p+"images/KaiGen-logo-64x64.a6e617bd.png",c=({isGenerating:e,onGenerateImage:n,isRegenerating:o,onRegenerateImage:i,isImageBlock:c,isTextSelected:s,supportsImageToImage:d})=>{const[m,g]=(0,a.useState)(!1),[u,p]=(0,a.useState)(""),[k,b]=(0,a.useState)(null);return c&&d?(0,t.createElement)(t.Fragment,null,(0,t.createElement)(r.ToolbarGroup,null,(0,t.createElement)(r.ToolbarButton,{icon:o?(0,t.createElement)(r.Spinner,null):(0,t.createElement)("img",{src:l,alt:"KaiGen logo",className:"kaigen-toolbar-icon"}),label:o?"KaiGen is generating...":"KaiGen",onClick:()=>g(!0),disabled:o})),m&&(0,t.createElement)(r.Modal,{title:(0,t.createElement)("img",{src:l,alt:"KaiGen logo",className:"kaigen-modal-logo"}),onRequestClose:()=>{g(!1),p(""),b(null)}},k&&(0,t.createElement)("p",{className:"kaigen-error-text"},k),(0,t.createElement)(r.TextareaControl,{label:"Editing Instructions (optional)",value:u,onChange:p,rows:4}),(0,t.createElement)(r.Button,{variant:"primary",onClick:()=>{i(u.trim()),g(!1),p(""),b(null)},disabled:o},o?(0,t.createElement)(t.Fragment,null,(0,t.createElement)(r.Spinner,null),"Regenerating..."):"Regenerate Image"))):s?(0,t.createElement)(r.ToolbarGroup,null,(0,t.createElement)(r.ToolbarButton,{icon:e?(0,t.createElement)(r.Spinner,null):"format-image",label:e?"KaiGen is generating...":"KaiGen",onClick:n,disabled:e})):null},s=window.wp.blockEditor,d=window.wp.data;(0,window.wp.richText.registerFormatType)("kaigen/custom-format",{title:"AI Image Gen",tagName:"span",className:"kaigen-format",edit:({isActive:e,value:r,onChange:n})=>{const[i,l]=(0,a.useState)(!1),m=(0,d.useSelect)((e=>e("core/block-editor").getSelectedBlock()),[]),{replaceBlocks:g}=(0,d.useDispatch)("core/block-editor"),u=(0,a.useCallback)((()=>{if(m&&"core/paragraph"===m.name){const e=r.text.slice(r.start,r.end).trim();if(!e)return void wp.data.dispatch("core/notices").createErrorNotice("Please select some text to use as the image generation prompt.",{type:"snackbar"});const t=wp.data.select("core/editor")?.getEditorSettings()?.kaigen_provider;if(!t)return void wp.data.dispatch("core/notices").createErrorNotice("No AI provider configured. Please set one in the plugin settings.",{type:"snackbar"});const a=wp.blocks.createBlock("core/heading",{content:"Generating AI image...",level:2,className:"kaigen-text-center"});g(m.clientId,[a,m]),l(!0),o(e,(e=>{if(l(!1),e.error)console.error("Image generation failed:",e.error),wp.data.dispatch("core/notices").createErrorNotice("Failed to generate image: "+e.error,{type:"snackbar"}),g(a.clientId,[]);else{let t={url:e.url,alt:e.alt,caption:""};e.id&&"number"==typeof e.id&&e.id>0&&(t.id=e.id);const r=wp.blocks.createBlock("core/image",t);g(a.clientId,[r])}}))}}),[m,r.text,r.start,r.end,g]),p=""!==r.text.slice(r.start,r.end).trim();return(0,t.createElement)(s.BlockControls,null,(0,t.createElement)(c,{isGenerating:i,onGenerateImage:u,isTextSelected:p}))}});const m=window.wp.hooks;(0,m.addFilter)("editor.MediaUpload","kaigen/add-ai-tab",(e=>a=>{const r=a.allowedTypes&&a.allowedTypes.includes("image")&&!a.multiple,n=wp.data.select("core/block-editor").getSelectedBlock(),o=n&&"core/image"===n.name,l=wp.data.select("core/editor")?.getEditorSettings()?.kaigen_has_api_key,c=r&&o&&!(n&&n.attributes&&n.attributes.url)&&l;return(0,t.createElement)(e,{...a,render:e=>(0,t.createElement)(t.Fragment,null,a.render(e),(0,t.createElement)(i,{onSelect:a.onSelect,shouldDisplay:c}))})}));const g=window.wp.apiFetch;var u=e.n(g);(0,m.addFilter)("editor.BlockEdit","kaigen/add-regenerate-button",(e=>n=>{if("core/image"!==n.name)return(0,t.createElement)(e,{...n});const i=n.attributes.id&&"number"==typeof n.attributes.id&&n.attributes.id>0,[l,d]=(0,a.useState)(!1),[m,g]=(0,a.useState)(null),[p,k]=(0,a.useState)(!1);return(0,a.useEffect)((()=>{(async()=>{try{const e=window.kaiGen?.provider,t=window.kaiGen?.supportsImageToImage||!1;if(!e)return;k(t)}catch(e){console.error("Failed to initialize provider:",e)}})()}),[]),(0,t.createElement)(t.Fragment,null,(0,t.createElement)(e,{...n}),(0,t.createElement)(s.BlockControls,null,(0,t.createElement)(c,{isRegenerating:l,onRegenerateImage:async e=>{g(null);const t=e||n.attributes.alt||"no alt text or prompt, please just enhance",a=window.kaiGen?.provider;if(!a)return console.error("No provider configured"),void wp.data.dispatch("core/notices").createErrorNotice("No AI provider configured. Please check your plugin settings.",{type:"snackbar"});d(!0);try{const e=n.attributes.url,a={};p&&e?a.sourceImageUrl=e:p&&!e&&(console.warn("Image-to-image requested but no source image URL available"),wp.data.dispatch("core/notices").createWarningNotice("Image-to-image generation requires a source image. Please ensure the image is properly loaded.",{type:"snackbar"}));const r=await new Promise(((e,r)=>{o(t,(t=>{t.error?r(new Error(t.error)):e(t)}),a)}));r.id&&"number"==typeof r.id&&r.id>0?n.setAttributes({url:r.url,id:r.id}):n.setAttributes({url:r.url,id:void 0}),wp.data.dispatch("core/notices").createSuccessNotice("Image regenerated successfully!",{type:"snackbar"})}catch(e){console.error("Image regeneration failed:",e);let t=e.message||"Unknown error",a="";t.includes("organization verification")?a=" Please verify your organization in the OpenAI dashboard.":t.includes("parameter")?t="API configuration error. Please contact the plugin developer.":t.includes("content policy")&&(a=" Try a different prompt."),wp.data.dispatch("core/notices").createErrorNotice("Failed to regenerate image: "+t+a,{type:"snackbar"})}finally{d(!1)}},isImageBlock:!0,supportsImageToImage:p})),i&&(0,t.createElement)(s.InspectorControls,null,(0,t.createElement)(r.PanelBody,{title:"KaiGen Settings",initialOpen:!1},(0,t.createElement)(r.CheckboxControl,{label:"Reference image",checked:n.attributes.kaigen_reference_image||!1,onChange:async e=>{n.setAttributes({kaigen_reference_image:e});try{await u()({path:`/wp/v2/media/${n.attributes.id}`,method:"POST",data:{meta:{kaigen_reference_image:e?1:0}}})}catch(e){console.error("Failed to update reference image meta:",e),wp.data.dispatch("core/notices").createErrorNotice("Failed to update reference image meta",{type:"snackbar"})}},help:"Add to the list of reference images."}))))})),(0,m.addFilter)("blocks.registerBlockType","kaigen/add-reference-image-attribute",((e,t)=>"core/image"!==t?e:{...e,attributes:{...e.attributes,kaigen_reference_image:{type:"boolean",default:!1}}}))})();1 (()=>{"use strict";var e={n:t=>{var a=t&&t.__esModule?()=>t.default:()=>t;return e.d(a,{a}),a},d:(t,a)=>{for(var r in a)e.o(a,r)&&!e.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:a[r]})}};e.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),e.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var t;e.g.importScripts&&(t=e.g.location+"");var a=e.g.document;if(!t&&a&&(a.currentScript&&(t=a.currentScript.src),!t)){var r=a.getElementsByTagName("script");if(r.length)for(var n=r.length-1;n>-1&&(!t||!/^http(s?):/.test(t));)t=r[n--].src}if(!t)throw new Error("Automatic publicPath is not supported in this browser");t=t.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),e.p=t})();const t=window.React,a=window.wp.element,r=window.wp.components,n=e.p+"images/KaiGen-logo-128x128.44b1814b.png",o=async(e,t,a={})=>{try{const r=wp.data.select("core/editor")?.getEditorSettings()?.kaigen_provider;if(!r)throw new Error("No provider configured. Please check your plugin settings.");const n=wp.data.select("core/editor")?.getEditorSettings()?.kaigen_has_api_key;if(!n)throw new Error("No API key configured for the selected provider. Please add one in the KaiGen settings.");const o={prompt:e,provider:r};a.sourceImageUrls&&Array.isArray(a.sourceImageUrls)?o.source_image_urls=a.sourceImageUrls:a.sourceImageUrl&&(o.source_image_url=a.sourceImageUrl),a.additionalImageUrls&&Array.isArray(a.additionalImageUrls)&&(o.additional_image_urls=a.additionalImageUrls),a.maskUrl&&(o.mask_url=a.maskUrl),a.moderation&&["auto","low"].includes(a.moderation)&&(o.moderation=a.moderation),a.style&&["natural","vivid"].includes(a.style)&&(o.style=a.style),a.aspectRatio&&["1:1","16:9","9:16","4:3","3:4"].includes(a.aspectRatio)&&(o.aspect_ratio=a.aspectRatio);const i=await wp.apiFetch({path:"/kaigen/v1/generate-image",method:"POST",data:o});if(i.code&&i.message){if("content_moderation"===i.code)throw new Error(i.message);if("replicate_error"===i.code)throw new Error("Image generation failed: "+i.message);throw new Error(i.message)}if(!i||!i.url)throw new Error("Invalid response from server: "+JSON.stringify(i));i.id&&"number"==typeof i.id&&i.id>0?t({url:i.url,alt:e,id:i.id,caption:""}):t({url:i.url,alt:e,caption:""})}catch(e){console.error("Image generation failed:",e),e.message&&console.error("Error message:",e.message),e.stack&&console.error("Error stack:",e.stack),t({error:e.message||"An unknown error occurred while generating the image"})}},i=({onSelect:e,shouldDisplay:i})=>{const[l,c]=(0,a.useState)(!1),[s,d]=(0,a.useState)(""),[m,g]=(0,a.useState)(!1),[u,p]=(0,a.useState)(null),[k,w]=(0,a.useState)([]),[b,h]=(0,a.useState)([]),[E,f]=(0,a.useState)("1:1"),y=window.kaiGen?.supportsImageToImage||!1,v="replicate"===(wp.data.select("core/editor")?.getEditorSettings()?.kaigen_provider||"replicate")?10:16;(0,a.useEffect)((()=>{l&&y&&(async()=>{try{const e=await wp.apiFetch({path:"/kaigen/v1/reference-images",method:"GET"});return Array.isArray(e)?e:[]}catch(e){return console.error("Failed to fetch reference images:",e),[]}})().then(w)}),[l]);const I=()=>{if(!s.trim())return void p("Please enter a prompt for image generation.");g(!0),p(null);const t={};b.length>0&&(t.sourceImageUrls=b.map((e=>e.url))),E&&(t.aspectRatio=E),o(s.trim(),(t=>{t.error?(p(t.error),g(!1)):(e(t),g(!1),c(!1))}),t)};return i?(0,t.createElement)(t.Fragment,null,(0,t.createElement)(r.Button,{onClick:()=>c(!0),className:"kaigen-placeholder-button","aria-label":"KaiGen",role:"button",title:"KaiGen",style:{order:10}},(0,t.createElement)("img",{src:n,alt:"KaiGen","aria-label":"KaiGen logo",role:"button",title:"KaiGen logo",style:{width:"64px",height:"64px"}})),l&&(0,t.createElement)(r.Modal,{className:"kaigen-modal",title:(0,t.createElement)("div",{className:"kaigen-modal__logo-container"},(0,t.createElement)("img",{src:n,alt:"KaiGen logo",className:"kaigen-modal__logo"})),"aria-label":"KaiGen",onRequestClose:()=>c(!1)},u&&(0,t.createElement)("p",{className:"kaigen-error-text"},u),(0,t.createElement)("div",{className:"kaigen-modal__input-container"},y&&k.length>0&&(0,t.createElement)(r.Dropdown,{onFocusOutside:()=>setIsOpen(!1),popoverProps:{placement:"bottom-start",focusOnMount:!0},renderToggle:({isOpen:e,onToggle:a})=>(0,t.createElement)(r.Button,{className:"kaigen-modal__ref-button "+(b.length>0?"kaigen-ref-button-selected":""),onClick:a,"aria-expanded":e,"aria-label":"Reference Images"},(0,t.createElement)(r.Dashicon,{icon:"format-image",className:b.length>0?"kaigen-ref-button-icon-selected":""})),renderContent:()=>(0,t.createElement)("div",{className:"kaigen-modal-dropdown-content-container"},(0,t.createElement)("h4",{className:"kaigen-modal-dropdown-content-title"},"Reference Images (up to ",v,")"),(0,t.createElement)("div",{className:"kaigen-modal-reference-images-container"},k.map((e=>(0,t.createElement)("img",{key:e.id,src:e.url,alt:e.alt||"",onClick:()=>{h((t=>t.some((t=>t.id===e.id))?t.filter((t=>t.id!==e.id)):t.length<v?[...t,e]:t))},className:"kaigen-modal-reference-image "+(b.some((t=>t.id===e.id))?"kaigen-modal-reference-image-selected":"")})))))}),(0,t.createElement)("div",{className:"kaigen-modal__textarea-container"},(0,t.createElement)(r.TextareaControl,{className:"kaigen-modal__textarea",placeholder:"Image prompt...",value:s,onChange:d,onKeyDown:e=>{"Enter"!==e.key||e.shiftKey||(e.preventDefault(),I())},rows:2})),s.trim()&&(0,t.createElement)(r.Button,{className:"kaigen-modal__submit-button",variant:"primary",onClick:I,disabled:m||!s.trim(),"aria-label":"Generate Image"},m?(0,t.createElement)(t.Fragment,null,(0,t.createElement)(r.Spinner,null)):(0,t.createElement)(r.Dashicon,{icon:"admin-appearance"})),(0,t.createElement)(r.Dropdown,{onFocusOutside:()=>setIsOpen(!1),popoverProps:{placement:"bottom-end",focusOnMount:!0},renderToggle:({isOpen:e,onToggle:a})=>(0,t.createElement)(r.Button,{className:"kaigen-modal__settings-button",onClick:a,"aria-expanded":e,"aria-label":"Settings"},(0,t.createElement)(r.Dashicon,{icon:"admin-generic"})),renderContent:()=>(0,t.createElement)("div",{className:"kaigen-modal-dropdown-content-container"},(0,t.createElement)("h4",{className:"kaigen-modal-dropdown-content-title"},"Aspect Ratio"),(0,t.createElement)("div",{className:"kaigen-modal-aspect-ratio-container"},[{value:"1:1",label:"1:1",title:"Square"},{value:"16:9",label:"16:9",title:"Landscape"},{value:"9:16",label:"9:16",title:"Portrait"}].map((e=>(0,t.createElement)("div",{key:e.value,onClick:()=>f((t=>t===e.value?null:e.value)),"aria-pressed":E===e.value,"aria-label":`${e.title} (${e.label})`,className:"kaigen-modal__aspect-ratio-button "+(E===e.value?"kaigen-modal__aspect-ratio-button-selected":"")},(0,t.createElement)("div",{className:"kaigen-modal-aspect-ratio-icon-container"},(0,t.createElement)("div",{className:`kaigen-modal-aspect-ratio-icon ${E===e.value?"kaigen-modal-aspect-ratio-icon-selected":""} kaigen-aspect-ratio-${e.value.replace(":","-")}`})),(0,t.createElement)("span",{className:"kaigen-modal-aspect-ratio-label"},e.label))))))})))):null},l=e.p+"images/KaiGen-logo-64x64.a6e617bd.png",c=({isGenerating:e,onGenerateImage:n,isRegenerating:o,onRegenerateImage:i,isImageBlock:c,isTextSelected:s,supportsImageToImage:d})=>{const[m,g]=(0,a.useState)(!1),[u,p]=(0,a.useState)(""),[k,w]=(0,a.useState)(null);return c&&d?(0,t.createElement)(t.Fragment,null,(0,t.createElement)(r.ToolbarGroup,null,(0,t.createElement)(r.ToolbarButton,{icon:o?(0,t.createElement)(r.Spinner,null):(0,t.createElement)("img",{src:l,alt:"KaiGen logo",className:"kaigen-toolbar-icon"}),label:o?"KaiGen is generating...":"KaiGen",onClick:()=>g(!0),disabled:o})),m&&(0,t.createElement)(r.Modal,{title:(0,t.createElement)("img",{src:l,alt:"KaiGen logo",className:"kaigen-modal-logo"}),onRequestClose:()=>{g(!1),p(""),w(null)}},k&&(0,t.createElement)("p",{className:"kaigen-error-text"},k),(0,t.createElement)(r.TextareaControl,{label:"Editing Instructions (optional)",value:u,onChange:p,rows:4}),(0,t.createElement)(r.Button,{variant:"primary",onClick:()=>{i(u.trim()),g(!1),p(""),w(null)},disabled:o},o?(0,t.createElement)(t.Fragment,null,(0,t.createElement)(r.Spinner,null),"Regenerating..."):"Regenerate Image"))):s?(0,t.createElement)(r.ToolbarGroup,null,(0,t.createElement)(r.ToolbarButton,{icon:e?(0,t.createElement)(r.Spinner,null):"format-image",label:e?"KaiGen is generating...":"KaiGen",onClick:n,disabled:e})):null},s=window.wp.blockEditor,d=window.wp.data;(0,window.wp.richText.registerFormatType)("kaigen/custom-format",{title:"AI Image Gen",tagName:"span",className:"kaigen-format",edit:({isActive:e,value:r,onChange:n})=>{const[i,l]=(0,a.useState)(!1),m=(0,d.useSelect)((e=>e("core/block-editor").getSelectedBlock()),[]),{replaceBlocks:g}=(0,d.useDispatch)("core/block-editor"),u=(0,a.useCallback)((()=>{if(m&&"core/paragraph"===m.name){const e=r.text.slice(r.start,r.end).trim();if(!e)return void wp.data.dispatch("core/notices").createErrorNotice("Please select some text to use as the image generation prompt.",{type:"snackbar"});const t=wp.data.select("core/editor")?.getEditorSettings()?.kaigen_provider;if(!t)return void wp.data.dispatch("core/notices").createErrorNotice("No AI provider configured. Please set one in the plugin settings.",{type:"snackbar"});const a=wp.blocks.createBlock("core/heading",{content:"Generating AI image...",level:2,className:"kaigen-text-center"});g(m.clientId,[a,m]),l(!0),o(e,(e=>{if(l(!1),e.error)console.error("Image generation failed:",e.error),wp.data.dispatch("core/notices").createErrorNotice("Failed to generate image: "+e.error,{type:"snackbar"}),g(a.clientId,[]);else{let t={url:e.url,alt:e.alt,caption:""};e.id&&"number"==typeof e.id&&e.id>0&&(t.id=e.id);const r=wp.blocks.createBlock("core/image",t);g(a.clientId,[r])}}))}}),[m,r.text,r.start,r.end,g]),p=""!==r.text.slice(r.start,r.end).trim();return(0,t.createElement)(s.BlockControls,null,(0,t.createElement)(c,{isGenerating:i,onGenerateImage:u,isTextSelected:p}))}});const m=window.wp.hooks;(0,m.addFilter)("editor.MediaUpload","kaigen/add-ai-tab",(e=>a=>{const r=a.allowedTypes&&a.allowedTypes.includes("image")&&!a.multiple,n=wp.data.select("core/block-editor").getSelectedBlock(),o=n&&"core/image"===n.name,l=wp.data.select("core/editor")?.getEditorSettings()?.kaigen_has_api_key,c=r&&o&&!(n&&n.attributes&&n.attributes.url)&&l;return(0,t.createElement)(e,{...a,render:e=>(0,t.createElement)(t.Fragment,null,a.render(e),(0,t.createElement)(i,{onSelect:a.onSelect,shouldDisplay:c}))})}));const g=window.wp.apiFetch;var u=e.n(g);(0,m.addFilter)("editor.BlockEdit","kaigen/add-regenerate-button",(e=>n=>{if("core/image"!==n.name)return(0,t.createElement)(e,{...n});const i=n.attributes.id&&"number"==typeof n.attributes.id&&n.attributes.id>0,[l,d]=(0,a.useState)(!1),[m,g]=(0,a.useState)(null),[p,k]=(0,a.useState)(!1);return(0,a.useEffect)((()=>{(async()=>{try{const e=window.kaiGen?.provider,t=window.kaiGen?.supportsImageToImage||!1;if(!e)return;k(t)}catch(e){console.error("Failed to initialize provider:",e)}})()}),[]),(0,t.createElement)(t.Fragment,null,(0,t.createElement)(e,{...n}),(0,t.createElement)(s.BlockControls,null,(0,t.createElement)(c,{isRegenerating:l,onRegenerateImage:async e=>{g(null);const t=e||n.attributes.alt||"no alt text or prompt, please just enhance",a=window.kaiGen?.provider;if(!a)return console.error("No provider configured"),void wp.data.dispatch("core/notices").createErrorNotice("No AI provider configured. Please check your plugin settings.",{type:"snackbar"});d(!0);try{const e=n.attributes.url,a={};p&&e?a.sourceImageUrl=e:p&&!e&&(console.warn("Image-to-image requested but no source image URL available"),wp.data.dispatch("core/notices").createWarningNotice("Image-to-image generation requires a source image. Please ensure the image is properly loaded.",{type:"snackbar"}));const r=await new Promise(((e,r)=>{o(t,(t=>{t.error?r(new Error(t.error)):e(t)}),a)}));r.id&&"number"==typeof r.id&&r.id>0?n.setAttributes({url:r.url,id:r.id}):n.setAttributes({url:r.url,id:void 0}),wp.data.dispatch("core/notices").createSuccessNotice("Image regenerated successfully!",{type:"snackbar"})}catch(e){console.error("Image regeneration failed:",e);let t=e.message||"Unknown error",a="";t.includes("organization verification")?a=" Please verify your organization in the OpenAI dashboard.":t.includes("parameter")?t="API configuration error. Please contact the plugin developer.":t.includes("content policy")&&(a=" Try a different prompt."),wp.data.dispatch("core/notices").createErrorNotice("Failed to regenerate image: "+t+a,{type:"snackbar"})}finally{d(!1)}},isImageBlock:!0,supportsImageToImage:p})),i&&(0,t.createElement)(s.InspectorControls,null,(0,t.createElement)(r.PanelBody,{title:"KaiGen Settings",initialOpen:!1},(0,t.createElement)(r.CheckboxControl,{label:"Reference image",checked:n.attributes.kaigen_reference_image||!1,onChange:async e=>{n.setAttributes({kaigen_reference_image:e});try{await u()({path:`/wp/v2/media/${n.attributes.id}`,method:"POST",data:{meta:{kaigen_reference_image:e?1:0}}})}catch(e){console.error("Failed to update reference image meta:",e),wp.data.dispatch("core/notices").createErrorNotice("Failed to update reference image meta",{type:"snackbar"})}},help:"Add to the list of reference images."}))))})),(0,m.addFilter)("blocks.registerBlockType","kaigen/add-reference-image-attribute",((e,t)=>"core/image"!==t?e:{...e,attributes:{...e.attributes,kaigen_reference_image:{type:"boolean",default:!1}}}))})(); -
kaigen/tags/v0.2.4/inc/class-admin.php
r3361350 r3401075 200 200 // Add quality field 201 201 add_settings_field( 202 'kaigen_quality_setting ',202 'kaigen_quality_settings', 203 203 'Image Quality', 204 204 [$this, 'render_quality_field'], … … 352 352 */ 353 353 public function render_quality_field() { 354 $quality_settings = get_option('kaigen_quality_settings', []); 355 $quality = isset($quality_settings['quality']) ? $quality_settings['quality'] : 'medium'; 354 $quality = KaiGen_Image_Provider::get_quality_setting(); 356 355 ?> 357 356 <select name="kaigen_quality_settings[quality]"> -
kaigen/tags/v0.2.4/inc/class-image-provider.php
r3315977 r3401075 171 171 */ 172 172 abstract public function process_api_response($response); 173 174 /** 175 * Gets the quality setting from the options. 176 * 177 * @return string The quality setting. 178 */ 179 public static function get_quality_setting() { 180 $quality_settings = get_option('kaigen_quality_settings', []); 181 182 // Ensure we have an array to work with. 183 if ( ! is_array( $quality_settings ) ) { 184 $quality_settings = []; 185 } 186 187 // If the quality setting is not set, check for the old option and migrate it. 188 if ( ! isset( $quality_settings['quality'] ) ) { 189 $legacy_quality_setting = get_option('kaigen_quality_setting'); 190 191 if ( ! empty( $legacy_quality_setting ) && in_array( $legacy_quality_setting, ['low', 'medium', 'high'], true ) ) { 192 $quality_settings['quality'] = $legacy_quality_setting; 193 update_option('kaigen_quality_settings', $quality_settings); 194 delete_option('kaigen_quality_setting'); 195 } else { 196 // Default to medium quality if neither exists. 197 $quality_settings['quality'] = 'medium'; 198 update_option('kaigen_quality_settings', $quality_settings); 199 } 200 } 201 202 return $quality_settings['quality']; 203 } 173 204 } -
kaigen/tags/v0.2.4/inc/class-rest-api.php
r3361350 r3401075 124 124 // For Replicate, get the model based on quality setting 125 125 if ($provider_id === 'replicate') { 126 $quality_settings = get_option('kaigen_quality_settings', []); 127 $quality = isset($quality_settings['quality']) ? $quality_settings['quality'] : 'medium'; 126 $quality = KaiGen_Image_Provider::get_quality_setting(); 128 127 129 128 $provider = kaigen_provider_manager()->get_provider($provider_id); … … 161 160 private function get_additional_params($request) { 162 161 // Get saved quality settings 162 $quality = KaiGen_Image_Provider::get_quality_setting(); 163 $quality_value = $quality === 'hd' ? 100 : 80; 163 164 $quality_settings = get_option('kaigen_quality_settings', []); 164 $quality_value = isset($quality_settings['quality']) && $quality_settings['quality'] === 'hd' ? 100 : 80;165 165 $style_value = isset($quality_settings['style']) ? $quality_settings['style'] : 'natural'; 166 166 … … 183 183 184 184 // Add source image URL if provided (single or array) 185 $source_image_url = $request->get_param('source_image_url'); 186 if (!empty($source_image_url)) { 187 $params['source_image_url'] = $source_image_url; 185 $source_image_urls = $request->get_param('source_image_urls'); 186 if (!empty($source_image_urls)) { 187 $params['source_image_urls'] = $source_image_urls; 188 } else { 189 $source_image_url = $request->get_param('source_image_url'); 190 if (!empty($source_image_url)) { 191 $params['source_image_url'] = $source_image_url; 192 } 188 193 } 189 194 … … 274 279 'empty_image_data', 275 280 'replicate_validation_error', 276 'content_moderation' 281 'content_moderation', 282 'api_error', 283 'openai_error', 284 'max_retries_exceeded', 285 'invalid_api_key_format' 277 286 ])) { 278 287 return $result; -
kaigen/tags/v0.2.4/inc/providers/class-image-provider-openai.php
r3315977 r3401075 48 48 } 49 49 50 // Handle source image URLs 51 $source_image_urls = $additional_params['source_image_urls'] ?? []; 50 52 $source_image_url = $additional_params['source_image_url'] ?? null; 51 $max_retries = 3; // Reduce max retries to fail faster 52 $timeout = 60; // Set request timeout to 60 seconds 53 if ($source_image_url) { 54 array_unshift($source_image_urls, $source_image_url); 55 } 56 57 // Limit the number of source image URLs to 16. 58 $source_image_urls = array_slice(array_unique($source_image_urls), 0, 16); 59 60 $max_retries = 3; 61 $timeout = 150; // Increased timeout for image generation (docs say up to 2 mins) 53 62 $retry_delay = 2; // Seconds to wait between retries 54 63 … … 61 70 add_filter('http_request_args', function($args) use ($timeout) { 62 71 $args['timeout'] = $timeout; 63 $args['httpversion'] = '1.1';64 72 $args['sslverify'] = true; 65 73 $args['blocking'] = true; … … 70 78 } 71 79 $args['curl'][CURLOPT_TIMEOUT] = $timeout; 72 $args['curl'][CURLOPT_CONNECTTIMEOUT] = 10; 73 $args['curl'][CURLOPT_LOW_SPEED_TIME] = 30; // Increased low speed time 74 $args['curl'][CURLOPT_LOW_SPEED_LIMIT] = 1024; // 1KB/s minimum speed 80 $args['curl'][CURLOPT_CONNECTTIMEOUT] = 30; // Increased connect timeout 81 $args['curl'][CURLOPT_TCP_KEEPALIVE] = 1; // Enable TCP keepalive 82 83 // Adjust low speed settings to prevent timeouts on slow generation 84 $args['curl'][CURLOPT_LOW_SPEED_TIME] = 600; // Wait 10 minutes before timing out due to low speed 85 $args['curl'][CURLOPT_LOW_SPEED_LIMIT] = 1; // Only timeout if speed is effectively 0 75 86 76 87 return $args; … … 81 92 82 93 // Log if we're using image-to-image 83 if ( ! empty( $source_image_url )) {94 if (!empty($source_image_urls)) { 84 95 $endpoint = self::IMAGE_EDIT_API_BASE_URL; 85 96 } 86 97 87 98 // Get quality setting from admin options 88 $quality_settings = get_option('kaigen_quality_settings', []); 89 $quality = isset($quality_settings['quality']) ? $quality_settings['quality'] : 'medium'; 99 $quality = self::get_quality_setting(); 90 100 91 101 // Map quality settings to supported values … … 100 110 101 111 // Prepare the request based on the type of request 102 if ( ! empty( $source_image_url )) {112 if (!empty($source_image_urls)) { 103 113 // For image edit requests, we need to use multipart/form-data 104 114 $boundary = wp_generate_password(24, false); … … 125 135 $body .= 'Content-Disposition: form-data; name="quality"' . "\r\n\r\n"; 126 136 $body .= $quality . "\r\n"; 137 138 // Add format parameter (jpeg is faster than png) 139 $body .= "--{$boundary}\r\n"; 140 $body .= 'Content-Disposition: form-data; name="output_format"' . "\r\n\r\n"; 141 $body .= "jpeg\r\n"; 127 142 128 143 // Add image files 129 if (is_array($source_image_url)) { 130 foreach ($source_image_url as $index => $image_url) { 131 $image_data = $this->get_image_data($image_url); 132 if (is_wp_error($image_data)) { 133 return $image_data; 134 } 135 136 $body .= "--{$boundary}\r\n"; 137 $body .= 'Content-Disposition: form-data; name="image[]"; filename="' . basename($image_url) . '"' . "\r\n"; 138 $body .= 'Content-Type: ' . $this->get_image_mime_type($image_url) . "\r\n\r\n"; 139 $body .= $image_data . "\r\n"; 140 } 141 } else { 142 $image_data = $this->get_image_data($source_image_url); 144 foreach ($source_image_urls as $index => $image_url) { 145 $image_data = $this->get_image_data($image_url); 143 146 if (is_wp_error($image_data)) { 144 147 return $image_data; … … 146 149 147 150 $body .= "--{$boundary}\r\n"; 148 $body .= 'Content-Disposition: form-data; name="image "; filename="' . basename($source_image_url) . '"' . "\r\n";149 $body .= 'Content-Type: ' . $this->get_image_mime_type($ source_image_url) . "\r\n\r\n";151 $body .= 'Content-Disposition: form-data; name="image[]"; filename="' . basename($image_url) . '"' . "\r\n"; 152 $body .= 'Content-Type: ' . $this->get_image_mime_type($image_url) . "\r\n\r\n"; 150 153 $body .= $image_data . "\r\n"; 151 154 } … … 158 161 $headers = $this->get_request_headers(); 159 162 $body = [ 160 'model' => 'gpt-image-1', 161 'prompt' => $prompt, 162 'quality' => $quality, 163 'model' => 'gpt-image-1', 164 'prompt' => $prompt, 165 'quality' => $quality, 166 'output_format' => 'jpeg', 163 167 ]; 164 168 165 169 // Add size parameter if aspect ratio is specified 166 170 if (isset($additional_params['aspect_ratio'])) { … … 168 172 $body['size'] = "{$width}x{$height}"; 169 173 } 170 174 171 175 $body = wp_json_encode($body); 172 176 } -
kaigen/tags/v0.2.4/inc/providers/class-image-provider-replicate.php
r3361350 r3401075 52 52 */ 53 53 public function get_current_model() { 54 // Get all quality-related options to debug 55 $quality_settings = get_option('kaigen_quality_settings'); 56 $quality_setting = get_option('kaigen_quality_setting'); 57 58 // Use the correct option name 59 $quality = 'medium'; // Default 60 if (is_array($quality_settings) && isset($quality_settings['quality'])) { 61 $quality = $quality_settings['quality']; 62 } 63 54 $quality = self::get_quality_setting(); 64 55 $model = $this->get_model_from_quality_setting($quality); 65 56 return $model; … … 85 76 $model_to_use = $this->model; 86 77 87 // Handle source_image_url parameter (convert to image_input for Replicate seedream-4) 88 $source_image_url = $additional_params['source_image_url'] ?? $additional_params['input_image'] ?? null; 89 90 // If source image is provided, use the hardcoded image-to-image model 91 if (!empty($source_image_url)) { 92 $model_to_use = $this->get_image_to_image_model(); 93 94 // Process image URL (converts to base64 only if local) 95 $processed_image = $this->process_image_url($source_image_url); 96 if (is_wp_error($processed_image)) { 97 // Return image processing errors immediately without retry 98 return $processed_image; 99 } 100 101 // Use 'image_input' parameter as array for seedream-4 model (confirmed by schema) 102 $input_data['image_input'] = [$processed_image]; 103 } 104 105 // Remove these parameters to prevent duplication 78 // Handle source image URLs (can be single string or array) 79 $source_image_urls = $additional_params['source_image_urls'] ?? $additional_params['source_image_url'] ?? null; 80 if (!empty($source_image_urls)) { 81 if (!is_array($source_image_urls)) { 82 $source_image_urls = [$source_image_urls]; 83 } 84 85 $image_inputs = []; 86 foreach ($source_image_urls as $url) { 87 if (count($image_inputs) >= 10) break; 88 $processed = $this->process_image_url($url); 89 if (!is_wp_error($processed)) { 90 $image_inputs[] = $processed; 91 } else { 92 // Log error but continue with other images 93 error_log('Failed to process image: ' . $processed->get_error_message()); 94 } 95 } 96 97 if (!empty($image_inputs)) { 98 $model_to_use = $this->get_image_to_image_model(); 99 $input_data['image_input'] = $image_inputs; 100 101 // Set size to 1k for low quality image edits, assumes we are using seedream-4 model so if that changes, this will need to be updated. 102 $quality = self::get_quality_setting(); 103 104 if ($quality === 'low') { 105 $additional_params['size'] = '1K'; 106 } 107 } 108 } 109 110 // Remove source image parameters to prevent duplication 111 unset($additional_params['source_image_urls']); 106 112 unset($additional_params['source_image_url']); 107 113 unset($additional_params['input_image']); 108 114 109 115 // Filter parameters based on the model being used 110 if (!empty($source_image_url )) {116 if (!empty($source_image_urls)) { 111 117 // For seedream-4, only keep valid parameters according to schema 112 118 $valid_params = ['size', 'width', 'height', 'max_images', 'aspect_ratio', 'sequential_image_generation']; … … 358 364 'black-forest-labs/flux-schnell' => 'Flux Schnell by Black Forest Labs (low quality)', 359 365 'bytedance/seedream-4' => 'Seedream 4 by Bytedance (high quality)', 360 'google/ imagen-4-ultra' => 'Imagen 4 Ultraby Google (highest quality)',366 'google/nano-banana-pro' => 'Nano Banana Pro by Google (highest quality)', 361 367 ]; 362 368 } 363 369 364 370 /** 365 * Gets the hardcoded image-to-image model for Replicate.371 * Gets the image-to-image model for Replicate based on quality setting. 366 372 * 367 373 * @return string The image-to-image model. 368 374 */ 369 375 private function get_image_to_image_model() { 370 return 'bytedance/seedream-4'; 376 $model = 'bytedance/seedream-4'; 377 $quality = self::get_quality_setting(); 378 379 if ($quality === 'high') { 380 $model = 'google/nano-banana-pro'; 381 } 382 383 return $model; 371 384 } 372 385 … … 395 408 break; 396 409 case 'high': 397 $model = 'google/ imagen-4-ultra';410 $model = 'google/nano-banana-pro'; 398 411 break; 399 412 default: -
kaigen/tags/v0.2.4/kaigen.php
r3361350 r3401075 5 5 * Requires at least: 6.1 6 6 * Requires PHP: 7.0 7 * Version: 0.2. 37 * Version: 0.2.4 8 8 * Author: Jacob Schweitzer 9 9 * License: GPL-2.0-or-later -
kaigen/trunk/build/index.asset.php
r3361350 r3401075 1 <?php return array('dependencies' => array('react', 'wp-api-fetch', 'wp-block-editor', 'wp-components', 'wp-data', 'wp-element', 'wp-hooks', 'wp-rich-text'), 'version' => 'fd cac31f2e1ee5e68851');1 <?php return array('dependencies' => array('react', 'wp-api-fetch', 'wp-block-editor', 'wp-components', 'wp-data', 'wp-element', 'wp-hooks', 'wp-rich-text'), 'version' => 'fd9194ab12765b897e21'); -
kaigen/trunk/build/index.js
r3361350 r3401075 1 (()=>{"use strict";var e={n:t=>{var a=t&&t.__esModule?()=>t.default:()=>t;return e.d(a,{a}),a},d:(t,a)=>{for(var r in a)e.o(a,r)&&!e.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:a[r]})}};e.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),e.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var t;e.g.importScripts&&(t=e.g.location+"");var a=e.g.document;if(!t&&a&&(a.currentScript&&(t=a.currentScript.src),!t)){var r=a.getElementsByTagName("script");if(r.length)for(var n=r.length-1;n>-1&&(!t||!/^http(s?):/.test(t));)t=r[n--].src}if(!t)throw new Error("Automatic publicPath is not supported in this browser");t=t.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),e.p=t})();const t=window.React,a=window.wp.element,r=window.wp.components,n=e.p+"images/KaiGen-logo-128x128.44b1814b.png",o=async(e,t,a={})=>{try{const r=wp.data.select("core/editor")?.getEditorSettings()?.kaigen_provider;if(!r)throw new Error("No provider configured. Please check your plugin settings.");const n=wp.data.select("core/editor")?.getEditorSettings()?.kaigen_has_api_key;if(!n)throw new Error("No API key configured for the selected provider. Please add one in the KaiGen settings.");const o={prompt:e,provider:r};a.sourceImageUrl &&(o.source_image_url=a.sourceImageUrl),a.additionalImageUrls&&Array.isArray(a.additionalImageUrls)&&(o.additional_image_urls=a.additionalImageUrls),a.maskUrl&&(o.mask_url=a.maskUrl),a.moderation&&["auto","low"].includes(a.moderation)&&(o.moderation=a.moderation),a.style&&["natural","vivid"].includes(a.style)&&(o.style=a.style),a.aspectRatio&&["1:1","16:9","9:16","4:3","3:4"].includes(a.aspectRatio)&&(o.aspect_ratio=a.aspectRatio);const i=await wp.apiFetch({path:"/kaigen/v1/generate-image",method:"POST",data:o});if(i.code&&i.message){if("content_moderation"===i.code)throw new Error(i.message);if("replicate_error"===i.code)throw new Error("Image generation failed: "+i.message);throw new Error(i.message)}if(!i||!i.url)throw new Error("Invalid response from server: "+JSON.stringify(i));i.id&&"number"==typeof i.id&&i.id>0?t({url:i.url,alt:e,id:i.id,caption:""}):t({url:i.url,alt:e,caption:""})}catch(e){console.error("Image generation failed:",e),e.message&&console.error("Error message:",e.message),e.stack&&console.error("Error stack:",e.stack),t({error:e.message||"An unknown error occurred while generating the image"})}},i=({onSelect:e,shouldDisplay:i})=>{const[l,c]=(0,a.useState)(!1),[s,d]=(0,a.useState)(""),[m,g]=(0,a.useState)(!1),[u,p]=(0,a.useState)(null),[k,b]=(0,a.useState)([]),[w,E]=(0,a.useState)(null),[f,h]=(0,a.useState)("1:1"),y=window.kaiGen?.supportsImageToImage||!1;(0,a.useEffect)((()=>{l&&y&&(async()=>{try{const e=await wp.apiFetch({path:"/kaigen/v1/reference-images",method:"GET"});return Array.isArray(e)?e:[]}catch(e){return console.error("Failed to fetch reference images:",e),[]}})().then(b)}),[l]);const v=()=>{if(!s.trim())return void p("Please enter a prompt for image generation.");g(!0),p(null);const t={};w&&(t.sourceImageUrl=w.url),f&&(t.aspectRatio=f),o(s.trim(),(t=>{t.error?(p(t.error),g(!1)):(e(t),g(!1),c(!1))}),t)};return i?(0,t.createElement)(t.Fragment,null,(0,t.createElement)(r.Button,{onClick:()=>c(!0),className:"kaigen-placeholder-button","aria-label":"KaiGen",role:"button",title:"KaiGen",style:{order:10}},(0,t.createElement)("img",{src:n,alt:"KaiGen","aria-label":"KaiGen logo",role:"button",title:"KaiGen logo",style:{width:"64px",height:"64px"}})),l&&(0,t.createElement)(r.Modal,{className:"kaigen-modal",title:(0,t.createElement)("div",{className:"kaigen-modal__logo-container"},(0,t.createElement)("img",{src:n,alt:"KaiGen logo",className:"kaigen-modal__logo"})),"aria-label":"KaiGen",onRequestClose:()=>c(!1)},u&&(0,t.createElement)("p",{className:"kaigen-error-text"},u),(0,t.createElement)("div",{className:"kaigen-modal__input-container"},y&&k.length>0&&(0,t.createElement)(r.Dropdown,{onFocusOutside:()=>setIsOpen(!1),popoverProps:{placement:"bottom-start",focusOnMount:!0},renderToggle:({isOpen:e,onToggle:a})=>(0,t.createElement)(r.Button,{className:"kaigen-modal__ref-button "+(w?"kaigen-ref-button-selected":""),onClick:a,"aria-expanded":e,"aria-label":"Reference Images"},(0,t.createElement)(r.Dashicon,{icon:"format-image",className:w?"kaigen-ref-button-icon-selected":""})),renderContent:()=>(0,t.createElement)("div",{className:"kaigen-modal-dropdown-content-container"},(0,t.createElement)("h4",{className:"kaigen-modal-dropdown-content-title"},"Reference Images"),(0,t.createElement)("div",{className:"kaigen-modal-reference-images-container"},k.map((e=>(0,t.createElement)("img",{key:e.id,src:e.url,alt:e.alt||"",onClick:()=>w&&w.id===e.id?E(null):E(e),className:"kaigen-modal-reference-image "+(w&&w.id===e.id?"kaigen-modal-reference-image-selected":"")})))))}),(0,t.createElement)("div",{className:"kaigen-modal__textarea-container"},(0,t.createElement)(r.TextareaControl,{className:"kaigen-modal__textarea",placeholder:"Image prompt...",value:s,onChange:d,onKeyDown:e=>{"Enter"!==e.key||e.shiftKey||(e.preventDefault(),v())},rows:2})),s.trim()&&(0,t.createElement)(r.Button,{className:"kaigen-modal__submit-button",variant:"primary",onClick:v,disabled:m||!s.trim(),"aria-label":"Generate Image"},m?(0,t.createElement)(t.Fragment,null,(0,t.createElement)(r.Spinner,null)):(0,t.createElement)(r.Dashicon,{icon:"admin-appearance"})),(0,t.createElement)(r.Dropdown,{onFocusOutside:()=>setIsOpen(!1),popoverProps:{placement:"bottom-end",focusOnMount:!0},renderToggle:({isOpen:e,onToggle:a})=>(0,t.createElement)(r.Button,{className:"kaigen-modal__settings-button",onClick:a,"aria-expanded":e,"aria-label":"Settings"},(0,t.createElement)(r.Dashicon,{icon:"admin-generic"})),renderContent:()=>(0,t.createElement)("div",{className:"kaigen-modal-dropdown-content-container"},(0,t.createElement)("h4",{className:"kaigen-modal-dropdown-content-title"},"Aspect Ratio"),(0,t.createElement)("div",{className:"kaigen-modal-aspect-ratio-container"},[{value:"1:1",label:"1:1",title:"Square"},{value:"16:9",label:"16:9",title:"Landscape"},{value:"9:16",label:"9:16",title:"Portrait"}].map((e=>(0,t.createElement)("div",{key:e.value,onClick:()=>h((t=>t===e.value?null:e.value)),"aria-pressed":f===e.value,"aria-label":`${e.title} (${e.label})`,className:"kaigen-modal__aspect-ratio-button "+(f===e.value?"kaigen-modal__aspect-ratio-button-selected":"")},(0,t.createElement)("div",{className:"kaigen-modal-aspect-ratio-icon-container"},(0,t.createElement)("div",{className:`kaigen-modal-aspect-ratio-icon ${f===e.value?"kaigen-modal-aspect-ratio-icon-selected":""} kaigen-aspect-ratio-${e.value.replace(":","-")}`})),(0,t.createElement)("span",{className:"kaigen-modal-aspect-ratio-label"},e.label))))))})))):null},l=e.p+"images/KaiGen-logo-64x64.a6e617bd.png",c=({isGenerating:e,onGenerateImage:n,isRegenerating:o,onRegenerateImage:i,isImageBlock:c,isTextSelected:s,supportsImageToImage:d})=>{const[m,g]=(0,a.useState)(!1),[u,p]=(0,a.useState)(""),[k,b]=(0,a.useState)(null);return c&&d?(0,t.createElement)(t.Fragment,null,(0,t.createElement)(r.ToolbarGroup,null,(0,t.createElement)(r.ToolbarButton,{icon:o?(0,t.createElement)(r.Spinner,null):(0,t.createElement)("img",{src:l,alt:"KaiGen logo",className:"kaigen-toolbar-icon"}),label:o?"KaiGen is generating...":"KaiGen",onClick:()=>g(!0),disabled:o})),m&&(0,t.createElement)(r.Modal,{title:(0,t.createElement)("img",{src:l,alt:"KaiGen logo",className:"kaigen-modal-logo"}),onRequestClose:()=>{g(!1),p(""),b(null)}},k&&(0,t.createElement)("p",{className:"kaigen-error-text"},k),(0,t.createElement)(r.TextareaControl,{label:"Editing Instructions (optional)",value:u,onChange:p,rows:4}),(0,t.createElement)(r.Button,{variant:"primary",onClick:()=>{i(u.trim()),g(!1),p(""),b(null)},disabled:o},o?(0,t.createElement)(t.Fragment,null,(0,t.createElement)(r.Spinner,null),"Regenerating..."):"Regenerate Image"))):s?(0,t.createElement)(r.ToolbarGroup,null,(0,t.createElement)(r.ToolbarButton,{icon:e?(0,t.createElement)(r.Spinner,null):"format-image",label:e?"KaiGen is generating...":"KaiGen",onClick:n,disabled:e})):null},s=window.wp.blockEditor,d=window.wp.data;(0,window.wp.richText.registerFormatType)("kaigen/custom-format",{title:"AI Image Gen",tagName:"span",className:"kaigen-format",edit:({isActive:e,value:r,onChange:n})=>{const[i,l]=(0,a.useState)(!1),m=(0,d.useSelect)((e=>e("core/block-editor").getSelectedBlock()),[]),{replaceBlocks:g}=(0,d.useDispatch)("core/block-editor"),u=(0,a.useCallback)((()=>{if(m&&"core/paragraph"===m.name){const e=r.text.slice(r.start,r.end).trim();if(!e)return void wp.data.dispatch("core/notices").createErrorNotice("Please select some text to use as the image generation prompt.",{type:"snackbar"});const t=wp.data.select("core/editor")?.getEditorSettings()?.kaigen_provider;if(!t)return void wp.data.dispatch("core/notices").createErrorNotice("No AI provider configured. Please set one in the plugin settings.",{type:"snackbar"});const a=wp.blocks.createBlock("core/heading",{content:"Generating AI image...",level:2,className:"kaigen-text-center"});g(m.clientId,[a,m]),l(!0),o(e,(e=>{if(l(!1),e.error)console.error("Image generation failed:",e.error),wp.data.dispatch("core/notices").createErrorNotice("Failed to generate image: "+e.error,{type:"snackbar"}),g(a.clientId,[]);else{let t={url:e.url,alt:e.alt,caption:""};e.id&&"number"==typeof e.id&&e.id>0&&(t.id=e.id);const r=wp.blocks.createBlock("core/image",t);g(a.clientId,[r])}}))}}),[m,r.text,r.start,r.end,g]),p=""!==r.text.slice(r.start,r.end).trim();return(0,t.createElement)(s.BlockControls,null,(0,t.createElement)(c,{isGenerating:i,onGenerateImage:u,isTextSelected:p}))}});const m=window.wp.hooks;(0,m.addFilter)("editor.MediaUpload","kaigen/add-ai-tab",(e=>a=>{const r=a.allowedTypes&&a.allowedTypes.includes("image")&&!a.multiple,n=wp.data.select("core/block-editor").getSelectedBlock(),o=n&&"core/image"===n.name,l=wp.data.select("core/editor")?.getEditorSettings()?.kaigen_has_api_key,c=r&&o&&!(n&&n.attributes&&n.attributes.url)&&l;return(0,t.createElement)(e,{...a,render:e=>(0,t.createElement)(t.Fragment,null,a.render(e),(0,t.createElement)(i,{onSelect:a.onSelect,shouldDisplay:c}))})}));const g=window.wp.apiFetch;var u=e.n(g);(0,m.addFilter)("editor.BlockEdit","kaigen/add-regenerate-button",(e=>n=>{if("core/image"!==n.name)return(0,t.createElement)(e,{...n});const i=n.attributes.id&&"number"==typeof n.attributes.id&&n.attributes.id>0,[l,d]=(0,a.useState)(!1),[m,g]=(0,a.useState)(null),[p,k]=(0,a.useState)(!1);return(0,a.useEffect)((()=>{(async()=>{try{const e=window.kaiGen?.provider,t=window.kaiGen?.supportsImageToImage||!1;if(!e)return;k(t)}catch(e){console.error("Failed to initialize provider:",e)}})()}),[]),(0,t.createElement)(t.Fragment,null,(0,t.createElement)(e,{...n}),(0,t.createElement)(s.BlockControls,null,(0,t.createElement)(c,{isRegenerating:l,onRegenerateImage:async e=>{g(null);const t=e||n.attributes.alt||"no alt text or prompt, please just enhance",a=window.kaiGen?.provider;if(!a)return console.error("No provider configured"),void wp.data.dispatch("core/notices").createErrorNotice("No AI provider configured. Please check your plugin settings.",{type:"snackbar"});d(!0);try{const e=n.attributes.url,a={};p&&e?a.sourceImageUrl=e:p&&!e&&(console.warn("Image-to-image requested but no source image URL available"),wp.data.dispatch("core/notices").createWarningNotice("Image-to-image generation requires a source image. Please ensure the image is properly loaded.",{type:"snackbar"}));const r=await new Promise(((e,r)=>{o(t,(t=>{t.error?r(new Error(t.error)):e(t)}),a)}));r.id&&"number"==typeof r.id&&r.id>0?n.setAttributes({url:r.url,id:r.id}):n.setAttributes({url:r.url,id:void 0}),wp.data.dispatch("core/notices").createSuccessNotice("Image regenerated successfully!",{type:"snackbar"})}catch(e){console.error("Image regeneration failed:",e);let t=e.message||"Unknown error",a="";t.includes("organization verification")?a=" Please verify your organization in the OpenAI dashboard.":t.includes("parameter")?t="API configuration error. Please contact the plugin developer.":t.includes("content policy")&&(a=" Try a different prompt."),wp.data.dispatch("core/notices").createErrorNotice("Failed to regenerate image: "+t+a,{type:"snackbar"})}finally{d(!1)}},isImageBlock:!0,supportsImageToImage:p})),i&&(0,t.createElement)(s.InspectorControls,null,(0,t.createElement)(r.PanelBody,{title:"KaiGen Settings",initialOpen:!1},(0,t.createElement)(r.CheckboxControl,{label:"Reference image",checked:n.attributes.kaigen_reference_image||!1,onChange:async e=>{n.setAttributes({kaigen_reference_image:e});try{await u()({path:`/wp/v2/media/${n.attributes.id}`,method:"POST",data:{meta:{kaigen_reference_image:e?1:0}}})}catch(e){console.error("Failed to update reference image meta:",e),wp.data.dispatch("core/notices").createErrorNotice("Failed to update reference image meta",{type:"snackbar"})}},help:"Add to the list of reference images."}))))})),(0,m.addFilter)("blocks.registerBlockType","kaigen/add-reference-image-attribute",((e,t)=>"core/image"!==t?e:{...e,attributes:{...e.attributes,kaigen_reference_image:{type:"boolean",default:!1}}}))})();1 (()=>{"use strict";var e={n:t=>{var a=t&&t.__esModule?()=>t.default:()=>t;return e.d(a,{a}),a},d:(t,a)=>{for(var r in a)e.o(a,r)&&!e.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:a[r]})}};e.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),e.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var t;e.g.importScripts&&(t=e.g.location+"");var a=e.g.document;if(!t&&a&&(a.currentScript&&(t=a.currentScript.src),!t)){var r=a.getElementsByTagName("script");if(r.length)for(var n=r.length-1;n>-1&&(!t||!/^http(s?):/.test(t));)t=r[n--].src}if(!t)throw new Error("Automatic publicPath is not supported in this browser");t=t.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),e.p=t})();const t=window.React,a=window.wp.element,r=window.wp.components,n=e.p+"images/KaiGen-logo-128x128.44b1814b.png",o=async(e,t,a={})=>{try{const r=wp.data.select("core/editor")?.getEditorSettings()?.kaigen_provider;if(!r)throw new Error("No provider configured. Please check your plugin settings.");const n=wp.data.select("core/editor")?.getEditorSettings()?.kaigen_has_api_key;if(!n)throw new Error("No API key configured for the selected provider. Please add one in the KaiGen settings.");const o={prompt:e,provider:r};a.sourceImageUrls&&Array.isArray(a.sourceImageUrls)?o.source_image_urls=a.sourceImageUrls:a.sourceImageUrl&&(o.source_image_url=a.sourceImageUrl),a.additionalImageUrls&&Array.isArray(a.additionalImageUrls)&&(o.additional_image_urls=a.additionalImageUrls),a.maskUrl&&(o.mask_url=a.maskUrl),a.moderation&&["auto","low"].includes(a.moderation)&&(o.moderation=a.moderation),a.style&&["natural","vivid"].includes(a.style)&&(o.style=a.style),a.aspectRatio&&["1:1","16:9","9:16","4:3","3:4"].includes(a.aspectRatio)&&(o.aspect_ratio=a.aspectRatio);const i=await wp.apiFetch({path:"/kaigen/v1/generate-image",method:"POST",data:o});if(i.code&&i.message){if("content_moderation"===i.code)throw new Error(i.message);if("replicate_error"===i.code)throw new Error("Image generation failed: "+i.message);throw new Error(i.message)}if(!i||!i.url)throw new Error("Invalid response from server: "+JSON.stringify(i));i.id&&"number"==typeof i.id&&i.id>0?t({url:i.url,alt:e,id:i.id,caption:""}):t({url:i.url,alt:e,caption:""})}catch(e){console.error("Image generation failed:",e),e.message&&console.error("Error message:",e.message),e.stack&&console.error("Error stack:",e.stack),t({error:e.message||"An unknown error occurred while generating the image"})}},i=({onSelect:e,shouldDisplay:i})=>{const[l,c]=(0,a.useState)(!1),[s,d]=(0,a.useState)(""),[m,g]=(0,a.useState)(!1),[u,p]=(0,a.useState)(null),[k,w]=(0,a.useState)([]),[b,h]=(0,a.useState)([]),[E,f]=(0,a.useState)("1:1"),y=window.kaiGen?.supportsImageToImage||!1,v="replicate"===(wp.data.select("core/editor")?.getEditorSettings()?.kaigen_provider||"replicate")?10:16;(0,a.useEffect)((()=>{l&&y&&(async()=>{try{const e=await wp.apiFetch({path:"/kaigen/v1/reference-images",method:"GET"});return Array.isArray(e)?e:[]}catch(e){return console.error("Failed to fetch reference images:",e),[]}})().then(w)}),[l]);const I=()=>{if(!s.trim())return void p("Please enter a prompt for image generation.");g(!0),p(null);const t={};b.length>0&&(t.sourceImageUrls=b.map((e=>e.url))),E&&(t.aspectRatio=E),o(s.trim(),(t=>{t.error?(p(t.error),g(!1)):(e(t),g(!1),c(!1))}),t)};return i?(0,t.createElement)(t.Fragment,null,(0,t.createElement)(r.Button,{onClick:()=>c(!0),className:"kaigen-placeholder-button","aria-label":"KaiGen",role:"button",title:"KaiGen",style:{order:10}},(0,t.createElement)("img",{src:n,alt:"KaiGen","aria-label":"KaiGen logo",role:"button",title:"KaiGen logo",style:{width:"64px",height:"64px"}})),l&&(0,t.createElement)(r.Modal,{className:"kaigen-modal",title:(0,t.createElement)("div",{className:"kaigen-modal__logo-container"},(0,t.createElement)("img",{src:n,alt:"KaiGen logo",className:"kaigen-modal__logo"})),"aria-label":"KaiGen",onRequestClose:()=>c(!1)},u&&(0,t.createElement)("p",{className:"kaigen-error-text"},u),(0,t.createElement)("div",{className:"kaigen-modal__input-container"},y&&k.length>0&&(0,t.createElement)(r.Dropdown,{onFocusOutside:()=>setIsOpen(!1),popoverProps:{placement:"bottom-start",focusOnMount:!0},renderToggle:({isOpen:e,onToggle:a})=>(0,t.createElement)(r.Button,{className:"kaigen-modal__ref-button "+(b.length>0?"kaigen-ref-button-selected":""),onClick:a,"aria-expanded":e,"aria-label":"Reference Images"},(0,t.createElement)(r.Dashicon,{icon:"format-image",className:b.length>0?"kaigen-ref-button-icon-selected":""})),renderContent:()=>(0,t.createElement)("div",{className:"kaigen-modal-dropdown-content-container"},(0,t.createElement)("h4",{className:"kaigen-modal-dropdown-content-title"},"Reference Images (up to ",v,")"),(0,t.createElement)("div",{className:"kaigen-modal-reference-images-container"},k.map((e=>(0,t.createElement)("img",{key:e.id,src:e.url,alt:e.alt||"",onClick:()=>{h((t=>t.some((t=>t.id===e.id))?t.filter((t=>t.id!==e.id)):t.length<v?[...t,e]:t))},className:"kaigen-modal-reference-image "+(b.some((t=>t.id===e.id))?"kaigen-modal-reference-image-selected":"")})))))}),(0,t.createElement)("div",{className:"kaigen-modal__textarea-container"},(0,t.createElement)(r.TextareaControl,{className:"kaigen-modal__textarea",placeholder:"Image prompt...",value:s,onChange:d,onKeyDown:e=>{"Enter"!==e.key||e.shiftKey||(e.preventDefault(),I())},rows:2})),s.trim()&&(0,t.createElement)(r.Button,{className:"kaigen-modal__submit-button",variant:"primary",onClick:I,disabled:m||!s.trim(),"aria-label":"Generate Image"},m?(0,t.createElement)(t.Fragment,null,(0,t.createElement)(r.Spinner,null)):(0,t.createElement)(r.Dashicon,{icon:"admin-appearance"})),(0,t.createElement)(r.Dropdown,{onFocusOutside:()=>setIsOpen(!1),popoverProps:{placement:"bottom-end",focusOnMount:!0},renderToggle:({isOpen:e,onToggle:a})=>(0,t.createElement)(r.Button,{className:"kaigen-modal__settings-button",onClick:a,"aria-expanded":e,"aria-label":"Settings"},(0,t.createElement)(r.Dashicon,{icon:"admin-generic"})),renderContent:()=>(0,t.createElement)("div",{className:"kaigen-modal-dropdown-content-container"},(0,t.createElement)("h4",{className:"kaigen-modal-dropdown-content-title"},"Aspect Ratio"),(0,t.createElement)("div",{className:"kaigen-modal-aspect-ratio-container"},[{value:"1:1",label:"1:1",title:"Square"},{value:"16:9",label:"16:9",title:"Landscape"},{value:"9:16",label:"9:16",title:"Portrait"}].map((e=>(0,t.createElement)("div",{key:e.value,onClick:()=>f((t=>t===e.value?null:e.value)),"aria-pressed":E===e.value,"aria-label":`${e.title} (${e.label})`,className:"kaigen-modal__aspect-ratio-button "+(E===e.value?"kaigen-modal__aspect-ratio-button-selected":"")},(0,t.createElement)("div",{className:"kaigen-modal-aspect-ratio-icon-container"},(0,t.createElement)("div",{className:`kaigen-modal-aspect-ratio-icon ${E===e.value?"kaigen-modal-aspect-ratio-icon-selected":""} kaigen-aspect-ratio-${e.value.replace(":","-")}`})),(0,t.createElement)("span",{className:"kaigen-modal-aspect-ratio-label"},e.label))))))})))):null},l=e.p+"images/KaiGen-logo-64x64.a6e617bd.png",c=({isGenerating:e,onGenerateImage:n,isRegenerating:o,onRegenerateImage:i,isImageBlock:c,isTextSelected:s,supportsImageToImage:d})=>{const[m,g]=(0,a.useState)(!1),[u,p]=(0,a.useState)(""),[k,w]=(0,a.useState)(null);return c&&d?(0,t.createElement)(t.Fragment,null,(0,t.createElement)(r.ToolbarGroup,null,(0,t.createElement)(r.ToolbarButton,{icon:o?(0,t.createElement)(r.Spinner,null):(0,t.createElement)("img",{src:l,alt:"KaiGen logo",className:"kaigen-toolbar-icon"}),label:o?"KaiGen is generating...":"KaiGen",onClick:()=>g(!0),disabled:o})),m&&(0,t.createElement)(r.Modal,{title:(0,t.createElement)("img",{src:l,alt:"KaiGen logo",className:"kaigen-modal-logo"}),onRequestClose:()=>{g(!1),p(""),w(null)}},k&&(0,t.createElement)("p",{className:"kaigen-error-text"},k),(0,t.createElement)(r.TextareaControl,{label:"Editing Instructions (optional)",value:u,onChange:p,rows:4}),(0,t.createElement)(r.Button,{variant:"primary",onClick:()=>{i(u.trim()),g(!1),p(""),w(null)},disabled:o},o?(0,t.createElement)(t.Fragment,null,(0,t.createElement)(r.Spinner,null),"Regenerating..."):"Regenerate Image"))):s?(0,t.createElement)(r.ToolbarGroup,null,(0,t.createElement)(r.ToolbarButton,{icon:e?(0,t.createElement)(r.Spinner,null):"format-image",label:e?"KaiGen is generating...":"KaiGen",onClick:n,disabled:e})):null},s=window.wp.blockEditor,d=window.wp.data;(0,window.wp.richText.registerFormatType)("kaigen/custom-format",{title:"AI Image Gen",tagName:"span",className:"kaigen-format",edit:({isActive:e,value:r,onChange:n})=>{const[i,l]=(0,a.useState)(!1),m=(0,d.useSelect)((e=>e("core/block-editor").getSelectedBlock()),[]),{replaceBlocks:g}=(0,d.useDispatch)("core/block-editor"),u=(0,a.useCallback)((()=>{if(m&&"core/paragraph"===m.name){const e=r.text.slice(r.start,r.end).trim();if(!e)return void wp.data.dispatch("core/notices").createErrorNotice("Please select some text to use as the image generation prompt.",{type:"snackbar"});const t=wp.data.select("core/editor")?.getEditorSettings()?.kaigen_provider;if(!t)return void wp.data.dispatch("core/notices").createErrorNotice("No AI provider configured. Please set one in the plugin settings.",{type:"snackbar"});const a=wp.blocks.createBlock("core/heading",{content:"Generating AI image...",level:2,className:"kaigen-text-center"});g(m.clientId,[a,m]),l(!0),o(e,(e=>{if(l(!1),e.error)console.error("Image generation failed:",e.error),wp.data.dispatch("core/notices").createErrorNotice("Failed to generate image: "+e.error,{type:"snackbar"}),g(a.clientId,[]);else{let t={url:e.url,alt:e.alt,caption:""};e.id&&"number"==typeof e.id&&e.id>0&&(t.id=e.id);const r=wp.blocks.createBlock("core/image",t);g(a.clientId,[r])}}))}}),[m,r.text,r.start,r.end,g]),p=""!==r.text.slice(r.start,r.end).trim();return(0,t.createElement)(s.BlockControls,null,(0,t.createElement)(c,{isGenerating:i,onGenerateImage:u,isTextSelected:p}))}});const m=window.wp.hooks;(0,m.addFilter)("editor.MediaUpload","kaigen/add-ai-tab",(e=>a=>{const r=a.allowedTypes&&a.allowedTypes.includes("image")&&!a.multiple,n=wp.data.select("core/block-editor").getSelectedBlock(),o=n&&"core/image"===n.name,l=wp.data.select("core/editor")?.getEditorSettings()?.kaigen_has_api_key,c=r&&o&&!(n&&n.attributes&&n.attributes.url)&&l;return(0,t.createElement)(e,{...a,render:e=>(0,t.createElement)(t.Fragment,null,a.render(e),(0,t.createElement)(i,{onSelect:a.onSelect,shouldDisplay:c}))})}));const g=window.wp.apiFetch;var u=e.n(g);(0,m.addFilter)("editor.BlockEdit","kaigen/add-regenerate-button",(e=>n=>{if("core/image"!==n.name)return(0,t.createElement)(e,{...n});const i=n.attributes.id&&"number"==typeof n.attributes.id&&n.attributes.id>0,[l,d]=(0,a.useState)(!1),[m,g]=(0,a.useState)(null),[p,k]=(0,a.useState)(!1);return(0,a.useEffect)((()=>{(async()=>{try{const e=window.kaiGen?.provider,t=window.kaiGen?.supportsImageToImage||!1;if(!e)return;k(t)}catch(e){console.error("Failed to initialize provider:",e)}})()}),[]),(0,t.createElement)(t.Fragment,null,(0,t.createElement)(e,{...n}),(0,t.createElement)(s.BlockControls,null,(0,t.createElement)(c,{isRegenerating:l,onRegenerateImage:async e=>{g(null);const t=e||n.attributes.alt||"no alt text or prompt, please just enhance",a=window.kaiGen?.provider;if(!a)return console.error("No provider configured"),void wp.data.dispatch("core/notices").createErrorNotice("No AI provider configured. Please check your plugin settings.",{type:"snackbar"});d(!0);try{const e=n.attributes.url,a={};p&&e?a.sourceImageUrl=e:p&&!e&&(console.warn("Image-to-image requested but no source image URL available"),wp.data.dispatch("core/notices").createWarningNotice("Image-to-image generation requires a source image. Please ensure the image is properly loaded.",{type:"snackbar"}));const r=await new Promise(((e,r)=>{o(t,(t=>{t.error?r(new Error(t.error)):e(t)}),a)}));r.id&&"number"==typeof r.id&&r.id>0?n.setAttributes({url:r.url,id:r.id}):n.setAttributes({url:r.url,id:void 0}),wp.data.dispatch("core/notices").createSuccessNotice("Image regenerated successfully!",{type:"snackbar"})}catch(e){console.error("Image regeneration failed:",e);let t=e.message||"Unknown error",a="";t.includes("organization verification")?a=" Please verify your organization in the OpenAI dashboard.":t.includes("parameter")?t="API configuration error. Please contact the plugin developer.":t.includes("content policy")&&(a=" Try a different prompt."),wp.data.dispatch("core/notices").createErrorNotice("Failed to regenerate image: "+t+a,{type:"snackbar"})}finally{d(!1)}},isImageBlock:!0,supportsImageToImage:p})),i&&(0,t.createElement)(s.InspectorControls,null,(0,t.createElement)(r.PanelBody,{title:"KaiGen Settings",initialOpen:!1},(0,t.createElement)(r.CheckboxControl,{label:"Reference image",checked:n.attributes.kaigen_reference_image||!1,onChange:async e=>{n.setAttributes({kaigen_reference_image:e});try{await u()({path:`/wp/v2/media/${n.attributes.id}`,method:"POST",data:{meta:{kaigen_reference_image:e?1:0}}})}catch(e){console.error("Failed to update reference image meta:",e),wp.data.dispatch("core/notices").createErrorNotice("Failed to update reference image meta",{type:"snackbar"})}},help:"Add to the list of reference images."}))))})),(0,m.addFilter)("blocks.registerBlockType","kaigen/add-reference-image-attribute",((e,t)=>"core/image"!==t?e:{...e,attributes:{...e.attributes,kaigen_reference_image:{type:"boolean",default:!1}}}))})(); -
kaigen/trunk/inc/class-admin.php
r3361350 r3401075 200 200 // Add quality field 201 201 add_settings_field( 202 'kaigen_quality_setting ',202 'kaigen_quality_settings', 203 203 'Image Quality', 204 204 [$this, 'render_quality_field'], … … 352 352 */ 353 353 public function render_quality_field() { 354 $quality_settings = get_option('kaigen_quality_settings', []); 355 $quality = isset($quality_settings['quality']) ? $quality_settings['quality'] : 'medium'; 354 $quality = KaiGen_Image_Provider::get_quality_setting(); 356 355 ?> 357 356 <select name="kaigen_quality_settings[quality]"> -
kaigen/trunk/inc/class-image-provider.php
r3315977 r3401075 171 171 */ 172 172 abstract public function process_api_response($response); 173 174 /** 175 * Gets the quality setting from the options. 176 * 177 * @return string The quality setting. 178 */ 179 public static function get_quality_setting() { 180 $quality_settings = get_option('kaigen_quality_settings', []); 181 182 // Ensure we have an array to work with. 183 if ( ! is_array( $quality_settings ) ) { 184 $quality_settings = []; 185 } 186 187 // If the quality setting is not set, check for the old option and migrate it. 188 if ( ! isset( $quality_settings['quality'] ) ) { 189 $legacy_quality_setting = get_option('kaigen_quality_setting'); 190 191 if ( ! empty( $legacy_quality_setting ) && in_array( $legacy_quality_setting, ['low', 'medium', 'high'], true ) ) { 192 $quality_settings['quality'] = $legacy_quality_setting; 193 update_option('kaigen_quality_settings', $quality_settings); 194 delete_option('kaigen_quality_setting'); 195 } else { 196 // Default to medium quality if neither exists. 197 $quality_settings['quality'] = 'medium'; 198 update_option('kaigen_quality_settings', $quality_settings); 199 } 200 } 201 202 return $quality_settings['quality']; 203 } 173 204 } -
kaigen/trunk/inc/class-rest-api.php
r3361350 r3401075 124 124 // For Replicate, get the model based on quality setting 125 125 if ($provider_id === 'replicate') { 126 $quality_settings = get_option('kaigen_quality_settings', []); 127 $quality = isset($quality_settings['quality']) ? $quality_settings['quality'] : 'medium'; 126 $quality = KaiGen_Image_Provider::get_quality_setting(); 128 127 129 128 $provider = kaigen_provider_manager()->get_provider($provider_id); … … 161 160 private function get_additional_params($request) { 162 161 // Get saved quality settings 162 $quality = KaiGen_Image_Provider::get_quality_setting(); 163 $quality_value = $quality === 'hd' ? 100 : 80; 163 164 $quality_settings = get_option('kaigen_quality_settings', []); 164 $quality_value = isset($quality_settings['quality']) && $quality_settings['quality'] === 'hd' ? 100 : 80;165 165 $style_value = isset($quality_settings['style']) ? $quality_settings['style'] : 'natural'; 166 166 … … 183 183 184 184 // Add source image URL if provided (single or array) 185 $source_image_url = $request->get_param('source_image_url'); 186 if (!empty($source_image_url)) { 187 $params['source_image_url'] = $source_image_url; 185 $source_image_urls = $request->get_param('source_image_urls'); 186 if (!empty($source_image_urls)) { 187 $params['source_image_urls'] = $source_image_urls; 188 } else { 189 $source_image_url = $request->get_param('source_image_url'); 190 if (!empty($source_image_url)) { 191 $params['source_image_url'] = $source_image_url; 192 } 188 193 } 189 194 … … 274 279 'empty_image_data', 275 280 'replicate_validation_error', 276 'content_moderation' 281 'content_moderation', 282 'api_error', 283 'openai_error', 284 'max_retries_exceeded', 285 'invalid_api_key_format' 277 286 ])) { 278 287 return $result; -
kaigen/trunk/inc/providers/class-image-provider-openai.php
r3315977 r3401075 48 48 } 49 49 50 // Handle source image URLs 51 $source_image_urls = $additional_params['source_image_urls'] ?? []; 50 52 $source_image_url = $additional_params['source_image_url'] ?? null; 51 $max_retries = 3; // Reduce max retries to fail faster 52 $timeout = 60; // Set request timeout to 60 seconds 53 if ($source_image_url) { 54 array_unshift($source_image_urls, $source_image_url); 55 } 56 57 // Limit the number of source image URLs to 16. 58 $source_image_urls = array_slice(array_unique($source_image_urls), 0, 16); 59 60 $max_retries = 3; 61 $timeout = 150; // Increased timeout for image generation (docs say up to 2 mins) 53 62 $retry_delay = 2; // Seconds to wait between retries 54 63 … … 61 70 add_filter('http_request_args', function($args) use ($timeout) { 62 71 $args['timeout'] = $timeout; 63 $args['httpversion'] = '1.1';64 72 $args['sslverify'] = true; 65 73 $args['blocking'] = true; … … 70 78 } 71 79 $args['curl'][CURLOPT_TIMEOUT] = $timeout; 72 $args['curl'][CURLOPT_CONNECTTIMEOUT] = 10; 73 $args['curl'][CURLOPT_LOW_SPEED_TIME] = 30; // Increased low speed time 74 $args['curl'][CURLOPT_LOW_SPEED_LIMIT] = 1024; // 1KB/s minimum speed 80 $args['curl'][CURLOPT_CONNECTTIMEOUT] = 30; // Increased connect timeout 81 $args['curl'][CURLOPT_TCP_KEEPALIVE] = 1; // Enable TCP keepalive 82 83 // Adjust low speed settings to prevent timeouts on slow generation 84 $args['curl'][CURLOPT_LOW_SPEED_TIME] = 600; // Wait 10 minutes before timing out due to low speed 85 $args['curl'][CURLOPT_LOW_SPEED_LIMIT] = 1; // Only timeout if speed is effectively 0 75 86 76 87 return $args; … … 81 92 82 93 // Log if we're using image-to-image 83 if ( ! empty( $source_image_url )) {94 if (!empty($source_image_urls)) { 84 95 $endpoint = self::IMAGE_EDIT_API_BASE_URL; 85 96 } 86 97 87 98 // Get quality setting from admin options 88 $quality_settings = get_option('kaigen_quality_settings', []); 89 $quality = isset($quality_settings['quality']) ? $quality_settings['quality'] : 'medium'; 99 $quality = self::get_quality_setting(); 90 100 91 101 // Map quality settings to supported values … … 100 110 101 111 // Prepare the request based on the type of request 102 if ( ! empty( $source_image_url )) {112 if (!empty($source_image_urls)) { 103 113 // For image edit requests, we need to use multipart/form-data 104 114 $boundary = wp_generate_password(24, false); … … 125 135 $body .= 'Content-Disposition: form-data; name="quality"' . "\r\n\r\n"; 126 136 $body .= $quality . "\r\n"; 137 138 // Add format parameter (jpeg is faster than png) 139 $body .= "--{$boundary}\r\n"; 140 $body .= 'Content-Disposition: form-data; name="output_format"' . "\r\n\r\n"; 141 $body .= "jpeg\r\n"; 127 142 128 143 // Add image files 129 if (is_array($source_image_url)) { 130 foreach ($source_image_url as $index => $image_url) { 131 $image_data = $this->get_image_data($image_url); 132 if (is_wp_error($image_data)) { 133 return $image_data; 134 } 135 136 $body .= "--{$boundary}\r\n"; 137 $body .= 'Content-Disposition: form-data; name="image[]"; filename="' . basename($image_url) . '"' . "\r\n"; 138 $body .= 'Content-Type: ' . $this->get_image_mime_type($image_url) . "\r\n\r\n"; 139 $body .= $image_data . "\r\n"; 140 } 141 } else { 142 $image_data = $this->get_image_data($source_image_url); 144 foreach ($source_image_urls as $index => $image_url) { 145 $image_data = $this->get_image_data($image_url); 143 146 if (is_wp_error($image_data)) { 144 147 return $image_data; … … 146 149 147 150 $body .= "--{$boundary}\r\n"; 148 $body .= 'Content-Disposition: form-data; name="image "; filename="' . basename($source_image_url) . '"' . "\r\n";149 $body .= 'Content-Type: ' . $this->get_image_mime_type($ source_image_url) . "\r\n\r\n";151 $body .= 'Content-Disposition: form-data; name="image[]"; filename="' . basename($image_url) . '"' . "\r\n"; 152 $body .= 'Content-Type: ' . $this->get_image_mime_type($image_url) . "\r\n\r\n"; 150 153 $body .= $image_data . "\r\n"; 151 154 } … … 158 161 $headers = $this->get_request_headers(); 159 162 $body = [ 160 'model' => 'gpt-image-1', 161 'prompt' => $prompt, 162 'quality' => $quality, 163 'model' => 'gpt-image-1', 164 'prompt' => $prompt, 165 'quality' => $quality, 166 'output_format' => 'jpeg', 163 167 ]; 164 168 165 169 // Add size parameter if aspect ratio is specified 166 170 if (isset($additional_params['aspect_ratio'])) { … … 168 172 $body['size'] = "{$width}x{$height}"; 169 173 } 170 174 171 175 $body = wp_json_encode($body); 172 176 } -
kaigen/trunk/inc/providers/class-image-provider-replicate.php
r3361350 r3401075 52 52 */ 53 53 public function get_current_model() { 54 // Get all quality-related options to debug 55 $quality_settings = get_option('kaigen_quality_settings'); 56 $quality_setting = get_option('kaigen_quality_setting'); 57 58 // Use the correct option name 59 $quality = 'medium'; // Default 60 if (is_array($quality_settings) && isset($quality_settings['quality'])) { 61 $quality = $quality_settings['quality']; 62 } 63 54 $quality = self::get_quality_setting(); 64 55 $model = $this->get_model_from_quality_setting($quality); 65 56 return $model; … … 85 76 $model_to_use = $this->model; 86 77 87 // Handle source_image_url parameter (convert to image_input for Replicate seedream-4) 88 $source_image_url = $additional_params['source_image_url'] ?? $additional_params['input_image'] ?? null; 89 90 // If source image is provided, use the hardcoded image-to-image model 91 if (!empty($source_image_url)) { 92 $model_to_use = $this->get_image_to_image_model(); 93 94 // Process image URL (converts to base64 only if local) 95 $processed_image = $this->process_image_url($source_image_url); 96 if (is_wp_error($processed_image)) { 97 // Return image processing errors immediately without retry 98 return $processed_image; 99 } 100 101 // Use 'image_input' parameter as array for seedream-4 model (confirmed by schema) 102 $input_data['image_input'] = [$processed_image]; 103 } 104 105 // Remove these parameters to prevent duplication 78 // Handle source image URLs (can be single string or array) 79 $source_image_urls = $additional_params['source_image_urls'] ?? $additional_params['source_image_url'] ?? null; 80 if (!empty($source_image_urls)) { 81 if (!is_array($source_image_urls)) { 82 $source_image_urls = [$source_image_urls]; 83 } 84 85 $image_inputs = []; 86 foreach ($source_image_urls as $url) { 87 if (count($image_inputs) >= 10) break; 88 $processed = $this->process_image_url($url); 89 if (!is_wp_error($processed)) { 90 $image_inputs[] = $processed; 91 } else { 92 // Log error but continue with other images 93 error_log('Failed to process image: ' . $processed->get_error_message()); 94 } 95 } 96 97 if (!empty($image_inputs)) { 98 $model_to_use = $this->get_image_to_image_model(); 99 $input_data['image_input'] = $image_inputs; 100 101 // Set size to 1k for low quality image edits, assumes we are using seedream-4 model so if that changes, this will need to be updated. 102 $quality = self::get_quality_setting(); 103 104 if ($quality === 'low') { 105 $additional_params['size'] = '1K'; 106 } 107 } 108 } 109 110 // Remove source image parameters to prevent duplication 111 unset($additional_params['source_image_urls']); 106 112 unset($additional_params['source_image_url']); 107 113 unset($additional_params['input_image']); 108 114 109 115 // Filter parameters based on the model being used 110 if (!empty($source_image_url )) {116 if (!empty($source_image_urls)) { 111 117 // For seedream-4, only keep valid parameters according to schema 112 118 $valid_params = ['size', 'width', 'height', 'max_images', 'aspect_ratio', 'sequential_image_generation']; … … 358 364 'black-forest-labs/flux-schnell' => 'Flux Schnell by Black Forest Labs (low quality)', 359 365 'bytedance/seedream-4' => 'Seedream 4 by Bytedance (high quality)', 360 'google/ imagen-4-ultra' => 'Imagen 4 Ultraby Google (highest quality)',366 'google/nano-banana-pro' => 'Nano Banana Pro by Google (highest quality)', 361 367 ]; 362 368 } 363 369 364 370 /** 365 * Gets the hardcoded image-to-image model for Replicate.371 * Gets the image-to-image model for Replicate based on quality setting. 366 372 * 367 373 * @return string The image-to-image model. 368 374 */ 369 375 private function get_image_to_image_model() { 370 return 'bytedance/seedream-4'; 376 $model = 'bytedance/seedream-4'; 377 $quality = self::get_quality_setting(); 378 379 if ($quality === 'high') { 380 $model = 'google/nano-banana-pro'; 381 } 382 383 return $model; 371 384 } 372 385 … … 395 408 break; 396 409 case 'high': 397 $model = 'google/ imagen-4-ultra';410 $model = 'google/nano-banana-pro'; 398 411 break; 399 412 default: -
kaigen/trunk/kaigen.php
r3361350 r3401075 5 5 * Requires at least: 6.1 6 6 * Requires PHP: 7.0 7 * Version: 0.2. 37 * Version: 0.2.4 8 8 * Author: Jacob Schweitzer 9 9 * License: GPL-2.0-or-later
Note: See TracChangeset
for help on using the changeset viewer.