2024-07-16 18:14:27 +08:00
|
|
|
<template>
|
2024-09-01 21:14:23 +08:00
|
|
|
<div class="database-container layout-container" v-if="configStore.config.enable_knowledge_base">
|
2024-09-14 02:46:44 +08:00
|
|
|
<HeaderComponent
|
|
|
|
|
title="文档知识库"
|
2024-11-14 20:07:49 +08:00
|
|
|
description="知识型数据库,主要是非结构化的文本组成,使用向量检索使用。如果出现问题,可以检查 saves/data/database.json 查看配置。"
|
2024-09-14 02:46:44 +08:00
|
|
|
>
|
|
|
|
|
<template #actions>
|
|
|
|
|
<a-button type="primary" @click="newDatabase.open=true">新建数据库</a-button>
|
|
|
|
|
</template>
|
|
|
|
|
</HeaderComponent>
|
|
|
|
|
|
2024-07-16 18:14:27 +08:00
|
|
|
<a-modal :open="newDatabase.open" title="新建数据库" @ok="createDatabase">
|
2024-09-25 13:46:51 +08:00
|
|
|
<h3>数据库名称<span style="color: var(--error-color)">*</span></h3>
|
2024-07-16 18:14:27 +08:00
|
|
|
<a-input v-model:value="newDatabase.name" placeholder="新建数据库名称" />
|
|
|
|
|
<h3 style="margin-top: 20px;">数据库描述</h3>
|
|
|
|
|
<a-textarea
|
|
|
|
|
v-model:value="newDatabase.description"
|
|
|
|
|
placeholder="新建数据库描述"
|
|
|
|
|
:auto-size="{ minRows: 2, maxRows: 5 }"
|
|
|
|
|
/>
|
2024-09-11 01:09:03 +08:00
|
|
|
<!-- <h3 style="margin-top: 20px;">向量维度</h3>
|
2024-08-25 20:29:24 +08:00
|
|
|
<p>必须与向量模型 {{ configStore.config.embed_model }} 一致</p>
|
2024-09-11 01:09:03 +08:00
|
|
|
<a-input v-model:value="newDatabase.dimension" placeholder="向量维度 (e.g. 768, 1024)" /> -->
|
2024-07-16 18:14:27 +08:00
|
|
|
<template #footer>
|
|
|
|
|
<a-button key="back" @click="newDatabase.open=false">取消</a-button>
|
|
|
|
|
<a-button key="submit" type="primary" :loading="newDatabase.loading" @click="createDatabase">创建</a-button>
|
|
|
|
|
</template>
|
|
|
|
|
</a-modal>
|
|
|
|
|
<div class="databases">
|
|
|
|
|
<div class="new-database dbcard" @click="newDatabase.open=true">
|
|
|
|
|
<div class="top">
|
|
|
|
|
<div class="icon"><PlusOutlined /></div>
|
|
|
|
|
<div class="info">
|
|
|
|
|
<h3>新建数据库</h3>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<p>导入您自己的文本数据或通过Webhook实时写入数据以增强 LLM 的上下文。</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div
|
|
|
|
|
v-for="database in databases"
|
|
|
|
|
:key="database.db_id"
|
|
|
|
|
class="database dbcard"
|
|
|
|
|
@click="navigateToDatabase(database.db_id)">
|
|
|
|
|
<div class="top">
|
|
|
|
|
<div class="icon"><ReadFilled /></div>
|
|
|
|
|
<div class="info">
|
|
|
|
|
<h3>{{ database.name }}</h3>
|
2025-03-20 19:51:46 +08:00
|
|
|
<p><span>{{ database.metadata.row_count }} 行</span></p>
|
2024-07-16 18:14:27 +08:00
|
|
|
</div>
|
|
|
|
|
</div>
|
2024-09-14 02:46:44 +08:00
|
|
|
<p class="description">{{ database.description || '暂无描述' }}</p>
|
2024-07-22 00:00:54 +08:00
|
|
|
<div class="tags">
|
2024-08-25 20:29:24 +08:00
|
|
|
<a-tag color="blue" v-if="database.embed_model">{{ database.embed_model }}</a-tag>
|
|
|
|
|
<a-tag color="green" v-if="database.dimension">{{ database.dimension }}</a-tag>
|
2024-07-22 00:00:54 +08:00
|
|
|
</div>
|
2024-07-16 18:14:27 +08:00
|
|
|
<!-- <button @click="deleteDatabase(database.collection_name)">删除</button> -->
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2024-09-01 18:10:50 +08:00
|
|
|
<!-- <h2>图数据库 <a-spin v-if="graphloading" :indicator="indicator" /></h2>
|
2024-07-16 18:14:27 +08:00
|
|
|
<p>基于 neo4j 构建的图数据库。</p>
|
2024-07-29 01:00:02 +08:00
|
|
|
<div :class="{'graphloading': graphloading, 'databases': true}" v-if="graph">
|
2024-07-17 18:52:20 +08:00
|
|
|
<div class="dbcard graphbase" @click="navigateToGraph">
|
2024-07-16 18:14:27 +08:00
|
|
|
<div class="top">
|
|
|
|
|
<div class="icon"><AppstoreFilled /></div>
|
|
|
|
|
<div class="info">
|
|
|
|
|
<h3>{{ graph?.database_name }}</h3>
|
|
|
|
|
<p>
|
|
|
|
|
<span>{{ graph?.status }}</span> ·
|
|
|
|
|
<span>{{ graph?.entity_count }}实体</span>
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<p class="description">基于 neo4j 构建的图数据库。基于 neo4j 构建的图数据库。基于 neo4j 构建的图数据库。</p>
|
|
|
|
|
</div>
|
2024-09-01 18:10:50 +08:00
|
|
|
</div> -->
|
2024-07-16 18:14:27 +08:00
|
|
|
</div>
|
2024-07-31 20:22:05 +08:00
|
|
|
<div class="database-empty" v-else>
|
|
|
|
|
<a-empty>
|
|
|
|
|
<template #description>
|
|
|
|
|
<span>
|
|
|
|
|
前往 <router-link to="/setting" style="color: var(--main-color); font-weight: bold;">设置</router-link> 页面配置知识库。
|
|
|
|
|
</span>
|
|
|
|
|
</template>
|
|
|
|
|
</a-empty>
|
|
|
|
|
</div>
|
2024-07-16 18:14:27 +08:00
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
2024-07-25 20:30:28 +08:00
|
|
|
import { ref, onMounted, reactive, watch, h } from 'vue'
|
2024-07-17 18:52:20 +08:00
|
|
|
import { useRouter, useRoute } from 'vue-router';
|
2024-07-16 18:14:27 +08:00
|
|
|
import { message, Button } from 'ant-design-vue'
|
2024-07-25 20:30:28 +08:00
|
|
|
import { ReadFilled, PlusOutlined, AppstoreFilled, LoadingOutlined } from '@ant-design/icons-vue'
|
2024-07-31 20:22:05 +08:00
|
|
|
import { useConfigStore } from '@/stores/config';
|
2024-09-14 02:46:44 +08:00
|
|
|
import HeaderComponent from '@/components/HeaderComponent.vue';
|
2024-07-16 18:14:27 +08:00
|
|
|
|
2024-07-17 18:52:20 +08:00
|
|
|
const route = useRoute()
|
2024-07-16 18:14:27 +08:00
|
|
|
const router = useRouter()
|
|
|
|
|
const databases = ref([])
|
|
|
|
|
const graph = ref(null)
|
|
|
|
|
const graphloading = ref(false)
|
|
|
|
|
|
2024-07-25 20:30:28 +08:00
|
|
|
const indicator = h(LoadingOutlined, {spin: true});
|
2024-07-31 20:22:05 +08:00
|
|
|
const configStore = useConfigStore()
|
2024-07-25 20:30:28 +08:00
|
|
|
|
2024-07-16 18:14:27 +08:00
|
|
|
const newDatabase = reactive({
|
|
|
|
|
name: '',
|
|
|
|
|
description: '',
|
2024-08-25 20:29:24 +08:00
|
|
|
dimension: '',
|
2024-07-16 18:14:27 +08:00
|
|
|
loading: false,
|
|
|
|
|
})
|
|
|
|
|
|
2024-07-17 18:52:20 +08:00
|
|
|
const loadDatabases = () => {
|
2024-09-01 21:14:23 +08:00
|
|
|
// loadGraph()
|
2024-10-02 20:11:28 +08:00
|
|
|
fetch('/api/data/', {
|
2024-07-16 18:14:27 +08:00
|
|
|
method: "GET",
|
|
|
|
|
})
|
|
|
|
|
.then(response => response.json())
|
|
|
|
|
.then(data => {
|
|
|
|
|
console.log(data)
|
|
|
|
|
databases.value = data.databases
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const createDatabase = () => {
|
|
|
|
|
newDatabase.loading = true
|
|
|
|
|
console.log(newDatabase)
|
|
|
|
|
if (!newDatabase.name) {
|
|
|
|
|
message.error('数据库名称不能为空')
|
|
|
|
|
newDatabase.loading = false
|
|
|
|
|
return
|
|
|
|
|
}
|
2024-10-02 20:11:28 +08:00
|
|
|
fetch('/api/data/', {
|
2024-07-16 18:14:27 +08:00
|
|
|
method: "POST",
|
2024-10-08 22:16:17 +08:00
|
|
|
headers: {
|
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
|
},
|
2024-07-16 18:14:27 +08:00
|
|
|
body: JSON.stringify({
|
|
|
|
|
database_name: newDatabase.name,
|
|
|
|
|
description: newDatabase.description,
|
2024-10-08 22:16:17 +08:00
|
|
|
dimension: newDatabase.dimension ? parseInt(newDatabase.dimension) : null,
|
2024-07-16 18:14:27 +08:00
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
.then(response => response.json())
|
|
|
|
|
.then(data => {
|
|
|
|
|
console.log(data)
|
2024-07-17 18:52:20 +08:00
|
|
|
loadDatabases()
|
2024-07-16 18:14:27 +08:00
|
|
|
newDatabase.open = false
|
|
|
|
|
newDatabase.name = ''
|
2024-08-25 20:29:24 +08:00
|
|
|
newDatabase.description = '',
|
|
|
|
|
newDatabase.dimension = ''
|
2024-07-16 18:14:27 +08:00
|
|
|
})
|
|
|
|
|
.finally(() => {
|
|
|
|
|
newDatabase.loading = false
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const navigateToDatabase = (databaseId) => {
|
|
|
|
|
router.push({ path: `/database/${databaseId}` });
|
|
|
|
|
};
|
|
|
|
|
|
2024-07-17 18:52:20 +08:00
|
|
|
const navigateToGraph = () => {
|
|
|
|
|
router.push({ path: `/database/graph` });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
watch(() => route.path, (newPath, oldPath) => {
|
|
|
|
|
if (newPath === '/database') {
|
|
|
|
|
loadDatabases();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2024-07-16 18:14:27 +08:00
|
|
|
onMounted(() => {
|
2024-07-17 18:52:20 +08:00
|
|
|
loadDatabases()
|
2024-07-16 18:14:27 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="less" scoped>
|
|
|
|
|
.database-actions, .document-actions {
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
}
|
|
|
|
|
.databases {
|
2024-09-14 02:46:44 +08:00
|
|
|
padding: 20px;
|
2024-09-28 00:41:02 +08:00
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
2024-07-16 18:14:27 +08:00
|
|
|
gap: 16px;
|
|
|
|
|
|
|
|
|
|
.new-database {
|
|
|
|
|
background-color: #F0F3F4;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.database, .graphbase {
|
2024-07-25 20:30:28 +08:00
|
|
|
background-color: white;
|
|
|
|
|
box-shadow: 0px 1px 2px 0px rgba(16,24,40,.06),0px 1px 3px 0px rgba(16,24,40,.1);
|
|
|
|
|
border: 2px solid white;
|
|
|
|
|
transition: box-shadow 0.2s ease-in-out;
|
2024-07-16 18:14:27 +08:00
|
|
|
|
2024-07-25 20:30:28 +08:00
|
|
|
&:hover {
|
|
|
|
|
box-shadow: 0px 4px 6px -2px rgba(16,24,40,.03),0px 12px 16px -4px rgba(16,24,40,.08);
|
2024-07-16 18:14:27 +08:00
|
|
|
}
|
2024-07-25 20:30:28 +08:00
|
|
|
}
|
2024-07-16 18:14:27 +08:00
|
|
|
|
|
|
|
|
.dbcard, .database {
|
2024-09-28 00:41:02 +08:00
|
|
|
width: 100%;
|
2024-07-16 18:14:27 +08:00
|
|
|
padding: 10px;
|
|
|
|
|
border-radius: 12px;
|
2024-07-22 00:00:54 +08:00
|
|
|
height: 160px;
|
2024-07-16 18:14:27 +08:00
|
|
|
padding: 20px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
|
|
|
|
.top {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
height: 50px;
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
|
|
|
|
.icon {
|
|
|
|
|
width: 50px;
|
|
|
|
|
height: 50px;
|
|
|
|
|
font-size: 28px;
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
background-color: #F5F8FF;
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
border: 1px solid #E0EAFF;
|
2024-08-25 20:29:24 +08:00
|
|
|
color: var(--main-color);
|
2024-07-16 18:14:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.info {
|
|
|
|
|
h3, p {
|
|
|
|
|
margin: 0;
|
2024-07-22 00:00:54 +08:00
|
|
|
color: black;
|
2024-07-16 18:14:27 +08:00
|
|
|
}
|
|
|
|
|
|
2024-08-25 20:29:24 +08:00
|
|
|
h3 {
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-16 18:14:27 +08:00
|
|
|
p {
|
2024-09-25 13:46:51 +08:00
|
|
|
color: var(--gray-900);
|
2024-07-16 18:14:27 +08:00
|
|
|
font-size: small;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.description {
|
2024-09-25 13:46:51 +08:00
|
|
|
color: var(--gray-900);
|
2024-07-16 18:14:27 +08:00
|
|
|
overflow: hidden;
|
|
|
|
|
display: -webkit-box;
|
2024-07-22 00:00:54 +08:00
|
|
|
-webkit-line-clamp: 1;
|
2024-07-16 18:14:27 +08:00
|
|
|
-webkit-box-orient: vertical;
|
|
|
|
|
text-overflow: ellipsis;
|
2024-07-22 00:00:54 +08:00
|
|
|
margin-bottom: 10px;
|
2024-07-16 18:14:27 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 整个卡片是模糊的
|
2024-09-01 21:14:23 +08:00
|
|
|
// .graphloading {
|
|
|
|
|
// filter: blur(2px);
|
|
|
|
|
// }
|
2024-07-31 20:22:05 +08:00
|
|
|
|
|
|
|
|
.database-empty {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
height: 100%;
|
|
|
|
|
flex-direction: column;
|
2024-09-25 13:46:51 +08:00
|
|
|
color: var(--gray-900);
|
2024-07-31 20:22:05 +08:00
|
|
|
}
|
2024-09-14 02:46:44 +08:00
|
|
|
|
|
|
|
|
.database-container {
|
|
|
|
|
padding: 0;
|
|
|
|
|
}
|
2024-07-16 18:14:27 +08:00
|
|
|
</style>
|