mirror of
https://github.com/Tencent/WeKnora.git
synced 2026-06-04 13:30:32 +08:00
feat: Add MinIO and graph database status handling with localization updates
- Introduced a new boolean field for MinIO status in the system info API response. - Updated localization files in English, Russian, and Chinese to include warnings and instructions related to MinIO and graph database configurations. - Enhanced the KBAdvancedSettings component to display alerts and disable options based on the status of MinIO and graph database. - Implemented logic to check system status on component mount and adjust settings accordingly.
This commit is contained in:
@@ -8,6 +8,7 @@ export interface SystemInfo {
|
||||
keyword_index_engine?: string
|
||||
vector_store_engine?: string
|
||||
graph_database_engine?: string
|
||||
minio_enabled?: boolean
|
||||
}
|
||||
|
||||
export interface ToolDefinition {
|
||||
|
||||
@@ -847,6 +847,7 @@ export default {
|
||||
minio: 'MinIO',
|
||||
cos: 'Tencent Cloud COS'
|
||||
},
|
||||
minioDisabledWarning: 'MinIO is not enabled. Automatically switched to Tencent Cloud COS. To use MinIO, please enable it in system configuration first.',
|
||||
minio: {
|
||||
bucketLabel: 'Bucket Name',
|
||||
bucketDescription: 'Name of the MinIO bucket (required)',
|
||||
@@ -887,7 +888,9 @@ export default {
|
||||
promptPlaceholder: 'Enter prompt text',
|
||||
tagsLabel: 'Tags',
|
||||
tagsDescription: 'Predefined entity tags (separate multiple tags with commas)',
|
||||
tagsPlaceholder: 'Enter a tag and press Enter'
|
||||
tagsPlaceholder: 'Enter a tag and press Enter',
|
||||
disabledWarning: 'Graph database is not enabled. Please enable the graph database first to use this feature.',
|
||||
howToEnable: 'How to enable'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -938,6 +938,7 @@ export default {
|
||||
minio: 'MinIO',
|
||||
cos: 'Tencent Cloud COS'
|
||||
},
|
||||
minioDisabledWarning: 'MinIO не включен. Автоматически переключено на Tencent Cloud COS. Чтобы использовать MinIO, сначала включите его в конфигурации системы.',
|
||||
minio: {
|
||||
bucketLabel: 'Имя Bucket',
|
||||
bucketDescription: 'Название бакета MinIO (обязательно)',
|
||||
@@ -978,7 +979,9 @@ export default {
|
||||
promptPlaceholder: 'Введите текст подсказки',
|
||||
tagsLabel: 'Теги',
|
||||
tagsDescription: 'Предопределённые теги сущностей (несколько тегов разделяйте запятыми)',
|
||||
tagsPlaceholder: 'Введите тег и нажмите Enter'
|
||||
tagsPlaceholder: 'Введите тег и нажмите Enter',
|
||||
disabledWarning: 'Графовая база данных не включена. Пожалуйста, сначала включите графовую базу данных, чтобы использовать эту функцию.',
|
||||
howToEnable: 'Как включить'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1171,6 +1171,7 @@ export default {
|
||||
minio: "MinIO",
|
||||
cos: "腾讯云 COS",
|
||||
},
|
||||
minioDisabledWarning: "MinIO 未启用,已自动切换到腾讯云 COS。如需使用 MinIO,请先在系统配置中启用 MinIO。",
|
||||
minio: {
|
||||
bucketLabel: "Bucket 名称",
|
||||
bucketDescription: "MinIO 存储桶名称(必填)",
|
||||
@@ -1212,6 +1213,8 @@ export default {
|
||||
tagsLabel: "标签",
|
||||
tagsDescription: "预定义的实体标签(多个标签用逗号分隔)",
|
||||
tagsPlaceholder: "输入标签后按回车",
|
||||
disabledWarning: "图数据库未启用,无法使用知识图谱功能。请先启用图数据库后再使用此功能。",
|
||||
howToEnable: "查看如何开启",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -424,7 +424,7 @@
|
||||
<!-- 导入模式选择 -->
|
||||
<div class="import-form-item">
|
||||
<label class="import-form-label required">{{ $t('knowledgeEditor.faqImport.modeLabel') }}</label>
|
||||
<t-radio-group v-model="importState.mode" variant="default-filled" class="import-radio-group">
|
||||
<t-radio-group v-model="importState.mode" class="import-radio-group">
|
||||
<t-radio-button value="append">{{ $t('knowledgeEditor.faqImport.appendMode') }}</t-radio-button>
|
||||
<t-radio-button value="replace">{{ $t('knowledgeEditor.faqImport.replaceMode') }}</t-radio-button>
|
||||
</t-radio-group>
|
||||
|
||||
@@ -50,10 +50,19 @@
|
||||
<div class="setting-info">
|
||||
<label>{{ $t('knowledgeEditor.advanced.multimodal.storageTypeLabel') }} <span class="required">*</span></label>
|
||||
<p class="desc">{{ $t('knowledgeEditor.advanced.multimodal.storageTypeDescription') }}</p>
|
||||
<!-- Warning message when MinIO is not enabled -->
|
||||
<t-alert
|
||||
v-if="!isMinioEnabled"
|
||||
theme="warning"
|
||||
:message="$t('knowledgeEditor.advanced.multimodal.minioDisabledWarning')"
|
||||
style="margin-top: 8px;"
|
||||
/>
|
||||
</div>
|
||||
<div class="setting-control">
|
||||
<t-radio-group v-model="localMultimodal.storageType" @change="handleStorageTypeChange">
|
||||
<t-radio value="minio">{{ $t('knowledgeEditor.advanced.multimodal.storageTypeOptions.minio') }}</t-radio>
|
||||
<t-radio value="minio" :disabled="!isMinioEnabled">
|
||||
{{ $t('knowledgeEditor.advanced.multimodal.storageTypeOptions.minio') }}
|
||||
</t-radio>
|
||||
<t-radio value="cos">{{ $t('knowledgeEditor.advanced.multimodal.storageTypeOptions.cos') }}</t-radio>
|
||||
</t-radio-group>
|
||||
</div>
|
||||
@@ -206,18 +215,32 @@
|
||||
<div class="setting-info">
|
||||
<label>{{ $t('knowledgeEditor.advanced.graph.label') }}</label>
|
||||
<p class="desc">{{ $t('knowledgeEditor.advanced.graph.description') }}</p>
|
||||
<!-- Warning message when graph database is not enabled -->
|
||||
<t-alert
|
||||
v-if="!isGraphDatabaseEnabled"
|
||||
theme="warning"
|
||||
:message="$t('knowledgeEditor.advanced.graph.disabledWarning')"
|
||||
style="margin-top: 8px;"
|
||||
>
|
||||
<template #operation>
|
||||
<t-link theme="primary" @click="handleOpenSystemInfo">
|
||||
{{ $t('knowledgeEditor.advanced.graph.howToEnable') }}
|
||||
</t-link>
|
||||
</template>
|
||||
</t-alert>
|
||||
</div>
|
||||
<div class="setting-control">
|
||||
<t-switch
|
||||
v-model="localNodeExtract.enabled"
|
||||
@change="handleNodeExtractToggle"
|
||||
:disabled="!isGraphDatabaseEnabled"
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Knowledge graph configuration -->
|
||||
<div v-if="localNodeExtract.enabled" class="subsection">
|
||||
<div v-if="localNodeExtract.enabled && isGraphDatabaseEnabled" class="subsection">
|
||||
<div class="subsection-header">
|
||||
<h4>{{ $t('knowledgeEditor.advanced.graph.configTitle') }}</h4>
|
||||
</div>
|
||||
@@ -258,9 +281,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import { ref, watch, onMounted } from 'vue'
|
||||
import ModelSelector from '@/components/ModelSelector.vue'
|
||||
import { useUIStore } from '@/stores/ui'
|
||||
import { getSystemInfo } from '@/api/system'
|
||||
|
||||
const uiStore = useUIStore()
|
||||
|
||||
@@ -306,6 +330,60 @@ const localMultimodal = ref<MultimodalConfig>({ ...props.multimodal })
|
||||
const localNodeExtract = ref<NodeExtractConfig>({ ...props.nodeExtract })
|
||||
|
||||
const vllmSelectorRef = ref()
|
||||
const isGraphDatabaseEnabled = ref(false)
|
||||
const isMinioEnabled = ref(false)
|
||||
|
||||
// Check system status on mount
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const systemInfo = await getSystemInfo()
|
||||
|
||||
// Check graph database status
|
||||
if (systemInfo.data?.graph_database_engine) {
|
||||
// Check if graph database is enabled
|
||||
// Enabled if it's "Neo4j" or any other non-empty value that's not a disabled indicator
|
||||
const engine = systemInfo.data.graph_database_engine.trim()
|
||||
const disabledIndicators = ['未启用', '未配置', 'Unknown', 'Неизвестно', '']
|
||||
isGraphDatabaseEnabled.value = !disabledIndicators.includes(engine) && engine.length > 0
|
||||
|
||||
// If graph database is disabled, also disable node extract
|
||||
if (!isGraphDatabaseEnabled.value && localNodeExtract.value.enabled) {
|
||||
localNodeExtract.value.enabled = false
|
||||
emit('update:nodeExtract', localNodeExtract.value)
|
||||
}
|
||||
} else {
|
||||
// No graph database engine info, assume disabled
|
||||
isGraphDatabaseEnabled.value = false
|
||||
if (localNodeExtract.value.enabled) {
|
||||
localNodeExtract.value.enabled = false
|
||||
emit('update:nodeExtract', localNodeExtract.value)
|
||||
}
|
||||
}
|
||||
|
||||
// Check MinIO status
|
||||
isMinioEnabled.value = systemInfo.data?.minio_enabled === true
|
||||
|
||||
// If MinIO is not enabled and storage type is minio, switch to cos
|
||||
if (!isMinioEnabled.value && localMultimodal.value.storageType === 'minio') {
|
||||
localMultimodal.value.storageType = 'cos'
|
||||
emit('update:multimodal', localMultimodal.value)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch system info:', error)
|
||||
// Default to disabled if we can't fetch the info
|
||||
isGraphDatabaseEnabled.value = false
|
||||
isMinioEnabled.value = false
|
||||
if (localNodeExtract.value.enabled) {
|
||||
localNodeExtract.value.enabled = false
|
||||
emit('update:nodeExtract', localNodeExtract.value)
|
||||
}
|
||||
// If MinIO status unknown and storage type is minio, switch to cos
|
||||
if (localMultimodal.value.storageType === 'minio') {
|
||||
localMultimodal.value.storageType = 'cos'
|
||||
emit('update:multimodal', localMultimodal.value)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Watch for prop changes
|
||||
watch(() => props.multimodal, (newVal) => {
|
||||
@@ -340,6 +418,10 @@ const handleMultimodalToggle = () => {
|
||||
|
||||
// Handle storage type change
|
||||
const handleStorageTypeChange = () => {
|
||||
// Prevent switching to minio if it's not enabled
|
||||
if (localMultimodal.value.storageType === 'minio' && !isMinioEnabled.value) {
|
||||
localMultimodal.value.storageType = 'cos'
|
||||
}
|
||||
emit('update:multimodal', localMultimodal.value)
|
||||
}
|
||||
|
||||
@@ -356,9 +438,19 @@ const handleAddModel = (subSection: string) => {
|
||||
|
||||
// Handle knowledge graph toggle
|
||||
const handleNodeExtractToggle = () => {
|
||||
// Prevent enabling if graph database is not enabled
|
||||
if (!isGraphDatabaseEnabled.value) {
|
||||
localNodeExtract.value.enabled = false
|
||||
return
|
||||
}
|
||||
emit('update:nodeExtract', localNodeExtract.value)
|
||||
}
|
||||
|
||||
// Open system info page to show how to enable graph database
|
||||
const handleOpenSystemInfo = () => {
|
||||
uiStore.openSettings('system')
|
||||
}
|
||||
|
||||
// Handle configuration change
|
||||
const handleConfigChange = () => {
|
||||
emit('update:multimodal', localMultimodal.value)
|
||||
|
||||
@@ -2283,6 +2283,10 @@ func (s *knowledgeService) SearchFAQEntries(ctx context.Context,
|
||||
entries = append(entries, entry)
|
||||
}
|
||||
|
||||
slices.SortFunc(entries, func(a, b *types.FAQEntry) int {
|
||||
return int(b.Score - a.Score)
|
||||
})
|
||||
|
||||
return entries, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -407,15 +407,12 @@ func (s *knowledgeBaseService) HybridSearch(ctx context.Context,
|
||||
// Check if we need iterative retrieval for FAQ with separate indexing
|
||||
// Only use iterative retrieval if we don't have enough unique chunks after first deduplication
|
||||
needsIterativeRetrieval := len(deduplicatedChunks) < params.MatchCount &&
|
||||
kb.Type == types.KnowledgeBaseTypeFAQ &&
|
||||
kb.FAQConfig != nil &&
|
||||
kb.FAQConfig.QuestionIndexMode == types.FAQQuestionIndexModeSeparate
|
||||
|
||||
kb.Type == types.KnowledgeBaseTypeFAQ && len(matchResults) >= params.MatchCount
|
||||
if needsIterativeRetrieval {
|
||||
logger.Infof(ctx, "Not enough unique chunks (%d < %d), using iterative retrieval for FAQ with separate indexing",
|
||||
logger.Infof(ctx, "Not enough unique chunks (%d < %d), using iterative retrieval for FAQ",
|
||||
len(deduplicatedChunks), params.MatchCount)
|
||||
// Use iterative retrieval to get more unique chunks (with negative question filtering inside)
|
||||
deduplicatedChunks = s.iterativeRetrieveWithDeduplication(ctx, retrieveEngine, retrieveParams, params.MatchCount, params.QueryText, kb.Type == types.KnowledgeBaseTypeFAQ)
|
||||
deduplicatedChunks = s.iterativeRetrieveWithDeduplication(ctx, retrieveEngine, retrieveParams, params.MatchCount, params.QueryText)
|
||||
} else if kb.Type == types.KnowledgeBaseTypeFAQ {
|
||||
// Filter by negative questions if not using iterative retrieval
|
||||
deduplicatedChunks = s.filterByNegativeQuestions(ctx, deduplicatedChunks, params.QueryText)
|
||||
@@ -438,7 +435,6 @@ func (s *knowledgeBaseService) iterativeRetrieveWithDeduplication(ctx context.Co
|
||||
retrieveParams []types.RetrieveParams,
|
||||
matchCount int,
|
||||
queryText string,
|
||||
isFAQ bool,
|
||||
) []*types.IndexWithScore {
|
||||
maxIterations := 5
|
||||
currentTopK := matchCount
|
||||
@@ -492,14 +488,12 @@ func (s *knowledgeBaseService) iterativeRetrieveWithDeduplication(ctx context.Co
|
||||
chunksSlice = append(chunksSlice, chunk)
|
||||
}
|
||||
|
||||
// Filter by negative questions if this is a FAQ knowledge base
|
||||
if isFAQ {
|
||||
chunksSlice = s.filterByNegativeQuestions(ctx, chunksSlice, queryText)
|
||||
// Update uniqueChunks map with filtered results
|
||||
uniqueChunks = make(map[string]*types.IndexWithScore, len(chunksSlice))
|
||||
for _, chunk := range chunksSlice {
|
||||
uniqueChunks[chunk.ChunkID] = chunk
|
||||
}
|
||||
// Filter by negative questions
|
||||
chunksSlice = s.filterByNegativeQuestions(ctx, chunksSlice, queryText)
|
||||
// Update uniqueChunks map with filtered results
|
||||
uniqueChunks = make(map[string]*types.IndexWithScore, len(chunksSlice))
|
||||
for _, chunk := range chunksSlice {
|
||||
uniqueChunks[chunk.ChunkID] = chunk
|
||||
}
|
||||
|
||||
logger.Infof(ctx, "After iteration %d: retrieved %d results, found %d unique chunks after filtering (target: %d)",
|
||||
|
||||
@@ -30,6 +30,7 @@ type GetSystemInfoResponse struct {
|
||||
KeywordIndexEngine string `json:"keyword_index_engine,omitempty"`
|
||||
VectorStoreEngine string `json:"vector_store_engine,omitempty"`
|
||||
GraphDatabaseEngine string `json:"graph_database_engine,omitempty"`
|
||||
MinioEnabled bool `json:"minio_enabled,omitempty"`
|
||||
}
|
||||
|
||||
// 编译时注入的版本信息
|
||||
@@ -53,6 +54,9 @@ func (h *SystemHandler) GetSystemInfo(c *gin.Context) {
|
||||
// Get graph database engine from NEO4J_ENABLE
|
||||
graphDatabaseEngine := h.getGraphDatabaseEngine()
|
||||
|
||||
// Get MinIO enabled status
|
||||
minioEnabled := h.isMinioEnabled()
|
||||
|
||||
response := GetSystemInfoResponse{
|
||||
Version: Version,
|
||||
CommitID: CommitID,
|
||||
@@ -61,6 +65,7 @@ func (h *SystemHandler) GetSystemInfo(c *gin.Context) {
|
||||
KeywordIndexEngine: keywordIndexEngine,
|
||||
VectorStoreEngine: vectorStoreEngine,
|
||||
GraphDatabaseEngine: graphDatabaseEngine,
|
||||
MinioEnabled: minioEnabled,
|
||||
}
|
||||
|
||||
logger.Info(ctx, "System info retrieved successfully")
|
||||
@@ -131,3 +136,13 @@ func (h *SystemHandler) getGraphDatabaseEngine() string {
|
||||
}
|
||||
return "未启用"
|
||||
}
|
||||
|
||||
// isMinioEnabled checks if MinIO is enabled
|
||||
func (h *SystemHandler) isMinioEnabled() bool {
|
||||
// Check if all required MinIO environment variables are set
|
||||
endpoint := os.Getenv("MINIO_ENDPOINT")
|
||||
accessKeyID := os.Getenv("MINIO_ACCESS_KEY_ID")
|
||||
secretAccessKey := os.Getenv("MINIO_SECRET_ACCESS_KEY")
|
||||
|
||||
return endpoint != "" && accessKeyID != "" && secretAccessKey != ""
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user