feat: remove faiss database (#10178)
This commit is contained in:
@@ -24,7 +24,6 @@ import {
|
||||
KnowledgeBase,
|
||||
KnowledgeItem,
|
||||
KnowledgeNoteItem,
|
||||
MigrationModeEnum,
|
||||
ProcessingStatus
|
||||
} from '@renderer/types'
|
||||
import { runAsyncFunction, uuid } from '@renderer/utils'
|
||||
@@ -231,7 +230,7 @@ export const useKnowledge = (baseId: string) => {
|
||||
}
|
||||
|
||||
// 迁移知识库(保留原知识库)
|
||||
const migrateBase = async (newBase: KnowledgeBase, mode: MigrationModeEnum) => {
|
||||
const migrateBase = async (newBase: KnowledgeBase) => {
|
||||
if (!base) return
|
||||
|
||||
const timestamp = dayjs().format('YYMMDDHHmmss')
|
||||
@@ -244,14 +243,9 @@ export const useKnowledge = (baseId: string) => {
|
||||
name: newName,
|
||||
created_at: Date.now(),
|
||||
updated_at: Date.now(),
|
||||
items: [],
|
||||
framework: mode === MigrationModeEnum.MigrationToLangChain ? 'langchain' : base.framework
|
||||
items: []
|
||||
} satisfies KnowledgeBase
|
||||
|
||||
if (mode === MigrationModeEnum.MigrationToLangChain) {
|
||||
await window.api.knowledgeBase.create(getKnowledgeBaseParams(migratedBase))
|
||||
}
|
||||
|
||||
dispatch(addBase(migratedBase))
|
||||
|
||||
const files: FileMetadata[] = []
|
||||
|
||||
@@ -14,11 +14,7 @@ const createInitialKnowledgeBase = (): KnowledgeBase => ({
|
||||
items: [],
|
||||
created_at: Date.now(),
|
||||
updated_at: Date.now(),
|
||||
version: 1,
|
||||
framework: 'langchain',
|
||||
retriever: {
|
||||
mode: 'hybrid'
|
||||
}
|
||||
version: 1
|
||||
})
|
||||
|
||||
/**
|
||||
|
||||
@@ -1063,10 +1063,6 @@
|
||||
"error": {
|
||||
"failed": "Migration failed"
|
||||
},
|
||||
"migrate_to_langchain": {
|
||||
"content": "The knowledge base migration does not delete the old knowledge base but creates a copy and reprocesses all entries, which may consume a significant number of tokens. Please proceed with caution.",
|
||||
"info": "The knowledge base architecture has been updated. Click to migrate to the new architecture."
|
||||
},
|
||||
"source_dimensions": "Source Dimensions",
|
||||
"source_model": "Source Model",
|
||||
"target_dimensions": "Target Dimensions",
|
||||
@@ -1085,20 +1081,6 @@
|
||||
"quota": "{{name}} Left Quota: {{quota}}",
|
||||
"quota_infinity": "{{name}} Quota: Unlimited",
|
||||
"rename": "Rename",
|
||||
"retriever": "Retrieve mode",
|
||||
"retriever_bm25": "full-text search",
|
||||
"retriever_bm25_desc": "Search for documents based on keyword relevance and frequency.",
|
||||
"retriever_hybrid": "Hybrid Search (Recommended)",
|
||||
"retriever_hybrid_desc": "Combine keyword search and semantic search to achieve optimal retrieval accuracy.",
|
||||
"retriever_hybrid_weight": {
|
||||
"bm25": "full text",
|
||||
"recommended": "recommend",
|
||||
"title": "Hybrid Search Weight Adjustment (Full-text/Vector)",
|
||||
"vector": "vector"
|
||||
},
|
||||
"retriever_tooltip": "Using different retrieval methods to search the knowledge base",
|
||||
"retriever_vector": "vector search",
|
||||
"retriever_vector_desc": "Retrieve documents based on semantic similarity and meaning.",
|
||||
"search": "Search knowledge base",
|
||||
"search_placeholder": "Enter text to search",
|
||||
"settings": {
|
||||
|
||||
@@ -1064,10 +1064,6 @@
|
||||
"error": {
|
||||
"failed": "迁移失败"
|
||||
},
|
||||
"migrate_to_langchain": {
|
||||
"content": "知识库迁移不会删除旧知识库,而是创建一个副本之后重新处理所有知识库条目,可能消耗大量 tokens,请谨慎操作。",
|
||||
"info": "知识库架构已更新,点击迁移到新架构"
|
||||
},
|
||||
"source_dimensions": "源维度",
|
||||
"source_model": "源模型",
|
||||
"target_dimensions": "目标维度",
|
||||
@@ -1086,20 +1082,6 @@
|
||||
"quota": "{{name}} 剩余额度:{{quota}}",
|
||||
"quota_infinity": "{{name}} 剩余额度:无限制",
|
||||
"rename": "重命名",
|
||||
"retriever": "检索模式",
|
||||
"retriever_bm25": "全文搜索",
|
||||
"retriever_bm25_desc": "根据关键字的相关性和频率查找文档。",
|
||||
"retriever_hybrid": "混合搜索 (推荐)",
|
||||
"retriever_hybrid_desc": "结合关键词搜索和语义搜索,以实现最佳检索准确性。",
|
||||
"retriever_hybrid_weight": {
|
||||
"bm25": "全文",
|
||||
"recommended": "推荐",
|
||||
"title": "混合搜索权重调整 (全文/向量)",
|
||||
"vector": "向量"
|
||||
},
|
||||
"retriever_tooltip": "使用不同的检索方式检索知识库",
|
||||
"retriever_vector": "向量搜索",
|
||||
"retriever_vector_desc": "根据语义相似性和含义查找文档。",
|
||||
"search": "搜索知识库",
|
||||
"search_placeholder": "输入查询内容",
|
||||
"settings": {
|
||||
|
||||
@@ -1063,10 +1063,6 @@
|
||||
"error": {
|
||||
"failed": "遷移失敗"
|
||||
},
|
||||
"migrate_to_langchain": {
|
||||
"content": "知識庫遷移不會刪除舊知識庫,而是建立一個副本後重新處理所有知識庫條目,可能消耗大量 tokens,請謹慎操作。",
|
||||
"info": "知識庫架構已更新,點擊遷移到新架構"
|
||||
},
|
||||
"source_dimensions": "源維度",
|
||||
"source_model": "源模型",
|
||||
"target_dimensions": "目標維度",
|
||||
@@ -1085,20 +1081,6 @@
|
||||
"quota": "{{name}} 剩餘配額:{{quota}}",
|
||||
"quota_infinity": "{{name}} 配額:無限制",
|
||||
"rename": "重新命名",
|
||||
"retriever": "搜尋模式",
|
||||
"retriever_bm25": "全文搜尋",
|
||||
"retriever_bm25_desc": "根據關鍵字的相關性和頻率查找文件。",
|
||||
"retriever_hybrid": "混合搜尋(推薦)",
|
||||
"retriever_hybrid_desc": "結合關鍵字搜索和語義搜索,以實現最佳檢索準確性。",
|
||||
"retriever_hybrid_weight": {
|
||||
"bm25": "全文",
|
||||
"recommended": "推薦",
|
||||
"title": "混合搜尋權重調整 (全文/向量)",
|
||||
"vector": "向量"
|
||||
},
|
||||
"retriever_tooltip": "使用不同的檢索方式檢索知識庫",
|
||||
"retriever_vector": "向量搜尋",
|
||||
"retriever_vector_desc": "根據語意相似性和含義查找文件。",
|
||||
"search": "搜尋知識庫",
|
||||
"search_placeholder": "輸入查詢內容",
|
||||
"settings": {
|
||||
|
||||
@@ -1063,10 +1063,6 @@
|
||||
"error": {
|
||||
"failed": "Αποτυχία μεταφοράς"
|
||||
},
|
||||
"migrate_to_langchain": {
|
||||
"content": "Η μετανάστευση της βάσης γνώσεων δεν διαγράφει την παλιά βάση γνώσεων, αλλά δημιουργεί ένα αντίγραφο και στη συνέχεια επεξεργάζεται ξανά όλες τις εγγραφές της βάσης γνώσεων, κάτι που μπορεί να καταναλώσει μεγάλο αριθμό tokens, οπότε ενεργήστε με προσοχή.",
|
||||
"info": "Η δομή της βάσης γνώσεων έχει ενημερωθεί, κάντε κλικ για μετεγκατάσταση στη νέα δομή"
|
||||
},
|
||||
"source_dimensions": "Πηγαίες διαστάσεις",
|
||||
"source_model": "Πηγαίο μοντέλο",
|
||||
"target_dimensions": "Προορισμένες διαστάσεις",
|
||||
@@ -1085,20 +1081,6 @@
|
||||
"quota": "Διαθέσιμο όριο για {{name}}: {{quota}}",
|
||||
"quota_infinity": "Διαθέσιμο όριο για {{name}}: Απεριόριστο",
|
||||
"rename": "Μετονομασία",
|
||||
"retriever": "Λειτουργία αναζήτησης",
|
||||
"retriever_bm25": "Πλήρης αναζήτηση κειμένου",
|
||||
"retriever_bm25_desc": "Αναζήτηση εγγράφων με βάση τη σχετικότητα και τη συχνότητα των λέξεων-κλειδιών.",
|
||||
"retriever_hybrid": "Μικτή αναζήτηση (συνιστάται)",
|
||||
"retriever_hybrid_desc": "Συνδυάστε την αναζήτηση με λέξεις-κλειδιά και την σημασιολογική αναζήτηση για την επίτευξη της βέλτιστης ακρίβειας ανάκτησης.",
|
||||
"retriever_hybrid_weight": {
|
||||
"bm25": "ολόκληρο το κείμενο",
|
||||
"recommended": "Προτείνω",
|
||||
"title": "Προσαρμογή βάρους μικτής αναζήτησης (πλήρες κείμενο/διανυσματικό)",
|
||||
"vector": "διάνυσμα"
|
||||
},
|
||||
"retriever_tooltip": "Χρησιμοποιώντας διαφορετικές μεθόδους αναζήτησης για αναζήτηση στη βάση γνώσης",
|
||||
"retriever_vector": "Αναζήτηση διανυσμάτων",
|
||||
"retriever_vector_desc": "Βρείτε έγγραφα βάση της σημασιολογικής ομοιότητας και της έννοιας.",
|
||||
"search": "Αναζήτηση βάσης γνώσεων",
|
||||
"search_placeholder": "Εισάγετε την αναζήτηση",
|
||||
"settings": {
|
||||
|
||||
@@ -1063,10 +1063,6 @@
|
||||
"error": {
|
||||
"failed": "Error en la migración"
|
||||
},
|
||||
"migrate_to_langchain": {
|
||||
"content": "La migración de la base de conocimiento no elimina la base antigua, sino que crea una copia y luego reprocesa todas las entradas, lo que puede consumir una gran cantidad de tokens. Proceda con precaución.",
|
||||
"info": "La estructura de la base de conocimiento ha sido actualizada. Haz clic para migrar a la nueva estructura."
|
||||
},
|
||||
"source_dimensions": "Dimensiones de origen",
|
||||
"source_model": "Modelo de origen",
|
||||
"target_dimensions": "Dimensiones de destino",
|
||||
@@ -1085,20 +1081,6 @@
|
||||
"quota": "Cupo restante de {{name}}: {{quota}}",
|
||||
"quota_infinity": "Cupo restante de {{name}}: ilimitado",
|
||||
"rename": "Renombrar",
|
||||
"retriever": "modo de recuperación",
|
||||
"retriever_bm25": "búsqueda de texto completo",
|
||||
"retriever_bm25_desc": "Encontrar documentos basados en la relevancia y frecuencia de las palabras clave.",
|
||||
"retriever_hybrid": "Búsqueda híbrida (recomendada)",
|
||||
"retriever_hybrid_desc": "Combinar la búsqueda por palabras clave con la búsqueda semántica para lograr la máxima precisión en la recuperación.",
|
||||
"retriever_hybrid_weight": {
|
||||
"bm25": "texto completo",
|
||||
"recommended": "Recomendado",
|
||||
"title": "Ajuste de ponderación en búsqueda híbrida (texto completo/vectorial)",
|
||||
"vector": "vector"
|
||||
},
|
||||
"retriever_tooltip": "Usar diferentes métodos de búsqueda para consultar la base de conocimiento",
|
||||
"retriever_vector": "búsqueda vectorial",
|
||||
"retriever_vector_desc": "Buscar documentos según similitud semántica y significado.",
|
||||
"search": "Buscar en la base de conocimientos",
|
||||
"search_placeholder": "Ingrese el contenido de la consulta",
|
||||
"settings": {
|
||||
|
||||
@@ -1063,10 +1063,6 @@
|
||||
"error": {
|
||||
"failed": "Erreur lors de la migration"
|
||||
},
|
||||
"migrate_to_langchain": {
|
||||
"content": "La migration de la base de connaissances ne supprime pas l'ancienne base, mais crée une copie avant de retraiter tous les éléments, ce qui peut consommer un grand nombre de tokens. Veuillez agir avec prudence.",
|
||||
"info": "L'architecture de la base de connaissances a été mise à jour, cliquez pour migrer vers la nouvelle architecture."
|
||||
},
|
||||
"source_dimensions": "Dimensions source",
|
||||
"source_model": "Modèle source",
|
||||
"target_dimensions": "Dimensions cible",
|
||||
@@ -1085,20 +1081,6 @@
|
||||
"quota": "Quota restant pour {{name}} : {{quota}}",
|
||||
"quota_infinity": "Quota restant pour {{name}} : illimité",
|
||||
"rename": "Renommer",
|
||||
"retriever": "Mode de recherche",
|
||||
"retriever_bm25": "Recherche plein texte",
|
||||
"retriever_bm25_desc": "Rechercher des documents en fonction de la pertinence et de la fréquence des mots-clés.",
|
||||
"retriever_hybrid": "Recherche hybride (recommandé)",
|
||||
"retriever_hybrid_desc": "Associez la recherche par mots-clés et la recherche sémantique pour une précision de recherche optimale.",
|
||||
"retriever_hybrid_weight": {
|
||||
"bm25": "texte intégral",
|
||||
"recommended": "Recommandé",
|
||||
"title": "Ajustement des pondérations de recherche hybride (texte intégral/vecteur)",
|
||||
"vector": "vecteur"
|
||||
},
|
||||
"retriever_tooltip": "Utiliser différentes méthodes de recherche pour interroger la base de connaissances",
|
||||
"retriever_vector": "Recherche vectorielle",
|
||||
"retriever_vector_desc": "Rechercher des documents selon la similarité sémantique et le sens.",
|
||||
"search": "Rechercher dans la base de connaissances",
|
||||
"search_placeholder": "Entrez votre requête",
|
||||
"settings": {
|
||||
|
||||
@@ -1063,10 +1063,6 @@
|
||||
"error": {
|
||||
"failed": "移行が失敗しました"
|
||||
},
|
||||
"migrate_to_langchain": {
|
||||
"content": "ナレッジベースの移行は旧ナレッジベースを削除せず、すべてのエントリーを再処理したコピーを作成します。大量のトークンを消費する可能性があるため、操作には十分注意してください。",
|
||||
"info": "ナレッジベースのアーキテクチャが更新されました、新しいアーキテクチャに移行するにはクリックしてください"
|
||||
},
|
||||
"source_dimensions": "ソース次元",
|
||||
"source_model": "ソースモデル",
|
||||
"target_dimensions": "ターゲット次元",
|
||||
@@ -1085,20 +1081,6 @@
|
||||
"quota": "{{name}} 残りクォータ: {{quota}}",
|
||||
"quota_infinity": "{{name}} クォータ: 無制限",
|
||||
"rename": "名前を変更",
|
||||
"retriever": "検索モード",
|
||||
"retriever_bm25": "全文検索",
|
||||
"retriever_bm25_desc": "キーワードの関連性と頻度に基づいてドキュメントを検索します。",
|
||||
"retriever_hybrid": "ハイブリッド検索(おすすめ)",
|
||||
"retriever_hybrid_desc": "キーワード検索と意味検索を組み合わせて、最高の検索精度を実現します。",
|
||||
"retriever_hybrid_weight": {
|
||||
"bm25": "全文(ぜんぶん)",
|
||||
"recommended": "おすすめ",
|
||||
"title": "ハイブリッド検索の重み付け調整 (全文/ベクトル)",
|
||||
"vector": "ベクトル"
|
||||
},
|
||||
"retriever_tooltip": "異なる検索方法を使用してナレッジベースを検索する",
|
||||
"retriever_vector": "ベクトル検索",
|
||||
"retriever_vector_desc": "意味的な類似性と意味に基づいて文書を検索します。",
|
||||
"search": "ナレッジベースを検索",
|
||||
"search_placeholder": "検索するテキストを入力",
|
||||
"settings": {
|
||||
|
||||
@@ -1063,10 +1063,6 @@
|
||||
"error": {
|
||||
"failed": "Falha na migração"
|
||||
},
|
||||
"migrate_to_langchain": {
|
||||
"content": "A migração da base de conhecimento não elimina a base antiga, mas sim cria uma cópia e reprocessa todas as entradas, o que pode consumir muitos tokens. Por favor, proceda com cautela.",
|
||||
"info": "A arquitetura da base de conhecimento foi atualizada, clique para migrar para a nova arquitetura."
|
||||
},
|
||||
"source_dimensions": "Dimensões de origem",
|
||||
"source_model": "Modelo de origem",
|
||||
"target_dimensions": "Dimensões de destino",
|
||||
@@ -1085,20 +1081,6 @@
|
||||
"quota": "Cota restante de {{name}}: {{quota}}",
|
||||
"quota_infinity": "Cota restante de {{name}}: ilimitada",
|
||||
"rename": "Renomear",
|
||||
"retriever": "Modo de pesquisa",
|
||||
"retriever_bm25": "pesquisa de texto completo",
|
||||
"retriever_bm25_desc": "Pesquisar documentos com base na relevância e frequência das palavras-chave.",
|
||||
"retriever_hybrid": "Pesquisa híbrida (recomendada)",
|
||||
"retriever_hybrid_desc": "Combine a pesquisa por palavras-chave com a pesquisa semântica para alcançar a melhor precisão de recuperação.",
|
||||
"retriever_hybrid_weight": {
|
||||
"bm25": "texto integral",
|
||||
"recommended": "Recomendar",
|
||||
"title": "Ajuste de ponderação de pesquisa híbrida (texto completo/vetorial)",
|
||||
"vector": "vetor"
|
||||
},
|
||||
"retriever_tooltip": "Utilize diferentes métodos de pesquisa para consultar a base de conhecimento.",
|
||||
"retriever_vector": "pesquisa vetorial",
|
||||
"retriever_vector_desc": "Encontrar documentos com base na similaridade semântica e significado.",
|
||||
"search": "Pesquisar repositório de conhecimento",
|
||||
"search_placeholder": "Digite o conteúdo da consulta",
|
||||
"settings": {
|
||||
|
||||
@@ -1063,10 +1063,6 @@
|
||||
"error": {
|
||||
"failed": "Миграция завершена с ошибками"
|
||||
},
|
||||
"migrate_to_langchain": {
|
||||
"content": "Миграция базы знаний не удаляет старую базу, а создает ее копию с последующей повторной обработкой всех записей, что может потребовать значительного количества токенов. Пожалуйста, действуйте осторожно.",
|
||||
"info": "Архитектура базы знаний обновлена, нажмите, чтобы перейти на новую архитектуру"
|
||||
},
|
||||
"source_dimensions": "Исходная размерность",
|
||||
"source_model": "Исходная модель",
|
||||
"target_dimensions": "Целевая размерность",
|
||||
@@ -1085,20 +1081,6 @@
|
||||
"quota": "{{name}} Остаток квоты: {{quota}}",
|
||||
"quota_infinity": "{{name}} Квота: Не ограничена",
|
||||
"rename": "Переименовать",
|
||||
"retriever": "Режим поиска",
|
||||
"retriever_bm25": "полнотекстовый поиск",
|
||||
"retriever_bm25_desc": "Поиск документов на основе релевантности и частоты ключевых слов.",
|
||||
"retriever_hybrid": "Гибридный поиск (рекомендуется)",
|
||||
"retriever_hybrid_desc": "Сочетание поиска по ключевым словам и семантического поиска для достижения оптимальной точности поиска.",
|
||||
"retriever_hybrid_weight": {
|
||||
"bm25": "Полный текст",
|
||||
"recommended": "рекомендовать",
|
||||
"title": "Регулировка весов гибридного поиска (полнотекстовый/векторный)",
|
||||
"vector": "вектор"
|
||||
},
|
||||
"retriever_tooltip": "Использование различных методов поиска в базе знаний",
|
||||
"retriever_vector": "векторный поиск",
|
||||
"retriever_vector_desc": "Поиск документов по семантическому сходству и смыслу.",
|
||||
"search": "Поиск в базе знаний",
|
||||
"search_placeholder": "Введите текст для поиска",
|
||||
"settings": {
|
||||
|
||||
@@ -14,7 +14,6 @@ import styled from 'styled-components'
|
||||
|
||||
import EditKnowledgeBasePopup from './components/EditKnowledgeBasePopup'
|
||||
import KnowledgeSearchPopup from './components/KnowledgeSearchPopup'
|
||||
import MigrationInfoTag from './components/MigrationInfoTag'
|
||||
import QuotaTag from './components/QuotaTag'
|
||||
import KnowledgeDirectories from './items/KnowledgeDirectories'
|
||||
import KnowledgeFiles from './items/KnowledgeFiles'
|
||||
@@ -109,13 +108,14 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
|
||||
content: <KnowledgeSitemaps selectedBase={selectedBase} />,
|
||||
show: true
|
||||
},
|
||||
// 暂时不显示,后续实现
|
||||
{
|
||||
key: 'videos',
|
||||
title: t('knowledge.videos'),
|
||||
icon: activeKey === 'videos' ? <Video size={16} color="var(--color-primary)" /> : <Video size={16} />,
|
||||
items: videoItems,
|
||||
content: <KnowledgeVideos selectedBase={selectedBase} />,
|
||||
show: base?.framework === 'langchain'
|
||||
show: false
|
||||
}
|
||||
]
|
||||
|
||||
@@ -162,7 +162,6 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
|
||||
{base.preprocessProvider && base.preprocessProvider.type === 'preprocess' && (
|
||||
<QuotaTag base={base} providerId={base.preprocessProvider?.provider.id} quota={quota} />
|
||||
)}
|
||||
{base.framework !== 'langchain' && <MigrationInfoTag base={base} />}
|
||||
</div>
|
||||
</ModelInfo>
|
||||
<HStack gap={8} alignItems="center">
|
||||
|
||||
@@ -78,7 +78,6 @@ function createKnowledgeBase(overrides: Partial<KnowledgeBase> = {}): KnowledgeB
|
||||
chunkSize: 500,
|
||||
chunkOverlap: 200,
|
||||
threshold: 0.5,
|
||||
framework: 'langchain',
|
||||
...overrides
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,24 +137,6 @@ vi.mock('antd', () => ({
|
||||
{children}
|
||||
</select>
|
||||
),
|
||||
Segmented: ({ value, onChange, options, style }: any) => (
|
||||
<div data-testid="retriever-segmented" style={style}>
|
||||
{options?.map((option: any) => (
|
||||
<button
|
||||
key={option.value}
|
||||
type="button"
|
||||
data-testid={`segmented-option-${option.value}`}
|
||||
onClick={() => onChange?.(option.value)}
|
||||
data-active={value === option.value}
|
||||
style={{
|
||||
backgroundColor: value === option.value ? '#1677ff' : '#fff',
|
||||
color: value === option.value ? '#fff' : '#000'
|
||||
}}>
|
||||
{option.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
),
|
||||
Slider: ({ value, onChange, min, max, step, marks, style }: any) => {
|
||||
// Determine test ID based on slider characteristics
|
||||
const isWeightSlider = min === 0 && max === 1 && step === 0.1
|
||||
@@ -193,14 +175,10 @@ function createKnowledgeBase(overrides: Partial<KnowledgeBase> = {}): KnowledgeB
|
||||
id: 'test-base-id',
|
||||
name: 'Test Knowledge Base',
|
||||
model: defaultModel,
|
||||
retriever: {
|
||||
mode: 'hybrid'
|
||||
},
|
||||
items: [],
|
||||
created_at: Date.now(),
|
||||
updated_at: Date.now(),
|
||||
version: 1,
|
||||
framework: 'langchain',
|
||||
...overrides
|
||||
}
|
||||
}
|
||||
@@ -319,42 +297,6 @@ describe('GeneralSettingsPanel', () => {
|
||||
expect(mockSetNewBase).toHaveBeenCalledWith(expect.any(Function))
|
||||
})
|
||||
|
||||
it('should handle hybrid weight change', async () => {
|
||||
renderComponent()
|
||||
|
||||
const weightSlider = screen.getByTestId('weight-slider')
|
||||
fireEvent.change(weightSlider, { target: { value: '0.7' } })
|
||||
|
||||
expect(mockSetNewBase).toHaveBeenCalledWith({
|
||||
...mockBase,
|
||||
retriever: {
|
||||
...mockBase.retriever,
|
||||
mode: 'hybrid',
|
||||
weight: 0.7
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('should handle retriever selection change', async () => {
|
||||
renderComponent()
|
||||
|
||||
// Test clicking on hybrid retriever option
|
||||
const hybridOption = screen.getByTestId('segmented-option-hybrid')
|
||||
await user.click(hybridOption)
|
||||
|
||||
expect(mockSetNewBase).toHaveBeenCalledWith({
|
||||
...mockBase,
|
||||
retriever: { mode: 'hybrid' }
|
||||
})
|
||||
})
|
||||
|
||||
it('should not render retriever segmented when framework is embedjs', () => {
|
||||
const baseWithEmbedjs = createKnowledgeBase({ framework: 'embedjs' })
|
||||
renderComponent({ newBase: baseWithEmbedjs })
|
||||
|
||||
expect(screen.queryByTestId('retriever-segmented')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should disable dimension input when no model is selected', () => {
|
||||
const baseWithoutModel = createKnowledgeBase({ model: undefined as any })
|
||||
renderComponent({ newBase: baseWithoutModel })
|
||||
|
||||
-63
@@ -170,69 +170,6 @@ exports[`GeneralSettingsPanel > basic rendering > should match snapshot 1`] = `
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div
|
||||
class="c1"
|
||||
>
|
||||
<div
|
||||
class="settings-label"
|
||||
>
|
||||
knowledge.retriever
|
||||
<span
|
||||
data-placement="right"
|
||||
data-testid="info-tooltip"
|
||||
title="knowledge.retriever_tooltip"
|
||||
>
|
||||
ℹ️
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
data-testid="retriever-segmented"
|
||||
>
|
||||
<button
|
||||
data-active="true"
|
||||
data-testid="segmented-option-hybrid"
|
||||
style="background-color: rgb(22, 119, 255); color: rgb(255, 255, 255);"
|
||||
type="button"
|
||||
>
|
||||
knowledge.retriever_hybrid
|
||||
</button>
|
||||
<button
|
||||
data-active="false"
|
||||
data-testid="segmented-option-vector"
|
||||
style="background-color: rgb(255, 255, 255); color: rgb(0, 0, 0);"
|
||||
type="button"
|
||||
>
|
||||
knowledge.retriever_vector
|
||||
</button>
|
||||
<button
|
||||
data-active="false"
|
||||
data-testid="segmented-option-bm25"
|
||||
style="background-color: rgb(255, 255, 255); color: rgb(0, 0, 0);"
|
||||
type="button"
|
||||
>
|
||||
knowledge.retriever_bm25
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="c1"
|
||||
>
|
||||
<div
|
||||
class="settings-label"
|
||||
>
|
||||
knowledge.retriever_hybrid_weight.title
|
||||
</div>
|
||||
<input
|
||||
data-marks="{"0":"knowledge.retriever_hybrid_weight.bm25","1":"knowledge.retriever_hybrid_weight.vector","0.5":"knowledge.retriever_hybrid_weight.recommended"}"
|
||||
data-testid="weight-slider"
|
||||
max="1"
|
||||
min="0"
|
||||
step="0.1"
|
||||
style="width: 100%;"
|
||||
type="range"
|
||||
value="0.5"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="c1"
|
||||
>
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ exports[`KnowledgeBaseFormModal > basic rendering > should match snapshot 1`] =
|
||||
data-title="Knowledge Base Settings"
|
||||
styles="[object Object]"
|
||||
transitionname="animation-move-down"
|
||||
width="min(900px, 75vw)"
|
||||
width="min(900px, 65vw)"
|
||||
>
|
||||
<div
|
||||
data-testid="modal-header"
|
||||
|
||||
@@ -51,8 +51,7 @@ const PopupContainer: React.FC<PopupContainerProps> = ({ title, resolve }) => {
|
||||
const _newBase: KnowledgeBase = {
|
||||
...newBase,
|
||||
created_at: Date.now(),
|
||||
updated_at: Date.now(),
|
||||
framework: 'langchain'
|
||||
updated_at: Date.now()
|
||||
}
|
||||
|
||||
await window.api.knowledgeBase.create(getKnowledgeBaseParams(_newBase))
|
||||
|
||||
@@ -4,7 +4,7 @@ import { TopView } from '@renderer/components/TopView'
|
||||
import { useKnowledge } from '@renderer/hooks/useKnowledge'
|
||||
import { useKnowledgeBaseForm } from '@renderer/hooks/useKnowledgeBaseForm'
|
||||
import { getModelUniqId } from '@renderer/services/ModelService'
|
||||
import { KnowledgeBase, MigrationModeEnum } from '@renderer/types'
|
||||
import { KnowledgeBase } from '@renderer/types'
|
||||
import { formatErrorMessage } from '@renderer/utils/error'
|
||||
import { Flex } from 'antd'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
@@ -48,7 +48,7 @@ const PopupContainer: React.FC<PopupContainerProps> = ({ base: _base, resolve })
|
||||
const handleEmbeddingModelChangeMigration = useCallback(async () => {
|
||||
const migratedBase = { ...newBase, id: nanoid() }
|
||||
try {
|
||||
await migrateBase(migratedBase, MigrationModeEnum.EmbeddingModelChange)
|
||||
await migrateBase(migratedBase)
|
||||
setOpen(false)
|
||||
resolve(migratedBase)
|
||||
} catch (error) {
|
||||
|
||||
+1
-50
@@ -6,7 +6,7 @@ import { isEmbeddingModel, isRerankModel } from '@renderer/config/models'
|
||||
import { useProviders } from '@renderer/hooks/useProvider'
|
||||
import { getModelUniqId } from '@renderer/services/ModelService'
|
||||
import { KnowledgeBase, PreprocessProvider } from '@renderer/types'
|
||||
import { Input, Segmented, Select, SelectProps, Slider } from 'antd'
|
||||
import { Input, Select, SelectProps, Slider } from 'antd'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { SettingsItem, SettingsPanel } from './styles'
|
||||
@@ -106,55 +106,6 @@ const GeneralSettingsPanel: React.FC<GeneralSettingsPanelProps> = ({
|
||||
/>
|
||||
</SettingsItem>
|
||||
|
||||
{newBase.framework !== 'embedjs' && (
|
||||
<>
|
||||
<SettingsItem>
|
||||
<div className="settings-label">
|
||||
{t('knowledge.retriever')}
|
||||
<InfoTooltip title={t('knowledge.retriever_tooltip')} placement="right" />
|
||||
</div>
|
||||
<Segmented
|
||||
value={newBase.retriever?.mode || 'hybrid'}
|
||||
onChange={(value) =>
|
||||
setNewBase({ ...newBase, retriever: { mode: value as 'vector' | 'bm25' | 'hybrid' } })
|
||||
}
|
||||
options={[
|
||||
{ label: t('knowledge.retriever_hybrid'), value: 'hybrid' },
|
||||
{ label: t('knowledge.retriever_vector'), value: 'vector' },
|
||||
{ label: t('knowledge.retriever_bm25'), value: 'bm25' }
|
||||
]}
|
||||
/>
|
||||
</SettingsItem>
|
||||
{newBase.retriever?.mode === 'hybrid' && (
|
||||
<SettingsItem>
|
||||
<div className="settings-label">{t('knowledge.retriever_hybrid_weight.title')}</div>
|
||||
<Slider
|
||||
style={{ width: '100%' }}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.1}
|
||||
value={newBase.retriever?.weight || 0.5}
|
||||
marks={{
|
||||
0: t('knowledge.retriever_hybrid_weight.bm25'),
|
||||
0.5: t('knowledge.retriever_hybrid_weight.recommended'),
|
||||
1: t('knowledge.retriever_hybrid_weight.vector')
|
||||
}}
|
||||
onChange={(value) =>
|
||||
setNewBase({
|
||||
...newBase,
|
||||
retriever: {
|
||||
...newBase.retriever,
|
||||
mode: 'hybrid',
|
||||
weight: value
|
||||
}
|
||||
})
|
||||
}
|
||||
/>
|
||||
</SettingsItem>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<SettingsItem>
|
||||
<div className="settings-label">
|
||||
{t('knowledge.document_count')}
|
||||
|
||||
+2
-2
@@ -25,9 +25,9 @@ const KnowledgeBaseFormModal: React.FC<KnowledgeBaseFormModalProps> = ({ panels,
|
||||
maskClosable={false}
|
||||
centered
|
||||
transitionName="animation-move-down"
|
||||
width="min(900px, 75vw)"
|
||||
width="min(900px, 65vw)"
|
||||
styles={{
|
||||
body: { padding: 0, height: 700 },
|
||||
body: { padding: 0, height: 550 },
|
||||
header: {
|
||||
padding: '10px 15px',
|
||||
borderBottom: '0.5px solid var(--color-border)',
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import { loggerService } from '@logger'
|
||||
import { nanoid } from '@reduxjs/toolkit'
|
||||
import { useKnowledge } from '@renderer/hooks/useKnowledge'
|
||||
import { useKnowledgeBaseForm } from '@renderer/hooks/useKnowledgeBaseForm'
|
||||
import { KnowledgeBase, MigrationModeEnum } from '@renderer/types'
|
||||
import { formatErrorMessage } from '@renderer/utils/error'
|
||||
import { Flex, Tag } from 'antd'
|
||||
import { FC, useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
const logger = loggerService.withContext('MigrationInfoTag')
|
||||
|
||||
const MigrationInfoTag: FC<{ base: KnowledgeBase }> = ({ base: _base }) => {
|
||||
const { t } = useTranslation()
|
||||
const { migrateBase } = useKnowledge(_base.id)
|
||||
const { newBase } = useKnowledgeBaseForm(_base)
|
||||
|
||||
// 处理嵌入模型更改迁移
|
||||
const handleMigration = useCallback(async () => {
|
||||
const migratedBase = { ...newBase, id: nanoid() }
|
||||
try {
|
||||
await migrateBase(migratedBase, MigrationModeEnum.MigrationToLangChain)
|
||||
} catch (error) {
|
||||
logger.error('KnowledgeBase migration failed:', error as Error)
|
||||
window.toast.error(t('knowledge.migrate.error.failed') + ': ' + formatErrorMessage(error))
|
||||
}
|
||||
}, [newBase, migrateBase, t])
|
||||
|
||||
const onClick = async () => {
|
||||
window.modal.confirm({
|
||||
title: t('knowledge.migrate.confirm.title'),
|
||||
content: (
|
||||
<Flex vertical align="self-start">
|
||||
<span>{t('knowledge.migrate.migrate_to_langchain.content')}</span>
|
||||
</Flex>
|
||||
),
|
||||
okText: t('knowledge.migrate.confirm.ok'),
|
||||
centered: true,
|
||||
onOk: handleMigration
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Tag
|
||||
color="blue"
|
||||
style={{
|
||||
borderRadius: 20,
|
||||
margin: 0,
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
onClick={onClick}>
|
||||
{t('knowledge.migrate.migrate_to_langchain.info')}
|
||||
</Tag>
|
||||
)
|
||||
}
|
||||
|
||||
export default MigrationInfoTag
|
||||
@@ -31,18 +31,10 @@ const QuotaTag: FC<{ base: KnowledgeBase; providerId: PreprocessProviderId; quot
|
||||
const userId = getStoreSetting('userId')
|
||||
const baseParams = getKnowledgeBaseParams(base)
|
||||
try {
|
||||
let response: number
|
||||
if (base.framework === 'langchain') {
|
||||
response = await window.api.knowledgeBase.checkQuota({
|
||||
base: baseParams,
|
||||
userId: userId as string
|
||||
})
|
||||
} else {
|
||||
response = await window.api.knowledgeBase.checkQuota({
|
||||
base: baseParams,
|
||||
userId: userId as string
|
||||
})
|
||||
}
|
||||
const response = await window.api.knowledgeBase.checkQuota({
|
||||
base: baseParams,
|
||||
userId: userId as string
|
||||
})
|
||||
setQuota(response)
|
||||
} catch (error) {
|
||||
logger.error('[KnowledgeContent] Error checking quota:', error as Error)
|
||||
|
||||
@@ -75,9 +75,7 @@ export const getKnowledgeBaseParams = (base: KnowledgeBase): KnowledgeBaseParams
|
||||
baseURL: rerankHost
|
||||
},
|
||||
documentCount: base.documentCount,
|
||||
preprocessProvider: updatedPreprocessProvider,
|
||||
framework: base.framework,
|
||||
retriever: base.retriever || { mode: 'hybrid' }
|
||||
preprocessProvider: updatedPreprocessProvider
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -244,8 +244,7 @@ class WebSearchService {
|
||||
items: [],
|
||||
created_at: Date.now(),
|
||||
updated_at: Date.now(),
|
||||
version: 1,
|
||||
framework: 'langchain'
|
||||
version: 1
|
||||
}
|
||||
|
||||
// 更新LRU cache
|
||||
|
||||
@@ -67,7 +67,7 @@ const persistedReducer = persistReducer(
|
||||
{
|
||||
key: 'cherry-studio',
|
||||
storage,
|
||||
version: 154,
|
||||
version: 155,
|
||||
blacklist: ['runtime', 'messages', 'messageBlocks', 'tabs'],
|
||||
migrate
|
||||
},
|
||||
|
||||
@@ -2376,8 +2376,8 @@ const migrateConfig = {
|
||||
'147': (state: RootState) => {
|
||||
try {
|
||||
state.knowledge.bases.forEach((base) => {
|
||||
if (!base.framework) {
|
||||
base.framework = 'embedjs'
|
||||
if ((base as any).framework) {
|
||||
delete (base as any).framework
|
||||
}
|
||||
})
|
||||
return state
|
||||
@@ -2398,8 +2398,8 @@ const migrateConfig = {
|
||||
'149': (state: RootState) => {
|
||||
try {
|
||||
state.knowledge.bases.forEach((base) => {
|
||||
if (!base.framework) {
|
||||
base.framework = 'embedjs'
|
||||
if ((base as any).framework) {
|
||||
delete (base as any).framework
|
||||
}
|
||||
})
|
||||
return state
|
||||
@@ -2463,6 +2463,19 @@ const migrateConfig = {
|
||||
logger.error('migrate 154 error', error as Error)
|
||||
return state
|
||||
}
|
||||
},
|
||||
'155': (state: RootState) => {
|
||||
try {
|
||||
state.knowledge.bases.forEach((base) => {
|
||||
if ((base as any).framework) {
|
||||
delete (base as any).framework
|
||||
}
|
||||
})
|
||||
return state
|
||||
} catch (error) {
|
||||
logger.error('migrate 155 error', error as Error)
|
||||
return state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -100,12 +100,6 @@ export interface KnowledgeBase {
|
||||
type: 'preprocess'
|
||||
provider: PreprocessProvider
|
||||
}
|
||||
framework: 'embedjs' | 'langchain'
|
||||
// default is hybrid
|
||||
retriever?: {
|
||||
mode: 'vector' | 'bm25' | 'hybrid'
|
||||
weight?: number
|
||||
}
|
||||
}
|
||||
|
||||
export type ProcessingStatus = 'pending' | 'processing' | 'completed' | 'failed'
|
||||
@@ -145,11 +139,6 @@ export type KnowledgeBaseParams = {
|
||||
type: 'preprocess'
|
||||
provider: PreprocessProvider
|
||||
}
|
||||
framework: 'embedjs' | 'langchain'
|
||||
retriever?: {
|
||||
mode: 'vector' | 'bm25' | 'hybrid'
|
||||
weight?: number
|
||||
}
|
||||
}
|
||||
|
||||
export type KnowledgeReference = {
|
||||
@@ -166,8 +155,3 @@ export interface KnowledgeSearchResult {
|
||||
score: number
|
||||
metadata: Record<string, any>
|
||||
}
|
||||
|
||||
export enum MigrationModeEnum {
|
||||
EmbeddingModelChange = 'EmbeddingModelChange',
|
||||
MigrationToLangChain = 'MigrationToLangChain'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user