feat: 滚动修改

This commit is contained in:
li
2025-08-12 18:23:40 +08:00
parent b3ed0438f5
commit 8f00e2ca6a
23 changed files with 399 additions and 457 deletions
@@ -1,7 +1,7 @@
function getImportPath(filename) {
return `./${filename}`;
}
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["copilot_web/workflowChat-CpUmiJ3F.js","copilot_web/vendor-markdown-BAJQc3l1.js","copilot_web/vendor-react-Dixhfmvb.js","copilot_web/message-components-Do0XU4ge.js","copilot_web/input.js","copilot_web/assets/input-CTambuX-.css","copilot_web/fonts.css"].map(path => {
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["copilot_web/workflowChat-CEA9Svxx.js","copilot_web/vendor-markdown-BAJQc3l1.js","copilot_web/vendor-react-Dixhfmvb.js","copilot_web/message-components-BpJmIhzt.js","copilot_web/input.js","copilot_web/assets/input-CTambuX-.css","copilot_web/fonts.css"].map(path => {
const apiBase = window.comfyAPI?.api?.api?.api_base;
if (apiBase) {
// 有 API base 时,使用完整路径
@@ -11,4 +11,4 @@ function getImportPath(filename) {
return `./${path}`;
}
}))))=>i.map(i=>d[i]);
import{_ as a}from"./input.js";import{j as e}from"./vendor-markdown-BAJQc3l1.js";import{r as t,R as i}from"./vendor-react-Dixhfmvb.js";import{C as n}from"./message-components-Do0XU4ge.js";const s={EXPLAIN_NODE:"copilot:explain-node",TOOLBOX_USAGE:"copilot:toolbox-usage",TOOLBOX_PARAMETERS:"copilot:toolbox-parameters",TOOLBOX_DOWNSTREAMNODES:"copilot:toolbox-downstreamnodes"},d=i.lazy(()=>a(()=>import(getImportPath("workflowChat-CpUmiJ3F.js")),__vite__mapDeps([0,1,2,3,4,5,6])).then(o=>({default:o.default})));function c(){const[o,r]=t.useState(!1);return t.useEffect(()=>{const l=()=>{r(!0)};return window.addEventListener(s.EXPLAIN_NODE,l),()=>window.removeEventListener(s.EXPLAIN_NODE,l)},[]),e.jsx(n,{children:e.jsx("div",{className:"h-full w-full flex flex-col",children:e.jsx(t.Suspense,{fallback:e.jsx("div",{className:"h-full w-full flex items-center justify-center",children:"Loading..."}),children:e.jsx(d,{visible:!0,triggerUsage:o,onUsageTriggered:()=>r(!1)})})})})}const O=Object.freeze(Object.defineProperty({__proto__:null,default:c},Symbol.toStringTag,{value:"Module"}));export{O as A,s as C};
import{_ as a}from"./input.js";import{j as e}from"./vendor-markdown-BAJQc3l1.js";import{r as t,R as i}from"./vendor-react-Dixhfmvb.js";import{C as n}from"./message-components-BpJmIhzt.js";const s={EXPLAIN_NODE:"copilot:explain-node",TOOLBOX_USAGE:"copilot:toolbox-usage",TOOLBOX_PARAMETERS:"copilot:toolbox-parameters",TOOLBOX_DOWNSTREAMNODES:"copilot:toolbox-downstreamnodes"},d=i.lazy(()=>a(()=>import(getImportPath("workflowChat-CEA9Svxx.js")),__vite__mapDeps([0,1,2,3,4,5,6])).then(o=>({default:o.default})));function c(){const[o,r]=t.useState(!1);return t.useEffect(()=>{const l=()=>{r(!0)};return window.addEventListener(s.EXPLAIN_NODE,l),()=>window.removeEventListener(s.EXPLAIN_NODE,l)},[]),e.jsx(n,{children:e.jsx("div",{className:"h-full w-full flex flex-col",children:e.jsx(t.Suspense,{fallback:e.jsx("div",{className:"h-full w-full flex items-center justify-center",children:"Loading..."}),children:e.jsx(d,{visible:!0,triggerUsage:o,onUsageTriggered:()=>r(!1)})})})})}const O=Object.freeze(Object.defineProperty({__proto__:null,default:c},Symbol.toStringTag,{value:"Module"}));export{O as A,s as C};
-5
View File
@@ -1,5 +0,0 @@
function getImportPath(filename) {
return `./${filename}`;
}
import{j as s}from"./vendor-markdown-BAJQc3l1.js";import{r as a}from"./vendor-react-Dixhfmvb.js";import{u as E,B as D,R as O,h as x,a as m,W as b}from"./message-components-Do0XU4ge.js";function P({content:g,name:k="Assistant",avatar:T,onAddMessage:y,onUpdateMessage:c,onFinishLoad:w,messageId:_}){const{dispatch:u,abortControllerRef:l}=E(),[d,S]=a.useState(!1),[G,J]=a.useState(""),[R,j]=a.useState(!1),[N,C]=a.useState(null);a.useEffect(()=>{w?.()},[]);const r=a.useMemo(()=>{try{return JSON.parse(g)}catch(e){return console.error("Failed to parse message content:",e),null}},[g]),h=a.useMemo(()=>{if(!r||!r.ext)return null;const e=r.ext.find(t=>t.type==="debug_start_checkpoint"||t.type==="debug_checkpoint"&&t.data?.checkpoint_type==="debug_start");return e&&e.data&&e.data.checkpoint_id?e.data.checkpoint_id:null},[r])||N,v=async()=>{if(d)return;const e=x(),t={id:e,role:"ai",content:JSON.stringify({text:`🔍 Starting workflow analysis...
`,ext:[]}),format:"markdown",name:"Assistant",finished:!1,debugGuide:!0};y?.(t);try{await I(),u({type:"SET_LOADING",payload:!0}),await A(e)}finally{S(!1)}},I=async()=>{try{const e=await m.graphToPrompt(),t=localStorage.getItem("sessionId")||"";if(t&&e){const n=await b.saveWorkflowCheckpoint(t,e.output,e.workflow,"debug_start");if(C(n.version_id),console.log(`Saved debug start checkpoint: ${n.version_id}`),c&&r){const o=[...r.ext||[]].filter(f=>f.type!=="debug_start_checkpoint"&&!(f.type==="debug_checkpoint"&&f.data?.checkpoint_type==="debug_start"));o.push({type:"debug_start_checkpoint",data:{checkpoint_id:n.version_id,checkpoint_type:"debug_start"}});const p={id:_||x(),role:"ai",content:JSON.stringify({text:r.text,ext:o}),format:"debug_guide",name:"Assistant"};c(p)}}}catch(e){console.error("Failed to save checkpoint before debug:",e)}},A=async e=>{try{const t=await m.graphToPrompt();let n="",i=null;l&&(l.current=new AbortController);for await(const o of b.streamDebugAgent(t,l?.current?.signal||void 0))if(o.text){n=o.text,o.ext&&(i=o.ext);const p={id:e,role:"ai",content:JSON.stringify({text:n,ext:i||[]}),format:"markdown",name:"Assistant",finished:!1,debugGuide:!0};c?.(p)}c?.({id:e,role:"ai",content:JSON.stringify({text:n,ext:i||[]}),format:"markdown",name:"Assistant",finished:!0,debugGuide:!0}),u({type:"SET_LOADING",payload:!1}),l.current=null}catch(t){console.error("Error calling debug agent:",t),j(!1);const i={id:e,role:"ai",content:JSON.stringify({text:`I encountered an error while analyzing your workflow: ${t.message||"Unknown error"}`,ext:[]}),format:"markdown",name:"Assistant",finished:!0};c?.(i),u({type:"SET_LOADING",payload:!1}),l.current=null}};return r?s.jsx(D,{name:k,children:s.jsxs("div",{className:"bg-gray-100 pt-4 px-4 pb-3 rounded-lg",children:[s.jsx("div",{className:"flex justify-between items-start",children:s.jsx("p",{className:"text-gray-700 text-sm flex-1",children:r.text})}),s.jsx("div",{className:"flex justify-end mt-4",children:s.jsx("button",{onClick:v,disabled:d,className:`debug-btn bg-debug-btn text-sm text-[#fff] rounded-lg px-4 py-2 ${d?"cursor-not-allowed":"cursor-pointer"}`,children:d?"Analyzing...":"Debug Errors"})}),s.jsx("div",{className:"flex justify-end mt-2",children:!!h&&s.jsx("div",{className:"ml-2 flex-shrink-0",children:s.jsx(O,{checkpointId:h,onRestore:()=>{console.log("Workflow restored from checkpoint")}})})})]})}):null}export{P as DebugGuide};
+5
View File
@@ -0,0 +1,5 @@
function getImportPath(filename) {
return `./${filename}`;
}
import{j as s}from"./vendor-markdown-BAJQc3l1.js";import{r as i}from"./vendor-react-Dixhfmvb.js";import{u as A,B as D,R as E,h as x,a as m,W as b}from"./message-components-BpJmIhzt.js";function M({content:f,name:k="Assistant",avatar:O,onAddMessage:y,onUpdateMessage:c,messageId:w}){const{dispatch:u,abortControllerRef:l}=A(),[d,_]=i.useState(!1),[T,G]=i.useState(""),[J,S]=i.useState(!1),[j,N]=i.useState(null),r=i.useMemo(()=>{try{return JSON.parse(f)}catch(e){return console.error("Failed to parse message content:",e),null}},[f]),h=i.useMemo(()=>{if(!r||!r.ext)return null;const e=r.ext.find(t=>t.type==="debug_start_checkpoint"||t.type==="debug_checkpoint"&&t.data?.checkpoint_type==="debug_start");return e&&e.data&&e.data.checkpoint_id?e.data.checkpoint_id:null},[r])||j,C=async()=>{if(d)return;const e=x(),t={id:e,role:"ai",content:JSON.stringify({text:`🔍 Starting workflow analysis...
`,ext:[]}),format:"markdown",name:"Assistant",finished:!1,debugGuide:!0};y?.(t);try{await v(),u({type:"SET_LOADING",payload:!0}),await I(e)}finally{_(!1)}},v=async()=>{try{const e=await m.graphToPrompt(),t=localStorage.getItem("sessionId")||"";if(t&&e){const n=await b.saveWorkflowCheckpoint(t,e.output,e.workflow,"debug_start");if(N(n.version_id),console.log(`Saved debug start checkpoint: ${n.version_id}`),c&&r){const o=[...r.ext||[]].filter(g=>g.type!=="debug_start_checkpoint"&&!(g.type==="debug_checkpoint"&&g.data?.checkpoint_type==="debug_start"));o.push({type:"debug_start_checkpoint",data:{checkpoint_id:n.version_id,checkpoint_type:"debug_start"}});const p={id:w||x(),role:"ai",content:JSON.stringify({text:r.text,ext:o}),format:"debug_guide",name:"Assistant"};c(p)}}}catch(e){console.error("Failed to save checkpoint before debug:",e)}},I=async e=>{try{const t=await m.graphToPrompt();let n="",a=null;l&&(l.current=new AbortController);for await(const o of b.streamDebugAgent(t,l?.current?.signal||void 0))if(o.text){n=o.text,o.ext&&(a=o.ext);const p={id:e,role:"ai",content:JSON.stringify({text:n,ext:a||[]}),format:"markdown",name:"Assistant",finished:!1,debugGuide:!0};c?.(p)}c?.({id:e,role:"ai",content:JSON.stringify({text:n,ext:a||[]}),format:"markdown",name:"Assistant",finished:!0,debugGuide:!0}),u({type:"SET_LOADING",payload:!1}),l.current=null}catch(t){console.error("Error calling debug agent:",t),S(!1);const a={id:e,role:"ai",content:JSON.stringify({text:`I encountered an error while analyzing your workflow: ${t.message||"Unknown error"}`,ext:[]}),format:"markdown",name:"Assistant",finished:!0};c?.(a),u({type:"SET_LOADING",payload:!1}),l.current=null}};return r?s.jsx(D,{name:k,children:s.jsxs("div",{className:"bg-gray-100 pt-4 px-4 pb-3 rounded-lg",children:[s.jsx("div",{className:"flex justify-between items-start",children:s.jsx("p",{className:"text-gray-700 text-sm flex-1",children:r.text})}),s.jsx("div",{className:"flex justify-end mt-4",children:s.jsx("button",{onClick:C,disabled:d,className:`debug-btn bg-debug-btn text-sm text-[#fff] rounded-lg px-4 py-2 ${d?"cursor-not-allowed":"cursor-pointer"}`,children:d?"Analyzing...":"Debug Errors"})}),s.jsx("div",{className:"flex justify-end mt-2",children:!!h&&s.jsx("div",{className:"ml-2 flex-shrink-0",children:s.jsx(E,{checkpointId:h,onRestore:()=>{console.log("Workflow restored from checkpoint")}})})})]})}):null}export{M as DebugGuide};
+4
View File
@@ -0,0 +1,4 @@
function getImportPath(filename) {
return `./${filename}`;
}
import{j as e}from"./vendor-markdown-BAJQc3l1.js";import{b as p,c as h,B as m,p as u,R as w}from"./message-components-BpJmIhzt.js";import{r as k}from"./vendor-react-Dixhfmvb.js";const v=a=>{const{title:i="",isWorkflowUpdate:d=!1,className:n="",children:c}=a,[s,r]=k.useState(!1);return e.jsxs("div",{className:`relative rounded-lg flex flex-col beautify-card ${n} ${s?"":"h-[200px]"}`,children:[e.jsx("div",{className:"card-border rounded-lg"}),e.jsxs("div",{className:"flex flex-1 justify-between items-center pb-2 border-b border-[#29292f]",children:[e.jsx("div",{children:typeof i=="string"?e.jsx("h3",{className:"text-sm text-[#fff] font-medium",children:i}):i}),e.jsx("button",{onClick:()=>{r(!s)},children:s?e.jsx(p,{color:"#E5E7EB"}):e.jsx(h,{color:"#E5E7EB"})})]}),e.jsx("div",{className:"overflow-hidden",children:c})]})};function _({content:a,name:i="Assistant",avatar:d,format:n="markdown"}){const c=()=>{let s=null,r=!1,o;try{if(o=JSON.parse(a),o.ext){let t=o.ext.find(l=>l.type==="workflow_rewrite_checkpoint"||l.type==="debug_checkpoint"&&l.data?.checkpoint_type==="workflow_rewrite_start");t&&t.data&&t.data.checkpoint_id?(s=t.data.checkpoint_id,r=!0):(t=o.ext.find(l=>l.type==="workflow_rewrite_complete"),t&&t.data&&t.data.version_id?(s=t.data.version_id,r=!0):(t=o.ext.find(l=>l.type==="debug_checkpoint"),t&&t.data&&t.data.checkpoint_id&&(s=t.data.checkpoint_id,r=!1))),o.ext.find(l=>l.type==="workflow_update")&&(r=!0)}}catch(t){return console.error("Failed to parse DebugResult content:",t),null}const f=r?e.jsxs("div",{className:"flex items-center text-green-500",children:[e.jsx("svg",{className:"w-5 h-5 mr-2",fill:"currentColor",viewBox:"0 0 20 20",children:e.jsx("path",{fillRule:"evenodd",d:"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z",clipRule:"evenodd"})}),e.jsx("h4",{className:"font-bold text-xl",children:"Workflow Updated Successfully"})]}):e.jsxs("div",{className:"flex items-center text-[#fff]",children:[e.jsx("svg",{className:"w-5 h-5 mr-2",viewBox:"0 0 1024 1024",version:"1.1",xmlns:"http://www.w3.org/2000/svg","p-id":"28108",fill:"currentColor",children:e.jsx("path",{d:"M401.048025 844.855924c0 20.341281 16.643052 36.984333 36.984333 36.984333l147.936307 0c20.341281 0 36.984333-16.643052 36.984333-36.984333L622.952998 807.872614 401.048025 807.872614 401.048025 844.855924zM512 142.159744c-142.943596 0-258.888282 115.944686-258.888282 258.888282 0 88.021729 44.011376 165.503405 110.951975 212.288964l0 83.58365c0 20.341281 16.643052 36.984333 36.984333 36.984333l221.903949 0c20.341281 0 36.984333-16.643052 36.984333-36.984333l0-83.58365c66.941622-46.784536 110.951975-124.266212 110.951975-212.288964C770.888282 258.104429 654.943596 142.159744 512 142.159744zM617.588827 552.682561l-31.621185 22.005176 0 85.248569L438.031335 659.936307l0-85.063351L406.41015 552.866756c-49.743938-34.764781-79.33079-91.350544-79.33079-151.634536 0-101.890598 83.029018-184.92064 184.92064-184.92064s184.92064 83.029018 184.92064 184.92064C696.919617 461.332017 667.332764 517.91778 617.588827 552.682561z","p-id":"28277"})}),e.jsx("h4",{className:"font-bold text-xl",children:"Workflow Updated Finished"})]}),x=r?e.jsx("div",{className:"mt-3 text-xs text-[#fff]/70",children:"💡 If you're not satisfied with the changes, click the restore button to revert to the previous version."}):null;return e.jsxs("div",{className:"sticky top-0 left-0 w-full bg-gray-100 p-4 rounded-lg overflow-hidden",children:[e.jsx(v,{title:f,isWorkflowUpdate:r,className:"p-4",children:e.jsxs("div",{className:"prose prose-sm max-w-none",children:[n==="markdown"?e.jsx(u,{response:o||{},isInCard:!0}):e.jsx("pre",{className:"whitespace-pre-wrap text-[#fff]/70 text-sm leading-relaxed h-full",children:o?.text||""}),x]})}),e.jsx("div",{className:"flex justify-end mt-2",children:!!s&&e.jsx("div",{className:"ml-2 flex-shrink-0",children:e.jsx(w,{checkpointId:s,onRestore:()=>{console.log(`Workflow restored from ${r?"workflow update":"debug"} checkpoint`)},title:r?`Restore to this version (Version ${s})`:`Restore checkpoint ${s}`})})})]})};return e.jsx(m,{name:i,children:c()})}export{_ as DebugResult};
-4
View File
@@ -1,4 +0,0 @@
function getImportPath(filename) {
return `./${filename}`;
}
import{j as e}from"./vendor-markdown-BAJQc3l1.js";import{b as m,c as u,B as w,p as k,R as v}from"./message-components-Do0XU4ge.js";import{r as f}from"./vendor-react-Dixhfmvb.js";const j=a=>{const{title:i="",isWorkflowUpdate:x=!1,className:n="",onFinishLoad:c,children:d}=a,[s,r]=f.useState(!1);return f.useEffect(()=>{c?.()},[]),e.jsxs("div",{className:`relative rounded-lg flex flex-col beautify-card ${n} ${s?"":"h-[200px]"}`,children:[e.jsx("div",{className:"card-border rounded-lg"}),e.jsxs("div",{className:"flex flex-1 justify-between items-center pb-2 border-b border-[#29292f]",children:[e.jsx("div",{children:typeof i=="string"?e.jsx("h3",{className:"text-sm text-[#fff] font-medium",children:i}):i}),e.jsx("button",{onClick:()=>{r(!s)},children:s?e.jsx(m,{color:"#E5E7EB"}):e.jsx(u,{color:"#E5E7EB"})})]}),e.jsx("div",{className:"overflow-hidden",children:d})]})};function y({content:a,name:i="Assistant",avatar:x,format:n="markdown",onFinishLoad:c}){const d=()=>{let s=null,r=!1,o;try{if(o=JSON.parse(a),o.ext){let t=o.ext.find(l=>l.type==="workflow_rewrite_checkpoint"||l.type==="debug_checkpoint"&&l.data?.checkpoint_type==="workflow_rewrite_start");t&&t.data&&t.data.checkpoint_id?(s=t.data.checkpoint_id,r=!0):(t=o.ext.find(l=>l.type==="workflow_rewrite_complete"),t&&t.data&&t.data.version_id?(s=t.data.version_id,r=!0):(t=o.ext.find(l=>l.type==="debug_checkpoint"),t&&t.data&&t.data.checkpoint_id&&(s=t.data.checkpoint_id,r=!1))),o.ext.find(l=>l.type==="workflow_update")&&(r=!0)}}catch(t){return console.error("Failed to parse DebugResult content:",t),null}const p=r?e.jsxs("div",{className:"flex items-center text-green-500",children:[e.jsx("svg",{className:"w-5 h-5 mr-2",fill:"currentColor",viewBox:"0 0 20 20",children:e.jsx("path",{fillRule:"evenodd",d:"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z",clipRule:"evenodd"})}),e.jsx("h4",{className:"font-bold text-xl",children:"Workflow Updated Successfully"})]}):e.jsxs("div",{className:"flex items-center text-[#fff]",children:[e.jsx("svg",{className:"w-5 h-5 mr-2",viewBox:"0 0 1024 1024",version:"1.1",xmlns:"http://www.w3.org/2000/svg","p-id":"28108",fill:"currentColor",children:e.jsx("path",{d:"M401.048025 844.855924c0 20.341281 16.643052 36.984333 36.984333 36.984333l147.936307 0c20.341281 0 36.984333-16.643052 36.984333-36.984333L622.952998 807.872614 401.048025 807.872614 401.048025 844.855924zM512 142.159744c-142.943596 0-258.888282 115.944686-258.888282 258.888282 0 88.021729 44.011376 165.503405 110.951975 212.288964l0 83.58365c0 20.341281 16.643052 36.984333 36.984333 36.984333l221.903949 0c20.341281 0 36.984333-16.643052 36.984333-36.984333l0-83.58365c66.941622-46.784536 110.951975-124.266212 110.951975-212.288964C770.888282 258.104429 654.943596 142.159744 512 142.159744zM617.588827 552.682561l-31.621185 22.005176 0 85.248569L438.031335 659.936307l0-85.063351L406.41015 552.866756c-49.743938-34.764781-79.33079-91.350544-79.33079-151.634536 0-101.890598 83.029018-184.92064 184.92064-184.92064s184.92064 83.029018 184.92064 184.92064C696.919617 461.332017 667.332764 517.91778 617.588827 552.682561z","p-id":"28277"})}),e.jsx("h4",{className:"font-bold text-xl",children:"Workflow Updated Finished"})]}),h=r?e.jsx("div",{className:"mt-3 text-xs text-[#fff]/70",children:"💡 If you're not satisfied with the changes, click the restore button to revert to the previous version."}):null;return e.jsxs("div",{className:"sticky top-0 left-0 w-full bg-gray-100 p-4 rounded-lg overflow-hidden",children:[e.jsx(j,{title:p,isWorkflowUpdate:r,className:"p-4",onFinishLoad:c,children:e.jsxs("div",{className:"prose prose-sm max-w-none",children:[n==="markdown"?e.jsx(k,{response:o||{},isInCard:!0}):e.jsx("pre",{className:"whitespace-pre-wrap text-[#fff]/70 text-sm leading-relaxed h-full",children:o?.text||""}),h]})}),e.jsx("div",{className:"flex justify-end mt-2",children:!!s&&e.jsx("div",{className:"ml-2 flex-shrink-0",children:e.jsx(v,{checkpointId:s,onRestore:()=>{console.log(`Workflow restored from ${r?"workflow update":"debug"} checkpoint`)},title:r?`Restore to this version (Version ${s})`:`Restore checkpoint ${s}`})})})]})};return e.jsx(w,{name:i,children:d()})}export{y as DebugResult};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+3 -3
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+25 -33
View File
@@ -64,6 +64,8 @@ export function MessageList({ messages, latestInput, onOptionClick, installedNod
const scrollRef = useRef<HTMLDivElement>(null)
const lastMessagesCount = useRef<number>(0)
const scrollHeightLast = useRef<number>(0) // 上一次的scrollHeight
const scrollTopLast = useRef<number>(0) // 上一次的scrollTop
const clientHeightLast = useRef<number>(0) // 上一次的clientHeight
const scrollHeightBeforeLoadMore = useRef<number>(0) // loadmore之前的scrollHeight
const isLoadHistory = useRef<boolean>(false)
// 用于跟踪已经处理过的工作流和参数更新,防止重复执行
@@ -143,17 +145,19 @@ export function MessageList({ messages, latestInput, onOptionClick, installedNod
const updateScrollHeight = () => {
requestAnimationFrame(() => {
console.log('updateScrollHeight1--->', el.scrollHeight, el.scrollTop, el.clientHeight)
console.log('updateScrollHeight2--->', scrollHeightLast.current, scrollHeightBeforeLoadMore.current, isLoadHistory.current, isAutoScroll.current)
// console.log('updateScrollHeight1--->', el.scrollHeight, el.scrollTop, el.clientHeight)
// console.log('updateScrollHeight2--->', scrollHeightLast.current, scrollHeightBeforeLoadMore.current, isLoadHistory.current, isAutoScroll.current)
if (isLoadHistory.current) {
el.scrollTop = el.scrollHeight - scrollHeightBeforeLoadMore.current
} else if (isAutoScroll.current) {
console.log('scrollTop1--->', el.scrollTop, el.scrollHeight, el.clientHeight)
el.scrollTop = el.scrollHeight - el.clientHeight
console.log('scrollTop2--->', el.scrollTop, el.scrollHeight, el.clientHeight)
} else {
if (scrollHeightLast.current < el.scrollHeight && scrollHeightLast.current - scrollTopLast.current - clientHeightLast.current < 1) {
el.scrollTop = el.scrollHeight - el.clientHeight
}
scrollHeightLast.current = el.scrollHeight
scrollTopLast.current = el.scrollTop
clientHeightLast.current = el.clientHeight
}
isAutoScroll.current = el.scrollHeight - el.scrollTop - el.clientHeight < 1
console.log('updateScrollHeight3--->', el.scrollHeight, el.scrollTop, el.clientHeight)
// console.log('updateScrollHeight3--->', el.scrollHeight, el.scrollTop, el.clientHeight)
});
};
@@ -173,34 +177,38 @@ export function MessageList({ messages, latestInput, onOptionClick, installedNod
updateScrollHeight();
const handleScroll = () => {
console.log('handleScroll--->', el.scrollHeight, el.scrollTop, el.clientHeight, el.scrollHeight - el.scrollTop - el.clientHeight)
console.log('handleScroll--->', scrollHeightLast.current, scrollHeightBeforeLoadMore.current)
console.log('handleScroll--->', isLoadHistory.current, isAutoScroll.current)
// console.log('handleScroll1--->', el.scrollHeight, el.scrollTop, el.clientHeight, el.scrollHeight - el.scrollTop - el.clientHeight)
// console.log('handleScroll2--->', scrollHeightLast.current, scrollHeightBeforeLoadMore.current)
// console.log('handleScroll3--->', isLoadHistory.current, isAutoScroll.current)
if (el.scrollHeight < scrollHeightLast.current && scrollHeightLast.current > 0)
return
if (isLoadHistory.current) {
if (el.scrollHeight > scrollHeightLast.current) {
el.scrollTop = el.scrollHeight - scrollHeightBeforeLoadMore.current
console.log('el.scrollTop--->', el.scrollTop)
// console.log('el.scrollTop--->', el.scrollTop)
scrollHeightLast.current = el.scrollHeight
} else {
isLoadHistory.current = false
scrollHeightLast.current = el.scrollHeight
scrollHeightBeforeLoadMore.current = el.scrollHeight
}
// console.log('handleScroll4--->', el.scrollHeight, el.scrollTop, el.clientHeight, el.scrollHeight - el.scrollTop - el.clientHeight)
} else {
if (isAutoScroll.current && el.scrollHeight - el.scrollTop - el.clientHeight < 1) {
// console.log('isAutoScroll.current1--->', el.scrollHeight, el.scrollTop, el.clientHeight, el.scrollHeight - el.scrollTop - el.clientHeight)
// 滚动高度有变化,说明是在新增消息,上一次是滚动到底部,则需要保持滚动在底部
if (scrollHeightLast.current < el.scrollHeight && scrollHeightLast.current - scrollTopLast.current - clientHeightLast.current < 1) {
el.scrollTop = el.scrollHeight - el.clientHeight
}
scrollHeightLast.current = el.scrollHeight
scrollTopLast.current = el.scrollTop
clientHeightLast.current = el.clientHeight
scrollHeightBeforeLoadMore.current = el.scrollHeight
}
console.log('scrollHeightBeforeLoadMore--->', scrollHeightLast.current, scrollHeightBeforeLoadMore.current)
}
const handleScrollEnd = () => {
console.log('handleScrollEnd--->', el.scrollHeight, el.scrollTop, el.clientHeight)
isAutoScroll.current = el.scrollHeight - el.scrollTop - el.clientHeight < 1
// console.log('handleScrollEnd--->', el.scrollHeight, el.scrollTop, el.clientHeight)
// isAutoScroll.current = el.scrollHeight - el.scrollTop - el.clientHeight < 1
}
el.addEventListener('scroll', handleScroll);
@@ -213,10 +221,6 @@ export function MessageList({ messages, latestInput, onOptionClick, installedNod
}
}, [])
const onFinishLoad = () => {
}
// 渲染对应的消息组件
const renderMessage = (message: Message, index: number) => {
// 移除频繁的日志输出
@@ -227,13 +231,12 @@ export function MessageList({ messages, latestInput, onOptionClick, installedNod
content={message.content}
trace_id={message.trace_id}
ext={message.ext}
onFinishLoad={onFinishLoad}
/>
</Suspense>
}
if (message.role === 'showcase') {
return <Showcase key={'showcase'} onFinishLoad={onFinishLoad} />
return <Showcase key={'showcase'} />
}
if (message.role === 'ai' || message.role === 'tool') {
@@ -439,7 +442,6 @@ export function MessageList({ messages, latestInput, onOptionClick, installedNod
latestInput={latestInput}
installedNodes={installedNodes}
onAddMessage={onAddMessage}
onFinishLoad={onFinishLoad}
/>
</Suspense>
);
@@ -451,7 +453,6 @@ export function MessageList({ messages, latestInput, onOptionClick, installedNod
name={message.name}
avatar={avatar}
installedNodes={installedNodes}
onFinishLoad={onFinishLoad}
/>
</Suspense>
);
@@ -463,7 +464,6 @@ export function MessageList({ messages, latestInput, onOptionClick, installedNod
name={message.name}
avatar={avatar}
onAddMessage={onAddMessage}
onFinishLoad={onFinishLoad}
/>
</Suspense>
);
@@ -483,7 +483,6 @@ export function MessageList({ messages, latestInput, onOptionClick, installedNod
metadata={message.metadata}
finished={message.finished}
debugGuide={message.debugGuide}
onFinishLoad={dsExtComponent ? undefined : onFinishLoad}
/>
</Suspense>
);
@@ -631,7 +630,6 @@ export function MessageList({ messages, latestInput, onOptionClick, installedNod
onAddMessage?.(successMessage);
}
}}
onFinishLoad={onFinishLoad}
/>
</Suspense>
);
@@ -645,7 +643,6 @@ export function MessageList({ messages, latestInput, onOptionClick, installedNod
avatar={avatar}
onAddMessage={onAddMessage}
onUpdateMessage={onUpdateMessage}
onFinishLoad={onFinishLoad}
messageId={message.id}
/>
</Suspense>
@@ -661,7 +658,6 @@ export function MessageList({ messages, latestInput, onOptionClick, installedNod
name={message.name}
avatar={avatar}
format={message.format}
onFinishLoad={onFinishLoad}
/>
</Suspense>
);
@@ -677,7 +673,6 @@ export function MessageList({ messages, latestInput, onOptionClick, installedNod
name={message.name}
avatar={avatar}
format={message.format}
onFinishLoad={onFinishLoad}
/>
</Suspense>
);
@@ -713,7 +708,6 @@ export function MessageList({ messages, latestInput, onOptionClick, installedNod
metadata={message.metadata}
finished={message.finished}
debugGuide={message.debugGuide}
onFinishLoad={ExtComponent ? undefined : onFinishLoad}
/>
</Suspense>
);
@@ -736,7 +730,6 @@ export function MessageList({ messages, latestInput, onOptionClick, installedNod
metadata={message.metadata}
finished={message.finished}
debugGuide={message.debugGuide}
onFinishLoad={onFinishLoad}
/>
</Suspense>
);
@@ -755,7 +748,6 @@ export function MessageList({ messages, latestInput, onOptionClick, installedNod
metadata={message.metadata}
finished={message.finished}
debugGuide={message.debugGuide}
onFinishLoad={onFinishLoad}
/>
</Suspense>
);
@@ -19,7 +19,6 @@ interface AIMessageProps {
metadata?: any;
finished?: boolean;
debugGuide?: boolean;
onFinishLoad?: () => void;
}
// Card component for node explanation intent
@@ -61,12 +60,8 @@ const NodeParamsCard = ({ content }: { content: React.ReactNode }) => {
);
};
export function AIMessage({ content, name = 'Assistant', avatar, format, onOptionClick, extComponent, metadata, finished, debugGuide, onFinishLoad }: AIMessageProps) {
export function AIMessage({ content, name = 'Assistant', avatar, format, onOptionClick, extComponent, metadata, finished, debugGuide }: AIMessageProps) {
const markdownWrapper = useRef<HTMLDivElement | null>(null)
useEffect(() => {
onFinishLoad?.()
}, [])
const renderContent = () => {
try {
@@ -13,20 +13,15 @@ interface DebugGuideProps {
avatar: string;
onAddMessage?: (message: any) => void;
onUpdateMessage?: (message: any) => void;
onFinishLoad?: () => void;
messageId?: string; // Add messageId prop to track the current message
}
export function DebugGuide({ content, name = 'Assistant', avatar, onAddMessage, onUpdateMessage, onFinishLoad, messageId }: DebugGuideProps) {
export function DebugGuide({ content, name = 'Assistant', avatar, onAddMessage, onUpdateMessage, messageId }: DebugGuideProps) {
const { dispatch, abortControllerRef } = useChatContext();
const [isDebugging, setIsDebugging] = useState(false);
const [streamingText, setStreamingText] = useState('');
const [showStreamingMessage, setShowStreamingMessage] = useState(false);
const [localCheckpointId, setLocalCheckpointId] = useState<number | null>(null);
useEffect(() => {
onFinishLoad?.()
}, [])
const response = useMemo(() => {
try {
@@ -8,10 +8,9 @@ interface DebugResultProps {
name?: string;
avatar: string;
format?: string;
onFinishLoad?: () => void;
}
export function DebugResult({ content, name = 'Assistant', avatar, format = 'markdown', onFinishLoad }: DebugResultProps) {
export function DebugResult({ content, name = 'Assistant', avatar, format = 'markdown' }: DebugResultProps) {
const formatContent = (text: string) => {
if (format === 'markdown') {
// Simple markdown rendering for basic formatting
@@ -111,7 +110,6 @@ export function DebugResult({ content, name = 'Assistant', avatar, format = 'mar
title={title}
isWorkflowUpdate={isWorkflowUpdate}
className='p-4'
onFinishLoad={onFinishLoad}
>
<div className="prose prose-sm max-w-none">
{/* {title} */}
@@ -3,7 +3,7 @@
import { app } from "../../../utils/comfyapp";
import { useState, useRef, useEffect, useCallback } from 'react';
import { ChatResponse, Message, Node, Subgraph } from "../../../types/types";
import { ChatResponse, Message, Subgraph } from "../../../types/types";
import { Network } from 'vis-network';
import { WorkflowChatAPI } from "../../../apis/workflowChatApi";
import { generateUUID } from "../../../utils/uuid";
@@ -15,10 +15,9 @@ interface DownstreamSubgraphsProps {
name?: string;
avatar: string;
onAddMessage?: (message: Message) => void;
onFinishLoad?: () => void;
}
export function DownstreamSubgraphs({ content, name = 'Assistant', avatar, onAddMessage, onFinishLoad }: DownstreamSubgraphsProps) {
export function DownstreamSubgraphs({ content, name = 'Assistant', avatar, onAddMessage }: DownstreamSubgraphsProps) {
const { state, dispatch } = useChatContext();
const { selectedNode, installedNodes } = state;
const response = JSON.parse(content) as ChatResponse;
@@ -27,10 +26,6 @@ export function DownstreamSubgraphs({ content, name = 'Assistant', avatar, onAdd
const nodes = response.ext?.find(item => item.type === 'downstream_subgraph_search')?.data || [];
useEffect(() => {
onFinishLoad?.()
}, [])
// 将 Subgraph 转换为 vis.js 格式的函数
const convertToVisFormat = (subgraph: Subgraph) => {
const visNodes = subgraph.json.nodes.map(node => ({
@@ -11,29 +11,22 @@
// Copyright (C) 2025 ComfyUI-Copilot Authors
// Licensed under the MIT License.
import React, { useEffect } from 'react';
interface NodeInstallGuideProps {
content: string;
onLoadSubgraph?: () => void;
onFinishLoad?: () => void;
}
export function NodeInstallGuide({ content, onLoadSubgraph, onFinishLoad }: NodeInstallGuideProps) {
export function NodeInstallGuide({ content, onLoadSubgraph }: NodeInstallGuideProps) {
const response = JSON.parse(content);
const nodeInfos = response.ext?.find((item: { type: string }) => item.type === 'node_install_guide')?.data || [];
const uniqueNodeInfos = nodeInfos.reduce((acc: any[], node) => {
const uniqueNodeInfos = nodeInfos.reduce((acc: any[], node: { name: any; }) => {
if (!acc.some(n => n.name === node.name)) {
acc.push(node);
}
return acc;
}, []);
useEffect(() => {
onFinishLoad?.()
}, [])
return (
<div>
<p>Before loading the graph to canvas, the following nodes need to be installed. Please visit the corresponding GitHub repositories to install them:</p>
+4 -11
View File
@@ -1,9 +1,7 @@
// Copyright (C) 2025 AIDC-AI
// Licensed under the MIT License.
import { app } from "../../../utils/comfyapp";
import { BaseMessage } from './BaseMessage';
import { useEffect, useState } from 'react';
import { useState } from 'react';
import { ChatResponse, Node } from "../../../types/types";
import { addNodeOnGraph } from "../../../utils/graphUtils";
import { WorkflowChatAPI } from "../../../apis/workflowChatApi";
@@ -13,10 +11,9 @@ interface NodeSearchProps {
name?: string;
avatar: string;
installedNodes: any[];
onFinishLoad?: () => void;
}
export function NodeSearch({ content, name = 'Assistant', avatar, installedNodes, onFinishLoad }: NodeSearchProps) {
export function NodeSearch({ content, name = 'Assistant', avatar, installedNodes }: NodeSearchProps) {
const response = JSON.parse(content) as ChatResponse;
const [hoveredNode, setHoveredNode] = useState<string | null>(null);
const [hoveredNodeData, setHoveredNodeData] = useState<Node | null>(null);
@@ -27,12 +24,8 @@ export function NodeSearch({ content, name = 'Assistant', avatar, installedNodes
return installedNodes.some(node => node === nodeName);
};
const installedNodesList = nodes.filter(node => isNodeInstalled(node.name));
const uninstalledNodesList = nodes.filter(node => !isNodeInstalled(node.name));
useEffect(() => {
onFinishLoad?.()
}, [])
const installedNodesList = nodes.filter((node: { name: string; }) => isNodeInstalled(node.name));
const uninstalledNodesList = nodes.filter((node: { name: string; }) => !isNodeInstalled(node.name));
// 添加一个格式化数字的辅助函数
const formatNumber = (num: number) => {
+1 -6
View File
@@ -1,4 +1,3 @@
import { useEffect } from 'react';
import showcases from '../../../../../public/showcase/showcase.json';
import showcases_en from '../../../../../public/showcase/showcase_en.json';
import { useChatContext } from '../../../context/ChatContext';
@@ -18,13 +17,9 @@ const ICONS = [
<svg t="1754619682466" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22382" width="16" height="16" fill="currentColor"><path d="M812.885333 302.08v227.370667a42.666667 42.666667 0 1 0 85.333334 0V302.08q0-74.197333-52.48-126.634667-52.48-52.48-126.634667-52.48H264.405333q-74.154667 0-126.634666 52.48Q85.333333 227.925333 85.333333 302.08v454.698667q0 74.197333 52.48 126.634666 52.394667 52.394667 126.506667 52.48h341.12a42.666667 42.666667 0 1 0 0-85.333333H372.053333l278.058667-261.76 38.954667 38.784a42.666667 42.666667 0 0 0 60.16-60.501333L681.045333 499.2a42.666667 42.666667 0 0 0-59.306666-0.853333L248.32 849.792Q170.666667 842.112 170.666667 756.778667V302.08q0-38.826667 27.477333-66.304 27.434667-27.434667 66.261333-27.434667h454.698667q93.781333 0 93.781333 93.738667z m-369.408 68.224q0-110.890667-110.848-110.890667-45.952 0-78.421333 32.469334-32.426667 32.469333-32.426667 78.421333 0 45.909333 32.426667 78.378667 32.469333 32.469333 78.421333 32.469333 45.909333 0 78.378667-32.469333 32.469333-32.469333 32.469333-78.378667z m-136.405333 0q0-25.557333 25.557333-25.557333 25.514667 0 25.514667 25.557333 0 25.514667-25.514667 25.514667-25.557333 0-25.557333-25.514667z m464.213333 427.221333q-14.890667 0-28.416-6.101333a42.666667 42.666667 0 0 0-56.405333 56.448q18.688 41.429333 56.917333 66.133333 38.186667 24.661333 83.669334 24.661334 63.914667 0 109.098666-45.226667Q981.333333 848.341333 981.333333 784.426667q0-45.482667-24.661333-83.669334-24.704-38.229333-66.133333-56.917333a42.666667 42.666667 0 0 0-56.448 56.405333q6.101333 13.525333 6.101333 28.373334 0 28.586667-20.181333 48.768t-48.768 20.181333z" p-id="22383" fill="currentColor"></path></svg>
]
const Showcase: React.FC<{onFinishLoad?: () => void}> = ({onFinishLoad}) => {
const Showcase = () => {
const { dispatch, isAutoScroll, showcasIng } = useChatContext();
useEffect(() => {
onFinishLoad?.()
}, [])
const doStreamString = (data: any, isUser: boolean = false, cb: () => void = () => {}) => {
let end = 0;
const messageId = generateUUID();
@@ -4,7 +4,7 @@
import { BaseMessage } from './BaseMessage';
import { InformationCircleIcon } from '@heroicons/react/24/outline';
import { useEffect, useState } from 'react';
import { useState } from 'react';
import RestoreCheckpoint from '../../ui/RestoreCheckpoint';
interface ExtItem {
@@ -16,17 +16,12 @@ interface UserMessageProps {
content: string;
trace_id?: string;
ext?: ExtItem[];
onFinishLoad?: () => void
}
export function UserMessage({ content, trace_id, ext, onFinishLoad }: UserMessageProps) {
export function UserMessage({ content, trace_id, ext }: UserMessageProps) {
const [showTooltip, setShowTooltip] = useState(false);
const [copied, setCopied] = useState(false);
useEffect(() => {
onFinishLoad?.()
}, [])
const handleCopyTraceId = async () => {
if (trace_id) {
await navigator.clipboard.writeText(trace_id);
@@ -2,7 +2,7 @@ import { app } from "../../../utils/comfyapp";
import { ChatResponse, Workflow } from "../../../types/types";
import { WorkflowChatAPI } from "../../../apis/workflowChatApi";
import { generateUUID } from "../../../utils/uuid";
import { useEffect, useMemo, useState } from "react";
import { useEffect, useState } from "react";
import { Tooltip } from 'antd';
interface WorkflowOptionProps {
content: string;
@@ -11,7 +11,6 @@ interface WorkflowOptionProps {
latestInput: string;
installedNodes: any[];
onAddMessage?: (message: any) => void;
onFinishLoad?: () => void
}
interface NodeInfo {
@@ -20,17 +19,13 @@ interface NodeInfo {
[key: string]: any;
}
export function WorkflowOption({ content, name = 'Assistant', avatar, latestInput, installedNodes, onAddMessage, onFinishLoad }: WorkflowOptionProps) {
export function WorkflowOption({ content, name = 'Assistant', avatar, latestInput, installedNodes, onAddMessage }: WorkflowOptionProps) {
// const response = JSON.parse(content) as ChatResponse;
// const workflows = response.ext?.find(item => item.type === 'workflow')?.data || [];
const [loadingWorkflows, setLoadingWorkflows] = useState<Record<string, boolean>>({});
const [response, setResponse] = useState<ChatResponse | null>(null);
const [workflows, setWorkflows] = useState<Workflow[]>([]);
useEffect(() => {
onFinishLoad?.()
}, [])
useEffect(() => {
const _response = JSON.parse(content) as ChatResponse;
setResponse(_response);
@@ -7,24 +7,19 @@
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { ChevronDown, ChevronUp } from "lucide-react";
import { useEffect, useState } from "react";
import { useState } from "react";
interface IProps {
title?: string | React.ReactNode;
isWorkflowUpdate?: boolean;
className?: string;
onFinishLoad?: () => void;
children: React.ReactNode;
}
const DebugCollapsibleCard: React.FC<IProps> = (props) => {
const { title = '', isWorkflowUpdate = false, className = '', onFinishLoad, children } = props;
const { title = '', isWorkflowUpdate = false, className = '', children } = props;
const [isOpen, setIsOpen] = useState(false);
useEffect(() => {
onFinishLoad?.();
}, []);
return (
<div className={`relative rounded-lg flex flex-col beautify-card ${className} ${!isOpen ? 'h-[200px]' : ''}`}>
+1
View File
@@ -39,6 +39,7 @@ export interface Node {
description: string;
image: string;
github_url: string;
github_stars: number;
from_index: number;
to_index: number;
}