Feat: Add Template operator #3556 (#3559)

### What problem does this PR solve?

Feat: Add Template operator #3560

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu 2024-11-21 18:05:31 +08:00 committed by GitHub
parent 30f111edb3
commit 3a3e23d8d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 136 additions and 5 deletions

View File

@ -0,0 +1,6 @@
<svg t="1732179100820" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7049"
width="200" height="200">
<path
d="M511.978 992c-264.277 0-479.292-215.037-479.292-479.314s215.016-479.314 479.292-479.314c76.843 0 153.272 18.628 221.05 53.901 40.872 21.308 78.499 48.368 111.745 80.459 94.491 91.135 146.54 213.665 146.54 344.953 0 264.277-215.037 479.314-479.335 479.314zM511.978 75.051c-241.313 0-437.614 196.323-437.614 437.635 0 241.291 196.323 437.635 437.614 437.635 241.312 0 437.657-196.344 437.657-437.635 0-119.872-47.539-231.727-133.816-314.975-30.393-29.325-64.729-54.032-102.072-73.488-62.681-32.637-130.569-49.173-201.77-49.173zM509.189 883.959c-204.928 0-371.643-166.714-371.643-371.664s166.714-371.643 371.643-371.643c68.825 0 136.059 18.977 194.406 54.838 9.804 6.035 12.877 18.867 6.819 28.672-6.013 9.804-18.89 12.832-28.65 6.841-51.766-31.831-111.462-48.672-172.575-48.672-181.943 0-329.964 148.021-329.964 329.986 0 181.943 148.021 329.986 329.964 329.986 181.965 0 329.986-148.042 329.986-329.986 0-11.503 9.324-20.85 20.828-20.85 11.526 0 20.85 9.324 20.85 20.85 0.022 204.928-166.736 371.643-371.664 371.643zM509.211 390.462c-42.136 0-76.407-34.271-76.407-76.407s34.271-76.429 76.407-76.429 76.429 34.293 76.429 76.429-34.293 76.407-76.429 76.407zM509.211 279.304c-19.15 0-34.75 15.599-34.75 34.75s15.599 34.729 34.75 34.729c19.15 0 34.75-15.577 34.75-34.729s-15.599-34.75-34.75-34.75z"
fill="#c2b909" p-id="7050"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -78,7 +78,7 @@ export const EditableCell: React.FC<EditableCellProps> = ({
if (editable) {
childNode = editing ? (
<Form.Item
style={{ margin: 0, width: 70 }}
style={{ margin: 0, minWidth: 70 }}
name={dataIndex}
rules={[
{

View File

@ -105,10 +105,10 @@ export default {
'Conduct a retrieval test to check if RAGFlow can recover the intended content for the LLM.',
similarityThreshold: 'Similarity threshold',
similarityThresholdTip:
"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.",
'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.',
vectorSimilarityWeight: 'Keywords similarity weight',
vectorSimilarityWeightTip:
"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.",
'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.',
testText: 'Test text',
testTextPlaceholder: 'Input your question here!',
testingLabel: 'Testing',
@ -1037,6 +1037,9 @@ The above is the content you need to summarize.`,
optional: 'Optional',
pasteFileLink: 'Paste file link',
testRun: 'Test Run',
template: 'Template',
templateDescription:
'This component is used for typesetting the outputs of various components.',
},
footer: {
profile: 'All rights reserved @ React',

View File

@ -997,6 +997,8 @@ export default {
optional: '可選項',
pasteFileLink: '貼上文件連結',
testRun: '試運行',
template: '模板轉換',
templateDescription: '此元件用於排版各種元件的輸出。 ',
},
footer: {
profile: '“保留所有權利 @ react”',

View File

@ -1017,6 +1017,8 @@ export default {
optional: '可选项',
pasteFileLink: '粘贴文件链接',
testRun: '试运行',
template: '模板转换',
templateDescription: '该组件用于排版各种组件的输出。',
},
footer: {
profile: 'All rights reserved @ React',

View File

@ -26,7 +26,7 @@ const ChatIdModal = ({
{id}
</Paragraph>
<Link
href="https://ragflow.io/docs/dev/http_api_reference#create-session"
href="https://ragflow.io/docs/dev/http_api_reference#create-session-with-chat-assistant"
target="_blank"
>
{t('howUseId')}

View File

@ -35,6 +35,7 @@ import { RelevantNode } from './node/relevant-node';
import { RetrievalNode } from './node/retrieval-node';
import { RewriteNode } from './node/rewrite-node';
import { SwitchNode } from './node/switch-node';
import { TemplateNode } from './node/template-node';
const nodeTypes = {
ragNode: RagNode,
@ -50,6 +51,7 @@ const nodeTypes = {
rewriteNode: RewriteNode,
keywordNode: KeywordNode,
invokeNode: InvokeNode,
templateNode: TemplateNode,
};
const edgeTypes = {

View File

@ -0,0 +1,68 @@
import { Flex } from 'antd';
import classNames from 'classnames';
import { get } from 'lodash';
import { Handle, NodeProps, Position } from 'reactflow';
import { useGetComponentLabelByValue } from '../../hooks';
import { IGenerateParameter, NodeData } from '../../interface';
import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
import NodeHeader from './node-header';
import styles from './index.less';
export function TemplateNode({
id,
data,
isConnectable = true,
selected,
}: NodeProps<NodeData>) {
const parameters: IGenerateParameter[] = get(data, 'form.parameters', []);
const getLabel = useGetComponentLabelByValue(id);
return (
<section
className={classNames(styles.logicNode, {
[styles.selectedNode]: selected,
})}
>
<Handle
id="c"
type="source"
position={Position.Left}
isConnectable={isConnectable}
className={styles.handle}
style={LeftHandleStyle}
></Handle>
<Handle
type="source"
position={Position.Right}
isConnectable={isConnectable}
className={styles.handle}
style={RightHandleStyle}
id="b"
></Handle>
<NodeHeader
id={id}
name={data.name}
label={data.label}
className={styles.nodeHeader}
></NodeHeader>
<Flex gap={8} vertical className={styles.generateParameters}>
{parameters.map((x) => (
<Flex
key={x.id}
align="center"
gap={6}
className={styles.conditionBlock}
>
<label htmlFor="">{x.key}</label>
<span className={styles.parameterValue}>
{getLabel(x.component_id)}
</span>
</Flex>
))}
</Flex>
</section>
);
}

View File

@ -19,6 +19,7 @@ import { ReactComponent as NoteIcon } from '@/assets/svg/note.svg';
import { ReactComponent as PubMedIcon } from '@/assets/svg/pubmed.svg';
import { ReactComponent as QWeatherIcon } from '@/assets/svg/qweather.svg';
import { ReactComponent as SwitchIcon } from '@/assets/svg/switch.svg';
import { ReactComponent as TemplateIcon } from '@/assets/svg/template.svg';
import { ReactComponent as TuShareIcon } from '@/assets/svg/tushare.svg';
import { ReactComponent as WenCaiIcon } from '@/assets/svg/wencai.svg';
import { ReactComponent as WikipediaIcon } from '@/assets/svg/wikipedia.svg';
@ -85,6 +86,7 @@ export enum Operator {
Note = 'Note',
Crawler = 'Crawler',
Invoke = 'Invoke',
Template = 'Template',
}
export const CommonOperatorList = Object.values(Operator).filter(
@ -124,6 +126,7 @@ export const operatorIconMap = {
[Operator.Note]: NoteIcon,
[Operator.Crawler]: CrawlerIcon,
[Operator.Invoke]: InvokeIcon,
[Operator.Template]: TemplateIcon,
};
export const operatorMap: Record<
@ -253,6 +256,9 @@ export const operatorMap: Record<
[Operator.Invoke]: {
backgroundColor: '#dee0e2',
},
[Operator.Template]: {
backgroundColor: '#dee0e2',
},
};
export const componentMenuList = [
@ -286,6 +292,9 @@ export const componentMenuList = [
{
name: Operator.Concentrator,
},
{
name: Operator.Template,
},
{
name: Operator.Note,
},
@ -566,6 +575,11 @@ export const initialInvokeValues = {
clean_html: false,
};
export const initialTemplateValues = {
content: '',
parameters: [],
};
export const CategorizeAnchorPointPositions = [
{ top: 1, right: 34 },
{ top: 8, right: 18 },
@ -645,6 +659,7 @@ export const RestrictedUpstreamMap = {
[Operator.Crawler]: [Operator.Begin],
[Operator.Note]: [],
[Operator.Invoke]: [Operator.Begin],
[Operator.Template]: [Operator.Begin, Operator.Relevant],
};
export const NodeMap = {
@ -680,6 +695,7 @@ export const NodeMap = {
[Operator.Note]: 'noteNode',
[Operator.Crawler]: 'ragNode',
[Operator.Invoke]: 'invokeNode',
[Operator.Template]: 'templateNode',
};
export const LanguageOptions = [

View File

@ -39,6 +39,7 @@ import OperatorIcon from '../operator-icon';
import { CloseOutlined } from '@ant-design/icons';
import { lowerFirst } from 'lodash';
import TemplateForm from '../form/template-form';
import { getDrawerWidth } from '../utils';
import styles from './index.less';
@ -79,6 +80,7 @@ const FormMap = {
[Operator.Invoke]: InvokeForm,
[Operator.Concentrator]: () => <></>,
[Operator.Note]: () => <></>,
[Operator.Template]: TemplateForm,
};
const EmptyContent = () => <div></div>;

View File

@ -24,7 +24,7 @@ const FlowIdModal = ({ hideModal }: IModalProps<any>) => {
{id}
</Paragraph>
<Link
href="https://ragflow.io/docs/dev/http_api_reference#create-agent-session"
href="https://ragflow.io/docs/dev/http_api_reference#create-session-with-an-agent"
target="_blank"
>
{t('howUseId')}

View File

@ -36,6 +36,7 @@ const DynamicParameters = ({ nodeId }: IProps) => {
title: t('key'),
dataIndex: 'key',
key: 'key',
width: '40%',
onCell: (record: IGenerateParameter) => ({
record,
editable: true,
@ -49,6 +50,7 @@ const DynamicParameters = ({ nodeId }: IProps) => {
dataIndex: 'component_id',
key: 'component_id',
align: 'center',
width: '40%',
render(text, record) {
return (
<Select

View File

@ -0,0 +1,26 @@
import { Form, Input } from 'antd';
import { useTranslation } from 'react-i18next';
import { IOperatorForm } from '../../interface';
import DynamicParameters from '../generate-form/dynamic-parameters';
const TemplateForm = ({ onValuesChange, form, node }: IOperatorForm) => {
const { t } = useTranslation();
return (
<Form
name="basic"
autoComplete="off"
form={form}
onValuesChange={onValuesChange}
layout={'vertical'}
>
<Form.Item name={['content']} label={t('flow.content')}>
<Input.TextArea rows={8} placeholder={t('flow.blank')} />
</Form.Item>
<DynamicParameters nodeId={node?.id}></DynamicParameters>
</Form>
);
};
export default TemplateForm;

View File

@ -60,6 +60,7 @@ import {
initialRetrievalValues,
initialRewriteQuestionValues,
initialSwitchValues,
initialTemplateValues,
initialTuShareValues,
initialWenCaiValues,
initialWikipediaValues,
@ -139,6 +140,7 @@ export const useInitializeOperatorParams = () => {
[Operator.Note]: initialNoteValues,
[Operator.Crawler]: initialCrawlerValues,
[Operator.Invoke]: initialInvokeValues,
[Operator.Template]: initialTemplateValues,
};
}, [llmId]);