mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-08-12 04:39:07 +08:00
### 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:
parent
30f111edb3
commit
3a3e23d8d9
6
web/src/assets/svg/template.svg
Normal file
6
web/src/assets/svg/template.svg
Normal 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 |
@ -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={[
|
||||
{
|
||||
|
@ -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',
|
||||
|
@ -997,6 +997,8 @@ export default {
|
||||
optional: '可選項',
|
||||
pasteFileLink: '貼上文件連結',
|
||||
testRun: '試運行',
|
||||
template: '模板轉換',
|
||||
templateDescription: '此元件用於排版各種元件的輸出。 ',
|
||||
},
|
||||
footer: {
|
||||
profile: '“保留所有權利 @ react”',
|
||||
|
@ -1017,6 +1017,8 @@ export default {
|
||||
optional: '可选项',
|
||||
pasteFileLink: '粘贴文件链接',
|
||||
testRun: '试运行',
|
||||
template: '模板转换',
|
||||
templateDescription: '该组件用于排版各种组件的输出。',
|
||||
},
|
||||
footer: {
|
||||
profile: 'All rights reserved @ React',
|
||||
|
@ -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')}
|
||||
|
@ -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 = {
|
||||
|
68
web/src/pages/flow/canvas/node/template-node.tsx
Normal file
68
web/src/pages/flow/canvas/node/template-node.tsx
Normal 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>
|
||||
);
|
||||
}
|
@ -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 = [
|
||||
|
@ -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>;
|
||||
|
@ -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')}
|
||||
|
@ -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
|
||||
|
26
web/src/pages/flow/form/template-form/index.tsx
Normal file
26
web/src/pages/flow/form/template-form/index.tsx
Normal 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;
|
@ -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]);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user