Pārlūkot izejas kodu

Feat: In a dialog message, users can enter different types of data #3221 (#8583)

### 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)
tags/v0.20.0
balibabu pirms 4 mēnešiem
vecāks
revīzija
d620432e3b
Revīzijas autora e-pasta adrese nav piesaistīta nevienam kontam

+ 43
- 3
web/src/pages/agent/chat/box.tsx Parādīt failu

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 {
derivedMessages, derivedMessages,
reference, reference,
stopOutputMessage, stopOutputMessage,
send,
sendFormMessage,
} = useSendNextMessage(); } = useSendNextMessage();


const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } = const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
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 (
<> <>
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>
); );
})} })}

+ 15
- 0
web/src/pages/agent/chat/hooks.ts Parādīt failu

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';


}); });
}, [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({
removeMessageById, removeMessageById,
stopOutputMessage, stopOutputMessage,
send, send,
sendFormMessage,
}; };
}; };

+ 31
- 69
web/src/pages/agent/debug-content/index.tsx Parādīt failu

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, { useCallback, useMemo, useState } from 'react';
import React, { ReactNode, useCallback, useMemo } 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';
isNext?: boolean; isNext?: boolean;
loading?: boolean; loading?: boolean;
submitButtonDisabled?: boolean; submitButtonDisabled?: boolean;
btnText?: ReactNode;
} }


const values = {}; const values = {};
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 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); 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) => {
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]: (
<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>
<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>

+ 2
- 10
web/src/pages/agent/run-sheet/index.tsx Parādīt failu

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,
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>>(
(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']); const currentNodes = updateNodeForm(BeginId, nextInputs, ['inputs']);
handleRun(currentNodes); handleRun(currentNodes);

+ 19
- 1
web/src/pages/agent/utils.ts Parādīt failu

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[],


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;
}

Notiek ielāde…
Atcelt
Saglabāt