set port (#39)

* set port

* add knowledge-search

* update text
This commit is contained in:
yqj123 2024-01-19 18:35:24 +08:00 committed by GitHub
parent 103e12b7c2
commit f3dd131403
15 changed files with 534 additions and 31 deletions

View File

@ -2,7 +2,7 @@
"private": true,
"author": "zhaofengchao <13723060510@163.com>",
"scripts": {
"dev": "set PORT=9000&&umi dev",
"dev": "cross-env PORT=9000 umi dev",
"build": "umi build",
"postinstall": "umi setup",
"setup": "umi setup",
@ -30,6 +30,7 @@
"@types/react": "^18.0.33",
"@types/react-dom": "^18.0.11",
"@umijs/plugins": "^4.1.0",
"cross-env": "^7.0.3",
"typescript": "^5.0.3",
"umi-plugin-icons": "^0.1.1"
}

View File

@ -14,10 +14,12 @@ interface kFProps {
dispatch: Dispatch;
chunkModel: chunkModelState;
getChunkList: () => void;
doc_id: string
isShowCreateModal: boolean;
doc_id: string;
chunk_id: string
}
const Index: React.FC<kFProps> = ({ chunkModel, dispatch, getChunkList, doc_id }) => {
const { isShowCreateModal, chunk_id, chunkInfo } = chunkModel
const Index: React.FC<kFProps> = ({ dispatch, getChunkList, doc_id, isShowCreateModal, chunk_id }) => {
// const { , chunkInfo } = chunkModel
const [important_kwd, setImportantKwd] = useState(['Unremovable', 'Tag 2', 'Tag 3']);
const { t } = useTranslation()
const handleCancel = () => {
@ -29,6 +31,7 @@ const Index: React.FC<kFProps> = ({ chunkModel, dispatch, getChunkList, doc_id }
});
};
useEffect(() => {
console.log(chunk_id, isShowCreateModal)
if (chunk_id && isShowCreateModal) {
dispatch({
type: 'chunkModel/get_chunk',
@ -85,7 +88,7 @@ const Index: React.FC<kFProps> = ({ chunkModel, dispatch, getChunkList, doc_id }
<Form.Item<FieldType>
label="chunk 内容"
name="content_ltks"
rules={[{ required: true, message: 'Please input name!' }]}
rules={[{ required: true, message: 'Please input value!' }]}
>
<Input.TextArea />
</Form.Item>

View File

@ -4,7 +4,7 @@ import { Card, Row, Col, Input, Select, Switch, Pagination, Spin, Button, Popcon
import { MinusSquareOutlined, DeleteOutlined, } from '@ant-design/icons';
import type { PaginationProps } from 'antd';
import { api_host } from '@/utils/api'
import CreateModal from './createModal'
import CreateModal from './components/createModal'
import styles from './index.less'
@ -21,7 +21,7 @@ const Index: React.FC<chunkProps> = ({ chunkModel, dispatch, doc_id }) => {
const navigate = useNavigate()
const [pagination, setPagination] = useState({ page: 1, size: 30 })
// const [datas, setDatas] = useState(data)
const { data = [], total, loading } = chunkModel
const { data = [], total, loading, chunk_id, isShowCreateModal } = chunkModel
console.log(chunkModel)
const getChunkList = (value?: string) => {
dispatch({
@ -66,7 +66,8 @@ const Index: React.FC<chunkProps> = ({ chunkModel, dispatch, doc_id }) => {
type: 'chunkModel/updateState',
payload: {
isShowCreateModal: true,
chunk_id
chunk_id,
doc_id
},
callback: getChunkList
});
@ -216,7 +217,7 @@ const Index: React.FC<chunkProps> = ({ chunkModel, dispatch, doc_id }) => {
</div>
</div >
<CreateModal doc_id={doc_id} getChunkList={getChunkList} />
<CreateModal doc_id={doc_id} isShowCreateModal={isShowCreateModal} chunk_id={chunk_id} getChunkList={getChunkList} />
</>
)
};

View File

@ -8,6 +8,7 @@ export interface chunkModelState {
total: number;
isShowCreateModal: boolean;
chunk_id: string;
doc_id: string;
chunkInfo: any
}
export interface chunkgModelType {
@ -33,6 +34,7 @@ const Model: chunkgModelType = {
total: 0,
isShowCreateModal: false,
chunk_id: '',
doc_id: '',
chunkInfo: {}
},
subscriptions: {

View File

@ -65,7 +65,7 @@ const Index: React.FC<kFProps> = ({ kFModel, dispatch, getKfList, kb_id }) => {
<Form.Item<FieldType>
label="文件名"
name="name"
rules={[{ required: true, message: 'Please input name!' }]}
rules={[{ required: true, message: 'Please input value!' }]}
>
<Input />
</Form.Item>

View File

@ -0,0 +1,79 @@
.chunkPage {
padding: 24px;
display: flex;
height: calc(100vh - 112px);
// flex-direction: column;
.filter {
margin-right: 20px;
display: flex;
height: 32px;
width: 300px;
flex-wrap: wrap;
justify-content: space-between;
}
.pageContainer {
flex: 1;
display: flex;
flex-direction: column;
.pageContent {
flex: 1;
width: 100%;
padding-right: 12px;
overflow-y: auto;
.spin {
min-height: 400px;
}
}
.pageFooter {
height: 32px;
float: right;
}
}
}
.container {
height: 100px;
display: flex;
flex-direction: column;
justify-content: space-between;
.content {
display: flex;
justify-content: space-between;
.context {
flex: 1;
// width: 207px;
height: 88px;
overflow: hidden;
}
}
.footer {
height: 20px;
.text {
margin-left: 10px;
}
}
}
.card {
:global {
.ant-card-body {
padding: 10px;
margin: 0;
}
margin-bottom: 10px;
}
cursor: pointer;
}

View File

@ -1,3 +1,247 @@
export default () => {
return <div></div>
}
import React, { useEffect, useState, useCallback, } from 'react';
import { useNavigate, connect, Dispatch } from 'umi'
import { Card, Row, Col, Input, Select, Switch, Pagination, Spin, Button, Popconfirm } from 'antd';
import { MinusSquareOutlined, DeleteOutlined, } from '@ant-design/icons';
import type { PaginationProps } from 'antd';
import { api_host } from '@/utils/api'
import CreateModal from '../knowledge-chunk/components/createModal'
import styles from './index.less'
import { debounce } from 'lodash';
import type { kSearchModelState } from './model'
import type { chunkModelState } from '../knowledge-chunk/model'
interface chunkProps {
dispatch: Dispatch;
kSearchModel: kSearchModelState;
chunkModel: chunkModelState;
kb_id: string
}
const Index: React.FC<chunkProps> = ({ kSearchModel, chunkModel, dispatch, kb_id }) => {
const { data = [], total, loading, d_list = [], question, doc_ids, pagination, } = kSearchModel
const { chunk_id, doc_id, isShowCreateModal } = chunkModel
const getChunkList = () => {
dispatch({
type: 'kSearchModel/updateState',
payload: {
loading: true
}
});
interface payloadType {
kb_id: string;
question?: string;
doc_ids: any[];
similarity_threshold?: number
}
const payload: payloadType = {
kb_id,
question,
doc_ids,
similarity_threshold: 0.1
}
dispatch({
type: 'kSearchModel/chunk_list',
payload: {
...payload,
...pagination
}
});
}
const confirm = (id: string) => {
console.log(id)
dispatch({
type: 'kSearchModel/rm_chunk',
payload: {
chunk_ids: [id]
},
callback: getChunkList
});
};
const handleEditchunk = (item: any) => {
const { chunk_id, doc_id } = item
dispatch({
type: 'chunkModel/updateState',
payload: {
isShowCreateModal: true,
chunk_id,
doc_id
},
callback: getChunkList
});
}
const onShowSizeChange: PaginationProps['onShowSizeChange'] = (page, size) => {
dispatch({
type: 'kSearchModel/updateState',
payload: {
pagination: { page, size }
}
});
};
useEffect(() => {
dispatch({
type: 'kSearchModel/updateState',
payload: {
loading: false,
doc_ids: [],
question: ""
}
});
dispatch({
type: 'kSearchModel/getKfList',
payload: {
kb_id
}
});
}, [])
const switchChunk = (item: any, available_int: boolean) => {
const { chunk_id, doc_id } = item
dispatch({
type: 'kSearchModel/updateState',
payload: {
loading: true
}
});
dispatch({
type: 'kSearchModel/switch_chunk',
payload: {
chunk_ids: [chunk_id],
doc_id,
available_int
},
callback: getChunkList
});
}
useEffect(() => {
getChunkList()
}, [doc_ids, pagination, question])
const debounceChange = debounce((value) => {
dispatch({
type: 'kSearchModel/updateState',
payload: {
question: value
}
});
}, 300)
const debounceCallback = useCallback((value: string) => debounceChange(value), [])
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const value = e.target.value
debounceCallback(value)
}
const handleSelectChange = (value:
any[]) => {
dispatch({
type: 'kSearchModel/updateState',
payload: {
doc_ids: value
}
});
}
console.log('loading', loading)
return (<>
<div className={styles.chunkPage}>
<div className={styles.filter}>
<Select
showSearch
placeholder="文件列表"
optionFilterProp="children"
onChange={handleSelectChange}
style={{ width: 300, marginBottom: 20 }}
options={d_list}
fieldNames={{ label: 'name', value: 'id' }}
mode='multiple'
/>
<Input.TextArea autoSize={{ minRows: 6, maxRows: 6 }} placeholder="搜索" style={{ width: 300 }} allowClear onChange={handleInputChange} />
</div>
<div className={styles.pageContainer}>
<div className={styles.pageContent}>
<Spin spinning={loading} className={styles.spin} size='large'>
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 24 }} >
{
data.map((item: any) => {
return (<Col className="gutter-row" key={item.chunk_id} xs={24} sm={12} md={12} lg={8}>
<Card className={styles.card}
onClick={() => { handleEditchunk(item) }}
>
<img style={{ width: '50px' }} src={`${api_host}/document/image/${item.img_id}`} alt="" />
<div className={styles.container}>
<div className={styles.content}>
<span className={styles.context}>
{item.content_ltks}
</span>
<span className={styles.delete}>
<Switch size="small" defaultValue={item.doc_ids == '1'} onChange={(checked: boolean, e: any) => {
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation(); switchChunk(item, checked)
}} />
</span>
</div>
<div className={styles.footer}>
<span className={styles.text}>
<MinusSquareOutlined />{item.doc_num}
</span>
<span className={styles.text}>
<MinusSquareOutlined />{item.chunk_num}
</span>
<span className={styles.text}>
<MinusSquareOutlined />{item.token_num}
</span>
<span style={{ float: 'right' }}>
<Popconfirm
title="Delete the task"
description="Are you sure to delete this task?"
onConfirm={(e: any) => {
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation()
console.log(confirm)
confirm(item.chunk_id)
}}
okText="Yes"
cancelText="No"
>
<DeleteOutlined onClick={(e) => {
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation()
}} />
</Popconfirm>
</span>
</div>
</div>
</Card>
</Col>)
})
}
</Row>
</Spin>
</div>
<div className={styles.pageFooter}>
<Pagination
responsive
showLessItems
showQuickJumper
showSizeChanger
onChange={onShowSizeChange}
defaultPageSize={30}
pageSizeOptions={[30, 60, 90]}
defaultCurrent={pagination.page}
total={total}
/>
</div>
</div>
</div >
<CreateModal getChunkList={getChunkList} isShowCreateModal={isShowCreateModal} chunk_id={chunk_id} doc_id={doc_id} />
</>
)
};
export default connect(({ kSearchModel, chunkModel, loading }) => ({ kSearchModel, chunkModel, loading }))(Index);

View File

@ -0,0 +1,158 @@
import { Effect, Reducer, Subscription } from 'umi'
import { message } from 'antd';
import kbService from '@/services/kbService';
export interface kSearchModelState {
loading: boolean;
data: any[];
total: number;
isShowCreateModal: boolean;
chunk_id: string;
chunkInfo: any;
d_list: any[];
question: string;
doc_ids: any[];
pagination: any;
doc_id: string
}
export interface chunkgModelType {
namespace: 'kSearchModel';
state: kSearchModelState;
effects: {
chunk_list: Effect;
get_chunk: Effect;
create_hunk: Effect;
switch_chunk: Effect;
rm_chunk: Effect;
getKfList: Effect;
};
reducers: {
updateState: Reducer<kSearchModelState>;
};
subscriptions: { setup: Subscription };
}
const Model: chunkgModelType = {
namespace: 'kSearchModel',
state: {
loading: false,
data: [],
total: 0,
isShowCreateModal: false,
chunk_id: '',
chunkInfo: {},
d_list: [],
question: '',
doc_ids: [],
pagination: { page: 1, size: 30 },
doc_id: ''
},
subscriptions: {
setup({ dispatch, history }) {
history.listen(location => {
console.log(location)
});
}
},
effects: {
*getKfList({ payload = {} }, { call, put }) {
const { data, response } = yield call(kbService.get_document_list, payload);
const { retcode, data: res, retmsg } = data
if (retcode === 0) {
yield put({
type: 'updateState',
payload: {
d_list: res
}
});
}
},
* chunk_list({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(kbService.retrieval_test, payload);
const { retcode, data: res, retmsg } = data
if (retcode === 0) {
console.log(res)
yield put({
type: 'updateState',
payload: {
data: res.chunks,
total: res.total,
loading: false
}
});
callback && callback()
}
},
*switch_chunk({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(kbService.switch_chunk, payload);
const { retcode, data: res, retmsg } = data
if (retcode === 0) {
callback && callback()
}
},
*rm_chunk({ payload = {}, callback }, { call, put }) {
console.log('shanchu')
const { data, response } = yield call(kbService.rm_chunk, payload);
const { retcode, data: res, retmsg } = data
if (retcode === 0) {
callback && callback()
}
},
* get_chunk({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(kbService.get_chunk, payload);
const { retcode, data: res, retmsg } = data
if (retcode === 0) {
yield put({
type: 'updateState',
payload: {
chunkInfo: res
}
});
callback && callback(res)
}
},
*create_hunk({ payload = {} }, { call, put }) {
yield put({
type: 'updateState',
payload: {
loading: true
}
});
let service = kbService.create_chunk
if (payload.chunk_id) {
service = kbService.set_chunk
}
const { data, response } = yield call(service, payload);
const { retcode, data: res, retmsg } = data
yield put({
type: 'updateState',
payload: {
loading: false
}
});
if (retcode === 0) {
yield put({
type: 'updateState',
payload: {
isShowCreateModal: false
}
});
}
},
},
reducers: {
updateState(state, { payload }) {
return {
...state,
...payload
};
}
}
};
export default Model;

View File

@ -1,5 +1,5 @@
import { connect, useNavigate, useLocation, Dispatch } from 'umi'
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useMemo } from 'react';
import type { MenuProps } from 'antd';
import { Menu } from 'antd';
import {
@ -70,8 +70,10 @@ const Index: React.FC<kAProps> = ({ kAModel, dispatch }) => {
label: React.ReactNode,
key: React.Key,
icon?: React.ReactNode,
disabled?: boolean,
children?: MenuItem[],
type?: 'group',
): MenuItem {
return {
key,
@ -79,13 +81,17 @@ const Index: React.FC<kAProps> = ({ kAModel, dispatch }) => {
children,
label,
type,
disabled
} as MenuItem;
}
const items: MenuItem[] = [
getItem('配置', 'setting', <ToolOutlined />),
getItem('知识库', 'file', <BarsOutlined />),
getItem('搜索测试', 'search', <SearchOutlined />),
];
const items: MenuItem[] = useMemo(() => {
const disabled = !id
return [
getItem('配置', 'setting', <ToolOutlined />),
getItem('知识库', 'file', <BarsOutlined />, disabled),
getItem('搜索测试', 'search', <SearchOutlined />, disabled),
]
}, [id]);
const handleSelect: MenuProps['onSelect'] = (e) => {
navigate(`/knowledge/add/setting?activeKey=${e.key}&id=${id}`);
}
@ -105,7 +111,7 @@ const Index: React.FC<kAProps> = ({ kAModel, dispatch }) => {
<div className={styles.content}>
{activeKey === 'file' && !doc_id && <File kb_id={id} />}
{activeKey === 'setting' && <Setting kb_id={id} />}
{activeKey === 'search' && <Search />}
{activeKey === 'search' && <Search kb_id={id} />}
{activeKey === 'file' && !!doc_id && <Chunk doc_id={doc_id} />}
</div>

View File

@ -79,9 +79,9 @@ const View: FC<LoginProps> = ({
{...formItemLayout}
name="email"
label="Email"
rules={[{ required: true, message: 'Please input your name' }]}
rules={[{ required: true, message: 'Please input value' }]}
>
<Input size='large' placeholder="Please input your name" />
<Input size='large' placeholder="Please input value" />
</Form.Item>
{
title === 'register' && <Form.Item
@ -97,9 +97,9 @@ const View: FC<LoginProps> = ({
{...formItemLayout}
name="password"
label="Password"
rules={[{ required: true, message: 'Please input your name' }]}
rules={[{ required: true, message: 'Please input value' }]}
>
<Input size='large' placeholder="Please input your name" />
<Input size='large' placeholder="Please input value" />
</Form.Item>
{
title === 'login' && <Form.Item

View File

@ -71,7 +71,7 @@ const Index: FC<CPwModalProps> = ({ settingModel, dispatch }) => {
<Form.Item<FieldType>
label="旧密码"
name="password"
rules={[{ required: true, message: 'Please input your password!' }]}
rules={[{ required: true, message: 'Please input value' }]}
>
<Input.Password />
</Form.Item>

View File

@ -76,7 +76,7 @@ const Index: FC<SSModalProps> = ({ settingModel, dispatch }) => {
<Form.Item<FieldType>
label="embedding 模型"
name="embd_id"
rules={[{ required: true, message: 'Please input your password!' }]}
rules={[{ required: true, message: 'Please input value' }]}
initialValue={tenantIfo.embd_id}
>
@ -93,7 +93,7 @@ const Index: FC<SSModalProps> = ({ settingModel, dispatch }) => {
<Form.Item<FieldType>
label="chat 模型"
name="llm_id"
rules={[{ required: true, message: 'Please input your password!' }]}
rules={[{ required: true, message: 'Please input value' }]}
initialValue={tenantIfo.llm_id}
>
@ -110,7 +110,7 @@ const Index: FC<SSModalProps> = ({ settingModel, dispatch }) => {
<Form.Item<FieldType>
label="image2text 模型"
name="img2txt_id"
rules={[{ required: true, message: 'Please input your password!' }]}
rules={[{ required: true, message: 'Please input value' }]}
initialValue={tenantIfo.img2txt_id}
>
@ -127,7 +127,7 @@ const Index: FC<SSModalProps> = ({ settingModel, dispatch }) => {
<Form.Item<FieldType>
label="speech2text 模型"
name="asr_id"
rules={[{ required: true, message: 'Please input your password!' }]}
rules={[{ required: true, message: 'Please input value' }]}
initialValue={tenantIfo.asr_id}
>

View File

@ -16,7 +16,10 @@ const {
chunk_list,
create_chunk,
set_chunk,
get_chunk, switch_chunk, rm_chunk } = api;
get_chunk,
switch_chunk,
rm_chunk,
retrieval_test } = api;
interface kbService {
createKb: () => void;
updateKb: () => void;
@ -34,6 +37,7 @@ interface kbService {
get_chunk: () => void;
switch_chunk: () => void;
rm_chunk: () => void;
retrieval_test: () => void;
}
const kbService: kbService = registerServer(
{
@ -104,7 +108,10 @@ const kbService: kbService = registerServer(
url: rm_chunk,
method: 'post'
},
retrieval_test: {
url: retrieval_test,
method: 'post'
},
},
request
);

View File

@ -39,6 +39,8 @@ export default {
get_chunk: `${api_host}/chunk/get`,
switch_chunk: `${api_host}/chunk/switch`,
rm_chunk: `${api_host}/chunk/rm`,
retrieval_test: `${api_host}/chunk/retrieval_test`,