Skip to content
Snippets Groups Projects
Unverified Commit fae00827 authored by balibabu's avatar balibabu Committed by GitHub
Browse files

feat: locate the specific location of the document based on the coordinates of...

feat: locate the specific location of the document based on the coordinates of the chunk and add Upload to AssistantSetting (#92)

* feat: add Upload to AssistantSetting

* feat: locate the specific location of the document based on the coordinates of the chunk
parent 685b4d8a
No related branches found
No related tags found
No related merge requests found
Showing
with 231 additions and 61 deletions
......@@ -74,6 +74,7 @@ export interface IChunk {
docnm_kwd: string;
img_id: string;
important_kwd: any[];
positions: number[][];
}
export interface ITestingChunk {
......
......@@ -8,6 +8,8 @@
@gray11: rgba(232, 232, 234, 1);
@purple: rgba(127, 86, 217, 1);
@selectedBackgroundColor: rgba(239, 248, 255, 1);
@blurBackground: rgba(22, 119, 255, 0.5);
@blurBackgroundHover: rgba(22, 119, 255, 0.2);
@fontSize12: 12px;
@fontSize14: 14px;
......
......@@ -13,6 +13,28 @@
color: red;
font-style: normal;
}
caption {
color: @blurBackground;
font-size: 20px;
height: 50px;
line-height: 50px;
font-weight: 600;
margin-bottom: 10px;
}
th {
color: #fff;
background-color: @blurBackground;
}
td:hover {
background: @blurBackgroundHover;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
}
.cardSelected {
......
......@@ -64,9 +64,7 @@ const ChunkCard = ({
onClick={handleContentClick}
className={styles.content}
dangerouslySetInnerHTML={{ __html: item.content_with_weight }}
>
{/* {item.content_with_weight} */}
</section>
></section>
<div>
<Switch checked={enabled} onChange={onChange} />
</div>
......
......@@ -6,21 +6,27 @@ export const testHighlights = [
position: {
boundingRect: {
x1: 219.7,
// x1: 419.7,
y1: 204.3,
// y1: 304.3,
x2: 547.0,
// x2: 747.0,
y2: 264.0,
width: 849,
height: 1200,
// y2: 364.0,
},
rects: [
{
x1: 219.7,
y1: 204.3,
x2: 547.0,
y2: 264.0,
width: 849,
height: 1200,
},
// {
// x1: 219.7,
// // x1: 419.7,
// y1: 204.3,
// // y1: 304.3,
// x2: 547.0,
// // x2: 747.0,
// y2: 264.0,
// // y2: 364.0,
// width: 849,
// height: 1200,
// },
],
pageNumber: 9,
},
......@@ -28,6 +34,56 @@ export const testHighlights = [
text: 'Flow or TypeScript?',
emoji: '🔥',
},
id: '8245652131754351',
id: 'jsdlihdkghergjl',
},
];
{
content: {
text: '图2:乘联会预计6 月新能源乘用车厂商批发销量74 万辆,环比增长10%,同比增长30%。',
},
position: {
boundingRect: {
x1: 219.0,
x2: 546.0,
y1: 616.0,
y2: 674.7,
},
rects: [],
pageNumber: 6,
},
comment: {
text: 'Flow or TypeScript?',
emoji: '🔥',
},
id: 'bfdbtymkhjildbfghserrgrt',
},
{
content: {
text: '图2:乘联会预计6 月新能源乘用车厂商批发销量74 万辆,环比增长10%,同比增长30%。',
},
position: {
boundingRect: {
x1: 73.7,
x2: 391.7,
y1: 570.3,
y2: 676.3,
},
rects: [],
pageNumber: 1,
},
comment: {
text: '',
emoji: '',
},
id: 'fgnhxdvsesgmghyu',
},
].map((x) => {
const boundingRect = x.position.boundingRect;
const ret: any = {
width: 849,
height: 1200,
};
Object.entries(boundingRect).forEach(([key, value]) => {
ret[key] = value / 0.7;
});
return { ...x, position: { ...x.position, boundingRect: ret, rects: [ret] } };
});
......@@ -6,6 +6,9 @@
position: relative;
:global(.PdfHighlighter) {
overflow-x: hidden;
// left: 0;
}
:global(.Highlight--scrolledTo .Highlight__part) {
overflow-x: hidden;
background-color: rgba(255, 226, 143, 1);
}
}
import { Spin } from 'antd';
import { useRef, useState } from 'react';
import type { NewHighlight } from 'react-pdf-highlighter';
import { useEffect, useRef } from 'react';
import {
AreaHighlight,
Highlight,
NewHighlight,
PdfHighlighter,
PdfLoader,
Popup,
Tip,
} from 'react-pdf-highlighter';
import { useGetSelectedChunk } from '../../hooks';
import { testHighlights } from './hightlights';
import { useGetChunkHighlights, useGetSelectedChunk } from '../../hooks';
import { useGetDocumentUrl } from './hooks';
import styles from './index.less';
......@@ -36,7 +35,9 @@ const Preview = ({ selectedChunkId }: IProps) => {
const url = useGetDocumentUrl();
const selectedChunk = useGetSelectedChunk(selectedChunkId);
const [state, setState] = useState<any>(testHighlights);
// const [state, setState] = useState<any>(testHighlights);
const state = useGetChunkHighlights(selectedChunkId);
const ref = useRef((highlight: any) => {});
const parseIdFromHash = () =>
......@@ -67,7 +68,7 @@ const Preview = ({ selectedChunkId }: IProps) => {
console.log('Saving highlight', highlight);
setState([{ ...highlight, id: getNextId() }, ...highlights]);
// setState([{ ...highlight, id: getNextId() }, ...highlights]);
};
const updateHighlight = (
......@@ -77,29 +78,31 @@ const Preview = ({ selectedChunkId }: IProps) => {
) => {
console.log('Updating highlight', highlightId, position, content);
setState(
state.map((h: any) => {
const {
id,
position: originalPosition,
content: originalContent,
...rest
} = h;
return id === highlightId
? {
id,
position: { ...originalPosition, ...position },
content: { ...originalContent, ...content },
...rest,
}
: h;
}),
);
// setState(
// state.map((h: any) => {
// const {
// id,
// position: originalPosition,
// content: originalContent,
// ...rest
// } = h;
// return id === highlightId
// ? {
// id,
// position: { ...originalPosition, ...position },
// content: { ...originalContent, ...content },
// ...rest,
// }
// : h;
// }),
// );
};
// useEffect(() => {
// ref.current(testHighlights[0]);
// }, [selectedChunk]);
useEffect(() => {
if (state.length > 0) {
ref.current(state[0]);
}
}, [state]);
return (
<div className={styles.documentContainer}>
......
import { IChunk, IKnowledgeFile } from '@/interfaces/database/knowledge';
import { useCallback, useState } from 'react';
import { useCallback, useMemo, useState } from 'react';
import { IHighlight } from 'react-pdf-highlighter';
import { useSelector } from 'umi';
import { v4 as uuid } from 'uuid';
export const useSelectDocumentInfo = () => {
const documentInfo: IKnowledgeFile = useSelector(
......@@ -28,5 +30,46 @@ export const useHandleChunkCardClick = () => {
export const useGetSelectedChunk = (selectedChunkId: string) => {
const chunkList: IChunk[] = useSelectChunkList();
return chunkList.find((x) => x.chunk_id === selectedChunkId);
return (
chunkList.find((x) => x.chunk_id === selectedChunkId) ?? ({} as IChunk)
);
};
export const useGetChunkHighlights = (
selectedChunkId: string,
): IHighlight[] => {
const selectedChunk: IChunk = useGetSelectedChunk(selectedChunkId);
const highlights: IHighlight[] = useMemo(() => {
return Array.isArray(selectedChunk?.positions)
? selectedChunk?.positions?.map((x) => {
const actualPositions = x.map((y, index) =>
index !== 0 ? y / 0.7 : y,
);
const boundingRect = {
width: 849,
height: 1200,
x1: actualPositions[1],
x2: actualPositions[2],
y1: actualPositions[3],
y2: actualPositions[4],
};
return {
id: uuid(),
comment: {
text: '',
emoji: '',
},
content: { text: selectedChunk.content_with_weight },
position: {
boundingRect: boundingRect,
rects: [boundingRect],
pageNumber: x[0],
},
};
})
: [];
}, [selectedChunk]);
return highlights;
};
......@@ -23,7 +23,7 @@ import {
import type { ColumnsType } from 'antd/es/table';
import { PaginationProps } from 'antd/lib';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Link, useDispatch, useNavigate, useSelector } from 'umi';
import { useDispatch, useNavigate, useSelector } from 'umi';
import CreateEPModal from './createEFileModal';
import styles from './index.less';
import ParsingActionCell from './parsing-action-cell';
......@@ -144,19 +144,22 @@ const KnowledgeFile = () => {
});
}, [dispatch]);
const linkToUploadPage = useCallback(() => {
navigate(`/knowledge/dataset/upload?id=${knowledgeBaseId}`);
}, [navigate, knowledgeBaseId]);
const actionItems: MenuProps['items'] = useMemo(() => {
return [
{
key: '1',
onClick: linkToUploadPage,
label: (
<div>
<Button type="link">
<Link to={`/knowledge/dataset/upload?id=${knowledgeBaseId}`}>
<Space>
<FileTextOutlined />
Local files
</Space>
</Link>
<Space>
<FileTextOutlined />
Local files
</Space>
</Button>
</div>
),
......@@ -164,9 +167,10 @@ const KnowledgeFile = () => {
{ type: 'divider' },
{
key: '2',
onClick: showCEFModal,
label: (
<div>
<Button type="link" onClick={showCEFModal}>
<Button type="link">
<FileOutlined />
Create empty file
</Button>
......@@ -175,7 +179,7 @@ const KnowledgeFile = () => {
// disabled: true,
},
];
}, [knowledgeBaseId, showCEFModal]);
}, [linkToUploadPage, showCEFModal]);
const toChunk = (id: string) => {
navigate(
......
import { Form, Input, Select } from 'antd';
import { Form, Input, Select, Upload } from 'antd';
import classNames from 'classnames';
import { ISegmentedContentProps } from '../interface';
import { useFetchKnowledgeList } from '@/hooks/knowledgeHook';
import { PlusOutlined } from '@ant-design/icons';
import styles from './index.less';
const AssistantSetting = ({ show }: ISegmentedContentProps) => {
......@@ -13,6 +14,13 @@ const AssistantSetting = ({ show }: ISegmentedContentProps) => {
value: x.id,
}));
const normFile = (e: any) => {
if (Array.isArray(e)) {
return e;
}
return e?.fileList;
};
return (
<section
className={classNames({
......@@ -26,8 +34,22 @@ const AssistantSetting = ({ show }: ISegmentedContentProps) => {
>
<Input placeholder="e.g. Resume Jarvis" />
</Form.Item>
<Form.Item name={'icon'} label="Assistant avatar">
<Input />
<Form.Item
name="icon"
label="Assistant avatar"
valuePropName="fileList"
getValueFromEvent={normFile}
>
<Upload
listType="picture-card"
maxCount={1}
showUploadList={{ showPreviewIcon: false, showRemoveIcon: false }}
>
<button style={{ border: 0, background: 'none' }} type="button">
<PlusOutlined />
<div style={{ marginTop: 8 }}>Upload</div>
</button>
</Upload>
</Form.Item>
<Form.Item name={'language'} label="Language" initialValue={'Chinese'}>
<Select
......
import { ReactComponent as ChatConfigurationAtom } from '@/assets/svg/chat-configuration-atom.svg';
import { IModalManagerChildrenProps } from '@/components/modal-manager';
import { Divider, Flex, Form, Modal, Segmented } from 'antd';
import { Divider, Flex, Form, Modal, Segmented, UploadFile } from 'antd';
import { SegmentedValue } from 'antd/es/segmented';
import omit from 'lodash/omit';
import { useEffect, useRef, useState } from 'react';
......@@ -67,6 +67,14 @@ const ChatConfigurationModal = ({ visible, hideModal, id }: IProps) => {
...excludeUnEnabledVariables(values),
]);
const emptyResponse = nextValues.prompt_config?.empty_response ?? '';
const fileList = values.icon;
let icon;
if (Array.isArray(fileList) && fileList.length > 0) {
icon = fileList[0].thumbUrl;
}
const finalValues = {
dialog_id: id,
...nextValues,
......@@ -75,6 +83,7 @@ const ChatConfigurationModal = ({ visible, hideModal, id }: IProps) => {
parameters: promptEngineRef.current,
empty_response: emptyResponse,
},
icon,
};
console.info(promptEngineRef.current);
console.info(nextValues);
......@@ -112,7 +121,13 @@ const ChatConfigurationModal = ({ visible, hideModal, id }: IProps) => {
);
useEffect(() => {
form.setFieldsValue(currentDialog);
const icon = currentDialog.icon;
let fileList: UploadFile[] = [];
if (icon) {
fileList = [{ uid: '1', name: 'file', thumbUrl: icon, status: 'done' }];
}
form.setFieldsValue({ ...currentDialog, icon: fileList });
}, [currentDialog, form]);
return (
......
......@@ -2,6 +2,7 @@ import { ReactComponent as ChatAppCube } from '@/assets/svg/chat-app-cube.svg';
import { useSetModalState } from '@/hooks/commonHooks';
import { DeleteOutlined, EditOutlined, FormOutlined } from '@ant-design/icons';
import {
Avatar,
Button,
Card,
Divider,
......@@ -208,8 +209,8 @@ const Chat = () => {
onClick={handleDialogCardClick(x.id)}
>
<Flex justify="space-between" align="center">
<Space>
{x.icon}
<Space size={15}>
<Avatar src={x.icon} shape={'square'} />
<section>
<b>{x.name}</b>
<div>{x.description}</div>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment