feat: send question with retrieval api #2247 (#2272)

### What problem does this PR solve?
feat: send question with retrieval api #2247

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2024-09-05 19:32:55 +08:00
committed by GitHub
parent 9377192859
commit 6ae0da92cb
17 changed files with 264 additions and 78 deletions

View File

@@ -0,0 +1,38 @@
import { MessageType } from '@/constants/chat';
import { useTestChunkRetrieval } from '@/hooks/knowledge-hooks';
import { useSendMessageWithSse } from '@/hooks/logic-hooks';
import api from '@/utils/api';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { IMessage } from '../chat/interface';
export const useSendQuestion = (kbIds: string[]) => {
const { send, answer, done } = useSendMessageWithSse(api.ask);
const { testChunk, loading } = useTestChunkRetrieval();
const [sendingLoading, setSendingLoading] = useState(false);
const message: IMessage = useMemo(() => {
return {
id: '',
content: answer.answer,
role: MessageType.Assistant,
reference: answer.reference,
};
}, [answer]);
const sendQuestion = useCallback(
(question: string) => {
setSendingLoading(true);
send({ kb_ids: kbIds, question });
testChunk({ kb_id: kbIds, highlight: true, question });
},
[send, testChunk, kbIds],
);
useEffect(() => {
if (done) {
setSendingLoading(false);
}
}, [done]);
return { sendQuestion, message, loading, sendingLoading };
};

View File

@@ -1,9 +1,17 @@
.searchPage {
// height: 100%;
}
.searchSide {
height: calc(100vh - 72px);
position: fixed !important;
// height: calc(100vh - 72px);
position: relative;
// position: fixed !important;
// top: 72px;
// bottom: 0;
:global(.ant-layout-sider-children) {
height: auto;
}
inset-inline-start: 0;
top: 72px;
bottom: 0;
.modelForm {
display: flex;
@@ -16,13 +24,29 @@
}
.list {
width: 100%;
height: 100%;
// height: 100%;
height: calc(100vh - 152px);
overflow: auto;
}
.checkbox {
width: 100%;
}
.knowledgeName {
width: 120px;
width: 130px;
}
}
.content {
height: 100%;
.main {
width: 60%;
// background-color: aqua;
overflow: auto;
padding: 10px;
}
.graph {
width: 40%;
background-color: bisque;
}
}

View File

@@ -1,37 +1,65 @@
import { Layout } from 'antd';
import React from 'react';
import HightLightMarkdown from '@/components/highlight-markdown';
import { ImageWithPopover } from '@/components/image';
import MessageItem from '@/components/message-item';
import { useSelectTestingResult } from '@/hooks/knowledge-hooks';
import { IReference } from '@/interfaces/database/chat';
import { Card, Flex, Input, Layout, List, Space } from 'antd';
import { useState } from 'react';
import { useSendQuestion } from './hooks';
import SearchSidebar from './sidebar';
const { Header, Content, Footer } = Layout;
import styles from './index.less';
const { Content } = Layout;
const { Search } = Input;
const SearchPage = () => {
const [checkedList, setCheckedList] = useState<string[]>([]);
const list = useSelectTestingResult();
const { sendQuestion, message, sendingLoading } =
useSendQuestion(checkedList);
return (
<Layout hasSider>
<SearchSidebar></SearchSidebar>
<Layout style={{ marginInlineStart: 200 }}>
<Header style={{ padding: 0 }} />
<Content style={{ margin: '24px 16px 0', overflow: 'initial' }}>
<div
style={{
padding: 24,
textAlign: 'center',
}}
>
<p>long content</p>
{
// indicates very long content
Array.from({ length: 100 }, (_, index) => (
<React.Fragment key={index}>
{index % 20 === 0 && index ? 'more' : '...'}
<br />
</React.Fragment>
))
}
</div>
<Layout className={styles.searchPage}>
<SearchSidebar
checkedList={checkedList}
setCheckedList={setCheckedList}
></SearchSidebar>
<Layout>
<Content>
<Flex className={styles.content}>
<section className={styles.main}>
<Search
placeholder="input search text"
onSearch={sendQuestion}
size="large"
/>
<MessageItem
item={message}
nickname="You"
reference={message.reference ?? ({} as IReference)}
loading={sendingLoading}
index={0}
></MessageItem>
<List
dataSource={list.chunks}
renderItem={(item) => (
<List.Item>
<Card>
<Space>
<ImageWithPopover id={item.img_id}></ImageWithPopover>
<HightLightMarkdown>
{item.highlight}
</HightLightMarkdown>
</Space>
</Card>
</List.Item>
)}
/>
</section>
<section className={styles.graph}></section>
</Flex>
</Content>
<Footer style={{ textAlign: 'center' }}>
Ant Design ©{new Date().getFullYear()} Created by Ant UED
</Footer>
</Layout>
</Layout>
);

View File

@@ -1,20 +1,30 @@
import { useNextFetchKnowledgeList } from '@/hooks/knowledge-hooks';
import type { CheckboxProps } from 'antd';
import { Checkbox, Layout, List, Typography } from 'antd';
import { Avatar, Checkbox, Layout, List, Space, Typography } from 'antd';
import { CheckboxValueType } from 'antd/es/checkbox/Group';
import { useCallback, useMemo, useState } from 'react';
import {
Dispatch,
SetStateAction,
useCallback,
useEffect,
useMemo,
} from 'react';
import { UserOutlined } from '@ant-design/icons';
import { CheckboxChangeEvent } from 'antd/es/checkbox';
import styles from './index.less';
const { Sider } = Layout;
const SearchSidebar = () => {
interface IProps {
checkedList: string[];
setCheckedList: Dispatch<SetStateAction<string[]>>;
}
const SearchSidebar = ({ checkedList, setCheckedList }: IProps) => {
const { list } = useNextFetchKnowledgeList();
const ids = useMemo(() => list.map((x) => x.id), [list]);
const [checkedList, setCheckedList] = useState<string[]>(ids);
const checkAll = list.length === checkedList.length;
const indeterminate =
@@ -31,8 +41,12 @@ const SearchSidebar = () => {
[ids],
);
useEffect(() => {
setCheckedList(ids);
}, [ids]);
return (
<Sider className={styles.searchSide} theme={'light'} width={260}>
<Sider className={styles.searchSide} theme={'light'} width={240}>
<Checkbox
className={styles.modelForm}
indeterminate={indeterminate}
@@ -53,12 +67,15 @@ const SearchSidebar = () => {
renderItem={(item) => (
<List.Item>
<Checkbox value={item.id} className={styles.checkbox}>
<Typography.Text
ellipsis={{ tooltip: item.name }}
className={styles.knowledgeName}
>
{item.name}
</Typography.Text>
<Space>
<Avatar size={30} icon={<UserOutlined />} src={item.avatar} />
<Typography.Text
ellipsis={{ tooltip: item.name }}
className={styles.knowledgeName}
>
{item.name}
</Typography.Text>
</Space>
</Checkbox>
</List.Item>
)}