comfyui-frontend-package 1.38.2__py3-none-any.whl → 1.38.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- comfyui_frontend_package/static/assets/{AboutPanel-C7253TdA.js → AboutPanel-CYH8kZrG.js} +2 -2
- comfyui_frontend_package/static/assets/{AboutPanel-C7253TdA.js.map → AboutPanel-CYH8kZrG.js.map} +1 -1
- comfyui_frontend_package/static/assets/{AudioPreviewPlayer-DgSsFFU7.js → AudioPreviewPlayer-BwJepJEw.js} +2 -2
- comfyui_frontend_package/static/assets/{AudioPreviewPlayer-DgSsFFU7.js.map → AudioPreviewPlayer-BwJepJEw.js.map} +1 -1
- comfyui_frontend_package/static/assets/{ComfyQueueButton-DriR7JtM.js → ComfyQueueButton-BM8zaTn_.js} +2 -2
- comfyui_frontend_package/static/assets/{ComfyQueueButton-DriR7JtM.js.map → ComfyQueueButton-BM8zaTn_.js.map} +1 -1
- comfyui_frontend_package/static/assets/{ExtensionPanel-yJP3r-dq.js → ExtensionPanel-CkIkopXr.js} +2 -2
- comfyui_frontend_package/static/assets/{ExtensionPanel-yJP3r-dq.js.map → ExtensionPanel-CkIkopXr.js.map} +1 -1
- comfyui_frontend_package/static/assets/{GraphView-D-tZ3xO5.css → GraphView-CoiT3fdb.css} +1 -1
- comfyui_frontend_package/static/assets/GraphView-Djp0ICHX.js +15 -0
- comfyui_frontend_package/static/assets/GraphView-Djp0ICHX.js.map +1 -0
- comfyui_frontend_package/static/assets/{KeybindingPanel-f7VKBCyl.js → KeybindingPanel-5iNg_eid.js} +2 -2
- comfyui_frontend_package/static/assets/{KeybindingPanel-f7VKBCyl.js.map → KeybindingPanel-5iNg_eid.js.map} +1 -1
- comfyui_frontend_package/static/assets/LazyImage.vue_vue_type_script_setup_true_lang-Bwob1r0X.js +2 -0
- comfyui_frontend_package/static/assets/LazyImage.vue_vue_type_script_setup_true_lang-Bwob1r0X.js.map +1 -0
- comfyui_frontend_package/static/assets/{LegacyCreditsPanel-e57J4OZv.js → LegacyCreditsPanel-D28HHk-A.js} +2 -2
- comfyui_frontend_package/static/assets/{LegacyCreditsPanel-e57J4OZv.js.map → LegacyCreditsPanel-D28HHk-A.js.map} +1 -1
- comfyui_frontend_package/static/assets/{Load3D-DYW1gw8I.js → Load3D-CPNYDT4-.js} +2 -2
- comfyui_frontend_package/static/assets/Load3D-CPNYDT4-.js.map +1 -0
- comfyui_frontend_package/static/assets/{Load3D.vue_vue_type_script_setup_true_lang-BLcsvL5E.js → Load3D.vue_vue_type_script_setup_true_lang-KEzORqB0.js} +2 -2
- comfyui_frontend_package/static/assets/{Load3D.vue_vue_type_script_setup_true_lang-BLcsvL5E.js.map → Load3D.vue_vue_type_script_setup_true_lang-KEzORqB0.js.map} +1 -1
- comfyui_frontend_package/static/assets/{Media3DTop-D77j8ukJ.js → Media3DTop-CQp4nFvB.js} +2 -2
- comfyui_frontend_package/static/assets/{Media3DTop-D77j8ukJ.js.map → Media3DTop-CQp4nFvB.js.map} +1 -1
- comfyui_frontend_package/static/assets/{ServerConfigPanel-CQPgIsZk.js → ServerConfigPanel-B3WCmowi.js} +2 -2
- comfyui_frontend_package/static/assets/{ServerConfigPanel-CQPgIsZk.js.map → ServerConfigPanel-B3WCmowi.js.map} +1 -1
- comfyui_frontend_package/static/assets/{SubscriptionRequiredDialogContent-DtxMOWxy.js → SubscriptionRequiredDialogContent-JgqOjXs3.js} +2 -2
- comfyui_frontend_package/static/assets/{SubscriptionRequiredDialogContent-DtxMOWxy.js.map → SubscriptionRequiredDialogContent-JgqOjXs3.js.map} +1 -1
- comfyui_frontend_package/static/assets/{UserPanel-BPwKKP_j.js → UserPanel-B5k84B9y.js} +2 -2
- comfyui_frontend_package/static/assets/{UserPanel-BPwKKP_j.js.map → UserPanel-B5k84B9y.js.map} +1 -1
- comfyui_frontend_package/static/assets/{UserSelectView-DNaXeKx4.js → UserSelectView-R_nCWiDS.js} +2 -2
- comfyui_frontend_package/static/assets/{UserSelectView-DNaXeKx4.js.map → UserSelectView-R_nCWiDS.js.map} +1 -1
- comfyui_frontend_package/static/assets/{ValueControlPopover-kd7h8GFO.js → ValueControlPopover-BqA-EaFY.js} +2 -2
- comfyui_frontend_package/static/assets/{ValueControlPopover-kd7h8GFO.js.map → ValueControlPopover-BqA-EaFY.js.map} +1 -1
- comfyui_frontend_package/static/assets/{WidgetAudioUI-B-Ra7X5I.js → WidgetAudioUI-Bu3u9PBZ.js} +2 -2
- comfyui_frontend_package/static/assets/{WidgetAudioUI-B-Ra7X5I.js.map → WidgetAudioUI-Bu3u9PBZ.js.map} +1 -1
- comfyui_frontend_package/static/assets/{WidgetButton-BQWWeE_x.js → WidgetButton-CS0lZIN_.js} +2 -2
- comfyui_frontend_package/static/assets/{WidgetButton-BQWWeE_x.js.map → WidgetButton-CS0lZIN_.js.map} +1 -1
- comfyui_frontend_package/static/assets/{WidgetColorPicker-4E2rnL8u.js → WidgetColorPicker-CQ_vqexP.js} +2 -2
- comfyui_frontend_package/static/assets/{WidgetColorPicker-4E2rnL8u.js.map → WidgetColorPicker-CQ_vqexP.js.map} +1 -1
- comfyui_frontend_package/static/assets/{WidgetGalleria-DaEjYhLq.js → WidgetGalleria-CE2__qNK.js} +2 -2
- comfyui_frontend_package/static/assets/{WidgetGalleria-DaEjYhLq.js.map → WidgetGalleria-CE2__qNK.js.map} +1 -1
- comfyui_frontend_package/static/assets/WidgetInputNumber-CR_vNT3l.js +2 -0
- comfyui_frontend_package/static/assets/WidgetInputNumber-CR_vNT3l.js.map +1 -0
- comfyui_frontend_package/static/assets/{WidgetInputNumber.vue_vue_type_script_setup_true_lang-CdvBpGed.js → WidgetInputNumber.vue_vue_type_script_setup_true_lang-rPX1TIkC.js} +2 -2
- comfyui_frontend_package/static/assets/{WidgetInputNumber.vue_vue_type_script_setup_true_lang-CdvBpGed.js.map → WidgetInputNumber.vue_vue_type_script_setup_true_lang-rPX1TIkC.js.map} +1 -1
- comfyui_frontend_package/static/assets/{WidgetInputText-B2YoBI4Y.js → WidgetInputText-NnOJku4t.js} +2 -2
- comfyui_frontend_package/static/assets/{WidgetInputText-B2YoBI4Y.js.map → WidgetInputText-NnOJku4t.js.map} +1 -1
- comfyui_frontend_package/static/assets/{WidgetLayoutField.vue_vue_type_script_setup_true_lang-CYDaxuge.js → WidgetLayoutField.vue_vue_type_script_setup_true_lang-BrNsu13j.js} +2 -2
- comfyui_frontend_package/static/assets/{WidgetLayoutField.vue_vue_type_script_setup_true_lang-CYDaxuge.js.map → WidgetLayoutField.vue_vue_type_script_setup_true_lang-BrNsu13j.js.map} +1 -1
- comfyui_frontend_package/static/assets/{WidgetLegacy-DgBI3-l2.js → WidgetLegacy-3d5GSSgo.js} +2 -2
- comfyui_frontend_package/static/assets/WidgetLegacy-3d5GSSgo.js.map +1 -0
- comfyui_frontend_package/static/assets/{WidgetMarkdown-Bqcf7Vpy.js → WidgetMarkdown-BTfwNVeV.js} +2 -2
- comfyui_frontend_package/static/assets/{WidgetMarkdown-Bqcf7Vpy.js.map → WidgetMarkdown-BTfwNVeV.js.map} +1 -1
- comfyui_frontend_package/static/assets/WidgetRecordAudio-X2n565MP.js +2 -0
- comfyui_frontend_package/static/assets/WidgetRecordAudio-X2n565MP.js.map +1 -0
- comfyui_frontend_package/static/assets/WidgetSelect-DsU3dEFm.js +2 -0
- comfyui_frontend_package/static/assets/WidgetSelect-DsU3dEFm.js.map +1 -0
- comfyui_frontend_package/static/assets/{WidgetSelect.vue_vue_type_script_setup_true_lang-Ua67RWUI.js → WidgetSelect.vue_vue_type_script_setup_true_lang-DLMXofNs.js} +2 -2
- comfyui_frontend_package/static/assets/{WidgetSelect.vue_vue_type_script_setup_true_lang-Ua67RWUI.js.map → WidgetSelect.vue_vue_type_script_setup_true_lang-DLMXofNs.js.map} +1 -1
- comfyui_frontend_package/static/assets/{WidgetTextarea-syfN9Olh.js → WidgetTextarea-BguNaUH3.js} +2 -2
- comfyui_frontend_package/static/assets/{WidgetTextarea-syfN9Olh.js.map → WidgetTextarea-BguNaUH3.js.map} +1 -1
- comfyui_frontend_package/static/assets/{WidgetToggleSwitch-C2c4CfAT.js → WidgetToggleSwitch-Cnenb1g4.js} +2 -2
- comfyui_frontend_package/static/assets/{WidgetToggleSwitch-C2c4CfAT.js.map → WidgetToggleSwitch-Cnenb1g4.js.map} +1 -1
- comfyui_frontend_package/static/assets/{WidgetWithControl.vue_vue_type_script_setup_true_lang-B5RYQ41H.js → WidgetWithControl.vue_vue_type_script_setup_true_lang-CWBg5k0x.js} +3 -3
- comfyui_frontend_package/static/assets/{WidgetWithControl.vue_vue_type_script_setup_true_lang-B5RYQ41H.js.map → WidgetWithControl.vue_vue_type_script_setup_true_lang-CWBg5k0x.js.map} +1 -1
- comfyui_frontend_package/static/assets/{audioService-CnSU5S1Z.js → audioService-C_4pv8R5.js} +2 -2
- comfyui_frontend_package/static/assets/{audioService-CnSU5S1Z.js.map → audioService-C_4pv8R5.js.map} +1 -1
- comfyui_frontend_package/static/assets/{audioUtils-BZ8b3tiu.js → audioUtils-CYVbzDGB.js} +2 -2
- comfyui_frontend_package/static/assets/{audioUtils-BZ8b3tiu.js.map → audioUtils-CYVbzDGB.js.map} +1 -1
- comfyui_frontend_package/static/assets/{index-BBvP0bLh.js → index-BST1SetX.js} +2 -2
- comfyui_frontend_package/static/assets/{index-BBvP0bLh.js.map → index-BST1SetX.js.map} +1 -1
- comfyui_frontend_package/static/assets/index-DOAA7WkP.css +1 -0
- comfyui_frontend_package/static/assets/{index-C5dKoXkW.js → index-DwjwpNvK.js} +2 -2
- comfyui_frontend_package/static/assets/index-DwjwpNvK.js.map +1 -0
- comfyui_frontend_package/static/assets/{index-Bc79VbnU.js → index-U7jagKl8.js} +22 -22
- comfyui_frontend_package/static/assets/index-U7jagKl8.js.map +1 -0
- comfyui_frontend_package/static/assets/{keybindingService-DOwK-S5D.js → keybindingService-6A6hKCpd.js} +2 -2
- comfyui_frontend_package/static/assets/{keybindingService-DOwK-S5D.js.map → keybindingService-6A6hKCpd.js.map} +1 -1
- comfyui_frontend_package/static/assets/{main-9V_ekXTj.js → main-7u-fkFqV.js} +4 -4
- comfyui_frontend_package/static/assets/main-7u-fkFqV.js.map +1 -0
- comfyui_frontend_package/static/assets/{main-Mk83jtey.js → main-BrRR7na1.js} +4 -4
- comfyui_frontend_package/static/assets/main-BrRR7na1.js.map +1 -0
- comfyui_frontend_package/static/assets/{main-QxfzWHY3.js → main-Btwx4xDf.js} +5 -5
- comfyui_frontend_package/static/assets/main-Btwx4xDf.js.map +1 -0
- comfyui_frontend_package/static/assets/{main-D8WRsxlG.js → main-CU-38qC-.js} +3 -3
- comfyui_frontend_package/static/assets/main-CU-38qC-.js.map +1 -0
- comfyui_frontend_package/static/assets/{main-DdPAQm8u.js → main-CZbK9-kR.js} +4 -4
- comfyui_frontend_package/static/assets/main-CZbK9-kR.js.map +1 -0
- comfyui_frontend_package/static/assets/{main-IIi2nOrM.js → main-Cv05dk1q.js} +4 -4
- comfyui_frontend_package/static/assets/main-Cv05dk1q.js.map +1 -0
- comfyui_frontend_package/static/assets/{main-Be2ivsXL.js → main-DVNhdlF2.js} +4 -6
- comfyui_frontend_package/static/assets/main-DVNhdlF2.js.map +1 -0
- comfyui_frontend_package/static/assets/{main-DnlhxsrE.js → main-DckcRPaY.js} +3 -3
- comfyui_frontend_package/static/assets/main-DckcRPaY.js.map +1 -0
- comfyui_frontend_package/static/assets/{main-B992pnxN.js → main-DeynLPZA.js} +4 -4
- comfyui_frontend_package/static/assets/main-DeynLPZA.js.map +1 -0
- comfyui_frontend_package/static/assets/{main-AFY0Q5Cd.js → main-DtCc3tTY.js} +4 -4
- comfyui_frontend_package/static/assets/main-DtCc3tTY.js.map +1 -0
- comfyui_frontend_package/static/assets/{main-QbQAnNpJ.js → main-apejL0E_.js} +4 -4
- comfyui_frontend_package/static/assets/main-apejL0E_.js.map +1 -0
- comfyui_frontend_package/static/index.html +1 -1
- {comfyui_frontend_package-1.38.2.dist-info → comfyui_frontend_package-1.38.3.dist-info}/METADATA +1 -1
- {comfyui_frontend_package-1.38.2.dist-info → comfyui_frontend_package-1.38.3.dist-info}/RECORD +105 -105
- comfyui_frontend_package/static/assets/GraphView-Dwrm8D3J.js +0 -15
- comfyui_frontend_package/static/assets/GraphView-Dwrm8D3J.js.map +0 -1
- comfyui_frontend_package/static/assets/LazyImage.vue_vue_type_script_setup_true_lang-CX9YtPlM.js +0 -2
- comfyui_frontend_package/static/assets/LazyImage.vue_vue_type_script_setup_true_lang-CX9YtPlM.js.map +0 -1
- comfyui_frontend_package/static/assets/Load3D-DYW1gw8I.js.map +0 -1
- comfyui_frontend_package/static/assets/WidgetInputNumber-u4JzBngV.js +0 -2
- comfyui_frontend_package/static/assets/WidgetInputNumber-u4JzBngV.js.map +0 -1
- comfyui_frontend_package/static/assets/WidgetLegacy-DgBI3-l2.js.map +0 -1
- comfyui_frontend_package/static/assets/WidgetRecordAudio-hHbaGdj1.js +0 -2
- comfyui_frontend_package/static/assets/WidgetRecordAudio-hHbaGdj1.js.map +0 -1
- comfyui_frontend_package/static/assets/WidgetSelect-Cv4W8ECC.js +0 -2
- comfyui_frontend_package/static/assets/WidgetSelect-Cv4W8ECC.js.map +0 -1
- comfyui_frontend_package/static/assets/index-Bc79VbnU.js.map +0 -1
- comfyui_frontend_package/static/assets/index-C5dKoXkW.js.map +0 -1
- comfyui_frontend_package/static/assets/index-gxCJ3H4T.css +0 -1
- comfyui_frontend_package/static/assets/main-9V_ekXTj.js.map +0 -1
- comfyui_frontend_package/static/assets/main-AFY0Q5Cd.js.map +0 -1
- comfyui_frontend_package/static/assets/main-B992pnxN.js.map +0 -1
- comfyui_frontend_package/static/assets/main-Be2ivsXL.js.map +0 -1
- comfyui_frontend_package/static/assets/main-D8WRsxlG.js.map +0 -1
- comfyui_frontend_package/static/assets/main-DdPAQm8u.js.map +0 -1
- comfyui_frontend_package/static/assets/main-DnlhxsrE.js.map +0 -1
- comfyui_frontend_package/static/assets/main-IIi2nOrM.js.map +0 -1
- comfyui_frontend_package/static/assets/main-Mk83jtey.js.map +0 -1
- comfyui_frontend_package/static/assets/main-QbQAnNpJ.js.map +0 -1
- comfyui_frontend_package/static/assets/main-QxfzWHY3.js.map +0 -1
- {comfyui_frontend_package-1.38.2.dist-info → comfyui_frontend_package-1.38.3.dist-info}/WHEEL +0 -0
- {comfyui_frontend_package-1.38.2.dist-info → comfyui_frontend_package-1.38.3.dist-info}/top_level.txt +0 -0
comfyui_frontend_package/static/assets/LazyImage.vue_vue_type_script_setup_true_lang-CX9YtPlM.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
var pe=Object.defineProperty;var m=(i,e)=>pe(i,"name",{value:e,configurable:!0});import{cT as j,a as C,c as W,_ as V,k as me,cz as fe,l as ge,h as K,s as ve,u as ae,d as se,m as he}from"./index-Bc79VbnU.js";import{b as re,E as B,a as be,a2 as I,dk as H,dl as q,j as F,d as u,a8 as p,m as ye,k as y,e as r,G as te,c as g,q as _,u as c,p as we,dE as _e,d4 as $e,z as k,w as R,dD as ke,fa as Me,r as x,A as D,F as Ue,f as ne,o as xe,bV as Se,d$ as Ce,Z as Fe,L as Ie,s as z,l as Ve,dT as Be,dN as Le,_ as je}from"./vendor-other-Dsj-QuOx.js";import{i as De,y as Ee,e as ie,a as Ae}from"./vendor-primevue-Cif--Rbw.js";import{b as de}from"./vendor-vue-DNQSPQQ2.js";function A(){const i=re({get supportsPreviewMetadata(){return C.getServerFeature("supports_preview_metadata")},get maxUploadSize(){return C.getServerFeature("max_upload_size")},get supportsManagerV4(){return C.getServerFeature("extension.manager.supports_v4")},get modelUploadButtonEnabled(){return j.value.model_upload_button_enabled??C.getServerFeature("model_upload_button_enabled",!1)},get assetDeletionEnabled(){return j.value.asset_deletion_enabled??C.getServerFeature("asset_deletion_enabled",!1)},get assetRenameEnabled(){return j.value.asset_rename_enabled??C.getServerFeature("asset_rename_enabled",!1)},get privateModelsEnabled(){return j.value.private_models_enabled??C.getServerFeature("private_models_enabled",!1)},get onboardingSurveyEnabled(){return j.value.onboarding_survey_enabled??C.getServerFeature("onboarding_survey_enabled",!0)},get huggingfaceModelImportEnabled(){return j.value.huggingface_model_import_enabled??C.getServerFeature("huggingface_model_import_enabled",!1)},get linearToggleEnabled(){return j.value.linear_toggle_enabled??C.getServerFeature("linear_toggle_enabled",!1)},get asyncModelUploadEnabled(){return j.value.async_model_upload_enabled??C.getServerFeature("async_model_upload_enabled",!1)}}),e=m((n,o)=>B(()=>C.getServerFeature(n,o)),"featureFlag");return{flags:be(i),featureFlag:e}}m(A,"useFeatureFlags");const ze={class:"flex items-center gap-2 text-sm"},Re={key:0,class:"text-base-foreground"},Te={key:1,class:"text-base-foreground"},Pe={class:"truncate"},We={key:0,class:"icon-[lucide--check] text-base-foreground"},He=I({inheritAttrs:!1,__name:"SingleSelect",props:H({label:{},options:{},listMaxHeight:{default:"28rem"},popoverMinWidth:{},popoverMaxWidth:{}},{modelValue:{required:!0},modelModifiers:{}}),emits:["update:modelValue"],setup(i){const e=q(i,"modelValue"),{t:n}=de(),o=m(l=>{if(l==null||!i.options)return i.label??"";const t=i.options.find(s=>s.value===l);return t?t.name:i.label??""},"getLabel"),a=B(()=>{if(!i.popoverMinWidth&&!i.popoverMaxWidth)return;const l=[];return i.popoverMinWidth&&l.push(`min-width: ${i.popoverMinWidth}`),i.popoverMaxWidth&&l.push(`max-width: ${i.popoverMaxWidth}`),l.join("; ")});return(l,t)=>(u(),F(p(De),ye({modelValue:e.value,"onUpdate:modelValue":t[0]||(t[0]=s=>e.value=s)},l.$attrs,{options:l.options,"option-label":"name","option-value":"value",unstyled:"",pt:{root:m(({props:s})=>({class:["h-10 relative inline-flex cursor-pointer select-none items-center","rounded-lg","bg-secondary-background text-base-foreground","border-[2.5px] border-solid border-transparent","transition-all duration-200 ease-in-out","focus-within:border-node-component-border",{"opacity-60 cursor-default":s.disabled}]}),"root"),label:{class:"flex-1 flex items-center whitespace-nowrap pl-4 py-2 outline-hidden"},dropdown:{class:"flex shrink-0 items-center justify-center px-3 py-2"},overlay:{class:p(W)("mt-2 p-2 rounded-lg","bg-base-background text-base-foreground","border border-solid border-border-default")},listContainer:m(()=>({style:`max-height: min(${l.listMaxHeight}, 50vh)`,class:"scrollbar-custom"}),"listContainer"),list:{class:"flex flex-col gap-0 p-0 m-0 list-none border-none text-sm"},option:m(({context:s})=>({class:p(W)("flex items-center justify-between gap-3 px-2 py-3 rounded","hover:bg-secondary-background-hover",s.focused&&"bg-secondary-background-hover",s.selected&&"bg-secondary-background-selected hover:bg-secondary-background-selected")}),"option"),optionLabel:{class:"truncate"},optionGroupLabel:{class:"px-3 py-2 text-xs uppercase tracking-wide text-muted-foreground"},emptyMessage:{class:"px-3 py-2 text-sm text-muted-foreground"}},"aria-label":l.label||p(n)("g.singleSelectDropdown"),role:"combobox","aria-expanded":!1,"aria-haspopup":"listbox",tabindex:0}),{value:y(s=>[r("div",ze,[we(l.$slots,"icon"),s.value!==null&&s.value!==void 0?(u(),g("span",Re,c(o(s.value)),1)):(u(),g("span",Te,c(l.label),1))])]),dropdownicon:y(()=>t[1]||(t[1]=[r("i",{class:"icon-[lucide--chevron-down] text-muted-foreground"},null,-1)])),option:y(({option:s,selected:d})=>[r("div",{class:"flex w-full items-center justify-between gap-3",style:te(a.value)},[r("span",Pe,c(s.name),1),d?(u(),g("i",We)):_("",!0)],4)]),_:3},16,["modelValue","options","pt","aria-label"]))}});function qe(i){const e={loras:"LoRA",ipadapter:"IP-Adapter",sams:"SAM",clip_vision:"CLIP Vision",animatediff_motion_lora:"AnimateDiff Motion LoRA",animatediff_models:"AnimateDiff Model",vae:"VAE",sam2:"SAM 2",controlnet:"ControlNet",gligen:"GLIGEN"};return e[i]?e[i]:i.split("_").map(n=>n.charAt(0).toUpperCase()+n.slice(1)).join(" ")}m(qe,"formatDisplayName");const Oe=["nlf"],ue=_e(()=>{const{state:i,isLoading:e,error:n,execute:o}=$e(async()=>(await C.getModelFolders()).filter(l=>!Oe.includes(l.name)).map(l=>({name:qe(l.name),value:l.name})).sort((l,t)=>l.name.localeCompare(t.name)),[],{immediate:!1,onError:m(a=>{console.error("Failed to fetch model types:",a)},"onError")});return{modelTypes:i,isLoading:e,error:n,fetchModelTypes:o}}),Ne={class:"flex flex-col gap-4 text-sm text-muted-foreground"},Ge={class:"flex flex-col gap-2"},Ke={class:"m-0"},Qe={class:"flex items-center gap-3 rounded-lg bg-secondary-background px-4 py-2"},Ye=["src","alt"],Ze={class:"m-0 min-w-0 flex-1 truncate text-base-foreground"},Je={class:"flex flex-col gap-2"},Xe={class:"flex items-center gap-2"},et={class:"text-muted-foreground"},tt=I({__name:"UploadModelConfirmation",props:H({metadata:{},previewImage:{}},{modelValue:{},modelModifiers:{}}),emits:["update:modelValue"],setup(i){const e=q(i,"modelValue"),{modelTypes:n,isLoading:o}=ue();return(a,l)=>(u(),g("div",Ne,[r("div",Ge,[r("p",Ke,c(a.$t("assetBrowser.modelAssociatedWithLink")),1),r("div",Qe,[a.previewImage?(u(),g("img",{key:0,src:a.previewImage,alt:a.metadata?.filename||a.metadata?.name||"Model preview",class:"size-14 flex-shrink-0 rounded object-cover"},null,8,Ye)):_("",!0),r("p",Ze,c(a.metadata?.filename||a.metadata?.name),1)])]),r("div",Je,[r("div",Xe,[r("label",null,c(a.$t("assetBrowser.modelTypeSelectorLabel")),1),l[1]||(l[1]=r("i",{class:"icon-[lucide--circle-question-mark] text-muted-foreground"},null,-1)),r("span",et,c(a.$t("assetBrowser.notSureLeaveAsIs")),1)]),k(He,{modelValue:e.value,"onUpdate:modelValue":l[0]||(l[0]=t=>e.value=t),label:p(o)?a.$t("g.loading"):a.$t("assetBrowser.modelTypeSelectorPlaceholder"),options:p(n),disabled:p(o),"data-attr":"upload-model-step2-type-selector"},null,8,["modelValue","label","options","disabled"])])]))}}),at={class:"relative"},st=["aria-label","src"],le=I({__name:"VideoHelpDialog",props:H({videoUrl:{},ariaLabel:{default:"Help video"}},{modelValue:{type:Boolean,required:!0},modelModifiers:{}}),emits:["update:modelValue"],setup(i){const e=q(i,"modelValue"),n=m(o=>{o.key==="Escape"&&(o.stopImmediatePropagation(),o.stopPropagation(),o.preventDefault(),e.value=!1)},"handleEscapeKey");return R(e,o=>{if(o){const a=ke(document,"keydown",n,{capture:!0});Me(a)}},{immediate:!0}),(o,a)=>(u(),F(p(Ee),{visible:e.value,"onUpdate:visible":a[1]||(a[1]=l=>e.value=l),modal:"",closable:!1,"close-on-escape":!1,"dismissable-mask":!0,pt:{root:{class:"video-help-dialog"},header:{class:"!hidden"},content:{class:"!p-0"},mask:{class:"!bg-black/70"}},style:{width:"90vw"}},{default:y(()=>[r("div",at,[k(V,{variant:"textonly",size:"icon",class:"absolute top-4 right-6 z-10","aria-label":o.$t("g.close"),onClick:a[0]||(a[0]=l=>e.value=!1)},{default:y(()=>a[2]||(a[2]=[r("i",{class:"pi pi-times text-sm"},null,-1)])),_:1},8,["aria-label"]),r("video",{autoplay:"",muted:"",loop:"","aria-label":o.ariaLabel,class:"w-full rounded-lg",src:o.videoUrl},c(o.$t("g.videoFailedToLoad")),9,st)])]),_:1},8,["visible"]))}}),ot={class:"flex justify-end gap-2 w-full"},lt={key:0,class:"mr-auto flex items-center gap-2"},rt={key:4},nt={key:0,class:"icon-[lucide--loader-circle] animate-spin"},it={key:0,class:"icon-[lucide--loader-circle] animate-spin"},dt=I({__name:"UploadModelFooter",props:{currentStep:{},isFetchingMetadata:{type:Boolean},isUploading:{type:Boolean},canFetchMetadata:{type:Boolean},canUploadModel:{type:Boolean},uploadStatus:{}},emits:["back","fetchMetadata","upload","close","importAnother"],setup(i,{emit:e}){const{flags:n}=A(),o=x(!1),a=x(!1),l=e;return(t,s)=>(u(),g("div",ot,[t.currentStep===1&&p(n).huggingfaceModelImportEnabled?(u(),g("div",lt,[s[11]||(s[11]=r("i",{class:"icon-[lucide--circle-question-mark] text-muted-foreground"},null,-1)),k(V,{variant:"muted-textonly",size:"sm","data-attr":"upload-model-step1-help-civitai",onClick:s[0]||(s[0]=d=>o.value=!0)},{default:y(()=>[D(c(t.$t("assetBrowser.providerCivitai")),1)]),_:1}),k(V,{variant:"muted-textonly",size:"sm","data-attr":"upload-model-step1-help-huggingface",onClick:s[1]||(s[1]=d=>a.value=!0)},{default:y(()=>[D(c(t.$t("assetBrowser.providerHuggingFace")),1)]),_:1})])):t.currentStep===1?(u(),F(V,{key:1,variant:"muted-textonly",size:"lg",class:"mr-auto underline","data-attr":"upload-model-step1-help-link",onClick:s[2]||(s[2]=d=>o.value=!0)},{default:y(()=>[s[12]||(s[12]=r("i",{class:"icon-[lucide--circle-question-mark]"},null,-1)),r("span",null,c(t.$t("assetBrowser.uploadModelHowDoIFindThis")),1)]),_:1})):_("",!0),t.currentStep===1?(u(),F(V,{key:2,variant:"muted-textonly",size:"lg","data-attr":"upload-model-step1-cancel-button",disabled:t.isFetchingMetadata||t.isUploading,onClick:s[3]||(s[3]=d=>l("close"))},{default:y(()=>[D(c(t.$t("g.cancel")),1)]),_:1},8,["disabled"])):_("",!0),t.currentStep!==1&&t.currentStep!==3?(u(),F(V,{key:3,variant:"muted-textonly",size:"lg","data-attr":`upload-model-step${t.currentStep}-back-button`,disabled:t.isFetchingMetadata||t.isUploading,onClick:s[4]||(s[4]=d=>l("back"))},{default:y(()=>[D(c(t.$t("g.back")),1)]),_:1},8,["data-attr","disabled"])):(u(),g("span",rt)),t.currentStep===1?(u(),F(V,{key:5,variant:"secondary",size:"lg","data-attr":"upload-model-step1-continue-button",disabled:!t.canFetchMetadata||t.isFetchingMetadata,onClick:s[5]||(s[5]=d=>l("fetchMetadata"))},{default:y(()=>[t.isFetchingMetadata?(u(),g("i",nt)):_("",!0),r("span",null,c(t.$t("g.continue")),1)]),_:1},8,["disabled"])):t.currentStep===2?(u(),F(V,{key:6,variant:"secondary",size:"lg","data-attr":"upload-model-step2-confirm-button",disabled:!t.canUploadModel||t.isUploading,onClick:s[6]||(s[6]=d=>l("upload"))},{default:y(()=>[t.isUploading?(u(),g("i",it)):_("",!0),r("span",null,c(t.$t("assetBrowser.upload")),1)]),_:1},8,["disabled"])):t.currentStep===3&&(t.uploadStatus==="success"||t.uploadStatus==="processing")?(u(),g(Ue,{key:7},[k(V,{variant:"muted-textonly",size:"lg","data-attr":"upload-model-step3-import-another-button",onClick:s[7]||(s[7]=d=>l("importAnother"))},{default:y(()=>[D(c(t.$t("assetBrowser.importAnother")),1)]),_:1}),k(V,{variant:"secondary",size:"lg","data-attr":"upload-model-step3-finish-button",onClick:s[8]||(s[8]=d=>l("close"))},{default:y(()=>[D(c(t.uploadStatus==="processing"?t.$t("g.close"):t.$t("assetBrowser.finish")),1)]),_:1})],64)):_("",!0),k(le,{modelValue:o.value,"onUpdate:modelValue":s[9]||(s[9]=d=>o.value=d),"video-url":"https://media.comfy.org/compressed_768/civitai_howto.webm","aria-label":t.$t("assetBrowser.uploadModelHelpVideo")},null,8,["modelValue","aria-label"]),k(le,{modelValue:a.value,"onUpdate:modelValue":s[10]||(s[10]=d=>a.value=d),"video-url":"https://media.comfy.org/byom/huggingfacehowto.mp4","aria-label":t.$t("assetBrowser.uploadModelHelpVideo")},null,8,["modelValue","aria-label"])]))}}),ut={class:"flex flex-1 flex-col gap-6 text-sm text-muted-foreground"},ct={key:0,class:"flex flex-col gap-2"},pt={class:"m-0 font-bold"},mt={class:"m-0"},ft={class:"flex flex-row items-center gap-3 rounded-lg bg-modal-card-background p-4"},gt=["src","alt"],vt={class:"flex min-w-0 flex-1 flex-col items-start justify-center gap-1"},ht={class:"m-0 w-full truncate text-base-foreground"},bt={class:"m-0 text-sm text-muted"},yt={key:1,class:"flex flex-col gap-2"},wt={class:"m-0 font-bold"},_t={class:"m-0"},$t={class:"flex flex-row items-center gap-3 rounded-lg bg-modal-card-background p-4"},kt=["src","alt"],Mt={class:"flex min-w-0 flex-1 flex-col items-start justify-center gap-1"},Ut={class:"m-0 w-full truncate text-base-foreground"},xt={class:"m-0 text-sm text-muted"},St={key:2,class:"flex flex-1 flex-col items-center justify-center gap-6"},Ct={class:"text-center"},Ft={class:"m-0 text-sm font-bold"},It={key:0,class:"text-sm text-muted mb-0"},Vt=I({__name:"UploadModelProgress",props:{result:{},error:{},metadata:{},modelType:{},previewImage:{}},setup(i){return(e,n)=>(u(),g("div",ut,[e.result==="processing"?(u(),g("div",ct,[r("p",pt,c(e.$t("assetBrowser.processingModel")),1),r("p",mt,c(e.$t("assetBrowser.processingModelDescription")),1),r("div",ft,[e.previewImage?(u(),g("img",{key:0,src:e.previewImage,alt:e.metadata?.filename||e.metadata?.name||"Model preview",class:"size-14 flex-shrink-0 rounded object-cover"},null,8,gt)):_("",!0),r("div",vt,[r("p",ht,c(e.metadata?.filename||e.metadata?.name),1),r("p",bt,c(e.modelType),1)])])])):e.result==="success"?(u(),g("div",yt,[r("p",wt,c(e.$t("assetBrowser.modelUploaded")),1),r("p",_t,c(e.$t("assetBrowser.findInLibrary",{type:e.modelType})),1),r("div",$t,[e.previewImage?(u(),g("img",{key:0,src:e.previewImage,alt:e.metadata?.filename||e.metadata?.name||"Model preview",class:"size-14 flex-shrink-0 rounded object-cover"},null,8,kt)):_("",!0),r("div",Mt,[r("p",Ut,c(e.metadata?.filename||e.metadata?.name),1),r("p",xt,c(e.modelType),1)])])])):e.result==="error"?(u(),g("div",St,[n[0]||(n[0]=r("i",{class:"icon-[lucide--x-circle] text-6xl text-error"},null,-1)),r("div",Ct,[r("p",Ft,c(e.$t("assetBrowser.uploadFailed")),1),e.error?(u(),g("p",It,c(e.error),1)):_("",!0)])])):_("",!0)]))}}),Q={type:"civitai",name:"Civitai",hostnames:["civitai.com"]},ce={type:"huggingface",name:"Hugging Face",hostnames:["huggingface.co"]};function oe(i,e){try{const n=new URL(i).hostname.toLowerCase();return e.hostnames.some(o=>n===o||n.endsWith(`.${o}`))}catch{return!1}}m(oe,"validateSourceUrl");const Bt={class:"flex flex-col justify-between h-full gap-6 text-sm"},Lt={class:"flex flex-col gap-6"},jt={class:"flex flex-col gap-2"},Dt={class:"m-0 text-foreground"},Et={class:"m-0"},At={class:"m-0 text-muted-foreground"},zt={class:"inline-flex items-center gap-1 flex-wrap mt-2"},Rt={class:"inline-flex items-center gap-1"},Tt=["alt"],Pt={class:"inline-flex items-center gap-1"},Wt=["alt"],Ht={class:"flex flex-col gap-2"},qt={class:"relative"},Ot={key:0,class:"icon-[lucide--circle-check-big] absolute top-1/2 right-3 size-5 -translate-y-1/2 text-green-500"},Nt={key:0,class:"text-sm text-error"},Gt={key:1,class:"text-foreground"},Kt={class:"font-bold italic"},Qt={class:"text-sm text-muted"},Yt="/assets/images/civitai.svg",Zt="https://civitai.com/models",Jt="/assets/images/hf-logo.svg",Xt="https://huggingface.co",ea=I({__name:"UploadModelUrlInput",props:{modelValue:{},error:{}},emits:["update:modelValue"],setup(i,{emit:e}){const{flags:n}=A(),o=i,a=e,l=B({get:m(()=>o.modelValue,"get"),set:m(d=>a("update:modelValue",d),"set")}),t=[Q,ce],s=B(()=>{const d=l.value.trim();return d?t.some(b=>oe(d,b)):!1});return(d,b)=>{const $=ne("i18n-t");return u(),g("div",Bt,[r("div",Lt,[r("div",jt,[r("p",Dt,c(d.$t("assetBrowser.uploadModelDescription1Generic")),1),r("div",Et,[r("p",At,c(d.$t("assetBrowser.uploadModelDescription2Generic")),1),r("span",zt,[r("span",Rt,[r("img",{src:Yt,alt:d.$t("assetBrowser.providerCivitai"),class:"w-4 h-4"},null,8,Tt),r("a",{href:Zt,target:"_blank",rel:"noopener noreferrer",class:"text-muted-foreground underline"},c(d.$t("assetBrowser.providerCivitai")),1),b[1]||(b[1]=r("span",null,",",-1))]),r("span",Pt,[r("img",{src:Jt,alt:d.$t("assetBrowser.providerHuggingFace"),class:"w-4 h-4"},null,8,Wt),r("a",{href:Xt,target:"_blank",rel:"noopener noreferrer",class:"text-muted-foreground underline"},c(d.$t("assetBrowser.providerHuggingFace")),1)])])])]),r("div",Ht,[r("div",qt,[k(p(ie),{modelValue:l.value,"onUpdate:modelValue":b[0]||(b[0]=v=>l.value=v),autofocus:"",placeholder:d.$t("assetBrowser.genericLinkPlaceholder"),class:"w-full border-0 bg-secondary-background p-4 pr-10","data-attr":"upload-model-step1-url-input"},null,8,["modelValue","placeholder"]),s.value?(u(),g("i",Ot)):_("",!0)]),d.error?(u(),g("p",Nt,c(d.error),1)):p(n).asyncModelUploadEnabled?_("",!0):(u(),g("p",Gt,[k($,{keypath:"assetBrowser.maxFileSize",tag:"span"},{size:y(()=>[r("span",Kt,c(d.$t("assetBrowser.maxFileSizeValue")),1)]),_:1})]))])]),r("div",Qt,c(d.$t("assetBrowser.uploadModelHelpFooterText")),1)])}}}),ta={class:"flex flex-col gap-6 text-sm text-muted-foreground"},aa={class:"flex flex-col gap-2"},sa={class:"m-0"},oa={class:"list-disc space-y-1 pl-5 mt-0"},la={href:"https://civitai.com/models",target:"_blank",class:"text-muted-foreground underline"},ra={key:0},na={class:"font-bold italic"},ia={class:"flex flex-col gap-2"},da={class:"font-bold italic"},ua={class:"relative"},ca={key:0,class:"icon-[lucide--circle-check-big] absolute top-1/2 right-3 size-5 -translate-y-1/2 text-green-500"},pa={key:0,class:"text-sm text-error"},ma={href:"https://civitai.com/models/10706/luisap-z-image-and-qwen-pixel-art-refiner?modelVersionId=2225295",target:"_blank",class:"text-muted-foreground underline"},fa=I({__name:"UploadModelUrlInputCivitai",props:H({error:{}},{modelValue:{required:!0},modelModifiers:{}}),emits:["update:modelValue"],setup(i){const{flags:e}=A(),n=q(i,"modelValue"),o=B(()=>{const a=n.value.trim();return a?oe(a,Q):!1});return(a,l)=>{const t=ne("i18n-t");return u(),g("div",ta,[r("div",aa,[r("p",sa,c(a.$t("assetBrowser.uploadModelDescription1")),1),r("ul",oa,[r("li",null,[k(t,{keypath:"assetBrowser.uploadModelDescription2",tag:"span"},{link:y(()=>[r("a",la,c(a.$t("assetBrowser.uploadModelDescription2Link")),1)]),_:1})]),p(e).asyncModelUploadEnabled?_("",!0):(u(),g("li",ra,[k(t,{keypath:"assetBrowser.uploadModelDescription3",tag:"span"},{size:y(()=>[r("span",na,c(a.$t("assetBrowser.maxFileSizeValue")),1)]),_:1})]))])]),r("div",ia,[k(t,{keypath:"assetBrowser.civitaiLinkLabel",tag:"label",class:"mb-0"},{download:y(()=>[r("span",da,c(a.$t("assetBrowser.civitaiLinkLabelDownload")),1)]),_:1}),r("div",ua,[k(p(ie),{modelValue:n.value,"onUpdate:modelValue":l[0]||(l[0]=s=>n.value=s),autofocus:"",placeholder:a.$t("assetBrowser.civitaiLinkPlaceholder"),class:"w-full border-0 bg-secondary-background p-4 pr-10","data-attr":"upload-model-step1-url-input"},null,8,["modelValue","placeholder"]),o.value?(u(),g("i",ca)):_("",!0)]),a.error?(u(),g("p",pa,c(a.error),1)):(u(),F(t,{key:1,keypath:"assetBrowser.civitaiLinkExample",tag:"p",class:"text-sm"},{example:y(()=>[r("strong",null,c(a.$t("assetBrowser.civitaiLinkExampleStrong")),1)]),link:y(()=>[r("a",ma,c(a.$t("assetBrowser.civitaiLinkExampleUrl")),1)]),_:1}))])])}}});function ga(i){const{t:e}=de(),n=me(),o=fe(),a=ge(),{flags:l}=A(),t=x(1),s=x(!1),d=x(!1),b=x(),$=x(""),v=x({url:"",name:"",tags:[]}),h=x(),M=l.huggingfaceModelImportEnabled?[Q,ce]:[Q],E=B(()=>{const U=v.value.url.trim();return U?M.find(w=>oe(U,w))??null:null});R(()=>v.value.url,()=>{$.value=""});const O=B(()=>v.value.url.trim().length>0),N=B(()=>!!h.value);async function Y(){if(!O.value)return;let U=v.value.url.trim();try{U=new URL(encodeURI(U)).toString()}catch{}if(v.value.url=U,!E.value){const f=M.map(S=>S.name).join(", ");$.value=e("assetBrowser.unsupportedUrlSource",{sources:f});return}s.value=!0;try{const f=await K.getAssetMetadata(v.value.url);if(f.filename)try{f.filename=decodeURIComponent(f.filename)}catch{}if(f.name)try{f.name=decodeURIComponent(f.name)}catch{}if(v.value.metadata=f,v.value.name=f.filename||f.name||"",v.value.previewImage=f.preview_image,f.tags&&f.tags.length>0){v.value.tags=f.tags;const S=f.tags.find(T=>i.value.some(P=>P.value===T));S&&(h.value=S)}t.value=2}catch(f){console.error("Failed to retrieve metadata:",f),$.value=f instanceof Error?f.message:ve("assetBrowser.uploadModelFailedToRetrieveMetadata","Failed to retrieve metadata. Please check the link and try again."),t.value=1}finally{s.value=!1}}m(Y,"fetchMetadata");async function Z(U){if(v.value.previewImage)try{const w=U.split(".")[0];let f="png";const S=v.value.previewImage.match(/^data:image\/([^;]+);/);return S&&(f=S[1]==="jpeg"?"jpg":S[1]),(await K.uploadAssetFromBase64({data:v.value.previewImage,name:`${w}_preview.${f}`,tags:["preview"]})).id}catch(w){console.error("Failed to upload preview image:",w);return}}m(Z,"uploadPreviewImage");async function G(){if(!h.value)return;const U=a.getAllNodeProviders(h.value);(await Promise.allSettled(U.map(f=>n.updateModelsForNodeType(f.nodeDef.name)))).forEach((f,S)=>{f.status==="rejected"&&console.error(`Failed to refresh ${U[S].nodeDef.name}:`,f.reason)})}m(G,"refreshModelCaches");async function J(){if(!N.value)return!1;const U=E.value;if(!U)return $.value=e("assetBrowser.noValidSourceDetected"),!1;d.value=!0;try{const w=h.value?["models",h.value]:["models"],f=v.value.metadata?.filename||v.value.metadata?.name||"model",S=await Z(f),T={source:U.type,source_url:v.value.url,model_type:h.value};if(l.asyncModelUploadEnabled){const P=await K.uploadAssetAsync({source_url:v.value.url,tags:w,user_metadata:T,preview_id:S});P.type==="async"&&P.task.status!=="completed"?(h.value&&o.trackDownload(P.task.task_id,h.value,f),b.value="processing"):(b.value="success",await G()),t.value=3}else await K.uploadAssetFromUrl({url:v.value.url,name:f,tags:w,user_metadata:T,preview_id:S}),b.value="success",await G(),t.value=3}catch(w){console.error("Failed to upload asset:",w),b.value="error",$.value=w instanceof Error?w.message:"Failed to upload model",t.value=3}finally{d.value=!1}return b.value!=="error"}m(J,"uploadModel");function X(){t.value>1&&(t.value=t.value-1)}m(X,"goToPreviousStep");function ee(){t.value=1,s.value=!1,d.value=!1,b.value=void 0,$.value="",v.value={url:"",name:"",tags:[]},h.value=void 0}return m(ee,"resetWizard"),{currentStep:t,isFetchingMetadata:s,isUploading:d,uploadStatus:b,uploadError:$,wizardData:v,selectedModelType:h,canFetchMetadata:O,canUploadModel:N,detectedSource:E,fetchMetadata:Y,uploadModel:J,goToPreviousStep:X,resetWizard:ee}}m(ga,"useUploadModelWizard");const va={class:"upload-model-dialog flex flex-col gap-6 border-t border-border-default p-4 pt-6"},ha={class:"min-h-0 flex-auto basis-0 overflow-y-auto"},ba=I({__name:"UploadModelDialog",emits:["upload-success"],setup(i,{emit:e}){const{flags:n}=A(),o=ae(),{modelTypes:a,fetchModelTypes:l}=ue(),t=e,{currentStep:s,isFetchingMetadata:d,isUploading:b,uploadStatus:$,uploadError:v,wizardData:h,selectedModelType:M,canFetchMetadata:E,canUploadModel:O,fetchMetadata:N,uploadModel:Y,goToPreviousStep:Z,resetWizard:G}=ga(a);async function J(){await N()}m(J,"handleFetchMetadata");async function X(){await Y()&&t("upload-success")}m(X,"handleUploadModel");function ee(){o.closeDialog({key:"upload-model"})}return m(ee,"handleClose"),xe(()=>{l()}),(U,w)=>(u(),g("div",va,[r("div",ha,[p(s)===1&&p(n).huggingfaceModelImportEnabled?(u(),F(ea,{key:0,modelValue:p(h).url,"onUpdate:modelValue":w[0]||(w[0]=f=>p(h).url=f),error:p(v)},null,8,["modelValue","error"])):p(s)===1?(u(),F(fa,{key:1,modelValue:p(h).url,"onUpdate:modelValue":w[1]||(w[1]=f=>p(h).url=f),error:p(v)},null,8,["modelValue","error"])):p(s)===2?(u(),F(tt,{key:2,modelValue:p(M),"onUpdate:modelValue":w[2]||(w[2]=f=>Se(M)?M.value=f:null),metadata:p(h).metadata,"preview-image":p(h).previewImage},null,8,["modelValue","metadata","preview-image"])):p(s)===3&&p($)!=null?(u(),F(Vt,{key:3,result:p($),error:p(v),metadata:p(h).metadata,"model-type":p(M),"preview-image":p(h).previewImage},null,8,["result","error","metadata","model-type","preview-image"])):_("",!0)]),k(dt,{class:"flex-shrink-0","current-step":p(s),"is-fetching-metadata":p(d),"is-uploading":p(b),"can-fetch-metadata":p(E),"can-upload-model":p(O),"upload-status":p($),onBack:p(Z),onFetchMetadata:J,onUpload:X,onClose:ee,onImportAnother:p(G)},null,8,["current-step","is-fetching-metadata","is-uploading","can-fetch-metadata","can-upload-model","upload-status","onBack","onImportAnother"])]))}}),ya=se(ba,[["__scopeId","data-v-f4fd265e"]]),wa=""+new URL("images/civitai.svg",import.meta.url).href,_a={class:"flex items-center gap-2 p-4 font-bold"},$a={key:0,src:wa,class:"size-4"},ka={class:"rounded-full bg-white px-1.5 py-0 text-xxs font-inter font-semibold uppercase text-black"},Ma=I({__name:"UploadModelDialogHeader",setup(i){const{flags:e}=A(),n=B(()=>e.huggingfaceModelImportEnabled?"assetBrowser.uploadModelGeneric":"assetBrowser.uploadModelFromCivitai");return(o,a)=>(u(),g("div",_a,[p(e).huggingfaceModelImportEnabled?_("",!0):(u(),g("img",$a)),r("span",null,c(o.$t(n.value)),1),r("span",ka,c(o.$t("g.beta")),1)]))}}),Ua={},xa={class:"flex flex-1 flex-col items-center justify-center text-base text-muted-foreground"},Sa={class:"m-0 max-w-md"};function Ca(i,e){return u(),g("div",xa,[r("p",Sa,c(i.$t("assetBrowser.upgradeFeatureDescription")),1)])}m(Ca,"_sfc_render$1");const Fa=se(Ua,[["render",Ca]]),Ia={class:"flex flex-wrap justify-end gap-2 w-full"},Va={href:"https://blog.comfy.org/p/comfy-cloud-new-features-and-pricing",target:"_blank",rel:"noopener noreferrer",class:"text-muted-foreground mr-auto underline flex items-center gap-2"},Ba=I({__name:"UploadModelUpgradeModalFooter",emits:["close","subscribe"],setup(i,{emit:e}){const n=e;return(o,a)=>(u(),g("div",Ia,[r("a",Va,[a[2]||(a[2]=r("i",{class:"icon-[lucide--external-link]"},null,-1)),r("span",null,c(o.$t("g.learnMore")),1)]),k(V,{variant:"textonly",onClick:a[0]||(a[0]=l=>n("close"))},{default:y(()=>[D(c(o.$t("g.close")),1)]),_:1}),k(V,{variant:"secondary",onClick:a[1]||(a[1]=l=>n("subscribe"))},{default:y(()=>[D(c(o.$t("subscription.required.subscribe")),1)]),_:1})]))}}),La={class:"flex flex-col justify-between gap-10 p-4 border-t border-border-default w-auto max-w-[min(500px,90vw)]"},ja=I({__name:"UploadModelUpgradeModal",setup(i){const e=ae(),{showSubscriptionDialog:n}=he();function o(){e.closeDialog({key:"upload-model-upgrade"})}m(o,"handleClose");function a(){n()}return m(a,"handleSubscribe"),(l,t)=>(u(),g("div",La,[k(Fa),k(Ba,{onClose:o,onSubscribe:a})]))}}),Da={},Ea={class:"flex items-center gap-2 p-4 font-bold"};function Aa(i,e){return u(),g("div",Ea,[r("span",null,c(i.$t("assetBrowser.upgradeToUnlockFeature")),1)])}m(Aa,"_sfc_render");const za=se(Da,[["render",Aa]]);function Xa(i){const e=ae(),{flags:n}=A(),o=B(()=>n.modelUploadButtonEnabled);function a(){n.privateModelsEnabled?e.showDialog({key:"upload-model",headerComponent:Ma,component:ya,props:{onUploadSuccess:m(async()=>{await i?.()},"onUploadSuccess")},dialogComponentProps:{pt:{header:"py-0! pl-0!",content:"p-0! overflow-y-hidden!"}}}):e.showDialog({key:"upload-model-upgrade",headerComponent:za,component:ja,dialogComponentProps:{pt:{header:"py-0! pl-0!",content:"p-0! overflow-y-hidden!"}}})}return m(a,"showUploadDialog"),{isUploadButtonEnabled:o,showUploadDialog:a}}m(Xa,"useModelUpload");const Ra=["placeholder","autofocus"],Ta=["aria-label"],es=I({__name:"FormSearchInput",props:H({searcher:{type:Function,default:m(async()=>{},"default")},updateKey:{},autofocus:{type:Boolean,default:!1},class:{}},{modelValue:{default:""},modelModifiers:{}}),emits:["update:modelValue"],setup(i){const e=q(i,"modelValue"),n=x(!1),o=Ce(e,250,{maxWait:1e3});R(e,t=>{n.value=t!==o.value});const a=Fe(()=>Ie(i.updateKey));R([o,a],(t,s,d)=>{let b=!1,$;d(()=>{b=!0,$?.()}),i.searcher(o.value,v=>$=v).catch(v=>{console.error("[SidePanelSearch] searcher failed",v)}).finally(()=>{b||(n.value=!1)})},{immediate:!0});function l(t){t.target.select()}return m(l,"handleFocus"),(t,s)=>(u(),g("label",{class:z(p(W)("group","bg-component-node-widget-background rounded-lg transition-all duration-150","flex-1 flex items-center","text-base-foreground border-0","focus-within:ring focus-within:ring-component-node-widget-background-highlighted/80",i.class))},[r("i",{class:z(p(W)("size-4 ml-2 shrink-0 transition-colors duration-150",n.value?"icon-[lucide--loader-circle] animate-spin":"icon-[lucide--search]",e.value?.trim()!==""?"text-base-foreground":"text-muted-foreground group-hover:text-base-foreground group-focus-within:text-base-foreground"))},null,2),Ve(r("input",{"onUpdate:modelValue":s[0]||(s[0]=d=>e.value=d),type:"text",class:"bg-transparent border-0 outline-0 ring-0 h-5 w-full my-1.5 mx-2",placeholder:t.$t("g.searchPlaceholder"),autofocus:t.autofocus,onFocus:l},null,40,Ra),[[Be,e.value]]),e.value.trim().length>0?(u(),g("button",{key:0,class:"text-muted-foreground hover:text-base-foreground bg-transparent shrink-0 border-0 outline-0 ring-0 p-0 m-0 pr-3 pl-1 flex items-center justify-center transition-all duration-150 hover:scale-108","aria-label":t.$t("g.clear"),onClick:s[1]||(s[1]=d=>e.value="")},[r("i",{class:z(p(W)("icon-[lucide--delete] size-4 cursor-pointer"))},null,2)],8,Ta)):_("",!0)],2))}}),Pa=""+new URL("images/default-template.png",import.meta.url).href;function Wa(i,e,n={}){const{immediate:o=!0,...a}=n,l=typeof window<"u"&&"IntersectionObserver"in window,t=x(!1);let s=null;const d=m(()=>{s&&(s.disconnect(),s=null)},"cleanup"),b=m(()=>{d(),!(!l||!i.value)&&(s=new IntersectionObserver(v=>{t.value=v.some(h=>h.isIntersecting),e(v,s)},a),s.observe(i.value))},"observe"),$=m(()=>{s&&i.value&&s.unobserve(i.value)},"unobserve");return o&&R(i,b,{immediate:!0,flush:"post"}),Le(d),{isSupported:l,isIntersecting:t,observe:b,unobserve:$,cleanup:d}}m(Wa,"useIntersectionObserver");class Ha{static{m(this,"MediaCacheService")}cache=re(new Map);maxSize;maxAge;cleanupInterval=null;urlRefCount=new Map;constructor(e={}){this.maxSize=e.maxSize??100,this.maxAge=e.maxAge??1800*1e3,this.startCleanupInterval()}startCleanupInterval(){this.cleanupInterval=window.setInterval(()=>{this.cleanup()},300*1e3)}cleanup(){const e=Date.now(),n=[];for(const[o,a]of Array.from(this.cache.entries()))e-a.lastAccessed>this.maxAge&&(a.objectUrl?(this.urlRefCount.get(a.objectUrl)||0)===0&&(URL.revokeObjectURL(a.objectUrl),this.urlRefCount.delete(a.objectUrl),n.push(o)):n.push(o));if(n.forEach(o=>this.cache.delete(o)),this.cache.size>this.maxSize){const o=Array.from(this.cache.entries());o.sort((t,s)=>t[1].lastAccessed-s[1].lastAccessed);let a=0;const l=this.cache.size-this.maxSize;for(const[t,s]of o){if(a>=l)break;s.objectUrl?(this.urlRefCount.get(s.objectUrl)||0)===0&&(URL.revokeObjectURL(s.objectUrl),this.urlRefCount.delete(s.objectUrl),this.cache.delete(t),a++):(this.cache.delete(t),a++)}}}async getCachedMedia(e){let n=this.cache.get(e);if(n)return n.lastAccessed=Date.now(),n;n={src:e,isLoading:!0,lastAccessed:Date.now()},this.cache.set(e,n);try{const o=await fetch(e,{cache:"force-cache"});if(!o.ok)throw new Error(`Failed to fetch: ${o.status}`);const a=await o.blob(),l=URL.createObjectURL(a),t={src:e,blob:a,objectUrl:l,isLoading:!1,lastAccessed:Date.now()};return this.cache.set(e,t),t}catch(o){console.warn("Failed to cache media:",e,o);const a={src:e,error:!0,isLoading:!1,lastAccessed:Date.now()};return this.cache.set(e,a),a}}acquireUrl(e){const n=this.cache.get(e);if(n?.objectUrl){const o=this.urlRefCount.get(n.objectUrl)||0;return this.urlRefCount.set(n.objectUrl,o+1),n.objectUrl}}releaseUrl(e){const n=this.cache.get(e);if(n?.objectUrl){const o=(this.urlRefCount.get(n.objectUrl)||1)-1;o<=0?(URL.revokeObjectURL(n.objectUrl),this.urlRefCount.delete(n.objectUrl),this.cache.delete(e)):this.urlRefCount.set(n.objectUrl,o)}}clearCache(){for(const e of Array.from(this.cache.values()))e.objectUrl&&URL.revokeObjectURL(e.objectUrl);this.cache.clear(),this.urlRefCount.clear()}destroy(){this.cleanupInterval&&(clearInterval(this.cleanupInterval),this.cleanupInterval=null),this.clearCache()}}let L=null;function qa(i){return L||(L=new Ha(i)),{getCachedMedia:m(l=>L.getCachedMedia(l),"getCachedMedia"),clearCache:m(()=>L.clearCache(),"clearCache"),acquireUrl:m(l=>L.acquireUrl(l),"acquireUrl"),releaseUrl:m(l=>L.releaseUrl(l),"releaseUrl"),cache:L.cache}}m(qa,"useMediaCache");typeof window<"u"&&window.addEventListener("beforeunload",()=>{L&&L.destroy()});const Oa=["src","alt"],Na={key:2,class:"absolute inset-0 flex items-center justify-center"},Ga=["alt"],ts=I({__name:"LazyImage",props:{src:{},alt:{default:""},containerClass:{type:[Array,Object,String,Number,null,Boolean],default:""},imageClass:{type:[Array,Object,String,Number,null,Boolean],default:""},imageStyle:{},rootMargin:{default:"300px"}},setup(i){const e=x(null),n=x(!1),o=x(!1),a=x(!1),l=x(void 0),{getCachedMedia:t,acquireUrl:s,releaseUrl:d}=qa();Wa(e,h=>{const M=h[0];n.value=M?.isIntersecting??!1},{rootMargin:i.rootMargin,threshold:.1});const b=B(()=>n.value);R(b,async h=>{if(h&&i.src&&!l.value&&!a.value)try{const M=await t(i.src);if(M.error)a.value=!0;else if(M.objectUrl){const E=s(i.src);l.value=E||M.objectUrl}else l.value=i.src}catch(M){console.warn("Failed to load cached media:",M),l.value=i.src}else h||(l.value?.startsWith("blob:")&&d(i.src),o.value=!1,l.value=void 0,a.value=!1)},{immediate:!0});const $=m(()=>{o.value=!0,a.value=!1},"onImageLoad"),v=m(()=>{a.value=!0,o.value=!1},"onImageError");return je(()=>{l.value?.startsWith("blob:")&&d(i.src)}),(h,M)=>(u(),g("div",{ref_key:"containerRef",ref:e,class:z(["relative flex h-full w-full items-center justify-center overflow-hidden",h.containerClass])},[o.value?_("",!0):(u(),F(p(Ae),{key:0,width:"100%",height:"100%",class:"absolute inset-0"})),l.value?(u(),g("img",{key:1,src:l.value,alt:h.alt,draggable:"false",class:z(h.imageClass),style:te(h.imageStyle),onLoad:$,onError:v},null,46,Oa)):_("",!0),a.value?(u(),g("div",Na,[r("img",{src:Pa,alt:h.alt,draggable:"false",class:z(h.imageClass),style:te(h.imageStyle)},null,14,Ga)])):_("",!0)],2))}});export{He as _,Xa as a,es as b,Pa as c,ts as d,Wa as e,A as u};
|
|
2
|
-
//# sourceMappingURL=LazyImage.vue_vue_type_script_setup_true_lang-CX9YtPlM.js.map
|
comfyui_frontend_package/static/assets/LazyImage.vue_vue_type_script_setup_true_lang-CX9YtPlM.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"LazyImage.vue_vue_type_script_setup_true_lang-CX9YtPlM.js","sources":["../../src/composables/useFeatureFlags.ts","../../src/components/input/SingleSelect.vue","../../src/platform/assets/composables/useModelTypes.ts","../../src/platform/assets/components/UploadModelConfirmation.vue","../../src/platform/assets/components/VideoHelpDialog.vue","../../src/platform/assets/components/UploadModelFooter.vue","../../src/platform/assets/importSources/civitaiImportSource.ts","../../src/platform/assets/importSources/huggingfaceImportSource.ts","../../src/platform/assets/utils/importSourceUtil.ts","../../src/platform/assets/components/UploadModelUrlInput.vue","../../src/platform/assets/components/UploadModelUrlInputCivitai.vue","../../src/platform/assets/composables/useUploadModelWizard.ts","../../src/platform/assets/components/UploadModelDialog.vue","../../../../../../../assets/images/civitai.svg","../../src/platform/assets/components/UploadModelDialogHeader.vue","../../src/platform/assets/components/UploadModelUpgradeModalBody.vue","../../src/platform/assets/components/UploadModelUpgradeModalFooter.vue","../../src/platform/assets/components/UploadModelUpgradeModal.vue","../../src/platform/assets/components/UploadModelUpgradeModalHeader.vue","../../src/platform/assets/composables/useModelUpload.ts","../../src/renderer/extensions/vueNodes/widgets/components/form/FormSearchInput.vue","../../../../../../../assets/images/default-template.png","../../src/composables/useIntersectionObserver.ts","../../src/services/mediaCacheService.ts","../../src/components/common/LazyImage.vue"],"sourcesContent":["import { computed, reactive, readonly } from 'vue'\n\nimport { remoteConfig } from '@/platform/remoteConfig/remoteConfig'\nimport { api } from '@/scripts/api'\n\n/**\n * Known server feature flags (top-level, not extensions)\n */\nexport enum ServerFeatureFlag {\n SUPPORTS_PREVIEW_METADATA = 'supports_preview_metadata',\n MAX_UPLOAD_SIZE = 'max_upload_size',\n MANAGER_SUPPORTS_V4 = 'extension.manager.supports_v4',\n MODEL_UPLOAD_BUTTON_ENABLED = 'model_upload_button_enabled',\n ASSET_DELETION_ENABLED = 'asset_deletion_enabled',\n ASSET_RENAME_ENABLED = 'asset_rename_enabled',\n PRIVATE_MODELS_ENABLED = 'private_models_enabled',\n ONBOARDING_SURVEY_ENABLED = 'onboarding_survey_enabled',\n HUGGINGFACE_MODEL_IMPORT_ENABLED = 'huggingface_model_import_enabled',\n LINEAR_TOGGLE_ENABLED = 'linear_toggle_enabled',\n ASYNC_MODEL_UPLOAD_ENABLED = 'async_model_upload_enabled'\n}\n\n/**\n * Composable for reactive access to server-side feature flags\n */\nexport function useFeatureFlags() {\n const flags = reactive({\n get supportsPreviewMetadata() {\n return api.getServerFeature(ServerFeatureFlag.SUPPORTS_PREVIEW_METADATA)\n },\n get maxUploadSize() {\n return api.getServerFeature(ServerFeatureFlag.MAX_UPLOAD_SIZE)\n },\n get supportsManagerV4() {\n return api.getServerFeature(ServerFeatureFlag.MANAGER_SUPPORTS_V4)\n },\n get modelUploadButtonEnabled() {\n // Check remote config first (from /api/features), fall back to websocket feature flags\n return (\n remoteConfig.value.model_upload_button_enabled ??\n api.getServerFeature(\n ServerFeatureFlag.MODEL_UPLOAD_BUTTON_ENABLED,\n false\n )\n )\n },\n get assetDeletionEnabled() {\n return (\n remoteConfig.value.asset_deletion_enabled ??\n api.getServerFeature(ServerFeatureFlag.ASSET_DELETION_ENABLED, false)\n )\n },\n get assetRenameEnabled() {\n return (\n remoteConfig.value.asset_rename_enabled ??\n api.getServerFeature(ServerFeatureFlag.ASSET_RENAME_ENABLED, false)\n )\n },\n get privateModelsEnabled() {\n // Check remote config first (from /api/features), fall back to websocket feature flags\n return (\n remoteConfig.value.private_models_enabled ??\n api.getServerFeature(ServerFeatureFlag.PRIVATE_MODELS_ENABLED, false)\n )\n },\n get onboardingSurveyEnabled() {\n return (\n remoteConfig.value.onboarding_survey_enabled ??\n api.getServerFeature(ServerFeatureFlag.ONBOARDING_SURVEY_ENABLED, true)\n )\n },\n get huggingfaceModelImportEnabled() {\n return (\n remoteConfig.value.huggingface_model_import_enabled ??\n api.getServerFeature(\n ServerFeatureFlag.HUGGINGFACE_MODEL_IMPORT_ENABLED,\n false\n )\n )\n },\n get linearToggleEnabled() {\n return (\n remoteConfig.value.linear_toggle_enabled ??\n api.getServerFeature(ServerFeatureFlag.LINEAR_TOGGLE_ENABLED, false)\n )\n },\n get asyncModelUploadEnabled() {\n return (\n remoteConfig.value.async_model_upload_enabled ??\n api.getServerFeature(\n ServerFeatureFlag.ASYNC_MODEL_UPLOAD_ENABLED,\n false\n )\n )\n }\n })\n\n const featureFlag = <T = unknown>(featurePath: string, defaultValue?: T) =>\n computed(() => api.getServerFeature(featurePath, defaultValue))\n\n return {\n flags: readonly(flags),\n featureFlag\n }\n}\n","<template>\n <!--\n Note: We explicitly pass options here (not just via $attrs) because:\n 1. Our custom value template needs options to look up labels from values\n 2. PrimeVue's value slot only provides 'value' and 'placeholder', not the selected item's label\n 3. We need to maintain the icon slot functionality in the value template\n option-label=\"name\" is required because our option template directly accesses option.name\n -->\n <Select\n v-model=\"selectedItem\"\n v-bind=\"$attrs\"\n :options=\"options\"\n option-label=\"name\"\n option-value=\"value\"\n unstyled\n :pt=\"{\n root: ({ props }: SelectPassThroughMethodOptions<SelectOption>) => ({\n class: [\n // container\n 'h-10 relative inline-flex cursor-pointer select-none items-center',\n // trigger surface\n 'rounded-lg',\n 'bg-secondary-background text-base-foreground',\n 'border-[2.5px] border-solid border-transparent',\n 'transition-all duration-200 ease-in-out',\n 'focus-within:border-node-component-border',\n // disabled\n { 'opacity-60 cursor-default': props.disabled }\n ]\n }),\n label: {\n class:\n // Align with MultiSelect labelContainer spacing\n 'flex-1 flex items-center whitespace-nowrap pl-4 py-2 outline-hidden'\n },\n dropdown: {\n class:\n // Right chevron touch area\n 'flex shrink-0 items-center justify-center px-3 py-2'\n },\n overlay: {\n class: cn(\n 'mt-2 p-2 rounded-lg',\n 'bg-base-background text-base-foreground',\n 'border border-solid border-border-default'\n )\n },\n listContainer: () => ({\n style: `max-height: min(${listMaxHeight}, 50vh)`,\n class: 'scrollbar-custom'\n }),\n list: {\n class:\n // Same list tone/size as MultiSelect\n 'flex flex-col gap-0 p-0 m-0 list-none border-none text-sm'\n },\n option: ({ context }: SelectPassThroughMethodOptions<SelectOption>) => ({\n class: cn(\n // Row layout\n 'flex items-center justify-between gap-3 px-2 py-3 rounded',\n 'hover:bg-secondary-background-hover',\n // Add focus state for keyboard navigation\n context.focused && 'bg-secondary-background-hover',\n // Selected state + check icon\n context.selected &&\n 'bg-secondary-background-selected hover:bg-secondary-background-selected'\n )\n }),\n optionLabel: {\n class: 'truncate'\n },\n optionGroupLabel: {\n class: 'px-3 py-2 text-xs uppercase tracking-wide text-muted-foreground'\n },\n emptyMessage: {\n class: 'px-3 py-2 text-sm text-muted-foreground'\n }\n }\"\n :aria-label=\"label || t('g.singleSelectDropdown')\"\n role=\"combobox\"\n :aria-expanded=\"false\"\n aria-haspopup=\"listbox\"\n :tabindex=\"0\"\n >\n <!-- Trigger value -->\n <template #value=\"slotProps\">\n <div class=\"flex items-center gap-2 text-sm\">\n <slot name=\"icon\" />\n <span\n v-if=\"slotProps.value !== null && slotProps.value !== undefined\"\n class=\"text-base-foreground\"\n >\n {{ getLabel(slotProps.value) }}\n </span>\n <span v-else class=\"text-base-foreground\">\n {{ label }}\n </span>\n </div>\n </template>\n\n <!-- Trigger caret -->\n <template #dropdownicon>\n <i class=\"icon-[lucide--chevron-down] text-muted-foreground\" />\n </template>\n\n <!-- Option row -->\n <template #option=\"{ option, selected }\">\n <div\n class=\"flex w-full items-center justify-between gap-3\"\n :style=\"optionStyle\"\n >\n <span class=\"truncate\">{{ option.name }}</span>\n <i v-if=\"selected\" class=\"icon-[lucide--check] text-base-foreground\" />\n </div>\n </template>\n </Select>\n</template>\n\n<script setup lang=\"ts\">\nimport type { SelectPassThroughMethodOptions } from 'primevue/select'\nimport Select from 'primevue/select'\nimport { computed } from 'vue'\nimport { useI18n } from 'vue-i18n'\n\nimport { cn } from '@/utils/tailwindUtil'\n\nimport type { SelectOption } from './types'\n\ndefineOptions({\n inheritAttrs: false\n})\n\nconst {\n label,\n options,\n listMaxHeight = '28rem',\n popoverMinWidth,\n popoverMaxWidth\n} = defineProps<{\n label?: string\n /**\n * Required for displaying the selected item's label.\n * Cannot rely on $attrs alone because we need to access options\n * in getLabel() to map values to their display names.\n */\n options?: SelectOption[]\n /** Maximum height of the dropdown panel (default: 28rem) */\n listMaxHeight?: string\n /** Minimum width of the popover (default: auto) */\n popoverMinWidth?: string\n /** Maximum width of the popover (default: auto) */\n popoverMaxWidth?: string\n}>()\n\nconst selectedItem = defineModel<string | undefined>({ required: true })\n\nconst { t } = useI18n()\n\n/**\n * Maps a value to its display label.\n * Necessary because PrimeVue's value slot doesn't provide the selected item's label,\n * only the raw value. We need this to show the correct text when an item is selected.\n */\nconst getLabel = (val: string | null | undefined) => {\n if (val == null) return label ?? ''\n if (!options) return label ?? ''\n const found = options.find((o) => o.value === val)\n return found ? found.name : (label ?? '')\n}\n\n// Extract complex style logic from template\nconst optionStyle = computed(() => {\n if (!popoverMinWidth && !popoverMaxWidth) return undefined\n\n const styles: string[] = []\n if (popoverMinWidth) styles.push(`min-width: ${popoverMinWidth}`)\n if (popoverMaxWidth) styles.push(`max-width: ${popoverMaxWidth}`)\n\n return styles.join('; ')\n})\n</script>\n","import { createSharedComposable, useAsyncState } from '@vueuse/core'\n\nimport { api } from '@/scripts/api'\n\n/**\n * Format folder name to display name\n * Converts \"upscale_models\" -> \"Upscale Model\"\n * Converts \"loras\" -> \"LoRA\"\n */\nfunction formatDisplayName(folderName: string): string {\n // Special cases for acronyms and proper nouns\n const specialCases: Record<string, string> = {\n loras: 'LoRA',\n ipadapter: 'IP-Adapter',\n sams: 'SAM',\n clip_vision: 'CLIP Vision',\n animatediff_motion_lora: 'AnimateDiff Motion LoRA',\n animatediff_models: 'AnimateDiff Model',\n vae: 'VAE',\n sam2: 'SAM 2',\n controlnet: 'ControlNet',\n gligen: 'GLIGEN'\n }\n\n if (specialCases[folderName]) {\n return specialCases[folderName]\n }\n\n return folderName\n .split('_')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ')\n}\n\ninterface ModelTypeOption {\n name: string // Display name\n value: string // Actual tag value\n}\n\nconst DISALLOWED_MODEL_TYPES = ['nlf'] as const\n\n/**\n * Composable for fetching and managing model types from the API\n * Uses shared state to ensure data is only fetched once\n */\nexport const useModelTypes = createSharedComposable(() => {\n const {\n state: modelTypes,\n isLoading,\n error,\n execute: fetchModelTypes\n } = useAsyncState(\n async (): Promise<ModelTypeOption[]> => {\n const response = await api.getModelFolders()\n return response\n .filter(\n (folder) =>\n !DISALLOWED_MODEL_TYPES.includes(\n folder.name as (typeof DISALLOWED_MODEL_TYPES)[number]\n )\n )\n .map((folder) => ({\n name: formatDisplayName(folder.name),\n value: folder.name\n }))\n .sort((a, b) => a.name.localeCompare(b.name))\n },\n [] as ModelTypeOption[],\n {\n immediate: false,\n onError: (err) => {\n console.error('Failed to fetch model types:', err)\n }\n }\n )\n\n return {\n modelTypes,\n isLoading,\n error,\n fetchModelTypes\n }\n})\n","<template>\n <div class=\"flex flex-col gap-4 text-sm text-muted-foreground\">\n <div class=\"flex flex-col gap-2\">\n <p class=\"m-0\">\n {{ $t('assetBrowser.modelAssociatedWithLink') }}\n </p>\n <div\n class=\"flex items-center gap-3 rounded-lg bg-secondary-background px-4 py-2\"\n >\n <img\n v-if=\"previewImage\"\n :src=\"previewImage\"\n :alt=\"metadata?.filename || metadata?.name || 'Model preview'\"\n class=\"size-14 flex-shrink-0 rounded object-cover\"\n />\n <p class=\"m-0 min-w-0 flex-1 truncate text-base-foreground\">\n {{ metadata?.filename || metadata?.name }}\n </p>\n </div>\n </div>\n\n <!-- Model Type Selection -->\n <div class=\"flex flex-col gap-2\">\n <div class=\"flex items-center gap-2\">\n <label>\n {{ $t('assetBrowser.modelTypeSelectorLabel') }}\n </label>\n <i class=\"icon-[lucide--circle-question-mark] text-muted-foreground\" />\n <span class=\"text-muted-foreground\">\n {{ $t('assetBrowser.notSureLeaveAsIs') }}\n </span>\n </div>\n <SingleSelect\n v-model=\"modelValue\"\n :label=\"\n isLoading\n ? $t('g.loading')\n : $t('assetBrowser.modelTypeSelectorPlaceholder')\n \"\n :options=\"modelTypes\"\n :disabled=\"isLoading\"\n data-attr=\"upload-model-step2-type-selector\"\n />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport SingleSelect from '@/components/input/SingleSelect.vue'\nimport { useModelTypes } from '@/platform/assets/composables/useModelTypes'\nimport type { AssetMetadata } from '@/platform/assets/schemas/assetSchema'\n\ndefineProps<{\n metadata?: AssetMetadata\n previewImage?: string\n}>()\n\nconst modelValue = defineModel<string | undefined>()\n\nconst { modelTypes, isLoading } = useModelTypes()\n</script>\n","<template>\n <Dialog\n v-model:visible=\"isVisible\"\n modal\n :closable=\"false\"\n :close-on-escape=\"false\"\n :dismissable-mask=\"true\"\n :pt=\"{\n root: { class: 'video-help-dialog' },\n header: { class: '!hidden' },\n content: { class: '!p-0' },\n mask: { class: '!bg-black/70' }\n }\"\n :style=\"{ width: '90vw' }\"\n >\n <div class=\"relative\">\n <Button\n variant=\"textonly\"\n size=\"icon\"\n class=\"absolute top-4 right-6 z-10\"\n :aria-label=\"$t('g.close')\"\n @click=\"isVisible = false\"\n >\n <i class=\"pi pi-times text-sm\" />\n </Button>\n <video\n autoplay\n muted\n loop\n :aria-label=\"ariaLabel\"\n class=\"w-full rounded-lg\"\n :src=\"videoUrl\"\n >\n {{ $t('g.videoFailedToLoad') }}\n </video>\n </div>\n </Dialog>\n</template>\n\n<script setup lang=\"ts\">\nimport { useEventListener } from '@vueuse/core'\nimport Dialog from 'primevue/dialog'\nimport { onWatcherCleanup, watch } from 'vue'\n\nimport Button from '@/components/ui/button/Button.vue'\n\nconst isVisible = defineModel<boolean>({ required: true })\n\nconst { videoUrl, ariaLabel = 'Help video' } = defineProps<{\n videoUrl: string\n ariaLabel?: string\n}>()\n\nconst handleEscapeKey = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.stopImmediatePropagation()\n event.stopPropagation()\n event.preventDefault()\n isVisible.value = false\n }\n}\n\n// Add listener with capture phase to intercept before parent dialogs\n// Only active when dialog is visible\nwatch(\n isVisible,\n (visible) => {\n if (visible) {\n const stop = useEventListener(document, 'keydown', handleEscapeKey, {\n capture: true\n })\n onWatcherCleanup(stop)\n }\n },\n { immediate: true }\n)\n</script>\n","<template>\n <div class=\"flex justify-end gap-2 w-full\">\n <div\n v-if=\"currentStep === 1 && flags.huggingfaceModelImportEnabled\"\n class=\"mr-auto flex items-center gap-2\"\n >\n <i class=\"icon-[lucide--circle-question-mark] text-muted-foreground\" />\n <Button\n variant=\"muted-textonly\"\n size=\"sm\"\n data-attr=\"upload-model-step1-help-civitai\"\n @click=\"showCivitaiHelp = true\"\n >\n {{ $t('assetBrowser.providerCivitai') }}\n </Button>\n <Button\n variant=\"muted-textonly\"\n size=\"sm\"\n data-attr=\"upload-model-step1-help-huggingface\"\n @click=\"showHuggingFaceHelp = true\"\n >\n {{ $t('assetBrowser.providerHuggingFace') }}\n </Button>\n </div>\n <Button\n v-else-if=\"currentStep === 1\"\n variant=\"muted-textonly\"\n size=\"lg\"\n class=\"mr-auto underline\"\n data-attr=\"upload-model-step1-help-link\"\n @click=\"showCivitaiHelp = true\"\n >\n <i class=\"icon-[lucide--circle-question-mark]\" />\n <span>{{ $t('assetBrowser.uploadModelHowDoIFindThis') }}</span>\n </Button>\n <Button\n v-if=\"currentStep === 1\"\n variant=\"muted-textonly\"\n size=\"lg\"\n data-attr=\"upload-model-step1-cancel-button\"\n :disabled=\"isFetchingMetadata || isUploading\"\n @click=\"emit('close')\"\n >\n {{ $t('g.cancel') }}\n </Button>\n <Button\n v-if=\"currentStep !== 1 && currentStep !== 3\"\n variant=\"muted-textonly\"\n size=\"lg\"\n :data-attr=\"`upload-model-step${currentStep}-back-button`\"\n :disabled=\"isFetchingMetadata || isUploading\"\n @click=\"emit('back')\"\n >\n {{ $t('g.back') }}\n </Button>\n <span v-else />\n\n <Button\n v-if=\"currentStep === 1\"\n variant=\"secondary\"\n size=\"lg\"\n data-attr=\"upload-model-step1-continue-button\"\n :disabled=\"!canFetchMetadata || isFetchingMetadata\"\n @click=\"emit('fetchMetadata')\"\n >\n <i\n v-if=\"isFetchingMetadata\"\n class=\"icon-[lucide--loader-circle] animate-spin\"\n />\n <span>{{ $t('g.continue') }}</span>\n </Button>\n <Button\n v-else-if=\"currentStep === 2\"\n variant=\"secondary\"\n size=\"lg\"\n data-attr=\"upload-model-step2-confirm-button\"\n :disabled=\"!canUploadModel || isUploading\"\n @click=\"emit('upload')\"\n >\n <i v-if=\"isUploading\" class=\"icon-[lucide--loader-circle] animate-spin\" />\n <span>{{ $t('assetBrowser.upload') }}</span>\n </Button>\n <template\n v-else-if=\"\n currentStep === 3 &&\n (uploadStatus === 'success' || uploadStatus === 'processing')\n \"\n >\n <Button\n variant=\"muted-textonly\"\n size=\"lg\"\n data-attr=\"upload-model-step3-import-another-button\"\n @click=\"emit('importAnother')\"\n >\n {{ $t('assetBrowser.importAnother') }}\n </Button>\n <Button\n variant=\"secondary\"\n size=\"lg\"\n data-attr=\"upload-model-step3-finish-button\"\n @click=\"emit('close')\"\n >\n {{\n uploadStatus === 'processing'\n ? $t('g.close')\n : $t('assetBrowser.finish')\n }}\n </Button>\n </template>\n <VideoHelpDialog\n v-model=\"showCivitaiHelp\"\n video-url=\"https://media.comfy.org/compressed_768/civitai_howto.webm\"\n :aria-label=\"$t('assetBrowser.uploadModelHelpVideo')\"\n />\n <VideoHelpDialog\n v-model=\"showHuggingFaceHelp\"\n video-url=\"https://media.comfy.org/byom/huggingfacehowto.mp4\"\n :aria-label=\"$t('assetBrowser.uploadModelHelpVideo')\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref } from 'vue'\n\nimport Button from '@/components/ui/button/Button.vue'\nimport { useFeatureFlags } from '@/composables/useFeatureFlags'\nimport VideoHelpDialog from '@/platform/assets/components/VideoHelpDialog.vue'\n\nconst { flags } = useFeatureFlags()\n\nconst showCivitaiHelp = ref(false)\nconst showHuggingFaceHelp = ref(false)\n\ndefineProps<{\n currentStep: number\n isFetchingMetadata: boolean\n isUploading: boolean\n canFetchMetadata: boolean\n canUploadModel: boolean\n uploadStatus?: 'processing' | 'success' | 'error'\n}>()\n\nconst emit = defineEmits<{\n (e: 'back'): void\n (e: 'fetchMetadata'): void\n (e: 'upload'): void\n (e: 'close'): void\n (e: 'importAnother'): void\n}>()\n</script>\n","import type { ImportSource } from '@/platform/assets/types/importSource'\n\n/**\n * Civitai model import source configuration\n */\nexport const civitaiImportSource: ImportSource = {\n type: 'civitai',\n name: 'Civitai',\n hostnames: ['civitai.com']\n}\n","import type { ImportSource } from '@/platform/assets/types/importSource'\n\n/**\n * Hugging Face model import source configuration\n */\nexport const huggingfaceImportSource: ImportSource = {\n type: 'huggingface',\n name: 'Hugging Face',\n hostnames: ['huggingface.co']\n}\n","import type { ImportSource } from '@/platform/assets/types/importSource'\n\n/**\n * Check if a URL belongs to a specific import source\n */\nexport function validateSourceUrl(url: string, source: ImportSource): boolean {\n try {\n const hostname = new URL(url).hostname.toLowerCase()\n return source.hostnames.some(\n (h) => hostname === h || hostname.endsWith(`.${h}`)\n )\n } catch {\n return false\n }\n}\n","<template>\n <div class=\"flex flex-col justify-between h-full gap-6 text-sm\">\n <div class=\"flex flex-col gap-6\">\n <div class=\"flex flex-col gap-2\">\n <p class=\"m-0 text-foreground\">\n {{ $t('assetBrowser.uploadModelDescription1Generic') }}\n </p>\n <div class=\"m-0\">\n <p class=\"m-0 text-muted-foreground\">\n {{ $t('assetBrowser.uploadModelDescription2Generic') }}\n </p>\n <span class=\"inline-flex items-center gap-1 flex-wrap mt-2\">\n <span class=\"inline-flex items-center gap-1\">\n <img\n :src=\"civitaiIcon\"\n :alt=\"$t('assetBrowser.providerCivitai')\"\n class=\"w-4 h-4\"\n />\n <a\n :href=\"civitaiUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"text-muted-foreground underline\"\n >\n {{ $t('assetBrowser.providerCivitai') }}</a\n ><span>,</span>\n </span>\n <span class=\"inline-flex items-center gap-1\">\n <img\n :src=\"huggingFaceIcon\"\n :alt=\"$t('assetBrowser.providerHuggingFace')\"\n class=\"w-4 h-4\"\n />\n <a\n :href=\"huggingFaceUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"text-muted-foreground underline\"\n >\n {{ $t('assetBrowser.providerHuggingFace') }}\n </a>\n </span>\n </span>\n </div>\n </div>\n\n <div class=\"flex flex-col gap-2\">\n <div class=\"relative\">\n <InputText\n v-model=\"url\"\n autofocus\n :placeholder=\"$t('assetBrowser.genericLinkPlaceholder')\"\n class=\"w-full border-0 bg-secondary-background p-4 pr-10\"\n data-attr=\"upload-model-step1-url-input\"\n />\n <i\n v-if=\"isValidUrl\"\n class=\"icon-[lucide--circle-check-big] absolute top-1/2 right-3 size-5 -translate-y-1/2 text-green-500\"\n />\n </div>\n <p v-if=\"error\" class=\"text-sm text-error\">\n {{ error }}\n </p>\n <p v-else-if=\"!flags.asyncModelUploadEnabled\" class=\"text-foreground\">\n <i18n-t keypath=\"assetBrowser.maxFileSize\" tag=\"span\">\n <template #size>\n <span class=\"font-bold italic\">{{\n $t('assetBrowser.maxFileSizeValue')\n }}</span>\n </template>\n </i18n-t>\n </p>\n </div>\n </div>\n\n <div class=\"text-sm text-muted\">\n {{ $t('assetBrowser.uploadModelHelpFooterText') }}\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport InputText from 'primevue/inputtext'\nimport { computed } from 'vue'\n\nimport { useFeatureFlags } from '@/composables/useFeatureFlags'\nimport { civitaiImportSource } from '@/platform/assets/importSources/civitaiImportSource'\nimport { huggingfaceImportSource } from '@/platform/assets/importSources/huggingfaceImportSource'\nimport { validateSourceUrl } from '@/platform/assets/utils/importSourceUtil'\n\nconst { flags } = useFeatureFlags()\n\nconst props = defineProps<{\n modelValue: string\n error?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n}>()\n\nconst url = computed({\n get: () => props.modelValue,\n set: (value: string) => emit('update:modelValue', value)\n})\n\nconst importSources = [civitaiImportSource, huggingfaceImportSource]\n\nconst isValidUrl = computed(() => {\n const trimmedUrl = url.value.trim()\n if (!trimmedUrl) return false\n return importSources.some((source) => validateSourceUrl(trimmedUrl, source))\n})\n\nconst civitaiIcon = '/assets/images/civitai.svg'\nconst civitaiUrl = 'https://civitai.com/models'\nconst huggingFaceIcon = '/assets/images/hf-logo.svg'\nconst huggingFaceUrl = 'https://huggingface.co'\n</script>\n","<template>\n <div class=\"flex flex-col gap-6 text-sm text-muted-foreground\">\n <div class=\"flex flex-col gap-2\">\n <p class=\"m-0\">\n {{ $t('assetBrowser.uploadModelDescription1') }}\n </p>\n <ul class=\"list-disc space-y-1 pl-5 mt-0\">\n <li>\n <i18n-t keypath=\"assetBrowser.uploadModelDescription2\" tag=\"span\">\n <template #link>\n <a\n href=\"https://civitai.com/models\"\n target=\"_blank\"\n class=\"text-muted-foreground underline\"\n >\n {{ $t('assetBrowser.uploadModelDescription2Link') }}\n </a>\n </template>\n </i18n-t>\n </li>\n <li v-if=\"!flags.asyncModelUploadEnabled\">\n <i18n-t keypath=\"assetBrowser.uploadModelDescription3\" tag=\"span\">\n <template #size>\n <span class=\"font-bold italic\">{{\n $t('assetBrowser.maxFileSizeValue')\n }}</span>\n </template>\n </i18n-t>\n </li>\n </ul>\n </div>\n\n <div class=\"flex flex-col gap-2\">\n <i18n-t keypath=\"assetBrowser.civitaiLinkLabel\" tag=\"label\" class=\"mb-0\">\n <template #download>\n <span class=\"font-bold italic\">{{\n $t('assetBrowser.civitaiLinkLabelDownload')\n }}</span>\n </template>\n </i18n-t>\n <div class=\"relative\">\n <InputText\n v-model=\"url\"\n autofocus\n :placeholder=\"$t('assetBrowser.civitaiLinkPlaceholder')\"\n class=\"w-full border-0 bg-secondary-background p-4 pr-10\"\n data-attr=\"upload-model-step1-url-input\"\n />\n <i\n v-if=\"isValidUrl\"\n class=\"icon-[lucide--circle-check-big] absolute top-1/2 right-3 size-5 -translate-y-1/2 text-green-500\"\n />\n </div>\n <p v-if=\"error\" class=\"text-sm text-error\">\n {{ error }}\n </p>\n <i18n-t\n v-else\n keypath=\"assetBrowser.civitaiLinkExample\"\n tag=\"p\"\n class=\"text-sm\"\n >\n <template #example>\n <strong>{{ $t('assetBrowser.civitaiLinkExampleStrong') }}</strong>\n </template>\n <template #link>\n <a\n href=\"https://civitai.com/models/10706/luisap-z-image-and-qwen-pixel-art-refiner?modelVersionId=2225295\"\n target=\"_blank\"\n class=\"text-muted-foreground underline\"\n >\n {{ $t('assetBrowser.civitaiLinkExampleUrl') }}\n </a>\n </template>\n </i18n-t>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport InputText from 'primevue/inputtext'\nimport { computed } from 'vue'\n\nimport { useFeatureFlags } from '@/composables/useFeatureFlags'\nimport { civitaiImportSource } from '@/platform/assets/importSources/civitaiImportSource'\nimport { validateSourceUrl } from '@/platform/assets/utils/importSourceUtil'\n\nconst { flags } = useFeatureFlags()\n\ndefineProps<{\n error?: string\n}>()\n\nconst url = defineModel<string>({ required: true })\n\nconst isValidUrl = computed(() => {\n const trimmedUrl = url.value.trim()\n if (!trimmedUrl) return false\n return validateSourceUrl(trimmedUrl, civitaiImportSource)\n})\n</script>\n","import type { Ref } from 'vue'\nimport { computed, ref, watch } from 'vue'\nimport { useI18n } from 'vue-i18n'\n\nimport { useFeatureFlags } from '@/composables/useFeatureFlags'\nimport { st } from '@/i18n'\nimport { civitaiImportSource } from '@/platform/assets/importSources/civitaiImportSource'\nimport { huggingfaceImportSource } from '@/platform/assets/importSources/huggingfaceImportSource'\nimport type { AssetMetadata } from '@/platform/assets/schemas/assetSchema'\nimport { assetService } from '@/platform/assets/services/assetService'\nimport type { ImportSource } from '@/platform/assets/types/importSource'\nimport { validateSourceUrl } from '@/platform/assets/utils/importSourceUtil'\nimport { useAssetDownloadStore } from '@/stores/assetDownloadStore'\nimport { useAssetsStore } from '@/stores/assetsStore'\nimport { useModelToNodeStore } from '@/stores/modelToNodeStore'\n\ninterface WizardData {\n url: string\n metadata?: AssetMetadata\n name: string\n tags: string[]\n previewImage?: string\n}\n\ninterface ModelTypeOption {\n name: string\n value: string\n}\n\nexport function useUploadModelWizard(modelTypes: Ref<ModelTypeOption[]>) {\n const { t } = useI18n()\n const assetsStore = useAssetsStore()\n const assetDownloadStore = useAssetDownloadStore()\n const modelToNodeStore = useModelToNodeStore()\n const { flags } = useFeatureFlags()\n const currentStep = ref(1)\n const isFetchingMetadata = ref(false)\n const isUploading = ref(false)\n const uploadStatus = ref<'processing' | 'success' | 'error'>()\n const uploadError = ref('')\n\n const wizardData = ref<WizardData>({\n url: '',\n name: '',\n tags: []\n })\n\n const selectedModelType = ref<string>()\n\n // Available import sources\n const importSources: ImportSource[] = flags.huggingfaceModelImportEnabled\n ? [civitaiImportSource, huggingfaceImportSource]\n : [civitaiImportSource]\n\n // Detected import source based on URL\n const detectedSource = computed(() => {\n const url = wizardData.value.url.trim()\n if (!url) return null\n return (\n importSources.find((source) => validateSourceUrl(url, source)) ?? null\n )\n })\n\n // Clear error when URL changes\n watch(\n () => wizardData.value.url,\n () => {\n uploadError.value = ''\n }\n )\n\n // Validation\n const canFetchMetadata = computed(() => {\n return wizardData.value.url.trim().length > 0\n })\n\n const canUploadModel = computed(() => {\n return !!selectedModelType.value\n })\n\n async function fetchMetadata() {\n if (!canFetchMetadata.value) return\n\n // Clean and normalize URL\n let cleanedUrl = wizardData.value.url.trim()\n try {\n cleanedUrl = new URL(encodeURI(cleanedUrl)).toString()\n } catch {\n // If URL parsing fails, just use the trimmed input\n }\n wizardData.value.url = cleanedUrl\n\n // Validate URL belongs to a supported import source\n const source = detectedSource.value\n if (!source) {\n const supportedSources = importSources.map((s) => s.name).join(', ')\n uploadError.value = t('assetBrowser.unsupportedUrlSource', {\n sources: supportedSources\n })\n return\n }\n\n isFetchingMetadata.value = true\n try {\n const metadata = await assetService.getAssetMetadata(wizardData.value.url)\n\n // Decode URL-encoded filenames (e.g., Chinese characters)\n if (metadata.filename) {\n try {\n metadata.filename = decodeURIComponent(metadata.filename)\n } catch {\n // Keep original if decoding fails\n }\n }\n if (metadata.name) {\n try {\n metadata.name = decodeURIComponent(metadata.name)\n } catch {\n // Keep original if decoding fails\n }\n }\n\n wizardData.value.metadata = metadata\n\n // Pre-fill name from metadata\n wizardData.value.name = metadata.filename || metadata.name || ''\n\n // Store preview image if available\n wizardData.value.previewImage = metadata.preview_image\n\n // Pre-fill model type from metadata tags if available\n if (metadata.tags && metadata.tags.length > 0) {\n wizardData.value.tags = metadata.tags\n // Try to detect model type from tags\n const typeTag = metadata.tags.find((tag) =>\n modelTypes.value.some((type) => type.value === tag)\n )\n if (typeTag) {\n selectedModelType.value = typeTag\n }\n }\n\n currentStep.value = 2\n } catch (error) {\n console.error('Failed to retrieve metadata:', error)\n uploadError.value =\n error instanceof Error\n ? error.message\n : st(\n 'assetBrowser.uploadModelFailedToRetrieveMetadata',\n 'Failed to retrieve metadata. Please check the link and try again.'\n )\n currentStep.value = 1\n } finally {\n isFetchingMetadata.value = false\n }\n }\n\n async function uploadPreviewImage(\n filename: string\n ): Promise<string | undefined> {\n if (!wizardData.value.previewImage) return undefined\n\n try {\n const baseFilename = filename.split('.')[0]\n let extension = 'png'\n const mimeMatch = wizardData.value.previewImage.match(\n /^data:image\\/([^;]+);/\n )\n if (mimeMatch) {\n extension = mimeMatch[1] === 'jpeg' ? 'jpg' : mimeMatch[1]\n }\n\n const previewAsset = await assetService.uploadAssetFromBase64({\n data: wizardData.value.previewImage,\n name: `${baseFilename}_preview.${extension}`,\n tags: ['preview']\n })\n return previewAsset.id\n } catch (error) {\n console.error('Failed to upload preview image:', error)\n return undefined\n }\n }\n\n async function refreshModelCaches() {\n if (!selectedModelType.value) return\n\n const providers = modelToNodeStore.getAllNodeProviders(\n selectedModelType.value\n )\n const results = await Promise.allSettled(\n providers.map((provider) =>\n assetsStore.updateModelsForNodeType(provider.nodeDef.name)\n )\n )\n results.forEach((result, index) => {\n if (result.status === 'rejected') {\n console.error(\n `Failed to refresh ${providers[index].nodeDef.name}:`,\n result.reason\n )\n }\n })\n }\n\n async function uploadModel(): Promise<boolean> {\n if (!canUploadModel.value) {\n return false\n }\n\n const source = detectedSource.value\n if (!source) {\n uploadError.value = t('assetBrowser.noValidSourceDetected')\n return false\n }\n\n isUploading.value = true\n\n try {\n const tags = selectedModelType.value\n ? ['models', selectedModelType.value]\n : ['models']\n const filename =\n wizardData.value.metadata?.filename ||\n wizardData.value.metadata?.name ||\n 'model'\n\n const previewId = await uploadPreviewImage(filename)\n const userMetadata = {\n source: source.type,\n source_url: wizardData.value.url,\n model_type: selectedModelType.value\n }\n\n if (flags.asyncModelUploadEnabled) {\n const result = await assetService.uploadAssetAsync({\n source_url: wizardData.value.url,\n tags,\n user_metadata: userMetadata,\n preview_id: previewId\n })\n\n if (result.type === 'async' && result.task.status !== 'completed') {\n if (selectedModelType.value) {\n assetDownloadStore.trackDownload(\n result.task.task_id,\n selectedModelType.value,\n filename\n )\n }\n uploadStatus.value = 'processing'\n } else {\n uploadStatus.value = 'success'\n await refreshModelCaches()\n }\n currentStep.value = 3\n } else {\n await assetService.uploadAssetFromUrl({\n url: wizardData.value.url,\n name: filename,\n tags,\n user_metadata: userMetadata,\n preview_id: previewId\n })\n uploadStatus.value = 'success'\n await refreshModelCaches()\n currentStep.value = 3\n }\n } catch (error) {\n console.error('Failed to upload asset:', error)\n uploadStatus.value = 'error'\n uploadError.value =\n error instanceof Error ? error.message : 'Failed to upload model'\n currentStep.value = 3\n } finally {\n isUploading.value = false\n }\n return uploadStatus.value !== 'error'\n }\n\n function goToPreviousStep() {\n if (currentStep.value > 1) {\n currentStep.value = currentStep.value - 1\n }\n }\n\n function resetWizard() {\n currentStep.value = 1\n isFetchingMetadata.value = false\n isUploading.value = false\n uploadStatus.value = undefined\n uploadError.value = ''\n wizardData.value = {\n url: '',\n name: '',\n tags: []\n }\n selectedModelType.value = undefined\n }\n\n return {\n // State\n currentStep,\n isFetchingMetadata,\n isUploading,\n uploadStatus,\n uploadError,\n wizardData,\n selectedModelType,\n\n // Computed\n canFetchMetadata,\n canUploadModel,\n detectedSource,\n\n // Actions\n fetchMetadata,\n uploadModel,\n goToPreviousStep,\n resetWizard\n }\n}\n","<template>\n <div\n class=\"upload-model-dialog flex flex-col gap-6 border-t border-border-default p-4 pt-6\"\n >\n <!-- Scrollable content area -->\n <div class=\"min-h-0 flex-auto basis-0 overflow-y-auto\">\n <!-- Step 1: Enter URL -->\n <UploadModelUrlInput\n v-if=\"currentStep === 1 && flags.huggingfaceModelImportEnabled\"\n v-model=\"wizardData.url\"\n :error=\"uploadError\"\n />\n <UploadModelUrlInputCivitai\n v-else-if=\"currentStep === 1\"\n v-model=\"wizardData.url\"\n :error=\"uploadError\"\n />\n\n <!-- Step 2: Confirm Metadata -->\n <UploadModelConfirmation\n v-else-if=\"currentStep === 2\"\n v-model=\"selectedModelType\"\n :metadata=\"wizardData.metadata\"\n :preview-image=\"wizardData.previewImage\"\n />\n\n <!-- Step 3: Upload Progress -->\n <UploadModelProgress\n v-else-if=\"currentStep === 3 && uploadStatus != null\"\n :result=\"uploadStatus\"\n :error=\"uploadError\"\n :metadata=\"wizardData.metadata\"\n :model-type=\"selectedModelType\"\n :preview-image=\"wizardData.previewImage\"\n />\n </div>\n\n <!-- Navigation Footer - always visible -->\n <UploadModelFooter\n class=\"flex-shrink-0\"\n :current-step=\"currentStep\"\n :is-fetching-metadata=\"isFetchingMetadata\"\n :is-uploading=\"isUploading\"\n :can-fetch-metadata=\"canFetchMetadata\"\n :can-upload-model=\"canUploadModel\"\n :upload-status=\"uploadStatus\"\n @back=\"goToPreviousStep\"\n @fetch-metadata=\"handleFetchMetadata\"\n @upload=\"handleUploadModel\"\n @close=\"handleClose\"\n @import-another=\"resetWizard\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { onMounted } from 'vue'\n\nimport { useFeatureFlags } from '@/composables/useFeatureFlags'\nimport UploadModelConfirmation from '@/platform/assets/components/UploadModelConfirmation.vue'\nimport UploadModelFooter from '@/platform/assets/components/UploadModelFooter.vue'\nimport UploadModelProgress from '@/platform/assets/components/UploadModelProgress.vue'\nimport UploadModelUrlInput from '@/platform/assets/components/UploadModelUrlInput.vue'\nimport UploadModelUrlInputCivitai from '@/platform/assets/components/UploadModelUrlInputCivitai.vue'\nimport { useModelTypes } from '@/platform/assets/composables/useModelTypes'\nimport { useUploadModelWizard } from '@/platform/assets/composables/useUploadModelWizard'\nimport { useDialogStore } from '@/stores/dialogStore'\n\nconst { flags } = useFeatureFlags()\nconst dialogStore = useDialogStore()\nconst { modelTypes, fetchModelTypes } = useModelTypes()\n\nconst emit = defineEmits<{\n 'upload-success': []\n}>()\n\nconst {\n currentStep,\n isFetchingMetadata,\n isUploading,\n uploadStatus,\n uploadError,\n wizardData,\n selectedModelType,\n canFetchMetadata,\n canUploadModel,\n fetchMetadata,\n uploadModel,\n goToPreviousStep,\n resetWizard\n} = useUploadModelWizard(modelTypes)\n\nasync function handleFetchMetadata() {\n await fetchMetadata()\n}\n\nasync function handleUploadModel() {\n const success = await uploadModel()\n if (success) {\n emit('upload-success')\n }\n}\n\nfunction handleClose() {\n dialogStore.closeDialog({ key: 'upload-model' })\n}\n\nonMounted(() => {\n fetchModelTypes()\n})\n</script>\n\n<style scoped>\n.upload-model-dialog {\n width: 90vw;\n max-width: 800px;\n min-height: min(400px, 80vh);\n max-height: 90vh;\n}\n\n@media (min-width: 640px) {\n .upload-model-dialog {\n width: auto;\n min-width: 600px;\n }\n}\n</style>\n","export default \"__VITE_PUBLIC_ASSET__53f47e52__\"","<template>\n <div class=\"flex items-center gap-2 p-4 font-bold\">\n <img\n v-if=\"!flags.huggingfaceModelImportEnabled\"\n src=\"/assets/images/civitai.svg\"\n class=\"size-4\"\n />\n <span>{{ $t(titleKey) }}</span>\n <span\n class=\"rounded-full bg-white px-1.5 py-0 text-xxs font-inter font-semibold uppercase text-black\"\n >\n {{ $t('g.beta') }}\n </span>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { useFeatureFlags } from '@/composables/useFeatureFlags'\n\nconst { flags } = useFeatureFlags()\n\nconst titleKey = computed(() => {\n return flags.huggingfaceModelImportEnabled\n ? 'assetBrowser.uploadModelGeneric'\n : 'assetBrowser.uploadModelFromCivitai'\n})\n</script>\n","<template>\n <div\n class=\"flex flex-1 flex-col items-center justify-center text-base text-muted-foreground\"\n >\n <p class=\"m-0 max-w-md\">\n {{ $t('assetBrowser.upgradeFeatureDescription') }}\n </p>\n </div>\n</template>\n","<template>\n <div class=\"flex flex-wrap justify-end gap-2 w-full\">\n <a\n href=\"https://blog.comfy.org/p/comfy-cloud-new-features-and-pricing\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"text-muted-foreground mr-auto underline flex items-center gap-2\"\n >\n <i class=\"icon-[lucide--external-link]\" />\n <span>{{ $t('g.learnMore') }}</span>\n </a>\n <Button variant=\"textonly\" @click=\"emit('close')\">{{\n $t('g.close')\n }}</Button>\n <Button variant=\"secondary\" @click=\"emit('subscribe')\">\n {{ $t('subscription.required.subscribe') }}\n </Button>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport Button from '@/components/ui/button/Button.vue'\n\nconst emit = defineEmits<{\n close: []\n subscribe: []\n}>()\n</script>\n","<template>\n <div\n class=\"flex flex-col justify-between gap-10 p-4 border-t border-border-default w-auto max-w-[min(500px,90vw)]\"\n >\n <UploadModelUpgradeModalBody />\n\n <UploadModelUpgradeModalFooter\n @close=\"handleClose\"\n @subscribe=\"handleSubscribe\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport UploadModelUpgradeModalBody from '@/platform/assets/components/UploadModelUpgradeModalBody.vue'\nimport UploadModelUpgradeModalFooter from '@/platform/assets/components/UploadModelUpgradeModalFooter.vue'\nimport { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'\nimport { useDialogStore } from '@/stores/dialogStore'\n\nconst dialogStore = useDialogStore()\nconst { showSubscriptionDialog } = useSubscription()\n\nfunction handleClose() {\n dialogStore.closeDialog({ key: 'upload-model-upgrade' })\n}\n\nfunction handleSubscribe() {\n showSubscriptionDialog()\n}\n</script>\n","<template>\n <div class=\"flex items-center gap-2 p-4 font-bold\">\n <span>{{ $t('assetBrowser.upgradeToUnlockFeature') }}</span>\n </div>\n</template>\n","import { useFeatureFlags } from '@/composables/useFeatureFlags'\nimport UploadModelDialog from '@/platform/assets/components/UploadModelDialog.vue'\nimport UploadModelDialogHeader from '@/platform/assets/components/UploadModelDialogHeader.vue'\nimport UploadModelUpgradeModal from '@/platform/assets/components/UploadModelUpgradeModal.vue'\nimport UploadModelUpgradeModalHeader from '@/platform/assets/components/UploadModelUpgradeModalHeader.vue'\nimport { useDialogStore } from '@/stores/dialogStore'\nimport { computed } from 'vue'\n\nexport function useModelUpload(\n onUploadSuccess?: () => Promise<unknown> | void\n) {\n const dialogStore = useDialogStore()\n const { flags } = useFeatureFlags()\n const isUploadButtonEnabled = computed(() => flags.modelUploadButtonEnabled)\n\n function showUploadDialog() {\n if (!flags.privateModelsEnabled) {\n // Show upgrade modal if private models are disabled\n dialogStore.showDialog({\n key: 'upload-model-upgrade',\n headerComponent: UploadModelUpgradeModalHeader,\n component: UploadModelUpgradeModal,\n dialogComponentProps: {\n pt: {\n header: 'py-0! pl-0!',\n content: 'p-0! overflow-y-hidden!'\n }\n }\n })\n } else {\n // Show regular upload modal\n dialogStore.showDialog({\n key: 'upload-model',\n headerComponent: UploadModelDialogHeader,\n component: UploadModelDialog,\n props: {\n onUploadSuccess: async () => {\n await onUploadSuccess?.()\n }\n },\n dialogComponentProps: {\n pt: {\n header: 'py-0! pl-0!',\n content: 'p-0! overflow-y-hidden!'\n }\n }\n })\n }\n }\n return { isUploadButtonEnabled, showUploadDialog }\n}\n","<script setup lang=\"ts\">\nimport { refDebounced } from '@vueuse/core'\nimport { ref, toRef, toValue, watch } from 'vue'\nimport type { HTMLAttributes, MaybeRefOrGetter } from 'vue'\n\nimport { cn } from '@/utils/tailwindUtil'\n\nconst {\n searcher = async () => {},\n updateKey,\n autofocus = false,\n class: customClass\n} = defineProps<{\n searcher?: (\n query: string,\n onCleanup: (cleanupFn: () => void) => void\n ) => Promise<void>\n updateKey?: MaybeRefOrGetter<unknown>\n autofocus?: boolean\n class?: HTMLAttributes['class']\n}>()\n\nconst searchQuery = defineModel<string>({ default: '' })\n\nconst isQuerying = ref(false)\nconst debouncedSearchQuery = refDebounced(searchQuery, 250, {\n maxWait: 1000\n})\nwatch(searchQuery, (value) => {\n isQuerying.value = value !== debouncedSearchQuery.value\n})\nconst updateKeyRef = toRef(() => toValue(updateKey))\n\nwatch(\n [debouncedSearchQuery, updateKeyRef],\n (_, __, onCleanup) => {\n let isCleanup = false\n let cleanupFn: undefined | (() => void)\n onCleanup(() => {\n isCleanup = true\n cleanupFn?.()\n })\n\n void searcher(debouncedSearchQuery.value, (cb) => (cleanupFn = cb))\n .catch((error) => {\n console.error('[SidePanelSearch] searcher failed', error)\n })\n .finally(() => {\n if (!isCleanup) isQuerying.value = false\n })\n },\n { immediate: true }\n)\n\nfunction handleFocus(event: FocusEvent) {\n const target = event.target as HTMLInputElement\n target.select()\n}\n</script>\n\n<template>\n <label\n :class=\"\n cn(\n 'group',\n 'bg-component-node-widget-background rounded-lg transition-all duration-150',\n 'flex-1 flex items-center',\n 'text-base-foreground border-0',\n 'focus-within:ring focus-within:ring-component-node-widget-background-highlighted/80',\n customClass\n )\n \"\n >\n <i\n :class=\"\n cn(\n 'size-4 ml-2 shrink-0 transition-colors duration-150',\n isQuerying\n ? 'icon-[lucide--loader-circle] animate-spin'\n : 'icon-[lucide--search]',\n searchQuery?.trim() !== ''\n ? 'text-base-foreground'\n : 'text-muted-foreground group-hover:text-base-foreground group-focus-within:text-base-foreground'\n )\n \"\n />\n <input\n v-model=\"searchQuery\"\n type=\"text\"\n class=\"bg-transparent border-0 outline-0 ring-0 h-5 w-full my-1.5 mx-2\"\n :placeholder=\"$t('g.searchPlaceholder')\"\n :autofocus\n @focus=\"handleFocus\"\n />\n <button\n v-if=\"searchQuery.trim().length > 0\"\n class=\"text-muted-foreground hover:text-base-foreground bg-transparent shrink-0 border-0 outline-0 ring-0 p-0 m-0 pr-3 pl-1 flex items-center justify-center transition-all duration-150 hover:scale-108\"\n :aria-label=\"$t('g.clear')\"\n @click=\"searchQuery = ''\"\n >\n <i :class=\"cn('icon-[lucide--delete] size-4 cursor-pointer')\" />\n </button>\n </label>\n</template>\n","export default \"__VITE_PUBLIC_ASSET__c8cdd13f__\"","import { onBeforeUnmount, ref, watch } from 'vue'\nimport type { Ref } from 'vue'\n\ninterface UseIntersectionObserverOptions extends IntersectionObserverInit {\n immediate?: boolean\n}\n\nexport function useIntersectionObserver(\n target: Ref<Element | null>,\n callback: IntersectionObserverCallback,\n options: UseIntersectionObserverOptions = {}\n) {\n const { immediate = true, ...observerOptions } = options\n\n const isSupported =\n typeof window !== 'undefined' && 'IntersectionObserver' in window\n const isIntersecting = ref(false)\n\n let observer: IntersectionObserver | null = null\n\n const cleanup = () => {\n if (observer) {\n observer.disconnect()\n observer = null\n }\n }\n\n const observe = () => {\n cleanup()\n\n if (!isSupported || !target.value) return\n\n observer = new IntersectionObserver((entries) => {\n isIntersecting.value = entries.some((entry) => entry.isIntersecting)\n callback(entries, observer!)\n }, observerOptions)\n\n observer.observe(target.value)\n }\n\n const unobserve = () => {\n if (observer && target.value) {\n observer.unobserve(target.value)\n }\n }\n\n if (immediate) {\n watch(target, observe, { immediate: true, flush: 'post' })\n }\n\n onBeforeUnmount(cleanup)\n\n return {\n isSupported,\n isIntersecting,\n observe,\n unobserve,\n cleanup\n }\n}\n","import { reactive } from 'vue'\n\ninterface CachedMedia {\n src: string\n blob?: Blob\n objectUrl?: string\n error?: boolean\n isLoading: boolean\n lastAccessed: number\n}\n\ninterface MediaCacheOptions {\n maxSize?: number\n maxAge?: number // in milliseconds\n preloadDistance?: number // pixels from viewport\n}\n\nclass MediaCacheService {\n public cache = reactive(new Map<string, CachedMedia>())\n private readonly maxSize: number\n private readonly maxAge: number\n private cleanupInterval: number | null = null\n private urlRefCount = new Map<string, number>()\n\n constructor(options: MediaCacheOptions = {}) {\n this.maxSize = options.maxSize ?? 100\n this.maxAge = options.maxAge ?? 30 * 60 * 1000 // 30 minutes\n\n // Start cleanup interval\n this.startCleanupInterval()\n }\n\n private startCleanupInterval() {\n // Clean up every 5 minutes\n this.cleanupInterval = window.setInterval(\n () => {\n this.cleanup()\n },\n 5 * 60 * 1000\n )\n }\n\n private cleanup() {\n const now = Date.now()\n const keysToDelete: string[] = []\n\n // Find expired entries\n for (const [key, entry] of Array.from(this.cache.entries())) {\n if (now - entry.lastAccessed > this.maxAge) {\n // Only revoke object URL if no components are using it\n if (entry.objectUrl) {\n const refCount = this.urlRefCount.get(entry.objectUrl) || 0\n if (refCount === 0) {\n URL.revokeObjectURL(entry.objectUrl)\n this.urlRefCount.delete(entry.objectUrl)\n keysToDelete.push(key)\n }\n // Don't delete cache entry if URL is still in use\n } else {\n keysToDelete.push(key)\n }\n }\n }\n\n // Remove expired entries\n keysToDelete.forEach((key) => this.cache.delete(key))\n\n // If still over size limit, remove oldest entries that aren't in use\n if (this.cache.size > this.maxSize) {\n const entries = Array.from(this.cache.entries())\n entries.sort((a, b) => a[1].lastAccessed - b[1].lastAccessed)\n\n let removedCount = 0\n const targetRemoveCount = this.cache.size - this.maxSize\n\n for (const [key, entry] of entries) {\n if (removedCount >= targetRemoveCount) break\n\n if (entry.objectUrl) {\n const refCount = this.urlRefCount.get(entry.objectUrl) || 0\n if (refCount === 0) {\n URL.revokeObjectURL(entry.objectUrl)\n this.urlRefCount.delete(entry.objectUrl)\n this.cache.delete(key)\n removedCount++\n }\n } else {\n this.cache.delete(key)\n removedCount++\n }\n }\n }\n }\n\n async getCachedMedia(src: string): Promise<CachedMedia> {\n let entry = this.cache.get(src)\n\n if (entry) {\n // Update last accessed time\n entry.lastAccessed = Date.now()\n return entry\n }\n\n // Create new entry\n entry = {\n src,\n isLoading: true,\n lastAccessed: Date.now()\n }\n\n // Update cache with loading entry\n this.cache.set(src, entry)\n\n try {\n // Fetch the media\n const response = await fetch(src, { cache: 'force-cache' })\n if (!response.ok) {\n throw new Error(`Failed to fetch: ${response.status}`)\n }\n\n const blob = await response.blob()\n const objectUrl = URL.createObjectURL(blob)\n\n // Update entry with successful result\n const updatedEntry: CachedMedia = {\n src,\n blob,\n objectUrl,\n isLoading: false,\n lastAccessed: Date.now()\n }\n\n this.cache.set(src, updatedEntry)\n return updatedEntry\n } catch (error) {\n console.warn('Failed to cache media:', src, error)\n\n // Update entry with error\n const errorEntry: CachedMedia = {\n src,\n error: true,\n isLoading: false,\n lastAccessed: Date.now()\n }\n\n this.cache.set(src, errorEntry)\n return errorEntry\n }\n }\n\n acquireUrl(src: string): string | undefined {\n const entry = this.cache.get(src)\n if (entry?.objectUrl) {\n const currentCount = this.urlRefCount.get(entry.objectUrl) || 0\n this.urlRefCount.set(entry.objectUrl, currentCount + 1)\n return entry.objectUrl\n }\n return undefined\n }\n\n releaseUrl(src: string): void {\n const entry = this.cache.get(src)\n if (entry?.objectUrl) {\n const count = (this.urlRefCount.get(entry.objectUrl) || 1) - 1\n if (count <= 0) {\n URL.revokeObjectURL(entry.objectUrl)\n this.urlRefCount.delete(entry.objectUrl)\n // Remove from cache as well\n this.cache.delete(src)\n } else {\n this.urlRefCount.set(entry.objectUrl, count)\n }\n }\n }\n\n clearCache() {\n // Revoke all object URLs\n for (const entry of Array.from(this.cache.values())) {\n if (entry.objectUrl) {\n URL.revokeObjectURL(entry.objectUrl)\n }\n }\n this.cache.clear()\n this.urlRefCount.clear()\n }\n\n destroy() {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval)\n this.cleanupInterval = null\n }\n this.clearCache()\n }\n}\n\n// Global instance\nlet mediaCacheInstance: MediaCacheService | null = null\n\nexport function useMediaCache(options?: MediaCacheOptions) {\n if (!mediaCacheInstance) {\n mediaCacheInstance = new MediaCacheService(options)\n }\n\n const getCachedMedia = (src: string) =>\n mediaCacheInstance!.getCachedMedia(src)\n const clearCache = () => mediaCacheInstance!.clearCache()\n const acquireUrl = (src: string) => mediaCacheInstance!.acquireUrl(src)\n const releaseUrl = (src: string) => mediaCacheInstance!.releaseUrl(src)\n\n return {\n getCachedMedia,\n clearCache,\n acquireUrl,\n releaseUrl,\n cache: mediaCacheInstance.cache\n }\n}\n\n// Cleanup on page unload\nif (typeof window !== 'undefined') {\n window.addEventListener('beforeunload', () => {\n if (mediaCacheInstance) {\n mediaCacheInstance.destroy()\n }\n })\n}\n","<template>\n <div\n ref=\"containerRef\"\n class=\"relative flex h-full w-full items-center justify-center overflow-hidden\"\n :class=\"containerClass\"\n >\n <Skeleton\n v-if=\"!isImageLoaded\"\n width=\"100%\"\n height=\"100%\"\n class=\"absolute inset-0\"\n />\n <img\n v-if=\"cachedSrc\"\n :src=\"cachedSrc\"\n :alt=\"alt\"\n draggable=\"false\"\n :class=\"imageClass\"\n :style=\"imageStyle\"\n @load=\"onImageLoad\"\n @error=\"onImageError\"\n />\n <div\n v-if=\"hasError\"\n class=\"absolute inset-0 flex items-center justify-center\"\n >\n <img\n src=\"/assets/images/default-template.png\"\n :alt=\"alt\"\n draggable=\"false\"\n :class=\"imageClass\"\n :style=\"imageStyle\"\n />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport Skeleton from 'primevue/skeleton'\nimport { computed, onUnmounted, ref, watch } from 'vue'\n\nimport { useIntersectionObserver } from '@/composables/useIntersectionObserver'\nimport { useMediaCache } from '@/services/mediaCacheService'\nimport type { ClassValue } from '@/utils/tailwindUtil'\n\nconst {\n src,\n alt = '',\n containerClass = '',\n imageClass = '',\n imageStyle,\n rootMargin = '300px'\n} = defineProps<{\n src: string\n alt?: string\n containerClass?: ClassValue\n imageClass?: ClassValue\n imageStyle?: Record<string, any>\n rootMargin?: string\n}>()\n\nconst containerRef = ref<HTMLElement | null>(null)\nconst isIntersecting = ref(false)\nconst isImageLoaded = ref(false)\nconst hasError = ref(false)\nconst cachedSrc = ref<string | undefined>(undefined)\n\nconst { getCachedMedia, acquireUrl, releaseUrl } = useMediaCache()\n\n// Use intersection observer to detect when the image container comes into view\nuseIntersectionObserver(\n containerRef,\n (entries) => {\n const entry = entries[0]\n isIntersecting.value = entry?.isIntersecting ?? false\n },\n {\n rootMargin,\n threshold: 0.1\n }\n)\n\n// Only start loading the image when it's in view\nconst shouldLoad = computed(() => isIntersecting.value)\n\nwatch(\n shouldLoad,\n async (shouldLoadVal) => {\n if (shouldLoadVal && src && !cachedSrc.value && !hasError.value) {\n try {\n const cachedMedia = await getCachedMedia(src)\n if (cachedMedia.error) {\n hasError.value = true\n } else if (cachedMedia.objectUrl) {\n const acquiredUrl = acquireUrl(src)\n cachedSrc.value = acquiredUrl || cachedMedia.objectUrl\n } else {\n cachedSrc.value = src\n }\n } catch (error) {\n console.warn('Failed to load cached media:', error)\n cachedSrc.value = src\n }\n } else if (!shouldLoadVal) {\n if (cachedSrc.value?.startsWith('blob:')) {\n releaseUrl(src)\n }\n // Hide image when out of view\n isImageLoaded.value = false\n cachedSrc.value = undefined\n hasError.value = false\n }\n },\n { immediate: true }\n)\n\nconst onImageLoad = () => {\n isImageLoaded.value = true\n hasError.value = false\n}\n\nconst onImageError = () => {\n hasError.value = true\n isImageLoaded.value = false\n}\n\nonUnmounted(() => {\n if (cachedSrc.value?.startsWith('blob:')) {\n releaseUrl(src)\n }\n})\n</script>\n"],"names":["useFeatureFlags","flags","reactive","api","remoteConfig","featureFlag","__name","featurePath","defaultValue","computed","readonly","selectedItem","_useModel","__props","t","useI18n","getLabel","val","found","o","optionStyle","styles","formatDisplayName","folderName","specialCases","word","DISALLOWED_MODEL_TYPES","useModelTypes","createSharedComposable","modelTypes","isLoading","error","fetchModelTypes","useAsyncState","folder","a","b","err","modelValue","isVisible","handleEscapeKey","event","watch","visible","stop","useEventListener","onWatcherCleanup","showCivitaiHelp","ref","showHuggingFaceHelp","emit","__emit","civitaiImportSource","huggingfaceImportSource","validateSourceUrl","url","source","hostname","h","civitaiIcon","civitaiUrl","huggingFaceIcon","huggingFaceUrl","props","value","importSources","isValidUrl","trimmedUrl","useUploadModelWizard","assetsStore","useAssetsStore","assetDownloadStore","useAssetDownloadStore","modelToNodeStore","useModelToNodeStore","currentStep","isFetchingMetadata","isUploading","uploadStatus","uploadError","wizardData","selectedModelType","detectedSource","canFetchMetadata","canUploadModel","fetchMetadata","cleanedUrl","supportedSources","s","metadata","assetService","typeTag","tag","type","st","uploadPreviewImage","filename","baseFilename","extension","mimeMatch","refreshModelCaches","providers","provider","result","index","uploadModel","tags","previewId","userMetadata","goToPreviousStep","resetWizard","dialogStore","useDialogStore","handleFetchMetadata","handleUploadModel","handleClose","onMounted","_imports_0$1","titleKey","_hoisted_1","_hoisted_2","_openBlock","_createElementBlock","_createElementVNode","_toDisplayString","_ctx","showSubscriptionDialog","useSubscription","handleSubscribe","useModelUpload","onUploadSuccess","isUploadButtonEnabled","showUploadDialog","UploadModelDialogHeader","UploadModelDialog","UploadModelUpgradeModalHeader","UploadModelUpgradeModal","searchQuery","isQuerying","debouncedSearchQuery","refDebounced","updateKeyRef","toRef","toValue","_","__","onCleanup","isCleanup","cleanupFn","cb","handleFocus","_imports_0","useIntersectionObserver","target","callback","options","immediate","observerOptions","isSupported","isIntersecting","observer","cleanup","observe","entries","entry","unobserve","onBeforeUnmount","MediaCacheService","now","keysToDelete","key","removedCount","targetRemoveCount","src","response","blob","objectUrl","updatedEntry","errorEntry","currentCount","count","mediaCacheInstance","useMediaCache","containerRef","isImageLoaded","hasError","cachedSrc","getCachedMedia","acquireUrl","releaseUrl","shouldLoad","shouldLoadVal","cachedMedia","acquiredUrl","onImageLoad","onImageError","onUnmounted"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Load3D-DYW1gw8I.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{_ as o}from"./WidgetInputNumber.vue_vue_type_script_setup_true_lang-CdvBpGed.js";import"./vendor-other-Dsj-QuOx.js";import"./vendor-vue-DNQSPQQ2.js";import"./index-Bc79VbnU.js";import"./vendor-primevue-Cif--Rbw.js";import"./vendor-reka-ui-WjwjFuZo.js";import"./vendor-xterm-CWYFmgbN.js";import"./vendor-three-ByuY8CdW.js";import"./vendor-tiptap-YMjM2h-Z.js";import"./widgetPropFilter-CygYoMQt.js";import"./index-BBvP0bLh.js";import"./WidgetLayoutField.vue_vue_type_script_setup_true_lang-CYDaxuge.js";import"./WidgetWithControl.vue_vue_type_script_setup_true_lang-B5RYQ41H.js";export{o as default};
|
|
2
|
-
//# sourceMappingURL=WidgetInputNumber-u4JzBngV.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WidgetInputNumber-u4JzBngV.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WidgetLegacy-DgBI3-l2.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
var $=Object.defineProperty;var a=(i,l)=>$(i,"name",{value:l,configurable:!0});import{ab as K,c as b,d as k,e as h,r as v,n as G,_ as F,fc as J,a2 as Q,dk as X,dP as Y,E as q,dl as Z,o as ee,q as U,z as D,k as ae,A as te,u as V,a8 as n,F as ne,y as oe,G as le}from"./vendor-other-Dsj-QuOx.js";import{r as H,t as R,f as N}from"./index-Bc79VbnU.js";import{u as O}from"./audioService-CnSU5S1Z.js";import{f as re}from"./audioUtils-BZ8b3tiu.js";import{a3 as ie}from"./vendor-primevue-Cif--Rbw.js";import"./vendor-vue-DNQSPQQ2.js";import"./vendor-reka-ui-WjwjFuZo.js";import"./vendor-xterm-CWYFmgbN.js";import"./vendor-three-ByuY8CdW.js";import"./vendor-tiptap-YMjM2h-Z.js";const ue={viewBox:"0 0 24 24",width:"1.2em",height:"1.2em"};function se(i,l){return k(),b("svg",ue,[...l[0]||(l[0]=[h("g",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2"},[h("path",{d:"M12 19v3m7-12v2a7 7 0 0 1-14 0v-2"}),h("rect",{width:"6",height:"13",x:"9",y:"2",rx:"3"})],-1)])])}a(se,"render");const ce=K({name:"lucide-mic",render:se});function de(i,l={}){const o=v(!1),f=v(0),u=v(null);async function e(){if(!i.value)return!1;try{return await i.value.play(),o.value=!0,!0}catch(A){return console.warn("Audio playback failed:",A),o.value=!1,!1}}a(e,"play");function t(){i.value&&(i.value.pause(),i.value.currentTime=0),o.value=!1,l.onPlaybackEnded&&l.onPlaybackEnded()}a(t,"stop");function s(){o.value=!1,l.onPlaybackEnded&&l.onPlaybackEnded()}a(s,"onPlaybackEnded");function g(){i.value?.duration&&l.onMetadataLoaded&&l.onMetadataLoaded(i.value.duration)}a(g,"onMetadataLoaded");async function p(){f.value+=1,await G()}a(p,"resetAudioElement");function r(){return i.value?.currentTime||0}a(r,"getCurrentTime");function y(){return i.value?.duration||0}return a(y,"getDuration"),{isPlaying:o,audioElementKey:f,play:e,stop:t,onPlaybackEnded:s,onMetadataLoaded:g,resetAudioElement:p,getCurrentTime:r,getDuration:y,playbackTimerInterval:u}}a(de,"useAudioPlayback");function ve(i={}){const l=v(!1),o=v(null),f=v([]),u=v(null),e=v(null);async function t(){try{e.value?.startsWith("blob:")&&URL.revokeObjectURL(e.value),f.value=[],e.value=null,await O().registerWavEncoder(),u.value=await navigator.mediaDevices.getUserMedia({audio:!0}),o.value=new J(u.value,{mimeType:"audio/wav"}),o.value.ondataavailable=r=>{f.value.push(r.data)},o.value.onstop=async()=>{const r=new Blob(f.value,{type:"audio/wav"});e.value?.startsWith("blob:")&&URL.revokeObjectURL(e.value),e.value=URL.createObjectURL(r),i.onRecordingComplete&&await i.onRecordingComplete(r),g()},o.value.start(100),l.value=!0}catch(r){throw i.onError&&i.onError(r),r}}a(t,"startRecording");function s(){o.value&&o.value.state!=="inactive"?o.value.stop():g()}a(s,"stopRecording");function g(){l.value=!1,u.value&&(u.value.getTracks().forEach(r=>r.stop()),u.value=null)}a(g,"cleanup");function p(){s(),e.value&&(URL.revokeObjectURL(e.value),e.value=null)}return a(p,"dispose"),F(()=>{p()}),{isRecording:l,recordedURL:e,mediaRecorder:o,startRecording:t,stopRecording:s,dispose:p}}a(ve,"useAudioRecorder");function me(i={}){const{barCount:l=18,minHeight:o=4,maxHeight:f=32}=i,u=v(Array.from({length:l},()=>({height:16}))),e=v(null),t=v(null),s=v(null),g=v(null),p=v(null);function r(){u.value=Array.from({length:l},()=>({height:Math.random()*(f-o)+o}))}a(r,"initWaveform");function y(m){m.value&&(t.value&&s.value?A():w(),g.value=requestAnimationFrame(()=>y(m)))}a(y,"updateWaveform");function A(){if(!t.value||!s.value)return;t.value.getByteFrequencyData(s.value);const m=Math.floor(s.value.length/l);u.value=u.value.map((L,I)=>{let S=0;for(let C=0;C<m;C++)S+=s.value[I*m+C]||0;return{height:S/m/255*(f-o)+o}})}a(A,"updateWaveformFromAudio");function w(){u.value=u.value.map(m=>({height:Math.max(o,Math.min(f,m.height+(Math.random()-.5)*4))}))}a(w,"updateWaveformRandom");async function W(){e.value&&e.value.state!=="closed"&&await e.value.close(),e.value=null,p.value=null}a(W,"setupAudioContext");async function M(m){e.value=new window.AudioContext,t.value=e.value.createAnalyser(),e.value.createMediaStreamSource(m).connect(t.value),t.value.fftSize=256,s.value=new Uint8Array(t.value.frequencyBinCount)}a(M,"setupRecordingVisualization");async function P(m){return e.value&&e.value.state!=="closed"&&await e.value.close(),p.value=null,m?(e.value=new window.AudioContext,t.value=e.value.createAnalyser(),p.value=e.value.createMediaElementSource(m),p.value.connect(t.value),t.value.connect(e.value.destination),t.value.fftSize=256,s.value=new Uint8Array(t.value.frequencyBinCount),!0):!1}a(P,"setupPlaybackVisualization");function T(){g.value&&(cancelAnimationFrame(g.value),g.value=null)}a(T,"stopWaveform");function z(){T(),e.value&&e.value.state!=="closed"&&e.value.close(),e.value=null,p.value=null}return a(z,"dispose"),F(()=>{z()}),{waveformBars:u,initWaveform:r,updateWaveform:y,setupAudioContext:W,setupRecordingVisualization:M,setupPlaybackVisualization:P,stopWaveform:T,dispose:z}}a(me,"useAudioWaveform");const fe={class:"relative"},pe={class:"mb-4"},ge={key:0,class:"flex h-14 w-full items-center gap-4 rounded-lg px-4 bg-node-component-surface text-text-secondary"},ye={class:"flex min-w-30 items-center gap-2"},he={class:"min-w-20 text-xs"},be={class:"min-w-10 text-sm"},ke={class:"flex h-8 flex-1 items-center gap-2 overflow-x-clip"},we=["title"],xe=["title"],Re=["title"],_e=["title"],Ae=["src"],Ue=Q({__name:"WidgetRecordAudio",props:X({readonly:{type:Boolean},nodeId:{}},{modelValue:{default:""},modelModifiers:{}}),emits:["update:modelValue"],setup(i){const l=i,o=v();let f="";const u=ve({onRecordingComplete:z,onError:a(()=>{N().addAlert(R("g.micPermissionDenied")||"Microphone permission denied")},"onError")}),e=me({barCount:18,minHeight:4,maxHeight:32}),t=de(o,{onPlaybackEnded:B,onMetadataLoaded:a(d=>{!w.value&&!r.value&&(s.value=Math.floor(d))},"onMetadataLoaded")}),s=v(0),{pause:g,resume:p}=Y(()=>{s.value+=1},1e3,{immediate:!1}),{isRecording:r,recordedURL:y}=u,{waveformBars:A}=e,{isPlaying:w,audioElementKey:W}=t,M=q(()=>r.value||w.value),P=Z(i,"modelValue"),T=q(()=>!l.nodeId||!H.canvas.graph?null:H.canvas.graph.getNodeById(l.nodeId));async function z(d){try{const c=await O().convertBlobToFileAndSubmit(d);P.value=c,f=c}catch{N().addAlert("Failed to upload recorded audio")}}a(z,"handleRecordingComplete");async function m(){if(!l.readonly)try{if(await e.setupAudioContext(),await u.startRecording(),u.mediaRecorder.value){const d=u.mediaRecorder.value.stream;d&&await e.setupRecordingVisualization(d)}s.value=0,p(),e.initWaveform(),e.updateWaveform(M)}catch(d){console.error("Failed to start recording:",d)}}a(m,"handleStartRecording");function L(){u.stopRecording(),g(),e.stopWaveform()}a(L,"handleStopRecording");async function I(){if(!y.value||(s.value=0,await t.resetAudioElement(),await new Promise(_=>setTimeout(_,50)),!o.value)||!await e.setupPlaybackVisualization(o.value))return;await t.play(),e.initWaveform(),e.updateWaveform(M);const c=setInterval(()=>{s.value=Math.floor(t.getCurrentTime())},100);t.playbackTimerInterval.value=c}a(I,"handlePlayRecording");function S(){t.stop(),B()}a(S,"handleStopPlayback");function B(){e.stopWaveform(),t.playbackTimerInterval.value!==null&&(clearInterval(t.playbackTimerInterval.value),t.playbackTimerInterval.value=null);const d=t.getDuration();d?s.value=Math.floor(d):s.value=0}a(B,"handlePlaybackEnded");async function j(){return r.value&&u.mediaRecorder.value&&(u.mediaRecorder.value.stop(),await new Promise((d,c)=>{let _=0;const x=50,E=a(()=>{!r.value&&P.value?d(void 0):++_>=x?c(new Error("Recording serialization timeout after 5 seconds")):setTimeout(E,100)},"checkRecording");E()})),P.value||f||""}a(j,"serializeValue");function C(){const d=T.value;if(!d?.widgets)return;const c=d.widgets.find(_=>_.name==="audio");c&&(c.serializeValue=j)}return a(C,"registerWidgetSerialization"),ee(()=>{e.initWaveform(),C()}),F(()=>{t.playbackTimerInterval.value!==null&&(clearInterval(t.playbackTimerInterval.value),t.playbackTimerInterval.value=null)}),(d,c)=>{const _=ce;return k(),b("div",fe,[h("div",pe,[D(n(ie),{class:"text-base-foreground w-full border-0 bg-secondary-background hover:bg-secondary-background-hover",disabled:n(r)||d.readonly,onClick:m},{default:ae(()=>[te(V(n(R)("g.startRecording","Start Recording"))+" ",1),D(_,{class:"ml-1"})]),_:1},8,["disabled"])]),n(r)||n(w)||n(y)?(k(),b("div",ge,[h("div",ye,[h("span",he,V(n(r)?n(R)("g.listening","Listening..."):n(w)?n(R)("g.playing","Playing..."):n(y)?n(R)("g.ready","Ready"):""),1),h("span",be,V(n(re)(s.value)),1)]),h("div",ke,[(k(!0),b(ne,null,oe(n(A),(x,E)=>(k(),b("div",{key:E,class:"max-h-8 min-h-1 w-0.75 rounded-[1.5px] bg-slate-100 transition-all duration-100",style:le({height:x.height+"px"}),title:`Bar ${E+1}: ${x.height}px`},null,12,we))),128))]),n(r)?(k(),b("button",{key:0,title:n(R)("g.stopRecording","Stop Recording"),class:"flex size-8 animate-pulse items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors",onClick:L},c[2]||(c[2]=[h("div",{class:"size-2.5 rounded-sm bg-danger-100"},null,-1)]),8,xe)):!n(r)&&n(y)&&!n(w)?(k(),b("button",{key:1,title:n(R)("g.playRecording")||"Play Recording",class:"flex size-8 items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors",onClick:I},c[3]||(c[3]=[h("i",{class:"text-text-secondary icon-[lucide--play] size-4"},null,-1)]),8,Re)):n(w)?(k(),b("button",{key:2,title:n(R)("g.stopPlayback")||"Stop Playback",class:"flex size-8 items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors",onClick:S},c[4]||(c[4]=[h("i",{class:"text-text-secondary icon-[lucide--square] size-4"},null,-1)]),8,_e)):U("",!0)])):U("",!0),n(y)?(k(),b("audio",{ref_key:"audioRef",ref:o,key:n(W),src:n(y),class:"hidden",onEnded:c[0]||(c[0]=(...x)=>n(t).onPlaybackEnded&&n(t).onPlaybackEnded(...x)),onLoadedmetadata:c[1]||(c[1]=(...x)=>n(t).onMetadataLoaded&&n(t).onMetadataLoaded(...x))},null,40,Ae)):U("",!0)])}}});export{Ue as default};
|
|
2
|
-
//# sourceMappingURL=WidgetRecordAudio-hHbaGdj1.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WidgetRecordAudio-hHbaGdj1.js","sources":["../../src/renderer/extensions/vueNodes/widgets/composables/audio/useAudioPlayback.ts","../../src/renderer/extensions/vueNodes/widgets/composables/audio/useAudioRecorder.ts","../../src/renderer/extensions/vueNodes/widgets/composables/audio/useAudioWaveform.ts","../../src/renderer/extensions/vueNodes/widgets/components/WidgetRecordAudio.vue"],"sourcesContent":["import { nextTick, ref } from 'vue'\nimport type { Ref } from 'vue'\n\ninterface AudioPlaybackOptions {\n onPlaybackEnded?: () => void\n onMetadataLoaded?: (duration: number) => void\n}\n\nexport function useAudioPlayback(\n audioRef: Ref<HTMLAudioElement | undefined>,\n options: AudioPlaybackOptions = {}\n) {\n const isPlaying = ref(false)\n const audioElementKey = ref(0)\n const playbackTimerInterval = ref<ReturnType<typeof setInterval> | null>(null)\n\n async function play() {\n if (!audioRef.value) return false\n\n try {\n await audioRef.value.play()\n isPlaying.value = true\n return true\n } catch (error) {\n console.warn('Audio playback failed:', error)\n isPlaying.value = false\n return false\n }\n }\n\n function stop() {\n if (audioRef.value) {\n audioRef.value.pause()\n audioRef.value.currentTime = 0\n }\n isPlaying.value = false\n if (options.onPlaybackEnded) {\n options.onPlaybackEnded()\n }\n }\n\n function onPlaybackEnded() {\n isPlaying.value = false\n if (options.onPlaybackEnded) {\n options.onPlaybackEnded()\n }\n }\n\n function onMetadataLoaded() {\n if (audioRef.value?.duration && options.onMetadataLoaded) {\n options.onMetadataLoaded(audioRef.value.duration)\n }\n }\n\n async function resetAudioElement() {\n audioElementKey.value += 1\n await nextTick()\n }\n\n function getCurrentTime() {\n return audioRef.value?.currentTime || 0\n }\n\n function getDuration() {\n return audioRef.value?.duration || 0\n }\n\n return {\n isPlaying,\n audioElementKey,\n play,\n stop,\n onPlaybackEnded,\n onMetadataLoaded,\n resetAudioElement,\n getCurrentTime,\n getDuration,\n playbackTimerInterval\n }\n}\n","import { MediaRecorder as ExtendableMediaRecorder } from 'extendable-media-recorder'\nimport { onUnmounted, ref } from 'vue'\n\nimport { useAudioService } from '@/services/audioService'\n\ninterface AudioRecorderOptions {\n onRecordingComplete?: (audioBlob: Blob) => Promise<void>\n onError?: (error: Error) => void\n}\n\nexport function useAudioRecorder(options: AudioRecorderOptions = {}) {\n const isRecording = ref(false)\n const mediaRecorder = ref<MediaRecorder | null>(null)\n const audioChunks = ref<Blob[]>([])\n const stream = ref<MediaStream | null>(null)\n const recordedURL = ref<string | null>(null)\n\n async function startRecording() {\n try {\n // Clean up previous recording\n if (recordedURL.value?.startsWith('blob:')) {\n URL.revokeObjectURL(recordedURL.value)\n }\n\n // Initialize\n audioChunks.value = []\n recordedURL.value = null\n\n // Register wav encoder and get media stream\n await useAudioService().registerWavEncoder()\n stream.value = await navigator.mediaDevices.getUserMedia({ audio: true })\n\n // Create media recorder\n mediaRecorder.value = new ExtendableMediaRecorder(stream.value, {\n mimeType: 'audio/wav'\n }) as unknown as MediaRecorder\n\n mediaRecorder.value.ondataavailable = (e) => {\n audioChunks.value.push(e.data)\n }\n\n mediaRecorder.value.onstop = async () => {\n const blob = new Blob(audioChunks.value, { type: 'audio/wav' })\n\n // Create blob URL for preview\n if (recordedURL.value?.startsWith('blob:')) {\n URL.revokeObjectURL(recordedURL.value)\n }\n recordedURL.value = URL.createObjectURL(blob)\n\n // Notify completion\n if (options.onRecordingComplete) {\n await options.onRecordingComplete(blob)\n }\n\n cleanup()\n }\n\n // Start recording\n mediaRecorder.value.start(100)\n isRecording.value = true\n } catch (err) {\n if (options.onError) {\n options.onError(err as Error)\n }\n throw err\n }\n }\n\n function stopRecording() {\n if (mediaRecorder.value && mediaRecorder.value.state !== 'inactive') {\n mediaRecorder.value.stop()\n } else {\n cleanup()\n }\n }\n\n function cleanup() {\n isRecording.value = false\n\n if (stream.value) {\n stream.value.getTracks().forEach((track) => track.stop())\n stream.value = null\n }\n }\n\n function dispose() {\n stopRecording()\n if (recordedURL.value) {\n URL.revokeObjectURL(recordedURL.value)\n recordedURL.value = null\n }\n }\n\n onUnmounted(() => {\n dispose()\n })\n\n return {\n isRecording,\n recordedURL,\n mediaRecorder,\n startRecording,\n stopRecording,\n dispose\n }\n}\n","import { onUnmounted, ref } from 'vue'\nimport type { Ref } from 'vue'\n\ninterface WaveformBar {\n height: number\n}\n\ninterface AudioWaveformOptions {\n barCount?: number\n minHeight?: number\n maxHeight?: number\n}\n\nexport function useAudioWaveform(options: AudioWaveformOptions = {}) {\n const { barCount = 18, minHeight = 4, maxHeight = 32 } = options\n\n const waveformBars = ref<WaveformBar[]>(\n Array.from({ length: barCount }, () => ({ height: 16 }))\n )\n const audioContext = ref<AudioContext | null>(null)\n const analyser = ref<AnalyserNode | null>(null)\n const dataArray = ref<Uint8Array | null>(null)\n const animationId = ref<number | null>(null)\n const mediaElementSource = ref<MediaElementAudioSourceNode | null>(null)\n\n function initWaveform() {\n waveformBars.value = Array.from({ length: barCount }, () => ({\n height: Math.random() * (maxHeight - minHeight) + minHeight\n }))\n }\n\n function updateWaveform(isActive: Ref<boolean>) {\n if (!isActive.value) return\n\n if (analyser.value && dataArray.value) {\n updateWaveformFromAudio()\n } else {\n updateWaveformRandom()\n }\n\n animationId.value = requestAnimationFrame(() => updateWaveform(isActive))\n }\n\n function updateWaveformFromAudio() {\n if (!analyser.value || !dataArray.value) return\n\n analyser.value.getByteFrequencyData(\n dataArray.value as Uint8Array<ArrayBuffer>\n )\n const samplesPerBar = Math.floor(dataArray.value.length / barCount)\n\n waveformBars.value = waveformBars.value.map((_, i) => {\n let sum = 0\n for (let j = 0; j < samplesPerBar; j++) {\n sum += dataArray.value![i * samplesPerBar + j] || 0\n }\n const average = sum / samplesPerBar\n const normalizedHeight =\n (average / 255) * (maxHeight - minHeight) + minHeight\n return { height: normalizedHeight }\n })\n }\n\n function updateWaveformRandom() {\n waveformBars.value = waveformBars.value.map((bar) => ({\n height: Math.max(\n minHeight,\n Math.min(maxHeight, bar.height + (Math.random() - 0.5) * 4)\n )\n }))\n }\n\n async function setupAudioContext() {\n if (audioContext.value && audioContext.value.state !== 'closed') {\n await audioContext.value.close()\n }\n audioContext.value = null\n mediaElementSource.value = null\n }\n\n async function setupRecordingVisualization(stream: MediaStream) {\n audioContext.value = new window.AudioContext()\n analyser.value = audioContext.value.createAnalyser()\n const source = audioContext.value.createMediaStreamSource(stream)\n source.connect(analyser.value)\n\n analyser.value.fftSize = 256\n dataArray.value = new Uint8Array(analyser.value.frequencyBinCount)\n }\n\n async function setupPlaybackVisualization(audioElement: HTMLAudioElement) {\n if (audioContext.value && audioContext.value.state !== 'closed') {\n await audioContext.value.close()\n }\n\n mediaElementSource.value = null\n\n if (!audioElement) return false\n\n audioContext.value = new window.AudioContext()\n analyser.value = audioContext.value.createAnalyser()\n\n mediaElementSource.value =\n audioContext.value.createMediaElementSource(audioElement)\n\n mediaElementSource.value.connect(analyser.value)\n analyser.value.connect(audioContext.value.destination)\n\n analyser.value.fftSize = 256\n dataArray.value = new Uint8Array(analyser.value.frequencyBinCount)\n\n return true\n }\n\n function stopWaveform() {\n if (animationId.value) {\n cancelAnimationFrame(animationId.value)\n animationId.value = null\n }\n }\n\n function dispose() {\n stopWaveform()\n if (audioContext.value && audioContext.value.state !== 'closed') {\n void audioContext.value.close()\n }\n audioContext.value = null\n mediaElementSource.value = null\n }\n\n onUnmounted(() => {\n dispose()\n })\n\n return {\n waveformBars,\n initWaveform,\n updateWaveform,\n setupAudioContext,\n setupRecordingVisualization,\n setupPlaybackVisualization,\n stopWaveform,\n dispose\n }\n}\n","<template>\n <div class=\"relative\">\n <div class=\"mb-4\">\n <Button\n class=\"text-base-foreground w-full border-0 bg-secondary-background hover:bg-secondary-background-hover\"\n :disabled=\"isRecording || readonly\"\n @click=\"handleStartRecording\"\n >\n {{ t('g.startRecording', 'Start Recording') }}\n <i-lucide:mic class=\"ml-1\" />\n </Button>\n </div>\n <div\n v-if=\"isRecording || isPlaying || recordedURL\"\n class=\"flex h-14 w-full items-center gap-4 rounded-lg px-4 bg-node-component-surface text-text-secondary\"\n >\n <!-- Recording Status -->\n <div class=\"flex min-w-30 items-center gap-2\">\n <span class=\"min-w-20 text-xs\">\n {{\n isRecording\n ? t('g.listening', 'Listening...')\n : isPlaying\n ? t('g.playing', 'Playing...')\n : recordedURL\n ? t('g.ready', 'Ready')\n : ''\n }}\n </span>\n <span class=\"min-w-10 text-sm\">{{ formatTime(timer) }}</span>\n </div>\n\n <!-- Waveform Visualization -->\n <div class=\"flex h-8 flex-1 items-center gap-2 overflow-x-clip\">\n <div\n v-for=\"(bar, index) in waveformBars\"\n :key=\"index\"\n class=\"max-h-8 min-h-1 w-0.75 rounded-[1.5px] bg-slate-100 transition-all duration-100\"\n :style=\"{ height: bar.height + 'px' }\"\n :title=\"`Bar ${index + 1}: ${bar.height}px`\"\n />\n </div>\n\n <!-- Control Button -->\n <button\n v-if=\"isRecording\"\n :title=\"t('g.stopRecording', 'Stop Recording')\"\n class=\"flex size-8 animate-pulse items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors\"\n @click=\"handleStopRecording\"\n >\n <div class=\"size-2.5 rounded-sm bg-danger-100\" />\n </button>\n\n <button\n v-else-if=\"!isRecording && recordedURL && !isPlaying\"\n :title=\"t('g.playRecording') || 'Play Recording'\"\n class=\"flex size-8 items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors\"\n @click=\"handlePlayRecording\"\n >\n <i class=\"text-text-secondary icon-[lucide--play] size-4\" />\n </button>\n\n <button\n v-else-if=\"isPlaying\"\n :title=\"t('g.stopPlayback') || 'Stop Playback'\"\n class=\"flex size-8 items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors\"\n @click=\"handleStopPlayback\"\n >\n <i class=\"text-text-secondary icon-[lucide--square] size-4\" />\n </button>\n </div>\n <audio\n v-if=\"recordedURL\"\n ref=\"audioRef\"\n :key=\"audioElementKey\"\n :src=\"recordedURL\"\n class=\"hidden\"\n @ended=\"playback.onPlaybackEnded\"\n @loadedmetadata=\"playback.onMetadataLoaded\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useIntervalFn } from '@vueuse/core'\nimport { Button } from 'primevue'\nimport { computed, onMounted, onUnmounted, ref } from 'vue'\n\nimport { t } from '@/i18n'\nimport type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'\nimport type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'\nimport { useToastStore } from '@/platform/updates/common/toastStore'\nimport { app } from '@/scripts/app'\nimport { useAudioService } from '@/services/audioService'\n\nimport { useAudioPlayback } from '../composables/audio/useAudioPlayback'\nimport { useAudioRecorder } from '../composables/audio/useAudioRecorder'\nimport { useAudioWaveform } from '../composables/audio/useAudioWaveform'\nimport { formatTime } from '../utils/audioUtils'\n\nconst props = defineProps<{\n readonly?: boolean\n nodeId: string\n}>()\n\n// Audio element ref\nconst audioRef = ref<HTMLAudioElement>()\n\n// Keep track of the last uploaded path as a backup\nlet lastUploadedPath = ''\n\n// Composables\nconst recorder = useAudioRecorder({\n onRecordingComplete: handleRecordingComplete,\n onError: () => {\n useToastStore().addAlert(\n t('g.micPermissionDenied') || 'Microphone permission denied'\n )\n }\n})\n\nconst waveform = useAudioWaveform({\n barCount: 18,\n minHeight: 4,\n maxHeight: 32\n})\n\nconst playback = useAudioPlayback(audioRef, {\n onPlaybackEnded: handlePlaybackEnded,\n onMetadataLoaded: (duration) => {\n if (!isPlaying.value && !isRecording.value) {\n timer.value = Math.floor(duration)\n }\n }\n})\n\n// Timer for recording\nconst timer = ref(0)\nconst { pause: pauseTimer, resume: resumeTimer } = useIntervalFn(\n () => {\n timer.value += 1\n },\n 1000,\n { immediate: false }\n)\n\n// Destructure for template access\nconst { isRecording, recordedURL } = recorder\nconst { waveformBars } = waveform\nconst { isPlaying, audioElementKey } = playback\n\n// Computed for waveform animation\nconst isWaveformActive = computed(() => isRecording.value || isPlaying.value)\n\nconst modelValue = defineModel<string>({ default: '' })\n\nconst litegraphNode = computed(() => {\n if (!props.nodeId || !app.canvas.graph) return null\n return app.canvas.graph.getNodeById(props.nodeId) as LGraphNode | null\n})\n\nasync function handleRecordingComplete(blob: Blob) {\n try {\n const path = await useAudioService().convertBlobToFileAndSubmit(blob)\n modelValue.value = path\n lastUploadedPath = path\n } catch (e) {\n useToastStore().addAlert('Failed to upload recorded audio')\n }\n}\n\nasync function handleStartRecording() {\n if (props.readonly) return\n\n try {\n await waveform.setupAudioContext()\n await recorder.startRecording()\n\n // Setup waveform visualization for recording\n if (recorder.mediaRecorder.value) {\n const stream = recorder.mediaRecorder.value.stream\n if (stream) {\n await waveform.setupRecordingVisualization(stream)\n }\n }\n\n // Start timer\n timer.value = 0\n resumeTimer()\n waveform.initWaveform()\n waveform.updateWaveform(isWaveformActive)\n } catch (err) {\n console.error('Failed to start recording:', err)\n }\n}\n\nfunction handleStopRecording() {\n recorder.stopRecording()\n pauseTimer()\n waveform.stopWaveform()\n}\n\nasync function handlePlayRecording() {\n if (!recordedURL.value) return\n\n // Reset timer\n timer.value = 0\n\n // Reset and setup audio element\n await playback.resetAudioElement()\n\n // Wait for audio element to be ready\n await new Promise((resolve) => setTimeout(resolve, 50))\n\n if (!audioRef.value) return\n\n // Setup waveform visualization for playback\n const setupSuccess = await waveform.setupPlaybackVisualization(audioRef.value)\n if (!setupSuccess) return\n\n // Start playback\n await playback.play()\n\n // Update waveform\n waveform.initWaveform()\n waveform.updateWaveform(isWaveformActive)\n\n // Update timer from audio current time\n const timerInterval = setInterval(() => {\n timer.value = Math.floor(playback.getCurrentTime())\n }, 100)\n\n // Store interval for cleanup\n playback.playbackTimerInterval.value = timerInterval\n}\n\nfunction handleStopPlayback() {\n playback.stop()\n handlePlaybackEnded()\n}\n\nfunction handlePlaybackEnded() {\n waveform.stopWaveform()\n\n // Clear playback timer interval\n if (playback.playbackTimerInterval.value !== null) {\n clearInterval(playback.playbackTimerInterval.value)\n playback.playbackTimerInterval.value = null\n }\n\n const duration = playback.getDuration()\n if (duration) {\n timer.value = Math.floor(duration)\n } else {\n timer.value = 0\n }\n}\n\n// Serialization function for workflow execution\nasync function serializeValue() {\n if (isRecording.value && recorder.mediaRecorder.value) {\n recorder.mediaRecorder.value.stop()\n\n await new Promise((resolve, reject) => {\n let attempts = 0\n const maxAttempts = 50 // 5 seconds max (50 * 100ms)\n const checkRecording = () => {\n if (!isRecording.value && modelValue.value) {\n resolve(undefined)\n } else if (++attempts >= maxAttempts) {\n reject(new Error('Recording serialization timeout after 5 seconds'))\n } else {\n setTimeout(checkRecording, 100)\n }\n }\n checkRecording()\n })\n }\n\n return modelValue.value || lastUploadedPath || ''\n}\n\nfunction registerWidgetSerialization() {\n const node = litegraphNode.value\n if (!node?.widgets) return\n const targetWidget = node.widgets.find((w: IBaseWidget) => w.name === 'audio')\n if (targetWidget) {\n targetWidget.serializeValue = serializeValue\n }\n}\n\nonMounted(() => {\n waveform.initWaveform()\n registerWidgetSerialization()\n})\n\nonUnmounted(() => {\n if (playback.playbackTimerInterval.value !== null) {\n clearInterval(playback.playbackTimerInterval.value)\n playback.playbackTimerInterval.value = null\n }\n})\n</script>\n"],"names":["useAudioPlayback","audioRef","options","isPlaying","ref","audioElementKey","playbackTimerInterval","play","error","__name","stop","onPlaybackEnded","onMetadataLoaded","resetAudioElement","nextTick","getCurrentTime","getDuration","useAudioRecorder","isRecording","mediaRecorder","audioChunks","stream","recordedURL","startRecording","useAudioService","ExtendableMediaRecorder","e","blob","cleanup","err","stopRecording","track","dispose","onUnmounted","useAudioWaveform","barCount","minHeight","maxHeight","waveformBars","audioContext","analyser","dataArray","animationId","mediaElementSource","initWaveform","updateWaveform","isActive","updateWaveformFromAudio","updateWaveformRandom","samplesPerBar","_","i","sum","j","bar","setupAudioContext","setupRecordingVisualization","setupPlaybackVisualization","audioElement","stopWaveform","props","__props","lastUploadedPath","recorder","handleRecordingComplete","useToastStore","t","waveform","playback","handlePlaybackEnded","duration","timer","pauseTimer","resumeTimer","useIntervalFn","isWaveformActive","computed","modelValue","_useModel","litegraphNode","app","path","handleStartRecording","handleStopRecording","handlePlayRecording","resolve","timerInterval","handleStopPlayback","serializeValue","reject","attempts","maxAttempts","checkRecording","registerWidgetSerialization","node","targetWidget","w","onMounted"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{_ as o}from"./WidgetSelect.vue_vue_type_script_setup_true_lang-Ua67RWUI.js";import"./index-Bc79VbnU.js";import"./vendor-primevue-Cif--Rbw.js";import"./vendor-other-Dsj-QuOx.js";import"./vendor-vue-DNQSPQQ2.js";import"./vendor-reka-ui-WjwjFuZo.js";import"./vendor-xterm-CWYFmgbN.js";import"./vendor-three-ByuY8CdW.js";import"./vendor-tiptap-YMjM2h-Z.js";import"./widgetPropFilter-CygYoMQt.js";import"./index-BBvP0bLh.js";import"./WidgetLayoutField.vue_vue_type_script_setup_true_lang-CYDaxuge.js";import"./LazyImage.vue_vue_type_script_setup_true_lang-CX9YtPlM.js";import"./WidgetWithControl.vue_vue_type_script_setup_true_lang-B5RYQ41H.js";export{o as default};
|
|
2
|
-
//# sourceMappingURL=WidgetSelect-Cv4W8ECC.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WidgetSelect-Cv4W8ECC.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|