mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: In a dialog message, users can enter different types of data #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -11,8 +11,14 @@ import PdfDrawer from '@/components/pdf-drawer';
|
|||||||
import { useClickDrawer } from '@/components/pdf-drawer/hooks';
|
import { useClickDrawer } from '@/components/pdf-drawer/hooks';
|
||||||
import { useFetchAgent } from '@/hooks/use-agent-request';
|
import { useFetchAgent } from '@/hooks/use-agent-request';
|
||||||
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
|
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
|
||||||
|
import { Message } from '@/interfaces/database/chat';
|
||||||
import { buildMessageUuidWithRole } from '@/utils/chat';
|
import { buildMessageUuidWithRole } from '@/utils/chat';
|
||||||
import { InputForm } from './input-form';
|
import { get } from 'lodash';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { useParams } from 'umi';
|
||||||
|
import DebugContent from '../debug-content';
|
||||||
|
import { BeginQuery } from '../interface';
|
||||||
|
import { buildBeginQueryWithObject } from '../utils';
|
||||||
|
|
||||||
const AgentChatBox = () => {
|
const AgentChatBox = () => {
|
||||||
const {
|
const {
|
||||||
@ -25,7 +31,7 @@ const AgentChatBox = () => {
|
|||||||
derivedMessages,
|
derivedMessages,
|
||||||
reference,
|
reference,
|
||||||
stopOutputMessage,
|
stopOutputMessage,
|
||||||
send,
|
sendFormMessage,
|
||||||
} = useSendNextMessage();
|
} = useSendNextMessage();
|
||||||
|
|
||||||
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
||||||
@ -33,6 +39,35 @@ const AgentChatBox = () => {
|
|||||||
useGetFileIcon();
|
useGetFileIcon();
|
||||||
const { data: userInfo } = useFetchUserInfo();
|
const { data: userInfo } = useFetchUserInfo();
|
||||||
const { data: canvasInfo } = useFetchAgent();
|
const { data: canvasInfo } = useFetchAgent();
|
||||||
|
const { id: canvasId } = useParams();
|
||||||
|
|
||||||
|
const getInputs = useCallback((message: Message) => {
|
||||||
|
return get(message, 'data.inputs', {}) as Record<string, BeginQuery>;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const buildInputList = useCallback(
|
||||||
|
(message: Message) => {
|
||||||
|
return Object.entries(getInputs(message)).map(([key, val]) => {
|
||||||
|
return {
|
||||||
|
...val,
|
||||||
|
key,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[getInputs],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleOk = useCallback(
|
||||||
|
(message: Message) => (values: BeginQuery[]) => {
|
||||||
|
const inputs = getInputs(message);
|
||||||
|
const nextInputs = buildBeginQueryWithObject(inputs, values);
|
||||||
|
sendFormMessage({
|
||||||
|
inputs: nextInputs,
|
||||||
|
id: canvasId,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[canvasId, getInputs, sendFormMessage],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -62,7 +97,12 @@ const AgentChatBox = () => {
|
|||||||
showLikeButton={false}
|
showLikeButton={false}
|
||||||
sendLoading={sendLoading}
|
sendLoading={sendLoading}
|
||||||
>
|
>
|
||||||
<InputForm send={send} message={message}></InputForm>
|
<DebugContent
|
||||||
|
parameters={buildInputList(message)}
|
||||||
|
ok={handleOk(message)}
|
||||||
|
isNext={false}
|
||||||
|
btnText={'Submit'}
|
||||||
|
></DebugContent>
|
||||||
</MessageItem>
|
</MessageItem>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import { useParams } from 'umi';
|
|||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { BeginId } from '../constant';
|
import { BeginId } from '../constant';
|
||||||
import { AgentChatLogContext } from '../context';
|
import { AgentChatLogContext } from '../context';
|
||||||
|
import { BeginQuery } from '../interface';
|
||||||
import useGraphStore from '../store';
|
import useGraphStore from '../store';
|
||||||
import { receiveMessageError } from '../utils';
|
import { receiveMessageError } from '../utils';
|
||||||
|
|
||||||
@ -176,6 +177,19 @@ export const useSendNextMessage = () => {
|
|||||||
});
|
});
|
||||||
}, [value, done, addNewestOneQuestion, setValue, handleSendMessage]);
|
}, [value, done, addNewestOneQuestion, setValue, handleSendMessage]);
|
||||||
|
|
||||||
|
const sendFormMessage = useCallback(
|
||||||
|
(body: { id?: string; inputs: Record<string, BeginQuery> }) => {
|
||||||
|
send(body);
|
||||||
|
addNewestOneQuestion({
|
||||||
|
content: Object.entries(body.inputs)
|
||||||
|
.map(([key, val]) => `${key}: ${val.value}`)
|
||||||
|
.join('<br/>'),
|
||||||
|
role: MessageType.User,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[addNewestOneQuestion, send],
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (prologue) {
|
if (prologue) {
|
||||||
addNewestOneAnswer({
|
addNewestOneAnswer({
|
||||||
@ -200,5 +214,6 @@ export const useSendNextMessage = () => {
|
|||||||
removeMessageById,
|
removeMessageById,
|
||||||
stopOutputMessage,
|
stopOutputMessage,
|
||||||
send,
|
send,
|
||||||
|
sendFormMessage,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -12,11 +12,8 @@ import { Input } from '@/components/ui/input';
|
|||||||
import { RAGFlowSelect } from '@/components/ui/select';
|
import { RAGFlowSelect } from '@/components/ui/select';
|
||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
import { Textarea } from '@/components/ui/textarea';
|
import { Textarea } from '@/components/ui/textarea';
|
||||||
import { useSetModalState } from '@/hooks/common-hooks';
|
|
||||||
import { useSetSelectedRecord } from '@/hooks/logic-hooks';
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { UploadChangeParam, UploadFile } from 'antd/es/upload';
|
import React, { ReactNode, useCallback, useMemo } from 'react';
|
||||||
import React, { useCallback, useMemo, useState } from 'react';
|
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
@ -44,6 +41,7 @@ interface IProps {
|
|||||||
isNext?: boolean;
|
isNext?: boolean;
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
submitButtonDisabled?: boolean;
|
submitButtonDisabled?: boolean;
|
||||||
|
btnText?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const values = {};
|
const values = {};
|
||||||
@ -54,76 +52,45 @@ const DebugContent = ({
|
|||||||
isNext = true,
|
isNext = true,
|
||||||
loading = false,
|
loading = false,
|
||||||
submitButtonDisabled = false,
|
submitButtonDisabled = false,
|
||||||
|
btnText,
|
||||||
}: IProps) => {
|
}: IProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const FormSchema = useMemo(() => {
|
const FormSchema = useMemo(() => {
|
||||||
const obj = parameters.reduce((pre, cur, idx) => {
|
const obj = parameters.reduce<Record<string, z.ZodType>>(
|
||||||
const type = cur.type;
|
(pre, cur, idx) => {
|
||||||
let fieldSchema;
|
const type = cur.type;
|
||||||
if (StringFields.some((x) => x === type)) {
|
let fieldSchema;
|
||||||
fieldSchema = z.string();
|
if (StringFields.some((x) => x === type)) {
|
||||||
} else if (type === BeginQueryType.Boolean) {
|
fieldSchema = z.string();
|
||||||
fieldSchema = z.boolean();
|
} else if (type === BeginQueryType.Boolean) {
|
||||||
} else if (type === BeginQueryType.Integer) {
|
fieldSchema = z.boolean();
|
||||||
fieldSchema = z.coerce.number();
|
} else if (type === BeginQueryType.Integer) {
|
||||||
} else {
|
fieldSchema = z.coerce.number();
|
||||||
fieldSchema = z.instanceof(File);
|
} else {
|
||||||
}
|
fieldSchema = z.instanceof(File);
|
||||||
|
}
|
||||||
|
|
||||||
if (cur.optional) {
|
if (cur.optional) {
|
||||||
fieldSchema.optional();
|
fieldSchema.optional();
|
||||||
}
|
}
|
||||||
|
|
||||||
pre[idx.toString()] = fieldSchema;
|
pre[idx.toString()] = fieldSchema;
|
||||||
|
|
||||||
return pre;
|
return pre;
|
||||||
}, {});
|
},
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
|
||||||
return z.object(obj);
|
return z.object(obj);
|
||||||
}, [parameters]);
|
}, [parameters]);
|
||||||
|
|
||||||
const form = useForm({
|
const form = useForm<z.infer<typeof FormSchema>>({
|
||||||
defaultValues: values,
|
defaultValues: values,
|
||||||
resolver: zodResolver(FormSchema),
|
resolver: zodResolver(FormSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
|
||||||
visible,
|
|
||||||
hideModal: hidePopover,
|
|
||||||
switchVisible,
|
|
||||||
showModal: showPopover,
|
|
||||||
} = useSetModalState();
|
|
||||||
|
|
||||||
const { setRecord, currentRecord } = useSetSelectedRecord<number>();
|
|
||||||
// const { submittable } = useHandleSubmittable(form);
|
|
||||||
const submittable = true;
|
const submittable = true;
|
||||||
const [isUploading, setIsUploading] = useState(false);
|
|
||||||
|
|
||||||
const handleShowPopover = useCallback(
|
|
||||||
(idx: number) => () => {
|
|
||||||
setRecord(idx);
|
|
||||||
showPopover();
|
|
||||||
},
|
|
||||||
[setRecord, showPopover],
|
|
||||||
);
|
|
||||||
|
|
||||||
const normFile = (e: any) => {
|
|
||||||
if (Array.isArray(e)) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
return e?.fileList;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onChange = useCallback(
|
|
||||||
(optional: boolean) =>
|
|
||||||
({ fileList }: UploadChangeParam<UploadFile>) => {
|
|
||||||
if (!optional) {
|
|
||||||
setIsUploading(fileList.some((x) => x.status === 'uploading'));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
const renderWidget = useCallback(
|
const renderWidget = useCallback(
|
||||||
(q: BeginQuery, idx: string) => {
|
(q: BeginQuery, idx: string) => {
|
||||||
@ -132,14 +99,6 @@ const DebugContent = ({
|
|||||||
label: q.name ?? q.key,
|
label: q.name ?? q.key,
|
||||||
name: idx,
|
name: idx,
|
||||||
};
|
};
|
||||||
if (q.optional === false) {
|
|
||||||
props.rules = [{ required: true }];
|
|
||||||
}
|
|
||||||
|
|
||||||
// const urlList: { url: string; result: string }[] =
|
|
||||||
// form.getFieldValue(idx) || [];
|
|
||||||
|
|
||||||
const urlList: { url: string; result: string }[] = [];
|
|
||||||
|
|
||||||
const BeginQueryTypeMap = {
|
const BeginQueryTypeMap = {
|
||||||
[BeginQueryType.Line]: (
|
[BeginQueryType.Line]: (
|
||||||
@ -183,7 +142,10 @@ const DebugContent = ({
|
|||||||
<RAGFlowSelect
|
<RAGFlowSelect
|
||||||
allowClear
|
allowClear
|
||||||
options={
|
options={
|
||||||
q.options?.map((x) => ({ label: x, value: x })) ?? []
|
q.options?.map((x) => ({
|
||||||
|
label: x,
|
||||||
|
value: x as string,
|
||||||
|
})) ?? []
|
||||||
}
|
}
|
||||||
{...field}
|
{...field}
|
||||||
></RAGFlowSelect>
|
></RAGFlowSelect>
|
||||||
@ -295,10 +257,10 @@ const DebugContent = ({
|
|||||||
<ButtonLoading
|
<ButtonLoading
|
||||||
type="submit"
|
type="submit"
|
||||||
loading={loading}
|
loading={loading}
|
||||||
disabled={!submittable || isUploading || submitButtonDisabled}
|
disabled={!submittable || submitButtonDisabled}
|
||||||
className="w-full"
|
className="w-full"
|
||||||
>
|
>
|
||||||
{t(isNext ? 'common.next' : 'flow.run')}
|
{btnText || t(isNext ? 'common.next' : 'flow.run')}
|
||||||
</ButtonLoading>
|
</ButtonLoading>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import { useGetBeginNodeDataQuery } from '../hooks/use-get-begin-query';
|
|||||||
import { useSaveGraphBeforeOpeningDebugDrawer } from '../hooks/use-save-graph';
|
import { useSaveGraphBeforeOpeningDebugDrawer } from '../hooks/use-save-graph';
|
||||||
import { BeginQuery } from '../interface';
|
import { BeginQuery } from '../interface';
|
||||||
import useGraphStore from '../store';
|
import useGraphStore from '../store';
|
||||||
|
import { buildBeginQueryWithObject } from '../utils';
|
||||||
|
|
||||||
const RunSheet = ({
|
const RunSheet = ({
|
||||||
hideModal,
|
hideModal,
|
||||||
@ -34,16 +35,7 @@ const RunSheet = ({
|
|||||||
const beginNode = getNode(BeginId);
|
const beginNode = getNode(BeginId);
|
||||||
const inputs: Record<string, BeginQuery> = beginNode?.data.form.inputs;
|
const inputs: Record<string, BeginQuery> = beginNode?.data.form.inputs;
|
||||||
|
|
||||||
const nextInputs = Object.keys(inputs).reduce<Record<string, BeginQuery>>(
|
const nextInputs = buildBeginQueryWithObject(inputs, nextValues);
|
||||||
(pre, key) => {
|
|
||||||
const item = nextValues.find((x) => x.key === key);
|
|
||||||
if (item) {
|
|
||||||
pre[key] = { ...item };
|
|
||||||
}
|
|
||||||
return pre;
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
);
|
|
||||||
|
|
||||||
const currentNodes = updateNodeForm(BeginId, nextInputs, ['inputs']);
|
const currentNodes = updateNodeForm(BeginId, nextInputs, ['inputs']);
|
||||||
handleRun(currentNodes);
|
handleRun(currentNodes);
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import {
|
|||||||
NodeMap,
|
NodeMap,
|
||||||
Operator,
|
Operator,
|
||||||
} from './constant';
|
} from './constant';
|
||||||
import { IPosition } from './interface';
|
import { BeginQuery, IPosition } from './interface';
|
||||||
|
|
||||||
const buildEdges = (
|
const buildEdges = (
|
||||||
operatorIds: string[],
|
operatorIds: string[],
|
||||||
@ -537,3 +537,21 @@ export function mapEdgeMouseEvent(
|
|||||||
|
|
||||||
return nextEdges;
|
return nextEdges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function buildBeginQueryWithObject(
|
||||||
|
inputs: Record<string, BeginQuery>,
|
||||||
|
values: BeginQuery[],
|
||||||
|
) {
|
||||||
|
const nextInputs = Object.keys(inputs).reduce<Record<string, BeginQuery>>(
|
||||||
|
(pre, key) => {
|
||||||
|
const item = values.find((x) => x.key === key);
|
||||||
|
if (item) {
|
||||||
|
pre[key] = { ...item };
|
||||||
|
}
|
||||||
|
return pre;
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
|
||||||
|
return nextInputs;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user