Merge branch 'parameter_debug_dev'

This commit is contained in:
ai-business-hql
2025-06-05 17:06:59 +08:00
24 changed files with 424 additions and 268 deletions
+14
View File
@@ -0,0 +1,14 @@
function getImportPath(filename) {
return `./${filename}`;
}
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["copilot_web/workflowChat-C3ZWZR1l.js","copilot_web/input.js","copilot_web/vendor-markdown-Dek94WS0.js","copilot_web/vendor-react-V04_Axys.js","copilot_web/message-components-C_KwPGE8.js","copilot_web/assets/input-BFxtFr8c.css","copilot_web/fonts.css"].map(path => {
const apiBase = window.comfyAPI?.api?.api?.api_base;
if (apiBase) {
// 有 API base 时,使用完整路径
return `${apiBase.substring(1)}/${path}`;
} else {
// 没有 API base 时,使用相对路径
return `./${path}`;
}
}))))=>i.map(i=>d[i]);
import{_ as a}from"./input.js";import{j as t}from"./vendor-markdown-Dek94WS0.js";import{r,R as i}from"./vendor-react-V04_Axys.js";import{C as n}from"./message-components-C_KwPGE8.js";/* empty css */const o={EXPLAIN_NODE:"copilot:explain-node"},d=i.lazy(()=>a(()=>import(getImportPath("workflowChat-C3ZWZR1l.js")).then(e=>e.w),__vite__mapDeps([0,1,2,3,4,5,6])).then(e=>({default:e.default})));function p(){const[e,s]=r.useState(!1);return r.useEffect(()=>{const l=()=>{s(!0)};return window.addEventListener(o.EXPLAIN_NODE,l),()=>window.removeEventListener(o.EXPLAIN_NODE,l)},[]),t.jsx(n,{children:t.jsx("div",{className:"h-full w-full flex flex-col",children:t.jsx(r.Suspense,{fallback:t.jsx("div",{className:"h-full w-full flex items-center justify-center",children:"Loading..."}),children:t.jsx(d,{visible:!0,triggerUsage:e,onUsageTriggered:()=>s(!1)})})})})}export{p as default};
-6
View File
@@ -1,6 +0,0 @@
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["copilot_web/workflowChat-QQb_1pUR.js","copilot_web/input.js","copilot_web/vendor-markdown-Dek94WS0.js","copilot_web/vendor-react-V04_Axys.js","copilot_web/message-components-B9b4Aopv.js","copilot_web/assets/input-CfrhPaqY.css","copilot_web/fonts.css"].map(path => {
const apiBase = window.comfyAPI?.api?.api?.api_base;
const prefix = apiBase ? `${apiBase.substring(1)}/` : '';
return `${prefix}${path}`;
}))))=>i.map(i=>d[i]);
import{_ as a}from"./input.js";import{j as t}from"./vendor-markdown-Dek94WS0.js";import{r,R as i}from"./vendor-react-V04_Axys.js";import{C as n}from"./message-components-B9b4Aopv.js";/* empty css */const o={EXPLAIN_NODE:"copilot:explain-node"},d=i.lazy(()=>a(()=>import("./workflowChat-QQb_1pUR.js").then(e=>e.w),__vite__mapDeps([0,1,2,3,4,5,6])).then(e=>({default:e.default})));function p(){const[e,s]=r.useState(!1);return r.useEffect(()=>{const l=()=>{s(!0)};return window.addEventListener(o.EXPLAIN_NODE,l),()=>window.removeEventListener(o.EXPLAIN_NODE,l)},[]),t.jsx(n,{children:t.jsx("div",{className:"h-full w-full flex flex-col",children:t.jsx(r.Suspense,{fallback:t.jsx("div",{className:"h-full w-full flex items-center justify-center",children:"Loading..."}),children:t.jsx(d,{visible:!0,triggerUsage:e,onUsageTriggered:()=>s(!1)})})})})}export{p as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
import{j as t}from"./vendor-markdown-Dek94WS0.js";import{W as p,g as u,a as d}from"./message-components-B9b4Aopv.js";import{r as N}from"./vendor-react-V04_Axys.js";function O({content:v,name:C="Assistant",avatar:_,latestInput:y,installedNodes:k,onAddMessage:g}){const h=JSON.parse(v),w=h.ext?.find(e=>e.type==="workflow")?.data||[],[i,c]=N.useState({}),b=async e=>{if(!e.id){console.error("No workflow id provided");return}const r=String(e.id);if(!i[r]){c(o=>({...o,[r]:!0})),p.trackEvent({event_type:"workflow_accept",message_type:"workflow",message_id:h.message_id,data:{workflow_id:e.id,workflow_name:e.name}});try{const o=await p.getOptimizedWorkflow(e.id,y);if(o.workflow){const a=new Set;if(o.workflow.nodes)for(const s of o.workflow.nodes)a.add(s.type);else for(const s of Object.values(o.workflow))a.add(s.class_type);const n=Array.from(a).filter(s=>!k.includes(s));if(console.log("[WorkflowOption] Missing node types:",n),n.length>0){try{console.log("[WorkflowOption] Fetching info for missing nodes");const s=await p.batchGetNodeInfo(n);console.log("[WorkflowOption] Received node infos:",s);const m={text:"",ext:[{type:"node_install_guide",data:s.map(l=>({name:l.name,repository_url:l.github_url}))}]},f={id:u(),role:"ai",content:JSON.stringify(m),format:"markdown",name:"Assistant",metadata:{pendingWorkflow:o.workflow,optimizedParams:o.optimized_params}};g?.(f)}catch(s){console.error("[WorkflowOption] Error fetching node info:",s),alert("Error checking required nodes. Please try again.")}finally{c(s=>({...s,[r]:!1}))}return}j(o.workflow,o.optimized_params)}}catch(o){console.error("Failed to optimize workflow:",o),alert("Failed to optimize workflow. Please try again.")}finally{c(o=>({...o,[r]:!1}))}}},j=(e,r)=>{e.nodes?d.loadGraphData(e):d.loadApiJson(e);for(const[a,n,s,m,f]of r){const l=d.graph._nodes_by_id[a].widgets;for(const x of l)x.name===m&&(x.value=f)}d.graph.setDirtyCanvas(!1,!0);const o={id:u(),role:"tool",content:JSON.stringify({text:"The workflow has been successfully loaded to the canvas",ext:[]}),format:"markdown",name:"Assistant"};g?.(o)};return t.jsx("div",{className:"space-y-3",children:w.length>0&&t.jsx("div",{className:"flex flex-col space-y-4",children:w.map((e,r)=>{const o=e.id?String(e.id):"";return t.jsxs("div",{className:"flex items-center gap-4 p-4 rounded-lg border border-gray-200 hover:bg-gray-50",children:[e.image&&t.jsx("img",{src:e.image,alt:e.name,className:"w-14 h-14 object-cover rounded-lg",onError:a=>{const n=a.target;n.onerror=null,n.src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='56' viewBox='0 0 56 56' fill='none'%3E%3Crect width='56' height='56' fill='%23F3F4F6'/%3E%3Cpath d='M28 28C30.2091 28 32 26.2091 32 24C32 21.7909 30.2091 20 28 20C25.7909 20 24 21.7909 24 24C24 26.2091 25.7909 28 28 28Z' fill='%239CA3AF'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M18.7253 37.6307C19.8278 35.1533 22.6897 33.6 26 33.6H30C33.3103 33.6 36.1722 35.1533 37.2747 37.6307C37.6419 38.4561 37.0611 39.2 36.1694 39.2H19.8306C18.9389 39.2 18.3581 38.4561 18.7253 37.6307Z' fill='%239CA3AF'/%3E%3C/svg%3E"}}),t.jsxs("div",{className:"flex-1 break-words flex flex-col h-[4.5rem] justify-between",children:[t.jsx("div",{children:t.jsx("h3",{className:"font-medium text-sm line-clamp-2 h-10 overflow-hidden",children:e.name})}),t.jsxs("div",{className:"flex justify-between items-center mt-1",children:[e.description&&t.jsxs("div",{className:"relative group",children:[t.jsx("div",{className:"w-5 h-5 flex items-center justify-center text-gray-500 cursor-help",children:t.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:1.5,stroke:"currentColor",className:"w-4 h-4",children:t.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z"})})}),t.jsx("div",{className:"absolute bottom-full left-0 mb-2 hidden group-hover:block",children:t.jsx("div",{className:"bg-gray-900 text-white text-xs rounded-md py-2 px-3 min-w-[400px] whitespace-normal break-words",children:e.description})})]}),t.jsx("button",{onClick:()=>b(e),disabled:i[o],className:`px-3 py-1.5 ${i[o]?"bg-gray-400 cursor-not-allowed":"bg-blue-500 hover:bg-blue-600"} text-white rounded-md transition-colors text-xs`,children:i[o]?"Loading...":"Accept"})]})]})]},r)})})})}export{O as WorkflowOption};
+4
View File
@@ -0,0 +1,4 @@
function getImportPath(filename) {
return `./${filename}`;
}
import{j as t}from"./vendor-markdown-Dek94WS0.js";import{W as p,g as u,a as d}from"./message-components-C_KwPGE8.js";import{r as N}from"./vendor-react-V04_Axys.js";function O({content:v,name:C="Assistant",avatar:_,latestInput:y,installedNodes:k,onAddMessage:g}){const h=JSON.parse(v),w=h.ext?.find(e=>e.type==="workflow")?.data||[],[i,c]=N.useState({}),b=async e=>{if(!e.id){console.error("No workflow id provided");return}const r=String(e.id);if(!i[r]){c(o=>({...o,[r]:!0})),p.trackEvent({event_type:"workflow_accept",message_type:"workflow",message_id:h.message_id,data:{workflow_id:e.id,workflow_name:e.name}});try{const o=await p.getOptimizedWorkflow(e.id,y);if(o.workflow){const a=new Set;if(o.workflow.nodes)for(const s of o.workflow.nodes)a.add(s.type);else for(const s of Object.values(o.workflow))a.add(s.class_type);const n=Array.from(a).filter(s=>!k.includes(s));if(console.log("[WorkflowOption] Missing node types:",n),n.length>0){try{console.log("[WorkflowOption] Fetching info for missing nodes");const s=await p.batchGetNodeInfo(n);console.log("[WorkflowOption] Received node infos:",s);const m={text:"",ext:[{type:"node_install_guide",data:s.map(l=>({name:l.name,repository_url:l.github_url}))}]},f={id:u(),role:"ai",content:JSON.stringify(m),format:"markdown",name:"Assistant",metadata:{pendingWorkflow:o.workflow,optimizedParams:o.optimized_params}};g?.(f)}catch(s){console.error("[WorkflowOption] Error fetching node info:",s),alert("Error checking required nodes. Please try again.")}finally{c(s=>({...s,[r]:!1}))}return}j(o.workflow,o.optimized_params)}}catch(o){console.error("Failed to optimize workflow:",o),alert("Failed to optimize workflow. Please try again.")}finally{c(o=>({...o,[r]:!1}))}}},j=(e,r)=>{e.nodes?d.loadGraphData(e):d.loadApiJson(e);for(const[a,n,s,m,f]of r){const l=d.graph._nodes_by_id[a].widgets;for(const x of l)x.name===m&&(x.value=f)}d.graph.setDirtyCanvas(!1,!0);const o={id:u(),role:"tool",content:JSON.stringify({text:"The workflow has been successfully loaded to the canvas",ext:[]}),format:"markdown",name:"Assistant"};g?.(o)};return t.jsx("div",{className:"space-y-3",children:w.length>0&&t.jsx("div",{className:"flex flex-col space-y-4",children:w.map((e,r)=>{const o=e.id?String(e.id):"";return t.jsxs("div",{className:"flex items-center gap-4 p-4 rounded-lg border border-gray-200 hover:bg-gray-50",children:[e.image&&t.jsx("img",{src:e.image,alt:e.name,className:"w-14 h-14 object-cover rounded-lg",onError:a=>{const n=a.target;n.onerror=null,n.src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='56' viewBox='0 0 56 56' fill='none'%3E%3Crect width='56' height='56' fill='%23F3F4F6'/%3E%3Cpath d='M28 28C30.2091 28 32 26.2091 32 24C32 21.7909 30.2091 20 28 20C25.7909 20 24 21.7909 24 24C24 26.2091 25.7909 28 28 28Z' fill='%239CA3AF'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M18.7253 37.6307C19.8278 35.1533 22.6897 33.6 26 33.6H30C33.3103 33.6 36.1722 35.1533 37.2747 37.6307C37.6419 38.4561 37.0611 39.2 36.1694 39.2H19.8306C18.9389 39.2 18.3581 38.4561 18.7253 37.6307Z' fill='%239CA3AF'/%3E%3C/svg%3E"}}),t.jsxs("div",{className:"flex-1 break-words flex flex-col h-[4.5rem] justify-between",children:[t.jsx("div",{children:t.jsx("h3",{className:"font-medium text-sm line-clamp-2 h-10 overflow-hidden",children:e.name})}),t.jsxs("div",{className:"flex justify-between items-center mt-1",children:[e.description&&t.jsxs("div",{className:"relative group",children:[t.jsx("div",{className:"w-5 h-5 flex items-center justify-center text-gray-500 cursor-help",children:t.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:1.5,stroke:"currentColor",className:"w-4 h-4",children:t.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z"})})}),t.jsx("div",{className:"absolute bottom-full left-0 mb-2 hidden group-hover:block",children:t.jsx("div",{className:"bg-gray-900 text-white text-xs rounded-md py-2 px-3 min-w-[400px] whitespace-normal break-words",children:e.description})})]}),t.jsx("button",{onClick:()=>b(e),disabled:i[o],className:`px-3 py-1.5 ${i[o]?"bg-gray-400 cursor-not-allowed":"bg-blue-500 hover:bg-blue-600"} text-white rounded-md transition-colors text-xs`,children:i[o]?"Loading...":"Accept"})]})]})]},r)})})})}export{O as WorkflowOption};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+14 -2
View File
@@ -1,2 +1,14 @@
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["copilot_web/App-mzuNw1xF.js","copilot_web/vendor-markdown-Dek94WS0.js","copilot_web/vendor-react-V04_Axys.js","copilot_web/message-components-B9b4Aopv.js","copilot_web/fonts.css"])))=>i.map(i=>d[i]);
import{j as s}from"./vendor-markdown-Dek94WS0.js";import{a as w,R as p,r as x}from"./vendor-react-V04_Axys.js";import{w as v,a as g}from"./message-components-B9b4Aopv.js";/* empty css */const R="modulepreload",b=function(e){return"/"+e},m={},C=function(c,a,P){let d=Promise.resolve();if(a&&a.length>0){document.getElementsByTagName("link");const r=document.querySelector("meta[property=csp-nonce]"),t=r?.nonce||r?.getAttribute("nonce");d=Promise.allSettled(a.map(o=>{if(o=b(o),o in m)return;m[o]=!0;const i=o.endsWith(".css"),h=i?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${o}"]${h}`))return;const n=document.createElement("link");if(n.rel=i?"stylesheet":R,i||(n.as="script"),n.crossOrigin="",n.href=o,t&&n.setAttribute("nonce",t),document.head.appendChild(n),i)return new Promise((y,E)=>{n.addEventListener("load",y),n.addEventListener("error",()=>E(new Error(`Unable to preload CSS for ${o}`)))})}))}function u(r){const t=new Event("vite:preloadError",{cancelable:!0});if(t.payload=r,window.dispatchEvent(t),!t.defaultPrevented)throw r}return d.then(r=>{for(const t of r||[])t.status==="rejected"&&u(t.reason);return c().catch(u)})};var l={},f=w;l.createRoot=f.createRoot,l.hydrateRoot=f.hydrateRoot;const S=p.lazy(()=>C(async()=>{const{default:e}=await import("./App-mzuNw1xF.js");return{default:e}},__vite__mapDeps([0,1,2,3,4])).then(({default:e})=>({default:e})));function j(){return new Promise(e=>{if(document.body)return e(document.body);document.addEventListener("DOMContentLoaded",()=>{e(document.body)})})}j().then(()=>v()).then(()=>{g.extensionManager.registerSidebarTab({id:"comfyui-copilot",icon:"cc-icon-logo",title:"ComfyUI Copilot",tooltip:"ComfyUI Copilot",type:"custom",render:e=>{const c=document.createElement("div");c.id="comfyui-copilot-plugin",c.className="h-full w-full flex flex-col",e.style.height="100%",e.appendChild(c),l.createRoot(c).render(s.jsx(p.StrictMode,{children:s.jsx(x.Suspense,{fallback:s.jsx("div",{className:"h-full w-full flex items-center justify-center",children:"Loading..."}),children:s.jsx(S,{})})}))}})});export{C as _};
function getImportPath(filename) {
return `./${filename}`;
}
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["copilot_web/App-C63C0sLF.js","copilot_web/vendor-markdown-Dek94WS0.js","copilot_web/vendor-react-V04_Axys.js","copilot_web/message-components-C_KwPGE8.js","copilot_web/fonts.css"].map(path => {
const apiBase = window.comfyAPI?.api?.api?.api_base;
if (apiBase) {
// 有 API base 时,使用完整路径
return `${apiBase.substring(1)}/${path}`;
} else {
// 没有 API base 时,使用相对路径
return `./${path}`;
}
}))))=>i.map(i=>d[i]);
import{j as s}from"./vendor-markdown-Dek94WS0.js";import{a as w,R as p,r as x}from"./vendor-react-V04_Axys.js";import{w as v,a as g}from"./message-components-C_KwPGE8.js";/* empty css */const R="modulepreload",b=function(e){return"/"+e},m={},C=function(c,a,P){let d=Promise.resolve();if(a&&a.length>0){document.getElementsByTagName("link");const r=document.querySelector("meta[property=csp-nonce]"),t=r?.nonce||r?.getAttribute("nonce");d=Promise.allSettled(a.map(o=>{if(o=b(o),o in m)return;m[o]=!0;const i=o.endsWith(".css"),h=i?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${o}"]${h}`))return;const n=document.createElement("link");if(n.rel=i?"stylesheet":R,i||(n.as="script"),n.crossOrigin="",n.href=o,t&&n.setAttribute("nonce",t),document.head.appendChild(n),i)return new Promise((y,E)=>{n.addEventListener("load",y),n.addEventListener("error",()=>E(new Error(`Unable to preload CSS for ${o}`)))})}))}function u(r){const t=new Event("vite:preloadError",{cancelable:!0});if(t.payload=r,window.dispatchEvent(t),!t.defaultPrevented)throw r}return d.then(r=>{for(const t of r||[])t.status==="rejected"&&u(t.reason);return c().catch(u)})};var l={},f=w;l.createRoot=f.createRoot,l.hydrateRoot=f.hydrateRoot;const S=p.lazy(()=>C(async()=>{const{default:e}=await import(getImportPath("App-C63C0sLF.js"));return{default:e}},__vite__mapDeps([0,1,2,3,4])).then(({default:e})=>({default:e})));function j(){return new Promise(e=>{if(document.body)return e(document.body);document.addEventListener("DOMContentLoaded",()=>{e(document.body)})})}j().then(()=>v()).then(()=>{g.extensionManager.registerSidebarTab({id:"comfyui-copilot",icon:"cc-icon-logo",title:"ComfyUI Copilot",tooltip:"ComfyUI Copilot",type:"custom",render:e=>{const c=document.createElement("div");c.id="comfyui-copilot-plugin",c.className="h-full w-full flex flex-col",e.style.height="100%",e.appendChild(c),l.createRoot(c).render(s.jsx(p.StrictMode,{children:s.jsx(x.Suspense,{fallback:s.jsx("div",{className:"h-full w-full flex items-center justify-center",children:"Loading..."}),children:s.jsx(S,{})})}))}})});export{C as _};
File diff suppressed because one or more lines are too long
+4 -1
View File
@@ -1,4 +1,7 @@
import{r as so,c as ri,g as oo}from"./vendor-react-V04_Axys.js";var $a={exports:{}},tn={};/**
function getImportPath(filename) {
return `./${filename}`;
}
import{r as so,c as ri,g as oo}from"./vendor-react-V04_Axys.js";var $a={exports:{}},tn={};/**
* @license React
* react-jsx-runtime.production.min.js
*
+4 -1
View File
@@ -1,4 +1,7 @@
var vd=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function Ja(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var Uo={exports:{}},T={};/**
function getImportPath(filename) {
return `./${filename}`;
}
var vd=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function Ja(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var Uo={exports:{}},T={};/**
* @license React
* react.production.min.js
*
+4 -1
View File
@@ -1 +1,4 @@
import"./vendor-react-V04_Axys.js";
function getImportPath(filename) {
return `./${filename}`;
}
import"./vendor-react-V04_Axys.js";
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "ComfyUI-Copilot"
description = "Your Intelligent Assistant for Comfy-UI."
version = "1.3.0"
version = "1.3.3"
license = {file = "LICENSE"}
[project.urls]
+1 -1
View File
@@ -5,7 +5,7 @@
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"build": "vite build && node scripts/post-build.js",
"build:css": "tailwindcss -i ./src/scoped-tailwind.css -o ./src/output.css --watch",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
+69 -18
View File
@@ -1,3 +1,11 @@
/*
* @Author: ai-business-hql qingli.hql@alibaba-inc.com
* @Date: 2025-02-17 20:53:45
* @LastEditors: ai-business-hql qingli.hql@alibaba-inc.com
* @LastEditTime: 2025-06-05 11:18:48
* @FilePath: /comfyui_copilot/ui/scripts/post-build.js
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import fs from 'fs';
import path from 'path';
import glob from 'glob';
@@ -8,44 +16,87 @@ import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// 在 dist/copilot_web 目录下查找包含 __vite__mapDeps 的 JS 文件
// 在 dist/copilot_web 目录下查找所有 JS 文件
const distDir = path.resolve(__dirname, '../../dist/copilot_web');
const files = glob.sync(`${distDir}/**/App-*.js`);
const files = glob.sync(`${distDir}/**/*.js`);
files.forEach(file => {
console.log('start modify', file)
let content = fs.readFileSync(file, 'utf-8');
// 检查是否已经有 getImportPath 函数(function 或 const 形式)
// if (!content.includes('getImportPath')) {
// content = `function getImportPath(filename) {
// const apiBase = window.comfyAPI?.api?.api?.api_base;
// if (apiBase) {
// // 有 API base 时,使用完整路径
// return \`\${apiBase.substring(1)}/copilot_web/\${filename}\`;
// } else {
// // 没有 API base 时,使用相对路径(因为所有文件都在同一目录)
// return \`./\${filename}\`;
// }
// }
// ` + content;
// }
if (!content.includes('getImportPath')) {
content = `function getImportPath(filename) {
return \`./\${filename}\`;
}
` + content;
}
if (content.includes('__vite__mapDeps')) {
// 提取新格式的依赖数组,使用非贪婪匹配
const depsMatch = content.match(/const __vite__mapDeps=\(.*?m\.f=\[(.*?)\]/);
// 尝试两种不同的格式
let depsMatch = content.match(/const __vite__mapDeps=\(.*?m\.f=\[(.*?)\]/);
// 如果第一种格式不匹配,尝试第二种格式(用于 input.js)
if (!depsMatch) {
depsMatch = content.match(/const __vite__mapDeps=\(.*?m\.f\|\|\(m\.f=\[(.*?)\]\)\)\)/);
}
if (depsMatch && depsMatch[1]) {
const originalDeps = depsMatch[1];
// 如果文件中还没有路径转换逻辑,则添加
if (!content.includes('window.comfyAPI?.api?.api?.api_base')) {
if (!content.includes('.map(path =>')) {
// 替换整个 __vite__mapDeps 函数,处理两种可能的格式
content = content.replace(
/const __vite__mapDeps=.*?\)=>i\.map\(i=>d\[i\]\);/,
/const __vite__mapDeps=\([^;]+\);/,
`const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=[${originalDeps}].map(path => {
const apiBase = window.comfyAPI?.api?.api?.api_base;
const prefix = apiBase ? \`\${apiBase.substring(1)}/\` : '';
return \`\${prefix}\${path}\`;
if (apiBase) {
// 有 API base 时,使用完整路径
return \`\${apiBase.substring(1)}/\${path}\`;
} else {
// 没有 API base 时,使用相对路径
return \`./\${path}\`;
}
}))))=>i.map(i=>d[i]);`
);
} else {
// 如果已经有路径转换逻辑,只替换依赖数组部分
content = content.replace(
/const __vite__mapDeps=\(.*?\)=>i\.map\(i=>d\[i\]\);/,
`const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=[${originalDeps}])))=>i.map(i=>d[i]);`
);
}
fs.writeFileSync(file, content, 'utf-8');
console.log(`Modified ${path.basename(file)}`);
console.log(`Modified ${path.basename(file)} - __vite__mapDeps`);
} else {
console.log(`No deps pattern found in ${path.basename(file)}`);
}
} else {
console.log(`No __vite__mapDeps found in ${path.basename(file)}`);
}
});
// 处理 import("filename") 形式的动态导入
const dynamicImportPattern = /import\("([^"]+\.js)"\)/g;
if (dynamicImportPattern.test(content)) {
content = content.replace(dynamicImportPattern, (match, filename) => {
// 只处理相对路径的导入
if (filename.startsWith('./') || !filename.includes('/')) {
const cleanFilename = filename.startsWith('./') ? filename.substring(2) : filename;
return `import(getImportPath("${cleanFilename}"))`;
}
return match;
});
}
fs.writeFileSync(file, content, 'utf-8');
console.log(`Modified ${path.basename(file)}`);
});
// 不需要单独处理 input.js,因为它已经在上面的循环中被处理了
+23
View File
@@ -480,6 +480,29 @@ export namespace WorkflowChatAPI {
// This should never be reached due to the throw in the loop, but TypeScript needs it
throw lastError;
}
export async function listModels(): Promise<{ models: { name: string; image_enable: boolean }[] }> {
const apiKey = getApiKey();
const browserLanguage = getBrowserLanguage();
// Prepare headers
const headers: Record<string, string> = {
'Content-Type': 'application/json',
'accept': 'application/json',
'Authorization': `Bearer ${apiKey}`,
'trace-id': generateUUID(),
'Accept-Language': browserLanguage,
};
const response = await fetch(`${BASE_URL}/v1/models`, {
method: 'GET',
headers,
});
const result = await response.json();
return result as { models: { name: string; image_enable: boolean }[] };
}
}
+3 -3
View File
@@ -1,8 +1,8 @@
/*
* @Author: 晴知 qingli.hql@alibaba-inc.com
* @Date: 2024-11-28 10:19:07
* @LastEditors: ai-business-hql ai.bussiness.hql@gmail.com
* @LastEditTime: 2025-04-22 17:52:22
* @LastEditors: ai-business-hql qingli.hql@alibaba-inc.com
* @LastEditTime: 2025-06-05 15:01:55
* @FilePath: /comfyui_copilot/ui/src/components/chat/ChatHeader.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
@@ -73,7 +73,7 @@ export function ChatHeader({
bg-white border-gray-200 sticky top-2 z-10">
<div className="flex items-center space-x-1">
<img
src={logoImage}
src={`.${logoImage}`}
alt="ComfyUI-Copilot Logo"
className="h-7 w-7 -ml-1"
/>
+38 -22
View File
@@ -4,6 +4,7 @@
import { ChangeEvent, KeyboardEvent, useState, useRef, useEffect } from 'react';
import { SendIcon, ImageIcon, PlusIcon, XIcon } from './Icons';
import React from 'react';
import { WorkflowChatAPI } from '../../apis/workflowChatApi';
interface ChatInputProps {
input: string;
@@ -27,25 +28,6 @@ export interface UploadedImage {
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
const SUPPORTED_FORMATS = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
const models_conf = [
{
"name": "gpt-4o",
"image_enable": true
},
{
"name": "gpt-4o-mini",
"image_enable": true
},
{
"name": "qwen-plus",
"image_enable": false
},
{
"name": "DeepSeek-V3",
"image_enable": false
}
]
export function ChatInput({
input,
loading,
@@ -59,6 +41,7 @@ export function ChatInput({
onModelChange,
}: ChatInputProps) {
const [showUploadModal, setShowUploadModal] = useState(false);
const [models, setModels] = useState<{ name: string; image_enable: boolean }[]>([]);
const fileInputRef = React.useRef<HTMLInputElement>(null);
const textareaRef = useRef<HTMLTextAreaElement>(null);
@@ -72,6 +55,39 @@ export function ChatInput({
}
}, [input]);
// Load models on component mount
useEffect(() => {
const loadModels = async () => {
try {
const result = await WorkflowChatAPI.listModels();
setModels(result.models);
} catch (error) {
console.error('Failed to load models:', error);
// Fallback to default models if API fails
setModels([
{
"name": "gpt-4o",
"image_enable": true
},
{
"name": "gpt-4o-mini",
"image_enable": true
},
{
"name": "qwen-plus",
"image_enable": false
},
{
"name": "DeepSeek-V3",
"image_enable": false
}
]);
}
};
loadModels();
}, []);
const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => {
if (event.target.files) {
const invalidFiles: string[] = [];
@@ -161,7 +177,7 @@ export function ChatInput({
focus:border-transparent hover:bg-gray-50
transition-colors border-0"
>
{models_conf.map((model) => (
{models.map((model) => (
<option value={model.name} key={model.name}>{model.name}</option>
))}
</select>
@@ -170,11 +186,11 @@ export function ChatInput({
<button
type="button"
onClick={() => setShowUploadModal(true)}
disabled={!models_conf.find(model => model.name === selectedModel)?.image_enable}
disabled={!models.find(model => model.name === selectedModel)?.image_enable}
className={`p-1.5 text-gray-500 bg-white border-none
hover:bg-gray-100 hover:text-gray-600
transition-all duration-200 outline-none
${!models_conf.find(model => model.name === selectedModel)?.image_enable ? 'opacity-50 cursor-not-allowed' : ''}`}>
${!models.find(model => model.name === selectedModel)?.image_enable ? 'opacity-50 cursor-not-allowed' : ''}`}>
<ImageIcon className="h-4 w-4" />
</button>
</div>
@@ -66,10 +66,11 @@ export const HistoryItemScreen: React.FC<HistoryItemScreenProps> = ({
<ImageModal
visible={modalVisible}
imageUrl={modalImageUrl}
params={{
...params,
params={modalImageParams ? {
...modalImageParams,
// Keep the nodeName for context, ensuring it's always available
nodeNames: { [historyItem.nodeName.split('<')[0]]: historyItem.nodeName.split('<')[0] }
}}
} : undefined}
onClose={closeImageModal}
/>
@@ -117,6 +117,18 @@ export const ResultGalleryScreen: React.FC<ResultGalleryScreenProps> = ({
className="w-full h-full object-cover"
/>
</div>
<div className="p-2 text-xs text-gray-600 bg-white max-h-16 overflow-y-auto">
{Object.entries(image.params)
// Filter out nodeParams and other complex objects from display
.filter(([paramName, value]) =>
paramName !== 'nodeParams' &&
typeof value !== 'object'
)
.map(([paramName, value]) => (
<div key={paramName}>{paramName}: {String(value)}</div>
))
}
</div>
</div>
);
})}
+3
View File
@@ -427,6 +427,9 @@
.h-px {
height: 1px;
}
.max-h-16 {
max-height: 4rem;
}
.max-h-60 {
max-height: 15rem;
}