feat: 优化前端页面和组件
- 重构 Agents 页面 - 优化 Knowledge 页面 - 更新侧边栏导航 - 添加前端依赖 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
29
web/package-lock.json
generated
29
web/package-lock.json
generated
@@ -20,6 +20,7 @@
|
|||||||
"vue-router": "^4.3.0"
|
"vue-router": "^4.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/papaparse": "^5.5.2",
|
||||||
"@vitejs/plugin-vue": "^5.0.4",
|
"@vitejs/plugin-vue": "^5.0.4",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
@@ -982,6 +983,27 @@
|
|||||||
"@types/lodash": "*"
|
"@types/lodash": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "25.3.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@types/node/-/node-25.3.5.tgz",
|
||||||
|
"integrity": "sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~7.18.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/papaparse": {
|
||||||
|
"version": "5.5.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@types/papaparse/-/papaparse-5.5.2.tgz",
|
||||||
|
"integrity": "sha512-gFnFp/JMzLHCwRf7tQHrNnfhN4eYBVYYI897CGX4MY1tzY9l2aLkVyx2IlKZ/SAqDbB3I1AOZW5gTMGGsqWliA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/web-bluetooth": {
|
"node_modules/@types/web-bluetooth": {
|
||||||
"version": "0.0.20",
|
"version": "0.0.20",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
|
||||||
@@ -2624,6 +2646,13 @@
|
|||||||
"node": ">=14.17"
|
"node": ">=14.17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "7.18.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-7.18.2.tgz",
|
||||||
|
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/update-browserslist-db": {
|
"node_modules/update-browserslist-db": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
|
"resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
"vue-router": "^4.3.0"
|
"vue-router": "^4.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/papaparse": "^5.5.2",
|
||||||
"@vitejs/plugin-vue": "^5.0.4",
|
"@vitejs/plugin-vue": "^5.0.4",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
|
|||||||
@@ -39,42 +39,45 @@ interface MenuItem {
|
|||||||
path?: string
|
path?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const mainMenu = computed<MenuItem[]>(() => [
|
// 第1组: Chat, Agents
|
||||||
{ name: 'Dashboard', icon: 'fa-gauge', path: '/dashboard' },
|
const group1 = computed(() => [
|
||||||
{ name: 'Agents', icon: 'fa-robot', badge: 3, path: '/agents' },
|
{ name: 'Chat', icon: 'fa-robot', path: '/agents' },
|
||||||
{ name: 'Script', icon: 'fa-code', path: '/script' },
|
{ name: 'Agents', icon: 'fa-users', badge: 3, path: '/agents' },
|
||||||
|
])
|
||||||
|
|
||||||
|
// 第2组: Database, Knowledge
|
||||||
|
const group2 = computed(() => [
|
||||||
{ name: 'Database', icon: 'fa-database', path: '/database', badge: databaseCount.value },
|
{ name: 'Database', icon: 'fa-database', path: '/database', badge: databaseCount.value },
|
||||||
{ name: 'Knowledge', icon: 'fa-brain', path: '/knowledge', badge: knowledgeCount.value },
|
{ name: 'Knowledge', icon: 'fa-brain', path: '/knowledge', badge: knowledgeCount.value },
|
||||||
])
|
])
|
||||||
|
|
||||||
const middleMenu: MenuItem[] = [
|
// 第3组: Skills, Tools, Script
|
||||||
|
const group3 = computed(() => [
|
||||||
{ name: 'Skills', icon: 'fa-wand-magic-sparkles', badge: 21, path: '/mcp' },
|
{ name: 'Skills', icon: 'fa-wand-magic-sparkles', badge: 21, path: '/mcp' },
|
||||||
{ name: 'Tools', icon: 'fa-tools', badge: 13, path: '/model-apis' },
|
{ name: 'Tools', icon: 'fa-tools', badge: 13, path: '/model-apis' },
|
||||||
]
|
{ name: 'Script', icon: 'fa-code', path: '/script' },
|
||||||
|
])
|
||||||
|
|
||||||
const bottomMenu: MenuItem[] = [
|
// 第4组: Dashboard, Account, Settings
|
||||||
{ name: 'Settings', icon: 'fa-gear', path: '/settings' },
|
const group4 = computed(() => [
|
||||||
]
|
{ name: 'Dashboard', icon: 'fa-gauge', path: '/dashboard' },
|
||||||
|
|
||||||
const bottomMenu2: MenuItem[] = [
|
|
||||||
{ name: 'Account', icon: 'fa-user', path: '/account' },
|
{ name: 'Account', icon: 'fa-user', path: '/account' },
|
||||||
]
|
{ name: 'Settings', icon: 'fa-gear', path: '/settings' },
|
||||||
|
])
|
||||||
|
|
||||||
const activeMenu = computed(() => {
|
const activeMenu = computed(() => {
|
||||||
const currentPath = route.path
|
const currentPath = route.path
|
||||||
// Check main menu
|
|
||||||
const menuItem = mainMenu.value.find(item => item.path === currentPath)
|
// Special case for /agents - prioritize Chat over Agents
|
||||||
if (menuItem) return menuItem.name
|
if (currentPath === '/agents') {
|
||||||
// Check middle menu (Skills, Tools)
|
return 'Chat'
|
||||||
const middleItem = middleMenu.find(item => item.path === currentPath)
|
}
|
||||||
if (middleItem) return middleItem.name
|
|
||||||
// Check bottom menu (Settings)
|
// Check all groups
|
||||||
const bottomItem = bottomMenu.find(item => item.path === currentPath)
|
const allGroups = [...group1.value, ...group2.value, ...group3.value, ...group4.value]
|
||||||
if (bottomItem) return bottomItem.name
|
const item = allGroups.find(item => item.path === currentPath)
|
||||||
// Check bottomMenu2 (Account)
|
if (item) return item.name
|
||||||
const bottomItem2 = bottomMenu2.find(item => item.path === currentPath)
|
return 'Chat'
|
||||||
if (bottomItem2) return bottomItem2.name
|
|
||||||
return 'Dashboard'
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const navigateTo = (item: MenuItem) => {
|
const navigateTo = (item: MenuItem) => {
|
||||||
@@ -129,8 +132,8 @@ const handleUserCommand = (command: string) => {
|
|||||||
<!-- 导航菜单 -->
|
<!-- 导航菜单 -->
|
||||||
<nav class="flex-1 px-3 py-2">
|
<nav class="flex-1 px-3 py-2">
|
||||||
<ul class="space-y-1">
|
<ul class="space-y-1">
|
||||||
<!-- Dashboard, Agents -->
|
<!-- 第1组: Chat, Agents -->
|
||||||
<li v-for="item in mainMenu.slice(0, 2)" :key="item.name">
|
<li v-for="item in group1" :key="item.name">
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
class="flex items-center justify-between px-3 py-2.5 rounded-lg transition-colors text-sm"
|
class="flex items-center justify-between px-3 py-2.5 rounded-lg transition-colors text-sm"
|
||||||
@@ -148,8 +151,8 @@ const handleUserCommand = (command: string) => {
|
|||||||
<!-- 分隔线1 -->
|
<!-- 分隔线1 -->
|
||||||
<li class="my-4 border-t border-dark-500"></li>
|
<li class="my-4 border-t border-dark-500"></li>
|
||||||
|
|
||||||
<!-- Database, Knowledge -->
|
<!-- 第2组: Database, Knowledge -->
|
||||||
<li v-for="item in mainMenu.slice(2)" :key="item.name">
|
<li v-for="item in group2" :key="item.name">
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
class="flex items-center justify-between px-3 py-2.5 rounded-lg transition-colors text-sm"
|
class="flex items-center justify-between px-3 py-2.5 rounded-lg transition-colors text-sm"
|
||||||
@@ -167,8 +170,8 @@ const handleUserCommand = (command: string) => {
|
|||||||
<!-- 分隔线2 -->
|
<!-- 分隔线2 -->
|
||||||
<li class="my-4 border-t border-dark-500"></li>
|
<li class="my-4 border-t border-dark-500"></li>
|
||||||
|
|
||||||
<!-- Skills & Tools -->
|
<!-- 第3组: Skills, Tools, Script -->
|
||||||
<li v-for="item in middleMenu" :key="item.name">
|
<li v-for="item in group3" :key="item.name">
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
class="flex items-center justify-between px-3 py-2.5 rounded-lg transition-colors text-sm"
|
class="flex items-center justify-between px-3 py-2.5 rounded-lg transition-colors text-sm"
|
||||||
@@ -183,8 +186,11 @@ const handleUserCommand = (command: string) => {
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<!-- Settings -->
|
<!-- 分隔线3 -->
|
||||||
<li v-for="item in bottomMenu" :key="item.name">
|
<li class="my-4 border-t border-dark-500"></li>
|
||||||
|
|
||||||
|
<!-- 第4组: Dashboard, Account, Settings -->
|
||||||
|
<li v-for="item in group4" :key="item.name">
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
class="flex items-center justify-between px-3 py-2.5 rounded-lg transition-colors text-sm"
|
class="flex items-center justify-between px-3 py-2.5 rounded-lg transition-colors text-sm"
|
||||||
@@ -202,24 +208,6 @@ const handleUserCommand = (command: string) => {
|
|||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<!-- 分隔线 -->
|
|
||||||
<li class="my-4 border-t border-dark-500"></li>
|
|
||||||
|
|
||||||
<!-- Account -->
|
|
||||||
<li v-for="item in bottomMenu2" :key="item.name">
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="flex items-center justify-between px-3 py-2.5 rounded-lg transition-colors text-sm"
|
|
||||||
:class="activeMenu === item.name ? 'bg-dark-600 text-white' : 'text-gray-400 hover:bg-dark-600 hover:text-white'"
|
|
||||||
@click="navigateTo(item)"
|
|
||||||
>
|
|
||||||
<div class="flex items-center gap-3">
|
|
||||||
<i :class="['fa-solid', item.icon, 'w-5', 'text-center']"></i>
|
|
||||||
<span>{{ item.name }}</span>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { useModelSettings } from './settings/useModelSettings'
|
import { useModelSettings } from './settings/useModelSettings'
|
||||||
import { fetchKnowledgeBases, createKnowledgeBase as apiCreateKnowledgeBase, deleteKnowledgeBase as apiDeleteKnowledgeBase, fetchKnowledgeDocuments } from './knowledge/useKnowledge'
|
import { fetchKnowledgeBases, createKnowledgeBase as apiCreateKnowledgeBase, deleteKnowledgeBase as apiDeleteKnowledgeBase, fetchKnowledgeDocuments } from './knowledge/useKnowledge'
|
||||||
import VueOfficeDocx from '@vue-office/docx'
|
import VueOfficeDocx from '@vue-office/docx'
|
||||||
@@ -42,6 +42,11 @@ const embeddingModels = computed(() => {
|
|||||||
return models.value.filter((m: any) => m.model_type === 'embedding')
|
return models.value.filter((m: any) => m.model_type === 'embedding')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 筛选 VLM 模型
|
||||||
|
const vlmModels = computed(() => {
|
||||||
|
return models.value.filter((m: any) => m.model_type === 'vlm')
|
||||||
|
})
|
||||||
|
|
||||||
// 步骤验证
|
// 步骤验证
|
||||||
const step1Valid = computed(() => !!newKbForm.value.name.trim())
|
const step1Valid = computed(() => !!newKbForm.value.name.trim())
|
||||||
const step2Valid = computed(() => !!modelConfig.value.llmModelId && !!modelConfig.value.embeddingModelId)
|
const step2Valid = computed(() => !!modelConfig.value.llmModelId && !!modelConfig.value.embeddingModelId)
|
||||||
@@ -188,6 +193,7 @@ const newKbForm = ref({
|
|||||||
const modelConfig = ref({
|
const modelConfig = ref({
|
||||||
llmModelId: '',
|
llmModelId: '',
|
||||||
embeddingModelId: '',
|
embeddingModelId: '',
|
||||||
|
vlmModelId: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
const parsingConfig = ref({
|
const parsingConfig = ref({
|
||||||
@@ -212,7 +218,11 @@ const storageConfig = ref({
|
|||||||
const openCreateDialog = () => {
|
const openCreateDialog = () => {
|
||||||
createStep.value = 1
|
createStep.value = 1
|
||||||
newKbForm.value = { name: '', description: '' }
|
newKbForm.value = { name: '', description: '' }
|
||||||
modelConfig.value = { llmModelId: '', embeddingModelId: '' }
|
modelConfig.value = {
|
||||||
|
llmModelId: '',
|
||||||
|
embeddingModelId: '',
|
||||||
|
vlmModelId: '',
|
||||||
|
}
|
||||||
parsingConfig.value = {
|
parsingConfig.value = {
|
||||||
enablePdf: true,
|
enablePdf: true,
|
||||||
engine: 'markitdown',
|
engine: 'markitdown',
|
||||||
@@ -222,13 +232,23 @@ const openCreateDialog = () => {
|
|||||||
highRes: false,
|
highRes: false,
|
||||||
fileSizeLimit: '5242880',
|
fileSizeLimit: '5242880',
|
||||||
}
|
}
|
||||||
storageConfig.value = { type: 'local' }
|
storageConfig.value = {
|
||||||
|
type: 'local',
|
||||||
|
endpoint: '',
|
||||||
|
accessKeyId: '',
|
||||||
|
secretAccessKey: '',
|
||||||
|
bucket: '',
|
||||||
|
}
|
||||||
showCreateDialog.value = true
|
showCreateDialog.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const cancelCreate = () => {
|
const cancelCreate = () => {
|
||||||
newKbForm.value = { name: '', description: '' }
|
newKbForm.value = { name: '', description: '' }
|
||||||
modelConfig.value = { llmModelId: '', embeddingModelId: '' }
|
modelConfig.value = {
|
||||||
|
llmModelId: '',
|
||||||
|
embeddingModelId: '',
|
||||||
|
vlmModelId: '',
|
||||||
|
}
|
||||||
parsingConfig.value = {
|
parsingConfig.value = {
|
||||||
enablePdf: true,
|
enablePdf: true,
|
||||||
engine: 'markitdown',
|
engine: 'markitdown',
|
||||||
@@ -238,7 +258,13 @@ const cancelCreate = () => {
|
|||||||
highRes: false,
|
highRes: false,
|
||||||
fileSizeLimit: '5242880',
|
fileSizeLimit: '5242880',
|
||||||
}
|
}
|
||||||
storageConfig.value = { type: 'local' }
|
storageConfig.value = {
|
||||||
|
type: 'local',
|
||||||
|
endpoint: '',
|
||||||
|
accessKeyId: '',
|
||||||
|
secretAccessKey: '',
|
||||||
|
bucket: '',
|
||||||
|
}
|
||||||
showCreateDialog.value = false
|
showCreateDialog.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,6 +280,10 @@ const createKnowledgeBase = async () => {
|
|||||||
enable_pdf: parsingConfig.value.enablePdf,
|
enable_pdf: parsingConfig.value.enablePdf,
|
||||||
pandoc: parsingConfig.value.pandoc,
|
pandoc: parsingConfig.value.pandoc,
|
||||||
},
|
},
|
||||||
|
vlm_config: modelConfig.value.vlmModelId ? {
|
||||||
|
enabled: true,
|
||||||
|
model_id: modelConfig.value.vlmModelId,
|
||||||
|
} : undefined,
|
||||||
storage_config: {
|
storage_config: {
|
||||||
type: storageConfig.value.type,
|
type: storageConfig.value.type,
|
||||||
endpoint: storageConfig.value.type === 'minio' ? storageConfig.value.endpoint : undefined,
|
endpoint: storageConfig.value.type === 'minio' ? storageConfig.value.endpoint : undefined,
|
||||||
@@ -266,7 +296,11 @@ const createKnowledgeBase = async () => {
|
|||||||
if (result.success) {
|
if (result.success) {
|
||||||
await fetchKbList()
|
await fetchKbList()
|
||||||
newKbForm.value = { name: '', description: '' }
|
newKbForm.value = { name: '', description: '' }
|
||||||
modelConfig.value = { llmModelId: '', embeddingModelId: '' }
|
modelConfig.value = {
|
||||||
|
llmModelId: '',
|
||||||
|
embeddingModelId: '',
|
||||||
|
vlmModelId: '',
|
||||||
|
}
|
||||||
parsingConfig.value = {
|
parsingConfig.value = {
|
||||||
enablePdf: true,
|
enablePdf: true,
|
||||||
engine: 'markitdown',
|
engine: 'markitdown',
|
||||||
@@ -316,12 +350,26 @@ const cancelEdit = () => {
|
|||||||
|
|
||||||
// 删除知识库
|
// 删除知识库
|
||||||
const deleteKb = async (id: string) => {
|
const deleteKb = async (id: string) => {
|
||||||
const result = await apiDeleteKnowledgeBase(id)
|
try {
|
||||||
if (result.success) {
|
await ElMessageBox.confirm(
|
||||||
await fetchKbList()
|
'Are you sure you want to delete this knowledge base? This action cannot be undone.',
|
||||||
ElMessage.success('Knowledge base deleted')
|
'Delete Knowledge Base',
|
||||||
} else {
|
{
|
||||||
ElMessage.error(result.message || 'Failed to delete knowledge base')
|
confirmButtonText: 'Delete',
|
||||||
|
cancelButtonText: 'Cancel',
|
||||||
|
type: 'warning',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const result = await apiDeleteKnowledgeBase(id)
|
||||||
|
if (result.success) {
|
||||||
|
await fetchKbList()
|
||||||
|
ElMessage.success('Knowledge base deleted')
|
||||||
|
} else {
|
||||||
|
ElMessage.error(result.message || 'Failed to delete knowledge base')
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// User cancelled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -890,6 +938,23 @@ const deleteDocument = async (docId: string) => {
|
|||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- VLM Configuration -->
|
||||||
|
<el-form-item label="VLM Model (Optional)">
|
||||||
|
<el-select v-model="modelConfig.vlmModelId" placeholder="Select a VLM model" class="w-full" popper-class="dark-select-dropdown" clearable>
|
||||||
|
<el-option
|
||||||
|
v-for="model in vlmModels"
|
||||||
|
:key="model.id"
|
||||||
|
:label="model.name"
|
||||||
|
:value="model.id"
|
||||||
|
>
|
||||||
|
<div class="model-option">
|
||||||
|
<span class="model-name">{{ model.name }}</span>
|
||||||
|
<span class="model-info">{{ model.provider }} - {{ model.model }}</span>
|
||||||
|
</div>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ export const createKnowledgeBase = async (params: {
|
|||||||
enable_pdf?: boolean
|
enable_pdf?: boolean
|
||||||
pandoc?: boolean
|
pandoc?: boolean
|
||||||
}
|
}
|
||||||
|
vlm_config?: {
|
||||||
|
enabled: boolean
|
||||||
|
model_id: string
|
||||||
|
}
|
||||||
storage_config?: {
|
storage_config?: {
|
||||||
type: string
|
type: string
|
||||||
endpoint?: string
|
endpoint?: string
|
||||||
@@ -195,7 +199,7 @@ export const reparseDocument = async (kbId: string, docId: string): Promise<{ su
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取文档预览内容
|
// 获取文档预览内容
|
||||||
export const getDocumentPreview = async (kbId: string, docId: string, page: number = 1): Promise<{ success: boolean; data?: { total_pages: number; current_page: number; content: string }; message?: string }> => {
|
export const getDocumentPreview = async (kbId: string, docId: string, page: number = 1): Promise<{ success: boolean; data?: { total_pages: number; current_page: number; content: string; content_type?: string }; message?: string }> => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE}/api/knowledge/${kbId}/documents/${docId}/preview?page=${page}`)
|
const response = await fetch(`${API_BASE}/api/knowledge/${kbId}/documents/${docId}/preview?page=${page}`)
|
||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
|
|||||||
Reference in New Issue
Block a user