mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-23 21:18:09 +00:00
feat(backend): 添加ChromaDB向量数据库支持 feat(backend): 实现智能体配置、知识库和文档管理 feat(backend): 重构WebSocket聊天服务为AgentService feat(frontend): 实现完整的聊天界面组件 feat(frontend): 添加智能体配置、知识库和文档管理页面 fix(user): 修复用户导入时性别转换问题 style(import): 优化导入组件加载状态处理
154 lines
4.4 KiB
Python
154 lines
4.4 KiB
Python
import os
|
|
from typing import Any
|
|
|
|
from langchain_chroma import Chroma
|
|
from langchain_core.documents import Document
|
|
from langchain_core.embeddings import Embeddings
|
|
|
|
from app.config.setting import settings
|
|
|
|
|
|
class DummyEmbeddings(Embeddings):
|
|
"""虚拟嵌入类,用于在没有嵌入模型时使用"""
|
|
|
|
def embed_documents(self, texts: list[str]) -> list[list[float]]:
|
|
return [[0.0] * 1536 for _ in texts]
|
|
|
|
def embed_query(self, text: str) -> list[float]:
|
|
return [0.0] * 1536
|
|
|
|
|
|
class ChromaDBManager:
|
|
"""ChromaDB 管理类 - 使用 langchain-chroma"""
|
|
|
|
_instance = None
|
|
_vectorstore = None
|
|
|
|
def __new__(cls):
|
|
if cls._instance is None:
|
|
cls._instance = super().__new__(cls)
|
|
return cls._instance
|
|
|
|
def __init__(self):
|
|
if self._vectorstore is None:
|
|
self._initialize_vectorstore()
|
|
|
|
def _initialize_vectorstore(self):
|
|
"""初始化 ChromaDB 向量存储"""
|
|
os.makedirs(settings.CHROMA_PERSIST_DIR, exist_ok=True)
|
|
self._vectorstore = Chroma(
|
|
collection_name=settings.CHROMA_COLLECTION_NAME,
|
|
persist_directory=settings.CHROMA_PERSIST_DIR,
|
|
embedding_function=DummyEmbeddings(),
|
|
)
|
|
|
|
def get_vectorstore(self) -> Chroma:
|
|
"""获取向量存储实例"""
|
|
if self._vectorstore is None:
|
|
self._initialize_vectorstore()
|
|
assert self._vectorstore is not None
|
|
return self._vectorstore
|
|
|
|
def add_documents(
|
|
self,
|
|
ids: list[str],
|
|
embeddings: list[list[float]],
|
|
documents: list[str],
|
|
metadatas: list[dict[str, Any]] | None = None,
|
|
):
|
|
"""添加文档到 ChromaDB"""
|
|
vectorstore = self.get_vectorstore()
|
|
|
|
docs = [
|
|
Document(page_content=doc, metadata=meta if meta else {})
|
|
for doc, meta in zip(documents, metadatas or [{}] * len(documents), strict=False)
|
|
]
|
|
|
|
vectorstore.add_documents(
|
|
documents=docs,
|
|
ids=ids,
|
|
embeddings=embeddings,
|
|
)
|
|
|
|
def query_documents(
|
|
self,
|
|
query_embeddings: list[list[float]],
|
|
n_results: int = 5,
|
|
where: dict[str, Any] | None = None,
|
|
where_document: dict[str, Any] | None = None,
|
|
) -> dict[str, Any]:
|
|
"""查询文档"""
|
|
vectorstore = self.get_vectorstore()
|
|
|
|
results = vectorstore.similarity_search_by_vector(
|
|
embedding=query_embeddings[0],
|
|
k=n_results,
|
|
filter=where,
|
|
)
|
|
|
|
return {
|
|
"documents": [[doc.page_content for doc in results]],
|
|
"metadatas": [[doc.metadata for doc in results]],
|
|
}
|
|
|
|
def delete_documents(
|
|
self,
|
|
ids: list[str],
|
|
):
|
|
"""删除文档"""
|
|
vectorstore = self.get_vectorstore()
|
|
vectorstore.delete(ids=ids)
|
|
|
|
def get_documents(
|
|
self,
|
|
ids: list[str] | None = None,
|
|
where: dict[str, Any] | None = None,
|
|
limit: int | None = None,
|
|
offset: int | None = None,
|
|
) -> dict[str, Any]:
|
|
"""获取文档"""
|
|
vectorstore = self.get_vectorstore()
|
|
|
|
if ids:
|
|
results = vectorstore.get_by_ids(ids)
|
|
else:
|
|
results = []
|
|
|
|
return {
|
|
"documents": [[doc.page_content for doc in results]] if results else [[]],
|
|
"metadatas": [[doc.metadata for doc in results]] if results else [[]],
|
|
}
|
|
|
|
def update_documents(
|
|
self,
|
|
ids: list[str],
|
|
embeddings: list[list[float]] | None = None,
|
|
documents: list[str] | None = None,
|
|
metadatas: list[dict[str, Any]] | None = None,
|
|
):
|
|
"""更新文档 - 通过删除旧文档再添加新文档的方式实现"""
|
|
vectorstore = self.get_vectorstore()
|
|
|
|
if documents or metadatas:
|
|
vectorstore.delete(ids=ids)
|
|
|
|
if documents:
|
|
docs = [
|
|
Document(page_content=doc, metadata=meta if meta else {})
|
|
for doc, meta in zip(documents, metadatas or [{}] * len(documents), strict=False)
|
|
]
|
|
vectorstore.add_documents(
|
|
documents=docs,
|
|
ids=ids,
|
|
embeddings=embeddings,
|
|
)
|
|
|
|
def reset(self):
|
|
"""重置 ChromaDB"""
|
|
if self._vectorstore is not None:
|
|
self._vectorstore.delete_collection()
|
|
self._vectorstore = None
|
|
|
|
|
|
chroma_manager = ChromaDBManager()
|