dishui 0.0.47 → 0.0.49
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.
- package/dist/components/pro/CodeEditor/editors/MarkdownEditor.js +1 -2
- package/dist/components/pro/CodeEditor/editors/MarkdownEditor.js.map +1 -1
- package/dist/components/pro/CodeEditor/themes.js +0 -25
- package/dist/components/pro/CodeEditor/themes.js.map +1 -1
- package/dist/components/pro/CodeEditor/types.d.ts +1 -1
- package/dist/components/pro/Flow/Flow.js +500 -483
- package/dist/components/pro/Flow/Flow.js.map +1 -1
- package/dist/components/pro/Flow/FlowCanvas.js +526 -524
- package/dist/components/pro/Flow/FlowCanvas.js.map +1 -1
- package/dist/components/pro/Flow/canvas/GridRenderer.d.ts +3 -0
- package/dist/components/pro/Flow/canvas/GridRenderer.js +28 -23
- package/dist/components/pro/Flow/canvas/GridRenderer.js.map +1 -1
- package/dist/components/pro/Flow/canvas/MiniMapRenderer.js +18 -17
- package/dist/components/pro/Flow/canvas/MiniMapRenderer.js.map +1 -1
- package/dist/components/pro/Flow/canvas/PixiApp.d.ts +2 -0
- package/dist/components/pro/Flow/canvas/PixiApp.js +14 -11
- package/dist/components/pro/Flow/canvas/PixiApp.js.map +1 -1
- package/dist/components/pro/Flow/constants.js +7 -7
- package/dist/components/pro/Flow/constants.js.map +1 -1
- package/dist/components/pro/Flow/context/FlowAIContext.d.ts +15 -0
- package/dist/components/pro/Flow/context/FlowAIContext.js +32 -0
- package/dist/components/pro/Flow/context/FlowAIContext.js.map +1 -0
- package/dist/components/pro/Flow/context/FlowUIContext.d.ts +4 -1
- package/dist/components/pro/Flow/context/FlowUIContext.js +58 -55
- package/dist/components/pro/Flow/context/FlowUIContext.js.map +1 -1
- package/dist/components/pro/Flow/edges/EdgeRenderer.js +22 -21
- package/dist/components/pro/Flow/edges/EdgeRenderer.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useFlowImportExport.js +32 -32
- package/dist/components/pro/Flow/hooks/useFlowImportExport.js.map +1 -1
- package/dist/components/pro/Flow/hooks/usePixiApp.d.ts +6 -1
- package/dist/components/pro/Flow/hooks/usePixiApp.js +49 -30
- package/dist/components/pro/Flow/hooks/usePixiApp.js.map +1 -1
- package/dist/components/pro/Flow/index.d.ts +2 -0
- package/dist/components/pro/Flow/lines/FreehandTool.js +21 -20
- package/dist/components/pro/Flow/lines/FreehandTool.js.map +1 -1
- package/dist/components/pro/Flow/lines/GeometricLineTool.js +22 -18
- package/dist/components/pro/Flow/lines/GeometricLineTool.js.map +1 -1
- package/dist/components/pro/Flow/lines/LineRenderer.js +19 -18
- package/dist/components/pro/Flow/lines/LineRenderer.js.map +1 -1
- package/dist/components/pro/Flow/nodes/MediaContent.js +143 -124
- package/dist/components/pro/Flow/nodes/MediaContent.js.map +1 -1
- package/dist/components/pro/Flow/nodes/MediaOverlay.js +22 -17
- package/dist/components/pro/Flow/nodes/MediaOverlay.js.map +1 -1
- package/dist/components/pro/Flow/nodes/NodeRenderer.js +77 -76
- package/dist/components/pro/Flow/nodes/NodeRenderer.js.map +1 -1
- package/dist/components/pro/Flow/nodes/aiClient.d.ts +22 -0
- package/dist/components/pro/Flow/nodes/aiClient.js +107 -54
- package/dist/components/pro/Flow/nodes/aiClient.js.map +1 -1
- package/dist/components/pro/Flow/nodes/svgIcons.js +6 -6
- package/dist/components/pro/Flow/nodes/svgIcons.js.map +1 -1
- package/dist/components/pro/Flow/panels/AIPanel.d.ts +2 -0
- package/dist/components/pro/Flow/panels/AIPanel.js +498 -0
- package/dist/components/pro/Flow/panels/AIPanel.js.map +1 -0
- package/dist/components/pro/Flow/panels/FlowPanelGroup.js +51 -39
- package/dist/components/pro/Flow/panels/FlowPanelGroup.js.map +1 -1
- package/dist/components/pro/Flow/panels/FlowToolbar.js +91 -85
- package/dist/components/pro/Flow/panels/FlowToolbar.js.map +1 -1
- package/dist/components/pro/Flow/panels/InspectorPanel.js +372 -332
- package/dist/components/pro/Flow/panels/InspectorPanel.js.map +1 -1
- package/dist/components/pro/Flow/panels/OutlinePanel.js +28 -27
- package/dist/components/pro/Flow/panels/OutlinePanel.js.map +1 -1
- package/dist/components/pro/Flow/panels/ShapePalette.js +107 -104
- package/dist/components/pro/Flow/panels/ShapePalette.js.map +1 -1
- package/dist/components/pro/Flow/panels/toolbarIcons.d.ts +1 -0
- package/dist/components/pro/Flow/panels/toolbarIcons.js +25 -20
- package/dist/components/pro/Flow/panels/toolbarIcons.js.map +1 -1
- package/dist/components/pro/Flow/types.d.ts +13 -0
- package/dist/components/pro/Flow/types.js.map +1 -1
- package/dist/components/pro/Flow/utils/themeColor.d.ts +87 -0
- package/dist/components/pro/Flow/utils/themeColor.js +212 -0
- package/dist/components/pro/Flow/utils/themeColor.js.map +1 -0
- package/dist/contexts/AppContext.d.ts +1 -1
- package/dist/contexts/AppContext.js +28 -29
- package/dist/contexts/AppContext.js.map +1 -1
- package/dist/dishui.css +1 -1
- package/dist/favicon.svg +10 -0
- package/dist/flow.js +56 -51
- package/dist/styles/themeStyles.js +6 -11
- package/dist/styles/themeStyles.js.map +1 -1
- package/dist/utils/themes.js +3 -23
- package/dist/utils/themes.js.map +1 -1
- package/package.json +17 -18
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
import C from "../../../Button/index.js";
|
|
2
|
+
import E from "../../../Input/index.js";
|
|
3
|
+
import O from "../../../Label/index.js";
|
|
4
|
+
import le from "../../../Select/index.js";
|
|
5
|
+
import { DEFAULT_EDGE_DATA as re, DEFAULT_NODE_DATA as ie, ROOT_CANVAS_ID as K } from "../constants.js";
|
|
6
|
+
import { useFlowContext as ce } from "../context/FlowContext.js";
|
|
7
|
+
import { useFlowAI as de } from "../context/FlowAIContext.js";
|
|
8
|
+
import { completeAIChatStream as ue } from "../nodes/aiClient.js";
|
|
9
|
+
import { useCallback as w, useEffect as W, useRef as A, useState as h } from "react";
|
|
10
|
+
import { jsx as a, jsxs as c } from "react/jsx-runtime";
|
|
11
|
+
var me = `You are a diagramming assistant for a flowchart editor. Convert the user's request (a description, or an uploaded diagram image to reproduce) into a flow document.
|
|
12
|
+
|
|
13
|
+
Reply with ONE fenced \`\`\`json code block and nothing else. The JSON must match:
|
|
14
|
+
{
|
|
15
|
+
"canvases": {
|
|
16
|
+
"root": {
|
|
17
|
+
"nodes": [
|
|
18
|
+
{ "id": "n1", "type": "shapeRoundRect", "position": {"x": 80, "y": 80}, "width": 160, "height": 64,
|
|
19
|
+
"data": { "label": "Start" } }
|
|
20
|
+
],
|
|
21
|
+
"edges": [
|
|
22
|
+
{ "id": "e1", "source": "n1", "target": "n2", "type": "smoothstep",
|
|
23
|
+
"data": { "labelText": "yes" } }
|
|
24
|
+
],
|
|
25
|
+
"lines": []
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"stack": ["root"]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
Rules:
|
|
32
|
+
- Node "type" is one of: shapeRect, shapeRoundRect, shapeEllipse, shapeDiamond, shapeParallelogram, shapeDocument, shapeHexagon. Use shapeDiamond for decisions, shapeRoundRect for processes, shapeEllipse for start/end.
|
|
33
|
+
- Give every node a unique "id". Every edge "source"/"target" must reference an existing node id.
|
|
34
|
+
- Lay nodes out on a readable grid (top-to-bottom or left-to-right), spacing ~180px, no overlaps. Widths ~140-180, heights ~56-72 (diamonds ~120x100).
|
|
35
|
+
- Put a short "label" on each node. Optional edge label goes in data.labelText.
|
|
36
|
+
- Do NOT include colors; the editor themes them automatically.
|
|
37
|
+
- Output ONLY the JSON code block.`;
|
|
38
|
+
function pe(i) {
|
|
39
|
+
let o = i.trim();
|
|
40
|
+
const d = /```(?:json)?\s*([\s\S]*?)```/i.exec(o);
|
|
41
|
+
if (d) o = d[1].trim();
|
|
42
|
+
else {
|
|
43
|
+
const n = o.indexOf("{"), u = o.lastIndexOf("}");
|
|
44
|
+
n >= 0 && u > n && (o = o.slice(n, u + 1));
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const n = JSON.parse(o);
|
|
48
|
+
return !n || typeof n != "object" || !n.canvases ? null : n;
|
|
49
|
+
} catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function he(i) {
|
|
54
|
+
const o = i.canvases ?? {}, d = o[i.stack?.[i.stack.length - 1] ?? "root"] ?? o.root ?? {
|
|
55
|
+
nodes: [],
|
|
56
|
+
edges: [],
|
|
57
|
+
lines: []
|
|
58
|
+
}, n = (d.nodes ?? []).map((t, m) => ({
|
|
59
|
+
id: t.id ?? `n${m + 1}`,
|
|
60
|
+
type: t.type ?? "shapeRoundRect",
|
|
61
|
+
position: {
|
|
62
|
+
x: Number(t.position?.x ?? 80),
|
|
63
|
+
y: Number(t.position?.y ?? 80 + m * 120)
|
|
64
|
+
},
|
|
65
|
+
width: Number(t.width ?? 160),
|
|
66
|
+
height: Number(t.height ?? 64),
|
|
67
|
+
zIndex: t.zIndex ?? m,
|
|
68
|
+
data: {
|
|
69
|
+
...ie,
|
|
70
|
+
...t.data ?? {},
|
|
71
|
+
label: t.data?.label ?? t.label ?? "Node"
|
|
72
|
+
}
|
|
73
|
+
})), u = new Map(n.map((t) => [t.id, t])), v = (d.edges ?? []).map((t, m) => ({
|
|
74
|
+
id: t.id ?? `e${m + 1}`,
|
|
75
|
+
source: t.source,
|
|
76
|
+
target: t.target,
|
|
77
|
+
type: t.type ?? "smoothstep",
|
|
78
|
+
data: {
|
|
79
|
+
...re,
|
|
80
|
+
...t.data ?? {}
|
|
81
|
+
}
|
|
82
|
+
})).filter((t) => t.source && t.target).map((t) => fe(t, u));
|
|
83
|
+
return {
|
|
84
|
+
canvases: { [K]: {
|
|
85
|
+
nodes: n,
|
|
86
|
+
edges: v,
|
|
87
|
+
lines: []
|
|
88
|
+
} },
|
|
89
|
+
stack: [K]
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function fe(i, o) {
|
|
93
|
+
const d = o.get(i.source), n = o.get(i.target);
|
|
94
|
+
if (!d || !n || d === n) return i;
|
|
95
|
+
const u = n.position.x + n.width / 2 - (d.position.x + d.width / 2), v = n.position.y + n.height / 2 - (d.position.y + d.height / 2);
|
|
96
|
+
if (Math.abs(u) >= Math.abs(v)) {
|
|
97
|
+
const m = u >= 0;
|
|
98
|
+
return {
|
|
99
|
+
...i,
|
|
100
|
+
sourceHandle: m ? "r_0.5" : "l_0.5",
|
|
101
|
+
targetHandle: m ? "l_0.5" : "r_0.5"
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
const t = v >= 0;
|
|
105
|
+
return {
|
|
106
|
+
...i,
|
|
107
|
+
sourceHandle: t ? "b_0.5" : "t_0.5",
|
|
108
|
+
targetHandle: t ? "t_0.5" : "b_0.5"
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
var ge = [{
|
|
112
|
+
value: "openai",
|
|
113
|
+
label: "OpenAI 兼容"
|
|
114
|
+
}, {
|
|
115
|
+
value: "anthropic",
|
|
116
|
+
label: "Anthropic"
|
|
117
|
+
}], we = 2e4;
|
|
118
|
+
function Oe() {
|
|
119
|
+
const { setDoc: i } = ce(), { aiConfig: o, setAIConfig: d, showAIConfig: n } = de(), [u, v] = h(""), [t, m] = h(null), [D, L] = h(!1), [S, R] = h(null), [M, y] = h(null), [_, Y] = h(!1), [q, F] = h(!1), [f, N] = h(null), [V, U] = h(0), T = A(null), H = A(null), $ = A(null), j = A(null), k = A(""), I = w((e) => {
|
|
120
|
+
d({
|
|
121
|
+
...o,
|
|
122
|
+
...e
|
|
123
|
+
});
|
|
124
|
+
}, [o, d]), Q = w((e) => {
|
|
125
|
+
const s = e.target.files?.[0];
|
|
126
|
+
if (e.target.value = "", !s) return;
|
|
127
|
+
const r = new FileReader();
|
|
128
|
+
r.onload = () => m(r.result), r.readAsDataURL(s);
|
|
129
|
+
}, []), J = w((e) => {
|
|
130
|
+
const s = e.clipboardData?.items;
|
|
131
|
+
if (s) {
|
|
132
|
+
for (const r of s) if (r.type.startsWith("image/")) {
|
|
133
|
+
const p = r.getAsFile();
|
|
134
|
+
if (p) {
|
|
135
|
+
e.preventDefault();
|
|
136
|
+
const x = new FileReader();
|
|
137
|
+
x.onload = () => m(x.result), x.readAsDataURL(p);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}, []);
|
|
143
|
+
W(() => {
|
|
144
|
+
const e = window.setInterval(() => {
|
|
145
|
+
U((s) => {
|
|
146
|
+
const r = k.current.length;
|
|
147
|
+
return s >= r ? s : s + Math.max(8, Math.ceil((r - s) / 8));
|
|
148
|
+
});
|
|
149
|
+
}, 40);
|
|
150
|
+
return () => window.clearInterval(e);
|
|
151
|
+
}, []);
|
|
152
|
+
const b = k.current.slice(0, V);
|
|
153
|
+
W(() => {
|
|
154
|
+
const e = $.current;
|
|
155
|
+
e && (e.scrollTop = e.scrollHeight);
|
|
156
|
+
const s = j.current;
|
|
157
|
+
s && (s.scrollTop = s.scrollHeight);
|
|
158
|
+
}, [b, _]);
|
|
159
|
+
const X = w(async () => {
|
|
160
|
+
if (D) return;
|
|
161
|
+
if (!o.gateway || !o.model) {
|
|
162
|
+
R("请先配置 AI 接口地址与模型");
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (!u.trim() && !t) {
|
|
166
|
+
R("请输入需求描述,或上传一张流程图");
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
R(null), y("正在生成…"), k.current = "", U(0), F(!1), N(null), L(!0);
|
|
170
|
+
const e = new AbortController();
|
|
171
|
+
T.current = e;
|
|
172
|
+
try {
|
|
173
|
+
const s = await ue(o, u.trim() || "请根据这张图片复刻出对应的流程图。", {
|
|
174
|
+
imageDataUrl: t ?? void 0,
|
|
175
|
+
systemPrompt: me,
|
|
176
|
+
signal: e.signal,
|
|
177
|
+
onDelta: (p) => {
|
|
178
|
+
k.current = p;
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
F(!0);
|
|
182
|
+
const r = pe(s);
|
|
183
|
+
if (!r) {
|
|
184
|
+
R("AI 返回内容无法解析为流程图,请重试或调整描述"), y(null);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
N(he(r)), y(null);
|
|
188
|
+
} catch (s) {
|
|
189
|
+
s?.name !== "AbortError" && R(s?.message ?? "生成失败"), y(null);
|
|
190
|
+
} finally {
|
|
191
|
+
L(!1), T.current = null;
|
|
192
|
+
}
|
|
193
|
+
}, [
|
|
194
|
+
D,
|
|
195
|
+
o,
|
|
196
|
+
u,
|
|
197
|
+
t
|
|
198
|
+
]), Z = w(() => T.current?.abort(), []), ee = w(() => {
|
|
199
|
+
if (!f) return;
|
|
200
|
+
const e = f.canvases.root ?? {
|
|
201
|
+
nodes: [],
|
|
202
|
+
edges: [],
|
|
203
|
+
lines: []
|
|
204
|
+
};
|
|
205
|
+
i((s) => {
|
|
206
|
+
const r = s.stack[s.stack.length - 1] ?? "root", p = s.canvases[r] ?? {
|
|
207
|
+
nodes: [],
|
|
208
|
+
edges: [],
|
|
209
|
+
lines: []
|
|
210
|
+
}, x = /* @__PURE__ */ new Set([
|
|
211
|
+
...p.nodes.map((l) => l.id),
|
|
212
|
+
...p.edges.map((l) => l.id),
|
|
213
|
+
...p.lines.map((l) => l.id)
|
|
214
|
+
]), G = (l) => {
|
|
215
|
+
let g = l, ne = 1;
|
|
216
|
+
for (; x.has(g); ) g = `${l}_${ne++}`;
|
|
217
|
+
return x.add(g), g;
|
|
218
|
+
}, P = /* @__PURE__ */ new Map(), se = e.nodes.map((l) => {
|
|
219
|
+
const g = G(l.id);
|
|
220
|
+
return P.set(l.id, g), {
|
|
221
|
+
...l,
|
|
222
|
+
id: g
|
|
223
|
+
};
|
|
224
|
+
}), oe = e.edges.map((l) => ({
|
|
225
|
+
...l,
|
|
226
|
+
id: G(l.id),
|
|
227
|
+
source: P.get(l.source) ?? l.source,
|
|
228
|
+
target: P.get(l.target) ?? l.target
|
|
229
|
+
}));
|
|
230
|
+
return {
|
|
231
|
+
...s,
|
|
232
|
+
canvases: {
|
|
233
|
+
...s.canvases,
|
|
234
|
+
[r]: {
|
|
235
|
+
nodes: [...p.nodes, ...se],
|
|
236
|
+
edges: [...p.edges, ...oe],
|
|
237
|
+
lines: p.lines
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
}), N(null), y("已插入流程图");
|
|
242
|
+
}, [f, i]), te = w(() => {
|
|
243
|
+
if (!f) return;
|
|
244
|
+
const e = f.canvases.root ?? {
|
|
245
|
+
nodes: [],
|
|
246
|
+
edges: [],
|
|
247
|
+
lines: []
|
|
248
|
+
};
|
|
249
|
+
i((s) => {
|
|
250
|
+
const r = s.stack[s.stack.length - 1] ?? "root";
|
|
251
|
+
return {
|
|
252
|
+
...s,
|
|
253
|
+
canvases: {
|
|
254
|
+
...s.canvases,
|
|
255
|
+
[r]: {
|
|
256
|
+
nodes: e.nodes,
|
|
257
|
+
edges: e.edges,
|
|
258
|
+
lines: []
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
}), N(null), y("已替换画布");
|
|
263
|
+
}, [f, i]), z = b.length, ae = z >= k.current.length, B = q && ae ? 100 : Math.min(99, Math.floor(z / we * 99));
|
|
264
|
+
return /* @__PURE__ */ c("div", {
|
|
265
|
+
className: "flow-ai-panel",
|
|
266
|
+
onPaste: J,
|
|
267
|
+
children: [
|
|
268
|
+
n && /* @__PURE__ */ c("div", {
|
|
269
|
+
className: "flow-ai-section",
|
|
270
|
+
children: [
|
|
271
|
+
/* @__PURE__ */ a("div", {
|
|
272
|
+
className: "flow-ai-section-title",
|
|
273
|
+
children: "模型配置"
|
|
274
|
+
}),
|
|
275
|
+
/* @__PURE__ */ c("div", {
|
|
276
|
+
className: "flow-inspector-row",
|
|
277
|
+
children: [/* @__PURE__ */ a(O, {
|
|
278
|
+
size: "xs",
|
|
279
|
+
className: "flow-inspector-label",
|
|
280
|
+
children: "协议"
|
|
281
|
+
}), /* @__PURE__ */ a(le, {
|
|
282
|
+
options: ge,
|
|
283
|
+
value: o.protocol,
|
|
284
|
+
onChange: (e) => I({ protocol: e }),
|
|
285
|
+
style: { fontSize: 12 }
|
|
286
|
+
})]
|
|
287
|
+
}),
|
|
288
|
+
/* @__PURE__ */ c("div", {
|
|
289
|
+
className: "flow-inspector-row",
|
|
290
|
+
children: [/* @__PURE__ */ a(O, {
|
|
291
|
+
size: "xs",
|
|
292
|
+
className: "flow-inspector-label",
|
|
293
|
+
children: "接口地址"
|
|
294
|
+
}), /* @__PURE__ */ a(E, {
|
|
295
|
+
size: "xs",
|
|
296
|
+
value: o.gateway,
|
|
297
|
+
placeholder: "https://api.moonshot.cn/v1",
|
|
298
|
+
onChange: (e) => I({ gateway: e.target.value })
|
|
299
|
+
})]
|
|
300
|
+
}),
|
|
301
|
+
/* @__PURE__ */ c("div", {
|
|
302
|
+
className: "flow-inspector-row",
|
|
303
|
+
children: [/* @__PURE__ */ a(O, {
|
|
304
|
+
size: "xs",
|
|
305
|
+
className: "flow-inspector-label",
|
|
306
|
+
children: "模型"
|
|
307
|
+
}), /* @__PURE__ */ a(E, {
|
|
308
|
+
size: "xs",
|
|
309
|
+
value: o.model,
|
|
310
|
+
placeholder: "gpt-4o-mini",
|
|
311
|
+
onChange: (e) => I({ model: e.target.value })
|
|
312
|
+
})]
|
|
313
|
+
}),
|
|
314
|
+
/* @__PURE__ */ c("div", {
|
|
315
|
+
className: "flow-inspector-row",
|
|
316
|
+
children: [/* @__PURE__ */ a(O, {
|
|
317
|
+
size: "xs",
|
|
318
|
+
className: "flow-inspector-label",
|
|
319
|
+
children: "API Key"
|
|
320
|
+
}), /* @__PURE__ */ a(E, {
|
|
321
|
+
size: "xs",
|
|
322
|
+
type: "password",
|
|
323
|
+
value: o.apiKey ?? "",
|
|
324
|
+
placeholder: "sk-…",
|
|
325
|
+
onChange: (e) => I({ apiKey: e.target.value })
|
|
326
|
+
})]
|
|
327
|
+
})
|
|
328
|
+
]
|
|
329
|
+
}),
|
|
330
|
+
/* @__PURE__ */ c("div", {
|
|
331
|
+
className: "flow-ai-section",
|
|
332
|
+
children: [
|
|
333
|
+
/* @__PURE__ */ a("div", {
|
|
334
|
+
className: "flow-ai-section-title",
|
|
335
|
+
children: "生成流程图"
|
|
336
|
+
}),
|
|
337
|
+
/* @__PURE__ */ a("textarea", {
|
|
338
|
+
className: "flow-ai-textarea",
|
|
339
|
+
value: u,
|
|
340
|
+
placeholder: "描述你想要的流程,例如:用户注册流程,包含邮箱校验、发送验证码、创建账号等步骤(可直接粘贴图片)",
|
|
341
|
+
onChange: (e) => v(e.target.value),
|
|
342
|
+
onPaste: J,
|
|
343
|
+
onPointerDown: (e) => e.stopPropagation()
|
|
344
|
+
}),
|
|
345
|
+
/* @__PURE__ */ c("div", {
|
|
346
|
+
className: "flow-ai-image-row",
|
|
347
|
+
children: [
|
|
348
|
+
/* @__PURE__ */ a("input", {
|
|
349
|
+
ref: H,
|
|
350
|
+
type: "file",
|
|
351
|
+
accept: "image/*",
|
|
352
|
+
style: { display: "none" },
|
|
353
|
+
onChange: Q
|
|
354
|
+
}),
|
|
355
|
+
t ? /* @__PURE__ */ c("div", {
|
|
356
|
+
className: "flow-ai-image-preview",
|
|
357
|
+
children: [/* @__PURE__ */ a("img", {
|
|
358
|
+
src: t,
|
|
359
|
+
alt: "参考图"
|
|
360
|
+
}), /* @__PURE__ */ a("button", {
|
|
361
|
+
type: "button",
|
|
362
|
+
className: "flow-ai-image-remove",
|
|
363
|
+
title: "移除图片",
|
|
364
|
+
onClick: () => m(null),
|
|
365
|
+
children: "×"
|
|
366
|
+
})]
|
|
367
|
+
}) : /* @__PURE__ */ a(C, {
|
|
368
|
+
size: "xs",
|
|
369
|
+
variant: "ghost",
|
|
370
|
+
onClick: () => H.current?.click(),
|
|
371
|
+
children: "上传流程图图片"
|
|
372
|
+
}),
|
|
373
|
+
/* @__PURE__ */ a("span", {
|
|
374
|
+
className: "flow-ai-hint",
|
|
375
|
+
children: "或粘贴图片 (Ctrl/⌘+V)"
|
|
376
|
+
})
|
|
377
|
+
]
|
|
378
|
+
}),
|
|
379
|
+
/* @__PURE__ */ a("div", {
|
|
380
|
+
className: "flow-ai-actions",
|
|
381
|
+
children: D ? /* @__PURE__ */ a(C, {
|
|
382
|
+
size: "xs",
|
|
383
|
+
variant: "ghost",
|
|
384
|
+
onClick: Z,
|
|
385
|
+
children: "停止"
|
|
386
|
+
}) : /* @__PURE__ */ a(C, {
|
|
387
|
+
size: "xs",
|
|
388
|
+
variant: "primary",
|
|
389
|
+
onClick: X,
|
|
390
|
+
children: "生成流程图"
|
|
391
|
+
})
|
|
392
|
+
}),
|
|
393
|
+
(D || b) && /* @__PURE__ */ c("div", {
|
|
394
|
+
className: "flow-ai-stream",
|
|
395
|
+
children: [
|
|
396
|
+
/* @__PURE__ */ c("div", {
|
|
397
|
+
className: "flow-ai-progress",
|
|
398
|
+
children: [/* @__PURE__ */ a("div", {
|
|
399
|
+
className: "flow-ai-progress-track",
|
|
400
|
+
children: /* @__PURE__ */ a("div", {
|
|
401
|
+
className: "flow-ai-progress-bar",
|
|
402
|
+
style: { width: `${B}%` }
|
|
403
|
+
})
|
|
404
|
+
}), /* @__PURE__ */ c("span", {
|
|
405
|
+
className: "flow-ai-progress-label",
|
|
406
|
+
children: [B, "%"]
|
|
407
|
+
})]
|
|
408
|
+
}),
|
|
409
|
+
/* @__PURE__ */ c("button", {
|
|
410
|
+
type: "button",
|
|
411
|
+
className: "flow-ai-stream-header",
|
|
412
|
+
onClick: () => Y((e) => !e),
|
|
413
|
+
children: [
|
|
414
|
+
/* @__PURE__ */ a("span", {
|
|
415
|
+
className: `flow-ai-stream-chevron${_ ? " flow-ai-stream-chevron--open" : ""}`,
|
|
416
|
+
children: "▸"
|
|
417
|
+
}),
|
|
418
|
+
/* @__PURE__ */ a("span", { children: "返回内容" }),
|
|
419
|
+
/* @__PURE__ */ c("span", {
|
|
420
|
+
className: "flow-ai-stream-count",
|
|
421
|
+
children: [z.toLocaleString(), " 字符"]
|
|
422
|
+
})
|
|
423
|
+
]
|
|
424
|
+
}),
|
|
425
|
+
_ ? /* @__PURE__ */ a("pre", {
|
|
426
|
+
ref: $,
|
|
427
|
+
className: "flow-ai-stream-body",
|
|
428
|
+
children: b || "等待返回…"
|
|
429
|
+
}) : b && /* @__PURE__ */ a("pre", {
|
|
430
|
+
ref: j,
|
|
431
|
+
className: "flow-ai-stream-tail",
|
|
432
|
+
children: b
|
|
433
|
+
})
|
|
434
|
+
]
|
|
435
|
+
}),
|
|
436
|
+
M && !S && /* @__PURE__ */ a("div", {
|
|
437
|
+
className: "flow-ai-status",
|
|
438
|
+
children: M
|
|
439
|
+
}),
|
|
440
|
+
S && /* @__PURE__ */ a("div", {
|
|
441
|
+
className: "flow-media-error",
|
|
442
|
+
children: S
|
|
443
|
+
})
|
|
444
|
+
]
|
|
445
|
+
}),
|
|
446
|
+
f && /* @__PURE__ */ a("div", {
|
|
447
|
+
className: "flow-ai-dialog-overlay",
|
|
448
|
+
onClick: () => N(null),
|
|
449
|
+
children: /* @__PURE__ */ c("div", {
|
|
450
|
+
className: "flow-ai-dialog",
|
|
451
|
+
role: "dialog",
|
|
452
|
+
"aria-modal": "true",
|
|
453
|
+
"aria-label": "流程图已生成",
|
|
454
|
+
onClick: (e) => e.stopPropagation(),
|
|
455
|
+
children: [
|
|
456
|
+
/* @__PURE__ */ a("div", {
|
|
457
|
+
className: "flow-ai-dialog-title",
|
|
458
|
+
children: "流程图已生成"
|
|
459
|
+
}),
|
|
460
|
+
/* @__PURE__ */ a("div", {
|
|
461
|
+
className: "flow-ai-dialog-desc",
|
|
462
|
+
children: "插入:将生成内容追加到当前画布;替换:清空当前画布后再插入。"
|
|
463
|
+
}),
|
|
464
|
+
/* @__PURE__ */ c("div", {
|
|
465
|
+
className: "flow-ai-dialog-actions",
|
|
466
|
+
children: [
|
|
467
|
+
/* @__PURE__ */ a(C, {
|
|
468
|
+
size: "xs",
|
|
469
|
+
variant: "ghost",
|
|
470
|
+
onClick: () => N(null),
|
|
471
|
+
children: "取消"
|
|
472
|
+
}),
|
|
473
|
+
/* @__PURE__ */ a(C, {
|
|
474
|
+
size: "xs",
|
|
475
|
+
variant: "neutral",
|
|
476
|
+
outline: !0,
|
|
477
|
+
onClick: ee,
|
|
478
|
+
children: "插入"
|
|
479
|
+
}),
|
|
480
|
+
/* @__PURE__ */ a(C, {
|
|
481
|
+
size: "xs",
|
|
482
|
+
variant: "primary",
|
|
483
|
+
onClick: te,
|
|
484
|
+
children: "替换"
|
|
485
|
+
})
|
|
486
|
+
]
|
|
487
|
+
})
|
|
488
|
+
]
|
|
489
|
+
})
|
|
490
|
+
})
|
|
491
|
+
]
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
export {
|
|
495
|
+
Oe as AIPanelContent
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
//# sourceMappingURL=AIPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AIPanel.js","names":[],"sources":["../../../../../src/components/pro/Flow/panels/AIPanel.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport Button from '../../../Button';\nimport Input from '../../../Input';\nimport Select from '../../../Select';\nimport Label from '../../../Label';\nimport { useFlowContext } from '../context/FlowContext';\nimport { useFlowAI } from '../context/FlowAIContext';\nimport { completeAIChatStream } from '../nodes/aiClient';\nimport { ROOT_CANVAS_ID, DEFAULT_NODE_DATA, DEFAULT_EDGE_DATA } from '../constants';\nimport type { FlowAIConfig, FlowDocument } from '../types';\n\n/**\n * System prompt that constrains the model to emit a FlowDocument JSON so the\n * result can be parsed and loaded directly onto the canvas.\n */\nconst SYSTEM_PROMPT = `You are a diagramming assistant for a flowchart editor. Convert the user's request (a description, or an uploaded diagram image to reproduce) into a flow document.\n\nReply with ONE fenced \\`\\`\\`json code block and nothing else. The JSON must match:\n{\n \"canvases\": {\n \"root\": {\n \"nodes\": [\n { \"id\": \"n1\", \"type\": \"shapeRoundRect\", \"position\": {\"x\": 80, \"y\": 80}, \"width\": 160, \"height\": 64,\n \"data\": { \"label\": \"Start\" } }\n ],\n \"edges\": [\n { \"id\": \"e1\", \"source\": \"n1\", \"target\": \"n2\", \"type\": \"smoothstep\",\n \"data\": { \"labelText\": \"yes\" } }\n ],\n \"lines\": []\n }\n },\n \"stack\": [\"root\"]\n}\n\nRules:\n- Node \"type\" is one of: shapeRect, shapeRoundRect, shapeEllipse, shapeDiamond, shapeParallelogram, shapeDocument, shapeHexagon. Use shapeDiamond for decisions, shapeRoundRect for processes, shapeEllipse for start/end.\n- Give every node a unique \"id\". Every edge \"source\"/\"target\" must reference an existing node id.\n- Lay nodes out on a readable grid (top-to-bottom or left-to-right), spacing ~180px, no overlaps. Widths ~140-180, heights ~56-72 (diamonds ~120x100).\n- Put a short \"label\" on each node. Optional edge label goes in data.labelText.\n- Do NOT include colors; the editor themes them automatically.\n- Output ONLY the JSON code block.`;\n\n/** Extract and parse the first JSON object from an AI reply. */\nfunction parseFlowJson(text: string): FlowDocument | null {\n let raw = text.trim();\n const fence = /```(?:json)?\\s*([\\s\\S]*?)```/i.exec(raw);\n if (fence) raw = fence[1].trim();\n else {\n const start = raw.indexOf('{');\n const end = raw.lastIndexOf('}');\n if (start >= 0 && end > start) raw = raw.slice(start, end + 1);\n }\n try {\n const parsed = JSON.parse(raw);\n if (!parsed || typeof parsed !== 'object' || !parsed.canvases) return null;\n return parsed as FlowDocument;\n } catch {\n return null;\n }\n}\n\n/** Normalize an AI-produced document: fill defaults, ensure a root canvas. */\nfunction normalizeAIDocument(doc: FlowDocument): FlowDocument {\n const canvases = doc.canvases ?? {};\n const rootKey = doc.stack?.[doc.stack.length - 1] ?? ROOT_CANVAS_ID;\n const canvas = canvases[rootKey] ?? canvases[ROOT_CANVAS_ID] ?? { nodes: [], edges: [], lines: [] };\n const nodes = (canvas.nodes ?? []).map((n: any, i: number) => ({\n id: n.id ?? `n${i + 1}`,\n type: n.type ?? 'shapeRoundRect',\n position: { x: Number(n.position?.x ?? 80), y: Number(n.position?.y ?? 80 + i * 120) },\n width: Number(n.width ?? 160),\n height: Number(n.height ?? 64),\n zIndex: n.zIndex ?? i,\n data: { ...DEFAULT_NODE_DATA, ...(n.data ?? {}), label: n.data?.label ?? n.label ?? 'Node' },\n }));\n const nodeById = new Map<string, any>(nodes.map((n) => [n.id, n]));\n const edges = (canvas.edges ?? []).map((e: any, i: number) => ({\n id: e.id ?? `e${i + 1}`,\n source: e.source,\n target: e.target,\n type: e.type ?? 'smoothstep',\n data: { ...DEFAULT_EDGE_DATA, ...(e.data ?? {}) },\n })).filter((e: any) => e.source && e.target)\n .map((e: any) => pinEdgeToSideMidpoints(e, nodeById));\n return {\n canvases: { [ROOT_CANVAS_ID]: { nodes, edges, lines: [] } },\n stack: [ROOT_CANVAS_ID],\n };\n}\n\n/**\n * Pin an AI-generated edge to the midpoint handles of the facing node sides\n * (`r_0.5` / `l_0.5` / `t_0.5` / `b_0.5`) so connections attach at the center\n * of each side instead of sliding along the side toward the other node.\n */\nfunction pinEdgeToSideMidpoints(edge: any, nodeById: Map<string, any>): any {\n const s = nodeById.get(edge.source);\n const t = nodeById.get(edge.target);\n if (!s || !t || s === t) return edge;\n const dx = (t.position.x + t.width / 2) - (s.position.x + s.width / 2);\n const dy = (t.position.y + t.height / 2) - (s.position.y + s.height / 2);\n if (Math.abs(dx) >= Math.abs(dy)) {\n const forward = dx >= 0;\n return {\n ...edge,\n sourceHandle: forward ? 'r_0.5' : 'l_0.5',\n targetHandle: forward ? 'l_0.5' : 'r_0.5',\n };\n }\n const forward = dy >= 0;\n return {\n ...edge,\n sourceHandle: forward ? 'b_0.5' : 't_0.5',\n targetHandle: forward ? 't_0.5' : 'b_0.5',\n };\n}\n\nconst PROTOCOL_OPTIONS = [\n { value: 'openai', label: 'OpenAI 兼容' },\n { value: 'anthropic', label: 'Anthropic' },\n];\n\n/** Char count at which the simulated progress bar saturates (99%). */\nconst PROGRESS_FULL_CHARS = 20000;\n\nexport function AIPanelContent() {\n const { setDoc } = useFlowContext();\n const { aiConfig, setAIConfig, showAIConfig } = useFlowAI();\n\n const [prompt, setPrompt] = useState('');\n const [imageDataUrl, setImageDataUrl] = useState<string | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [status, setStatus] = useState<string | null>(null);\n const [streamOpen, setStreamOpen] = useState(false);\n const [finished, setFinished] = useState(false);\n const [pendingDoc, setPendingDoc] = useState<FlowDocument | null>(null);\n const [displayLen, setDisplayLen] = useState(0);\n const abortRef = useRef<AbortController | null>(null);\n const fileRef = useRef<HTMLInputElement>(null);\n const streamBodyRef = useRef<HTMLPreElement>(null);\n const streamTailRef = useRef<HTMLPreElement>(null);\n /** Full text received from the model so far (grows on every SSE delta). */\n const targetRef = useRef('');\n\n const updateConfig = useCallback((patch: Partial<FlowAIConfig>) => {\n setAIConfig({ ...aiConfig, ...patch });\n }, [aiConfig, setAIConfig]);\n\n const onPickImage = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = '';\n if (!file) return;\n const reader = new FileReader();\n reader.onload = () => setImageDataUrl(reader.result as string);\n reader.readAsDataURL(file);\n }, []);\n\n // Accept an image pasted from the clipboard (Ctrl/Cmd+V) anywhere in the panel\n // or into the textarea. Falls through to normal text paste otherwise.\n const onPaste = useCallback((e: React.ClipboardEvent) => {\n const items = e.clipboardData?.items;\n if (!items) return;\n for (const item of items) {\n if (item.type.startsWith('image/')) {\n const file = item.getAsFile();\n if (file) {\n e.preventDefault();\n const reader = new FileReader();\n reader.onload = () => setImageDataUrl(reader.result as string);\n reader.readAsDataURL(file);\n return;\n }\n }\n }\n }, []);\n\n // Progressive reveal: SSE deltas land in `targetRef` (often several chunks\n // per network read, which React would batch into a single paint), and this\n // timer types the text out with an exponential catch-up so the panel always\n // shows the reply growing character-by-character.\n useEffect(() => {\n const timer = window.setInterval(() => {\n setDisplayLen((len) => {\n const target = targetRef.current.length;\n if (len >= target) return len;\n return len + Math.max(8, Math.ceil((target - len) / 8));\n });\n }, 40);\n return () => window.clearInterval(timer);\n }, []);\n\n const streamText = targetRef.current.slice(0, displayLen);\n\n // Keep the streaming output pinned to the latest chunk while visible.\n useEffect(() => {\n const el = streamBodyRef.current;\n if (el) el.scrollTop = el.scrollHeight;\n const tail = streamTailRef.current;\n if (tail) tail.scrollTop = tail.scrollHeight;\n }, [streamText, streamOpen]);\n\n const generate = useCallback(async () => {\n if (busy) return;\n if (!aiConfig.gateway || !aiConfig.model) {\n setError('请先配置 AI 接口地址与模型');\n return;\n }\n if (!prompt.trim() && !imageDataUrl) {\n setError('请输入需求描述,或上传一张流程图');\n return;\n }\n setError(null);\n setStatus('正在生成…');\n targetRef.current = '';\n setDisplayLen(0);\n setFinished(false);\n setPendingDoc(null);\n setBusy(true);\n const ac = new AbortController();\n abortRef.current = ac;\n try {\n const text = await completeAIChatStream(\n aiConfig,\n prompt.trim() || '请根据这张图片复刻出对应的流程图。',\n {\n imageDataUrl: imageDataUrl ?? undefined,\n systemPrompt: SYSTEM_PROMPT,\n signal: ac.signal,\n onDelta: (accumulated) => { targetRef.current = accumulated; },\n },\n );\n setFinished(true);\n const parsed = parseFlowJson(text);\n if (!parsed) {\n setError('AI 返回内容无法解析为流程图,请重试或调整描述');\n setStatus(null);\n return;\n }\n setPendingDoc(normalizeAIDocument(parsed));\n setStatus(null);\n } catch (err: any) {\n if (err?.name !== 'AbortError') setError(err?.message ?? '生成失败');\n setStatus(null);\n } finally {\n setBusy(false);\n abortRef.current = null;\n }\n }, [busy, aiConfig, prompt, imageDataUrl]);\n\n const cancel = useCallback(() => abortRef.current?.abort(), []);\n\n /** Merge the generated canvas into the current canvas, remapping ids. */\n const applyInsert = useCallback(() => {\n if (!pendingDoc) return;\n const gen = pendingDoc.canvases[ROOT_CANVAS_ID] ?? { nodes: [], edges: [], lines: [] };\n setDoc((prev) => {\n const canvasId = prev.stack[prev.stack.length - 1] ?? ROOT_CANVAS_ID;\n const cur = prev.canvases[canvasId] ?? { nodes: [], edges: [], lines: [] };\n const used = new Set([\n ...cur.nodes.map((n) => n.id),\n ...cur.edges.map((e) => e.id),\n ...cur.lines.map((l) => l.id),\n ]);\n const fresh = (id: string) => {\n let next = id;\n let i = 1;\n while (used.has(next)) next = `${id}_${i++}`;\n used.add(next);\n return next;\n };\n const idMap = new Map<string, string>();\n const nodes = gen.nodes.map((n) => {\n const id = fresh(n.id);\n idMap.set(n.id, id);\n return { ...n, id };\n });\n const edges = gen.edges.map((e) => ({\n ...e,\n id: fresh(e.id),\n source: idMap.get(e.source) ?? e.source,\n target: idMap.get(e.target) ?? e.target,\n }));\n return {\n ...prev,\n canvases: {\n ...prev.canvases,\n [canvasId]: { nodes: [...cur.nodes, ...nodes], edges: [...cur.edges, ...edges], lines: cur.lines },\n },\n };\n });\n setPendingDoc(null);\n setStatus('已插入流程图');\n }, [pendingDoc, setDoc]);\n\n /** Clear the current canvas, then place the generated content onto it. */\n const applyReplace = useCallback(() => {\n if (!pendingDoc) return;\n const gen = pendingDoc.canvases[ROOT_CANVAS_ID] ?? { nodes: [], edges: [], lines: [] };\n setDoc((prev) => {\n const canvasId = prev.stack[prev.stack.length - 1] ?? ROOT_CANVAS_ID;\n return {\n ...prev,\n canvases: {\n ...prev.canvases,\n [canvasId]: { nodes: gen.nodes, edges: gen.edges, lines: [] },\n },\n };\n });\n setPendingDoc(null);\n setStatus('已替换画布');\n }, [pendingDoc, setDoc]);\n\n const charCount = streamText.length;\n const fullyRevealed = charCount >= targetRef.current.length;\n const progress = finished && fullyRevealed\n ? 100\n : Math.min(99, Math.floor((charCount / PROGRESS_FULL_CHARS) * 99));\n\n return (\n <div className=\"flow-ai-panel\" onPaste={onPaste}>\n {showAIConfig && (\n <div className=\"flow-ai-section\">\n <div className=\"flow-ai-section-title\">模型配置</div>\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">协议</Label>\n <Select\n options={PROTOCOL_OPTIONS}\n value={aiConfig.protocol}\n onChange={(v) => updateConfig({ protocol: v as FlowAIConfig['protocol'] })}\n style={{ fontSize: 12 }}\n />\n </div>\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">接口地址</Label>\n <Input\n size=\"xs\"\n value={aiConfig.gateway}\n placeholder=\"https://api.moonshot.cn/v1\"\n onChange={(e) => updateConfig({ gateway: e.target.value })}\n />\n </div>\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">模型</Label>\n <Input\n size=\"xs\"\n value={aiConfig.model}\n placeholder=\"gpt-4o-mini\"\n onChange={(e) => updateConfig({ model: e.target.value })}\n />\n </div>\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">API Key</Label>\n <Input\n size=\"xs\"\n type=\"password\"\n value={aiConfig.apiKey ?? ''}\n placeholder=\"sk-…\"\n onChange={(e) => updateConfig({ apiKey: e.target.value })}\n />\n </div>\n </div>\n )}\n\n <div className=\"flow-ai-section\">\n <div className=\"flow-ai-section-title\">生成流程图</div>\n <textarea\n className=\"flow-ai-textarea\"\n value={prompt}\n placeholder=\"描述你想要的流程,例如:用户注册流程,包含邮箱校验、发送验证码、创建账号等步骤(可直接粘贴图片)\"\n onChange={(e) => setPrompt(e.target.value)}\n onPaste={onPaste}\n onPointerDown={(e) => e.stopPropagation()}\n />\n\n <div className=\"flow-ai-image-row\">\n <input\n ref={fileRef}\n type=\"file\"\n accept=\"image/*\"\n style={{ display: 'none' }}\n onChange={onPickImage}\n />\n {imageDataUrl ? (\n <div className=\"flow-ai-image-preview\">\n <img src={imageDataUrl} alt=\"参考图\" />\n <button\n type=\"button\"\n className=\"flow-ai-image-remove\"\n title=\"移除图片\"\n onClick={() => setImageDataUrl(null)}\n >×</button>\n </div>\n ) : (\n <Button size=\"xs\" variant=\"ghost\" onClick={() => fileRef.current?.click()}>\n 上传流程图图片\n </Button>\n )}\n <span className=\"flow-ai-hint\">或粘贴图片 (Ctrl/⌘+V)</span>\n </div>\n\n <div className=\"flow-ai-actions\">\n {busy ? (\n <Button size=\"xs\" variant=\"ghost\" onClick={cancel}>停止</Button>\n ) : (\n <Button size=\"xs\" variant=\"primary\" onClick={generate}>生成流程图</Button>\n )}\n </div>\n\n {(busy || streamText) && (\n <div className=\"flow-ai-stream\">\n <div className=\"flow-ai-progress\">\n <div className=\"flow-ai-progress-track\">\n <div className=\"flow-ai-progress-bar\" style={{ width: `${progress}%` }} />\n </div>\n <span className=\"flow-ai-progress-label\">{progress}%</span>\n </div>\n <button\n type=\"button\"\n className=\"flow-ai-stream-header\"\n onClick={() => setStreamOpen((open) => !open)}\n >\n <span className={`flow-ai-stream-chevron${streamOpen ? ' flow-ai-stream-chevron--open' : ''}`}>▸</span>\n <span>返回内容</span>\n <span className=\"flow-ai-stream-count\">{charCount.toLocaleString()} 字符</span>\n </button>\n {streamOpen ? (\n <pre ref={streamBodyRef} className=\"flow-ai-stream-body\">{streamText || '等待返回…'}</pre>\n ) : (\n streamText && <pre ref={streamTailRef} className=\"flow-ai-stream-tail\">{streamText}</pre>\n )}\n </div>\n )}\n\n {status && !error && <div className=\"flow-ai-status\">{status}</div>}\n {error && <div className=\"flow-media-error\">{error}</div>}\n </div>\n\n {pendingDoc && (\n <div className=\"flow-ai-dialog-overlay\" onClick={() => setPendingDoc(null)}>\n <div\n className=\"flow-ai-dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"流程图已生成\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"flow-ai-dialog-title\">流程图已生成</div>\n <div className=\"flow-ai-dialog-desc\">\n 插入:将生成内容追加到当前画布;替换:清空当前画布后再插入。\n </div>\n <div className=\"flow-ai-dialog-actions\">\n <Button size=\"xs\" variant=\"ghost\" onClick={() => setPendingDoc(null)}>取消</Button>\n <Button size=\"xs\" variant=\"neutral\" outline onClick={applyInsert}>插入</Button>\n <Button size=\"xs\" variant=\"primary\" onClick={applyReplace}>替换</Button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|