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 { useFetchAgent } from '@/hooks/use-agent-request';
|
||||
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
|
||||
import { Message } from '@/interfaces/database/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 {
|
||||
@ -25,7 +31,7 @@ const AgentChatBox = () => {
|
||||
derivedMessages,
|
||||
reference,
|
||||
stopOutputMessage,
|
||||
send,
|
||||
sendFormMessage,
|
||||
} = useSendNextMessage();
|
||||
|
||||
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
||||
@ -33,6 +39,35 @@ const AgentChatBox = () => {
|
||||
useGetFileIcon();
|
||||
const { data: userInfo } = useFetchUserInfo();
|
||||
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 (
|
||||
<>
|
||||
@ -62,7 +97,12 @@ const AgentChatBox = () => {
|
||||
showLikeButton={false}
|
||||
sendLoading={sendLoading}
|
||||
>
|
||||
<InputForm send={send} message={message}></InputForm>
|
||||
<DebugContent
|
||||
parameters={buildInputList(message)}
|
||||
ok={handleOk(message)}
|
||||
isNext={false}
|
||||
btnText={'Submit'}
|
||||
></DebugContent>
|
||||
</MessageItem>
|
||||
);
|
||||
})}
|
||||
|
||||
@ -22,6 +22,7 @@ import { useParams } from 'umi';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { BeginId } from '../constant';
|
||||
import { AgentChatLogContext } from '../context';
|
||||
import { BeginQuery } from '../interface';
|
||||
import useGraphStore from '../store';
|
||||
import { receiveMessageError } from '../utils';
|
||||
|
||||
@ -176,6 +177,19 @@ export const useSendNextMessage = () => {
|
||||
});
|
||||
}, [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(() => {
|
||||
if (prologue) {
|
||||
addNewestOneAnswer({
|
||||
@ -200,5 +214,6 @@ export const useSendNextMessage = () => {
|
||||
removeMessageById,
|
||||
stopOutputMessage,
|
||||
send,
|
||||
sendFormMessage,
|
||||
};
|
||||
};
|
||||
|
||||
@ -12,11 +12,8 @@ import { Input } from '@/components/ui/input';
|
||||
import { RAGFlowSelect } from '@/components/ui/select';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
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 { UploadChangeParam, UploadFile } from 'antd/es/upload';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import React, { ReactNode, useCallback, useMemo } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { z } from 'zod';
|
||||
@ -44,6 +41,7 @@ interface IProps {
|
||||
isNext?: boolean;
|
||||
loading?: boolean;
|
||||
submitButtonDisabled?: boolean;
|
||||
btnText?: ReactNode;
|
||||
}
|
||||
|
||||
const values = {};
|
||||
@ -54,76 +52,45 @@ const DebugContent = ({
|
||||
isNext = true,
|
||||
loading = false,
|
||||
submitButtonDisabled = false,
|
||||
btnText,
|
||||
}: IProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const FormSchema = useMemo(() => {
|
||||
const obj = parameters.reduce((pre, cur, idx) => {
|
||||
const type = cur.type;
|
||||
let fieldSchema;
|
||||
if (StringFields.some((x) => x === type)) {
|
||||
fieldSchema = z.string();
|
||||
} else if (type === BeginQueryType.Boolean) {
|
||||
fieldSchema = z.boolean();
|
||||
} else if (type === BeginQueryType.Integer) {
|
||||
fieldSchema = z.coerce.number();
|
||||
} else {
|
||||
fieldSchema = z.instanceof(File);
|
||||
}
|
||||
const obj = parameters.reduce<Record<string, z.ZodType>>(
|
||||
(pre, cur, idx) => {
|
||||
const type = cur.type;
|
||||
let fieldSchema;
|
||||
if (StringFields.some((x) => x === type)) {
|
||||
fieldSchema = z.string();
|
||||
} else if (type === BeginQueryType.Boolean) {
|
||||
fieldSchema = z.boolean();
|
||||
} else if (type === BeginQueryType.Integer) {
|
||||
fieldSchema = z.coerce.number();
|
||||
} else {
|
||||
fieldSchema = z.instanceof(File);
|
||||
}
|
||||
|
||||
if (cur.optional) {
|
||||
fieldSchema.optional();
|
||||
}
|
||||
if (cur.optional) {
|
||||
fieldSchema.optional();
|
||||
}
|
||||
|
||||
pre[idx.toString()] = fieldSchema;
|
||||
pre[idx.toString()] = fieldSchema;
|
||||
|
||||
return pre;
|
||||
}, {});
|
||||
return pre;
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
return z.object(obj);
|
||||
}, [parameters]);
|
||||
|
||||
const form = useForm({
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
defaultValues: values,
|
||||
resolver: zodResolver(FormSchema),
|
||||
});
|
||||
|
||||
const {
|
||||
visible,
|
||||
hideModal: hidePopover,
|
||||
switchVisible,
|
||||
showModal: showPopover,
|
||||
} = useSetModalState();
|
||||
|
||||
const { setRecord, currentRecord } = useSetSelectedRecord<number>();
|
||||
// const { submittable } = useHandleSubmittable(form);
|
||||
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(
|
||||
(q: BeginQuery, idx: string) => {
|
||||
@ -132,14 +99,6 @@ const DebugContent = ({
|
||||
label: q.name ?? q.key,
|
||||
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 = {
|
||||
[BeginQueryType.Line]: (
|
||||
@ -183,7 +142,10 @@ const DebugContent = ({
|
||||
<RAGFlowSelect
|
||||
allowClear
|
||||
options={
|
||||
q.options?.map((x) => ({ label: x, value: x })) ?? []
|
||||
q.options?.map((x) => ({
|
||||
label: x,
|
||||
value: x as string,
|
||||
})) ?? []
|
||||
}
|
||||
{...field}
|
||||
></RAGFlowSelect>
|
||||
@ -295,10 +257,10 @@ const DebugContent = ({
|
||||
<ButtonLoading
|
||||
type="submit"
|
||||
loading={loading}
|
||||
disabled={!submittable || isUploading || submitButtonDisabled}
|
||||
disabled={!submittable || submitButtonDisabled}
|
||||
className="w-full"
|
||||
>
|
||||
{t(isNext ? 'common.next' : 'flow.run')}
|
||||
{btnText || t(isNext ? 'common.next' : 'flow.run')}
|
||||
</ButtonLoading>
|
||||
</form>
|
||||
</Form>
|
||||
|
||||
@ -14,6 +14,7 @@ import { useGetBeginNodeDataQuery } from '../hooks/use-get-begin-query';
|
||||
import { useSaveGraphBeforeOpeningDebugDrawer } from '../hooks/use-save-graph';
|
||||
import { BeginQuery } from '../interface';
|
||||
import useGraphStore from '../store';
|
||||
import { buildBeginQueryWithObject } from '../utils';
|
||||
|
||||
const RunSheet = ({
|
||||
hideModal,
|
||||
@ -34,16 +35,7 @@ const RunSheet = ({
|
||||
const beginNode = getNode(BeginId);
|
||||
const inputs: Record<string, BeginQuery> = beginNode?.data.form.inputs;
|
||||
|
||||
const nextInputs = Object.keys(inputs).reduce<Record<string, BeginQuery>>(
|
||||
(pre, key) => {
|
||||
const item = nextValues.find((x) => x.key === key);
|
||||
if (item) {
|
||||
pre[key] = { ...item };
|
||||
}
|
||||
return pre;
|
||||
},
|
||||
{},
|
||||
);
|
||||
const nextInputs = buildBeginQueryWithObject(inputs, nextValues);
|
||||
|
||||
const currentNodes = updateNodeForm(BeginId, nextInputs, ['inputs']);
|
||||
handleRun(currentNodes);
|
||||
|
||||
@ -19,7 +19,7 @@ import {
|
||||
NodeMap,
|
||||
Operator,
|
||||
} from './constant';
|
||||
import { IPosition } from './interface';
|
||||
import { BeginQuery, IPosition } from './interface';
|
||||
|
||||
const buildEdges = (
|
||||
operatorIds: string[],
|
||||
@ -537,3 +537,21 @@ export function mapEdgeMouseEvent(
|
||||
|
||||
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