balibabu commited on
Commit
e618152
·
1 Parent(s): 481246c

Feat: Add Template operator #3556 (#3559)

Browse files

### What problem does this PR solve?

Feat: Add Template operator #3560

### Type of change


- [x] New Feature (non-breaking change which adds functionality)

web/src/assets/svg/template.svg ADDED
web/src/components/editable-cell.tsx CHANGED
@@ -78,7 +78,7 @@ export const EditableCell: React.FC<EditableCellProps> = ({
78
  if (editable) {
79
  childNode = editing ? (
80
  <Form.Item
81
- style={{ margin: 0, width: 70 }}
82
  name={dataIndex}
83
  rules={[
84
  {
 
78
  if (editable) {
79
  childNode = editing ? (
80
  <Form.Item
81
+ style={{ margin: 0, minWidth: 70 }}
82
  name={dataIndex}
83
  rules={[
84
  {
web/src/locales/en.ts CHANGED
@@ -105,10 +105,10 @@ export default {
105
  'Conduct a retrieval test to check if RAGFlow can recover the intended content for the LLM.',
106
  similarityThreshold: 'Similarity threshold',
107
  similarityThresholdTip:
108
- "RAGFlow employs either a combination of weighted keyword similarity and weighted vector cosine similarity, or a combination of weighted keyword similarity and weighted reranking score during retrieval. This parameter sets the threshold for similarities between the user query and chunks. Any chunk with a similarity score below this threshold will be excluded from the results.",
109
  vectorSimilarityWeight: 'Keywords similarity weight',
110
  vectorSimilarityWeightTip:
111
- "This sets the weight of keyword similarity in the combined similarity score, either used with vector cosine similarity or with reranking score. The total of the two weights must equal 1.0.",
112
  testText: 'Test text',
113
  testTextPlaceholder: 'Input your question here!',
114
  testingLabel: 'Testing',
@@ -1037,6 +1037,9 @@ The above is the content you need to summarize.`,
1037
  optional: 'Optional',
1038
  pasteFileLink: 'Paste file link',
1039
  testRun: 'Test Run',
 
 
 
1040
  },
1041
  footer: {
1042
  profile: 'All rights reserved @ React',
 
105
  'Conduct a retrieval test to check if RAGFlow can recover the intended content for the LLM.',
106
  similarityThreshold: 'Similarity threshold',
107
  similarityThresholdTip:
108
+ 'RAGFlow employs either a combination of weighted keyword similarity and weighted vector cosine similarity, or a combination of weighted keyword similarity and weighted reranking score during retrieval. This parameter sets the threshold for similarities between the user query and chunks. Any chunk with a similarity score below this threshold will be excluded from the results.',
109
  vectorSimilarityWeight: 'Keywords similarity weight',
110
  vectorSimilarityWeightTip:
111
+ 'This sets the weight of keyword similarity in the combined similarity score, either used with vector cosine similarity or with reranking score. The total of the two weights must equal 1.0.',
112
  testText: 'Test text',
113
  testTextPlaceholder: 'Input your question here!',
114
  testingLabel: 'Testing',
 
1037
  optional: 'Optional',
1038
  pasteFileLink: 'Paste file link',
1039
  testRun: 'Test Run',
1040
+ template: 'Template',
1041
+ templateDescription:
1042
+ 'This component is used for typesetting the outputs of various components.',
1043
  },
1044
  footer: {
1045
  profile: 'All rights reserved @ React',
web/src/locales/zh-traditional.ts CHANGED
@@ -997,6 +997,8 @@ export default {
997
  optional: '可選項',
998
  pasteFileLink: '貼上文件連結',
999
  testRun: '試運行',
 
 
1000
  },
1001
  footer: {
1002
  profile: '“保留所有權利 @ react”',
 
997
  optional: '可選項',
998
  pasteFileLink: '貼上文件連結',
999
  testRun: '試運行',
1000
+ template: '模板轉換',
1001
+ templateDescription: '此元件用於排版各種元件的輸出。 ',
1002
  },
1003
  footer: {
1004
  profile: '“保留所有權利 @ react”',
web/src/locales/zh.ts CHANGED
@@ -1017,6 +1017,8 @@ export default {
1017
  optional: '可选项',
1018
  pasteFileLink: '粘贴文件链接',
1019
  testRun: '试运行',
 
 
1020
  },
1021
  footer: {
1022
  profile: 'All rights reserved @ React',
 
1017
  optional: '可选项',
1018
  pasteFileLink: '粘贴文件链接',
1019
  testRun: '试运行',
1020
+ template: '模板转换',
1021
+ templateDescription: '该组件用于排版各种组件的输出。',
1022
  },
1023
  footer: {
1024
  profile: 'All rights reserved @ React',
web/src/pages/chat/chat-id-modal/index.tsx CHANGED
@@ -26,7 +26,7 @@ const ChatIdModal = ({
26
  {id}
27
  </Paragraph>
28
  <Link
29
- href="https://ragflow.io/docs/dev/http_api_reference#create-session"
30
  target="_blank"
31
  >
32
  {t('howUseId')}
 
26
  {id}
27
  </Paragraph>
28
  <Link
29
+ href="https://ragflow.io/docs/dev/http_api_reference#create-session-with-chat-assistant"
30
  target="_blank"
31
  >
32
  {t('howUseId')}
web/src/pages/flow/canvas/index.tsx CHANGED
@@ -35,6 +35,7 @@ import { RelevantNode } from './node/relevant-node';
35
  import { RetrievalNode } from './node/retrieval-node';
36
  import { RewriteNode } from './node/rewrite-node';
37
  import { SwitchNode } from './node/switch-node';
 
38
 
39
  const nodeTypes = {
40
  ragNode: RagNode,
@@ -50,6 +51,7 @@ const nodeTypes = {
50
  rewriteNode: RewriteNode,
51
  keywordNode: KeywordNode,
52
  invokeNode: InvokeNode,
 
53
  };
54
 
55
  const edgeTypes = {
 
35
  import { RetrievalNode } from './node/retrieval-node';
36
  import { RewriteNode } from './node/rewrite-node';
37
  import { SwitchNode } from './node/switch-node';
38
+ import { TemplateNode } from './node/template-node';
39
 
40
  const nodeTypes = {
41
  ragNode: RagNode,
 
51
  rewriteNode: RewriteNode,
52
  keywordNode: KeywordNode,
53
  invokeNode: InvokeNode,
54
+ templateNode: TemplateNode,
55
  };
56
 
57
  const edgeTypes = {
web/src/pages/flow/canvas/node/template-node.tsx ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Flex } from 'antd';
2
+ import classNames from 'classnames';
3
+ import { get } from 'lodash';
4
+ import { Handle, NodeProps, Position } from 'reactflow';
5
+ import { useGetComponentLabelByValue } from '../../hooks';
6
+ import { IGenerateParameter, NodeData } from '../../interface';
7
+ import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
8
+ import NodeHeader from './node-header';
9
+
10
+ import styles from './index.less';
11
+
12
+ export function TemplateNode({
13
+ id,
14
+ data,
15
+ isConnectable = true,
16
+ selected,
17
+ }: NodeProps<NodeData>) {
18
+ const parameters: IGenerateParameter[] = get(data, 'form.parameters', []);
19
+ const getLabel = useGetComponentLabelByValue(id);
20
+
21
+ return (
22
+ <section
23
+ className={classNames(styles.logicNode, {
24
+ [styles.selectedNode]: selected,
25
+ })}
26
+ >
27
+ <Handle
28
+ id="c"
29
+ type="source"
30
+ position={Position.Left}
31
+ isConnectable={isConnectable}
32
+ className={styles.handle}
33
+ style={LeftHandleStyle}
34
+ ></Handle>
35
+ <Handle
36
+ type="source"
37
+ position={Position.Right}
38
+ isConnectable={isConnectable}
39
+ className={styles.handle}
40
+ style={RightHandleStyle}
41
+ id="b"
42
+ ></Handle>
43
+
44
+ <NodeHeader
45
+ id={id}
46
+ name={data.name}
47
+ label={data.label}
48
+ className={styles.nodeHeader}
49
+ ></NodeHeader>
50
+
51
+ <Flex gap={8} vertical className={styles.generateParameters}>
52
+ {parameters.map((x) => (
53
+ <Flex
54
+ key={x.id}
55
+ align="center"
56
+ gap={6}
57
+ className={styles.conditionBlock}
58
+ >
59
+ <label htmlFor="">{x.key}</label>
60
+ <span className={styles.parameterValue}>
61
+ {getLabel(x.component_id)}
62
+ </span>
63
+ </Flex>
64
+ ))}
65
+ </Flex>
66
+ </section>
67
+ );
68
+ }
web/src/pages/flow/constant.tsx CHANGED
@@ -19,6 +19,7 @@ import { ReactComponent as NoteIcon } from '@/assets/svg/note.svg';
19
  import { ReactComponent as PubMedIcon } from '@/assets/svg/pubmed.svg';
20
  import { ReactComponent as QWeatherIcon } from '@/assets/svg/qweather.svg';
21
  import { ReactComponent as SwitchIcon } from '@/assets/svg/switch.svg';
 
22
  import { ReactComponent as TuShareIcon } from '@/assets/svg/tushare.svg';
23
  import { ReactComponent as WenCaiIcon } from '@/assets/svg/wencai.svg';
24
  import { ReactComponent as WikipediaIcon } from '@/assets/svg/wikipedia.svg';
@@ -85,6 +86,7 @@ export enum Operator {
85
  Note = 'Note',
86
  Crawler = 'Crawler',
87
  Invoke = 'Invoke',
 
88
  }
89
 
90
  export const CommonOperatorList = Object.values(Operator).filter(
@@ -124,6 +126,7 @@ export const operatorIconMap = {
124
  [Operator.Note]: NoteIcon,
125
  [Operator.Crawler]: CrawlerIcon,
126
  [Operator.Invoke]: InvokeIcon,
 
127
  };
128
 
129
  export const operatorMap: Record<
@@ -253,6 +256,9 @@ export const operatorMap: Record<
253
  [Operator.Invoke]: {
254
  backgroundColor: '#dee0e2',
255
  },
 
 
 
256
  };
257
 
258
  export const componentMenuList = [
@@ -286,6 +292,9 @@ export const componentMenuList = [
286
  {
287
  name: Operator.Concentrator,
288
  },
 
 
 
289
  {
290
  name: Operator.Note,
291
  },
@@ -566,6 +575,11 @@ export const initialInvokeValues = {
566
  clean_html: false,
567
  };
568
 
 
 
 
 
 
569
  export const CategorizeAnchorPointPositions = [
570
  { top: 1, right: 34 },
571
  { top: 8, right: 18 },
@@ -645,6 +659,7 @@ export const RestrictedUpstreamMap = {
645
  [Operator.Crawler]: [Operator.Begin],
646
  [Operator.Note]: [],
647
  [Operator.Invoke]: [Operator.Begin],
 
648
  };
649
 
650
  export const NodeMap = {
@@ -680,6 +695,7 @@ export const NodeMap = {
680
  [Operator.Note]: 'noteNode',
681
  [Operator.Crawler]: 'ragNode',
682
  [Operator.Invoke]: 'invokeNode',
 
683
  };
684
 
685
  export const LanguageOptions = [
 
19
  import { ReactComponent as PubMedIcon } from '@/assets/svg/pubmed.svg';
20
  import { ReactComponent as QWeatherIcon } from '@/assets/svg/qweather.svg';
21
  import { ReactComponent as SwitchIcon } from '@/assets/svg/switch.svg';
22
+ import { ReactComponent as TemplateIcon } from '@/assets/svg/template.svg';
23
  import { ReactComponent as TuShareIcon } from '@/assets/svg/tushare.svg';
24
  import { ReactComponent as WenCaiIcon } from '@/assets/svg/wencai.svg';
25
  import { ReactComponent as WikipediaIcon } from '@/assets/svg/wikipedia.svg';
 
86
  Note = 'Note',
87
  Crawler = 'Crawler',
88
  Invoke = 'Invoke',
89
+ Template = 'Template',
90
  }
91
 
92
  export const CommonOperatorList = Object.values(Operator).filter(
 
126
  [Operator.Note]: NoteIcon,
127
  [Operator.Crawler]: CrawlerIcon,
128
  [Operator.Invoke]: InvokeIcon,
129
+ [Operator.Template]: TemplateIcon,
130
  };
131
 
132
  export const operatorMap: Record<
 
256
  [Operator.Invoke]: {
257
  backgroundColor: '#dee0e2',
258
  },
259
+ [Operator.Template]: {
260
+ backgroundColor: '#dee0e2',
261
+ },
262
  };
263
 
264
  export const componentMenuList = [
 
292
  {
293
  name: Operator.Concentrator,
294
  },
295
+ {
296
+ name: Operator.Template,
297
+ },
298
  {
299
  name: Operator.Note,
300
  },
 
575
  clean_html: false,
576
  };
577
 
578
+ export const initialTemplateValues = {
579
+ content: '',
580
+ parameters: [],
581
+ };
582
+
583
  export const CategorizeAnchorPointPositions = [
584
  { top: 1, right: 34 },
585
  { top: 8, right: 18 },
 
659
  [Operator.Crawler]: [Operator.Begin],
660
  [Operator.Note]: [],
661
  [Operator.Invoke]: [Operator.Begin],
662
+ [Operator.Template]: [Operator.Begin, Operator.Relevant],
663
  };
664
 
665
  export const NodeMap = {
 
695
  [Operator.Note]: 'noteNode',
696
  [Operator.Crawler]: 'ragNode',
697
  [Operator.Invoke]: 'invokeNode',
698
+ [Operator.Template]: 'templateNode',
699
  };
700
 
701
  export const LanguageOptions = [
web/src/pages/flow/flow-drawer/index.tsx CHANGED
@@ -39,6 +39,7 @@ import OperatorIcon from '../operator-icon';
39
 
40
  import { CloseOutlined } from '@ant-design/icons';
41
  import { lowerFirst } from 'lodash';
 
42
  import { getDrawerWidth } from '../utils';
43
  import styles from './index.less';
44
 
@@ -79,6 +80,7 @@ const FormMap = {
79
  [Operator.Invoke]: InvokeForm,
80
  [Operator.Concentrator]: () => <></>,
81
  [Operator.Note]: () => <></>,
 
82
  };
83
 
84
  const EmptyContent = () => <div></div>;
 
39
 
40
  import { CloseOutlined } from '@ant-design/icons';
41
  import { lowerFirst } from 'lodash';
42
+ import TemplateForm from '../form/template-form';
43
  import { getDrawerWidth } from '../utils';
44
  import styles from './index.less';
45
 
 
80
  [Operator.Invoke]: InvokeForm,
81
  [Operator.Concentrator]: () => <></>,
82
  [Operator.Note]: () => <></>,
83
+ [Operator.Template]: TemplateForm,
84
  };
85
 
86
  const EmptyContent = () => <div></div>;
web/src/pages/flow/flow-id-modal/index.tsx CHANGED
@@ -24,7 +24,7 @@ const FlowIdModal = ({ hideModal }: IModalProps<any>) => {
24
  {id}
25
  </Paragraph>
26
  <Link
27
- href="https://ragflow.io/docs/dev/http_api_reference#create-agent-session"
28
  target="_blank"
29
  >
30
  {t('howUseId')}
 
24
  {id}
25
  </Paragraph>
26
  <Link
27
+ href="https://ragflow.io/docs/dev/http_api_reference#create-session-with-an-agent"
28
  target="_blank"
29
  >
30
  {t('howUseId')}
web/src/pages/flow/form/generate-form/dynamic-parameters.tsx CHANGED
@@ -36,6 +36,7 @@ const DynamicParameters = ({ nodeId }: IProps) => {
36
  title: t('key'),
37
  dataIndex: 'key',
38
  key: 'key',
 
39
  onCell: (record: IGenerateParameter) => ({
40
  record,
41
  editable: true,
@@ -49,6 +50,7 @@ const DynamicParameters = ({ nodeId }: IProps) => {
49
  dataIndex: 'component_id',
50
  key: 'component_id',
51
  align: 'center',
 
52
  render(text, record) {
53
  return (
54
  <Select
 
36
  title: t('key'),
37
  dataIndex: 'key',
38
  key: 'key',
39
+ width: '40%',
40
  onCell: (record: IGenerateParameter) => ({
41
  record,
42
  editable: true,
 
50
  dataIndex: 'component_id',
51
  key: 'component_id',
52
  align: 'center',
53
+ width: '40%',
54
  render(text, record) {
55
  return (
56
  <Select
web/src/pages/flow/form/template-form/index.tsx ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Form, Input } from 'antd';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { IOperatorForm } from '../../interface';
4
+ import DynamicParameters from '../generate-form/dynamic-parameters';
5
+
6
+ const TemplateForm = ({ onValuesChange, form, node }: IOperatorForm) => {
7
+ const { t } = useTranslation();
8
+
9
+ return (
10
+ <Form
11
+ name="basic"
12
+ autoComplete="off"
13
+ form={form}
14
+ onValuesChange={onValuesChange}
15
+ layout={'vertical'}
16
+ >
17
+ <Form.Item name={['content']} label={t('flow.content')}>
18
+ <Input.TextArea rows={8} placeholder={t('flow.blank')} />
19
+ </Form.Item>
20
+
21
+ <DynamicParameters nodeId={node?.id}></DynamicParameters>
22
+ </Form>
23
+ );
24
+ };
25
+
26
+ export default TemplateForm;
web/src/pages/flow/hooks.tsx CHANGED
@@ -60,6 +60,7 @@ import {
60
  initialRetrievalValues,
61
  initialRewriteQuestionValues,
62
  initialSwitchValues,
 
63
  initialTuShareValues,
64
  initialWenCaiValues,
65
  initialWikipediaValues,
@@ -139,6 +140,7 @@ export const useInitializeOperatorParams = () => {
139
  [Operator.Note]: initialNoteValues,
140
  [Operator.Crawler]: initialCrawlerValues,
141
  [Operator.Invoke]: initialInvokeValues,
 
142
  };
143
  }, [llmId]);
144
 
 
60
  initialRetrievalValues,
61
  initialRewriteQuestionValues,
62
  initialSwitchValues,
63
+ initialTemplateValues,
64
  initialTuShareValues,
65
  initialWenCaiValues,
66
  initialWikipediaValues,
 
140
  [Operator.Note]: initialNoteValues,
141
  [Operator.Crawler]: initialCrawlerValues,
142
  [Operator.Invoke]: initialInvokeValues,
143
+ [Operator.Template]: initialTemplateValues,
144
  };
145
  }, [llmId]);
146