Spaces:
Sleeping
Sleeping
File size: 5,055 Bytes
1dd9186 cfaaa6c 1dd9186 cfaaa6c 1dd9186 cfaaa6c 1dd9186 cfaaa6c 1dd9186 cfaaa6c 1dd9186 cfaaa6c 1dd9186 cfaaa6c 1dd9186 cfaaa6c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | import { memo, useEffect } from 'react';
import { useUpdateNodeInternals } from '@xyflow/react';
import NodeShell from '../components/NodeShell.jsx';
import { NodeDraftInput, NodeDraftTextarea } from '../components/NodeDraftField.jsx';
import { useWorkflow } from '../context/WorkflowContext.jsx';
import { createBrowserId } from '../lib/ids.js';
import { getNodeAccent } from '../lib/nodeRegistry.js';
function SemanticBranchFlowNode({ id, data, selected, type }) {
const { getNodeHandles, replaceNodeData, removeHandleConnections } = useWorkflow();
const updateNodeInternals = useUpdateNodeInternals();
const handles = getNodeHandles(type, data);
const runtime = data.runtime || {};
useEffect(() => {
updateNodeInternals(id);
}, [id, data.choices.length, updateNodeInternals]);
const addChoice = () => {
replaceNodeData(id, (current) => ({
...current,
choices: [...current.choices, { id: createBrowserId('choice'), label: '' }],
}));
};
const updateChoice = (choiceId, label) => {
replaceNodeData(id, (current) => ({
...current,
choices: current.choices.map((choice) =>
choice.id === choiceId && choice.label !== label ? { ...choice, label } : choice,
),
}));
};
const removeChoice = (choiceId) => {
if (data.choices.length <= 1) {
return;
}
removeHandleConnections(id, choiceId, 'source');
replaceNodeData(id, (current) => ({
...current,
choices: current.choices.filter((choice) => choice.id !== choiceId),
}));
};
const matchedChoice = data.choices.find((choice) => choice.id === runtime.matchId);
return (
<NodeShell
nodeId={id}
title={data.title}
accent={getNodeAccent(type)}
selected={selected}
status={runtime.status}
inputs={handles.inputs}
outputs={handles.outputs}
>
<div className="field-stack">
<div className="condition-list">
{data.choices.map((choice, index) => (
<div key={choice.id} className="condition-row">
<NodeDraftInput
className="nodrag node-input"
type="text"
value={choice.label}
placeholder={`вариант ${index + 1}`}
onCommit={(value) => updateChoice(choice.id, value)}
/>
<button
type="button"
className="nodrag chip__remove"
onClick={() => removeChoice(choice.id)}
disabled={data.choices.length <= 1}
>
x
</button>
</div>
))}
</div>
<button type="button" className="nodrag node-button node-button--ghost" onClick={addChoice}>
+ Добавить вариант
</button>
<div className="node-note">
Используйте точку с запятой для альтернатив внутри одного варианта: да; хочу еще; давай.
</div>
<label className="field-row semantic-branch__retry-toggle">
<input
className="nodrag"
type="checkbox"
checked={data.retryOnUnclear !== false}
onChange={(event) =>
replaceNodeData(id, (current) => ({
...current,
retryOnUnclear: event.target.checked,
}))
}
/>
<span>Переспрашивать при unclear</span>
</label>
{data.retryOnUnclear !== false ? (
<>
<NodeDraftTextarea
className="nodrag nowheel node-textarea"
value={data.retryQuestion || ''}
placeholder="Вопрос для повтора..."
style={{ minHeight: '70px' }}
onCommit={(value) =>
replaceNodeData(id, (current) => ({
...current,
retryQuestion: value,
}))
}
/>
<label className="field-row">
<input
className="nodrag"
type="checkbox"
checked={Boolean(data.retryParaphrase)}
onChange={(event) =>
replaceNodeData(id, (current) => ({
...current,
retryParaphrase: event.target.checked,
}))
}
/>
<span>Перефразировать unclear-вопрос</span>
</label>
</>
) : null}
<div className="node-note">
{runtime.result
? `Классификация: ${runtime.result}${matchedChoice ? ` -> ${matchedChoice.label}` : ''}`
: 'LLM классифицирует ответ и активирует один выход.'}
</div>
{runtime.error ? <div className="node-error">{runtime.error}</div> : null}
</div>
</NodeShell>
);
}
export default memo(SemanticBranchFlowNode);
|