chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:36:28 +08:00
commit 9d3590ab86
509 changed files with 2512422 additions and 0 deletions
@@ -0,0 +1,95 @@
## FunctionDef list_kbs
**list_kbs**: 此函数的功能是获取知识库列表。
**参数**: 此函数不接受任何参数。
**代码描述**: `list_kbs` 函数是一个无参数函数,用于从数据库中获取知识库的列表。它通过调用 `list_kbs_from_db` 函数来实现这一功能。`list_kbs_from_db` 函数从数据库中查询满足特定条件的知识库名称列表,并返回这些名称。然后,`list_kbs` 函数将这些名称封装在 `ListResponse` 类的实例中返回。`ListResponse` 类是专门用于封装列表数据响应的类,它继承自 `BaseResponse` 类,能够提供状态码、状态消息以及数据列表。这样的设计使得 API 的响应格式保持一致,便于前端开发者理解和使用。
**注意**:
- `list_kbs` 函数依赖于 `list_kbs_from_db` 函数正确地从数据库中获取知识库名称列表。因此,确保数据库连接和查询逻辑正确是使用此函数的前提。
- 返回的 `ListResponse` 实例中包含的数据列表应正确反映数据库中的知识库情况。这要求 `list_kbs_from_db` 函数能准确地执行其查询逻辑。
- 在实际部署和使用时,应注意数据库的性能和响应时间,尤其是在知识库数量较多的情况下,以保证良好的用户体验。
**输出示例**:
假设数据库中存在三个知识库,名称分别为 "知识库A", "知识库B", "知识库C",则函数可能返回的 `ListResponse` 实例如下所示:
```
{
"code": 200,
"msg": "success",
"data": ["知识库A", "知识库B", "知识库C"]
}
```
这表示 API 调用成功,且返回了包含三个知识库名称的列表。
## FunctionDef create_kb(knowledge_base_name, vector_store_type, embed_model)
**create_kb**: 此函数用于创建一个新的知识库。
**参数**:
- `knowledge_base_name`: 知识库的名称,类型为字符串。通过示例参数可以提供默认示例值。
- `vector_store_type`: 向量存储类型,类型为字符串,默认值为"faiss"。
- `embed_model`: 嵌入模型的名称,类型为字符串,默认使用项目配置的嵌入模型。
**代码描述**:
此函数首先通过调用`validate_kb_name`函数验证知识库名称的合法性。如果名称不合法或为空,则分别返回403和404状态码的`BaseResponse`对象,提示错误信息。接下来,使用`KBServiceFactory.get_service_by_name`方法检查是否已存在同名的知识库,如果存在,则返回404状态码的`BaseResponse`对象,提示知识库已存在。如果验证通过,函数将通过`KBServiceFactory.get_service`方法获取对应的知识库服务实例,并调用该实例的`create_kb`方法创建知识库。如果在创建过程中发生异常,将记录错误信息并返回500状态码的`BaseResponse`对象。成功创建知识库后,返回200状态码的`BaseResponse`对象,提示已新增知识库。
**注意**:
- 在调用此函数创建知识库之前,需要确保知识库名称不为空且不包含非法字符,以避免安全风险。
- 向量存储类型和嵌入模型应根据项目需求和配置进行选择,以确保知识库的正确创建和后续操作的有效性。
- 在处理异常时,应注意记录详细的错误信息,以便于问题的定位和解决。
**输出示例**:
如果成功创建名为"技术文档库"的知识库,函数将返回以下`BaseResponse`对象:
```
{
"code": 200,
"msg": "已新增知识库 技术文档库"
}
```
如果尝试创建一个已存在的知识库,例如名为"技术文档库",函数将返回:
```
{
"code": 404,
"msg": "已存在同名知识库 技术文档库"
}
```
如果知识库名称不合法,将返回:
```
{
"code": 403,
"msg": "Don't attack me"
}
```
## FunctionDef delete_kb(knowledge_base_name)
**delete_kb**: 此函数的功能是删除指定的知识库。
**参数**:
- `knowledge_base_name`: 字符串类型,表示要删除的知识库的名称。此参数通过请求体传入,且提供了示例值 "samples"。
**代码描述**:
`delete_kb` 函数首先验证知识库名称的合法性。如果名称不合法,即不通过 `validate_kb_name` 函数的验证,将返回一个状态码为403的 `BaseResponse` 对象,消息内容为 "Don't attack me",表示请求被拒绝。接着,函数对知识库名称进行URL解码,以确保名称的正确性。
通过 `KBServiceFactory.get_service_by_name` 方法,根据知识库名称获取对应的知识库服务实例。如果实例为 `None`,即知识库不存在,将返回一个状态码为404的 `BaseResponse` 对象,消息内容为 "未找到知识库 {knowledge_base_name}"。
若知识库服务实例获取成功,函数尝试调用知识库服务实例的 `clear_vs` 方法来清除知识库中的向量数据,然后调用 `drop_kb` 方法删除知识库。如果删除操作成功,将返回一个状态码为200的 `BaseResponse` 对象,消息内容为 "成功删除知识库 {knowledge_base_name}"。
如果在删除过程中发生异常,将捕获异常并记录错误日志,然后返回一个状态码为500的 `BaseResponse` 对象,消息内容为 "删除知识库时出现意外: {e}",其中 `{e}` 是异常信息。
**注意**:
- 在调用此函数之前,确保传入的知识库名称是经过URL编码的。
- 此函数依赖于 `validate_kb_name` 函数来验证知识库名称的合法性,以防止潜在的安全风险。
- 删除知识库是一个不可逆的操作,一旦执行,知识库中的所有数据将被永久删除。
**输出示例**:
如果尝试删除一个不存在的知识库 "unknown_kb",函数可能返回的 `BaseResponse` 对象如下:
```
{
"code": 404,
"msg": "未找到知识库 unknown_kb"
}
```
如果成功删除名为 "samples" 的知识库,函数可能返回的 `BaseResponse` 对象如下:
```
{
"code": 200,
"msg": "成功删除知识库 samples"
}
```
@@ -0,0 +1,374 @@
## ClassDef ThreadSafeObject
**ThreadSafeObject**: ThreadSafeObject 类的功能是提供一个线程安全的对象封装,用于在多线程环境中安全地访问和修改对象。
**属性**:
- `_obj`: 存储实际对象的属性,可以是任何类型。
- `_key`: 对象的键,用于标识对象,可以是字符串或元组。
- `_pool`: 对象所属的缓存池,类型为 `CachePool`,默认为 None。
- `_lock`: 一个重入锁(`threading.RLock`),用于确保线程安全。
- `_loaded`: 一个事件(`threading.Event`),用于控制对象加载状态。
**代码描述**:
ThreadSafeObject 类通过封装对象、键、所属缓存池以及同步机制(重入锁和事件),提供了一个线程安全的方式来访问和修改对象。通过 `acquire` 方法,可以安全地获取对象的引用,进行操作,并在操作完成后自动释放锁。此外,`start_loading``finish_loading` 方法允许控制对象的加载状态,而 `wait_for_loading` 方法可以阻塞当前线程,直到对象加载完成。
在项目中,ThreadSafeObject 类与 CachePool 类紧密相关,后者负责管理缓存中的 ThreadSafeObject 实例。例如,CachePool 的 `get` 方法在返回缓存对象之前会调用 `wait_for_loading` 方法,确保对象已经加载完成。`set``pop` 方法则用于向缓存中添加或移除 ThreadSafeObject 实例。此外,`acquire` 方法提供了一种机制,允许在执行操作前安全地获取对象的引用。
ThreadSafeObject 类还被用作其他特定类型对象的基类,例如 ThreadSafeFaiss 类,后者在 ThreadSafeObject 的基础上增加了与 FAISS 相关的功能,如文档计数和保存到磁盘等。
**注意**:
- 在多线程环境中操作共享资源时,使用 ThreadSafeObject 可以避免数据竞争和其他并发问题。
- 使用 `acquire` 方法时,应确保使用 `with` 语句或手动释放锁,以避免死锁。
- 修改 `_obj` 属性时,应通过 `obj` 属性的 setter 方法,以确保线程安全。
**输出示例**:
假设有一个 ThreadSafeObject 实例,其 `_key` 为 "example_key"`_obj` 为某个自定义对象。调用 `__repr__` 方法可能会返回如下字符串:
`"<ThreadSafeObject: key: example_key, obj: <自定义对象的表示>>"`
### FunctionDef __init__(self, key, obj, pool)
**__init__**: 该函数用于初始化ThreadSafeObject对象。
**参数**:
- `key`: 可以是字符串或元组,用于标识对象。
- `obj`: 初始化时分配给ThreadSafeObject的对象,默认为None。
- `pool`: 一个CachePool实例,用于存储缓存对象,默认为None。
**代码描述**:
这个`__init__`方法是`ThreadSafeObject`类的构造函数,负责初始化一个线程安全的对象。它接收三个参数:`key``obj``pool``key`是一个标识符,可以是字符串或元组,用于唯一标识这个对象。`obj`参数是任意类型,代表需要被线程安全访问的数据对象,默认值为None。`pool`参数是一个`CachePool`类型的实例,它是一个可选参数,默认值为None,用于指定这个对象所属的缓存池。
在对象初始化过程中,首先将传入的`obj``key``pool`参数分别赋值给内部变量`_obj``_key``_pool`。接着,使用`threading.RLock()`创建一个可重入锁(Reentrant Lock),并将其赋值给`_lock`属性,这样可以确保对象的线程安全访问。最后,创建一个`threading.Event()`实例赋值给`_loaded`属性,这个事件对象用于控制对象加载状态的同步。
**注意**:
- 在多线程环境下操作同一个`ThreadSafeObject`实例时,应确保正确使用`_lock`来避免数据竞争。
- `key`参数是必须的,因为它用于唯一标识一个`ThreadSafeObject`实例。
- 如果提供了`pool`参数,那么这个`ThreadSafeObject`实例将与指定的缓存池相关联,这在管理多个缓存对象时非常有用。
***
### FunctionDef __repr__(self)
**__repr__**: 此函数的功能是返回对象的官方字符串表示。
**参数**: 此函数没有参数。
**代码描述**: `__repr__` 方法是一个特殊的方法,用于定义对象的“官方”字符串表示。在这个实现中,首先通过 `type(self).__name__` 获取对象的类名,然后结合对象的 `key` 属性和 `_obj` 属性构造并返回一个格式化的字符串。这个字符串以 `<类名: key: 键值, obj: 对象值>` 的格式展示,其中 `键值` 是通过调用对象的 `key` 方法获取的,而 `对象值` 直接访问的是对象的 `_obj` 属性。这种表示方式不仅提供了对象的基本信息,还包括了对象的关键数据,使得调试和日志记录更为方便。
从项目的结构来看,`__repr__` 方法与 `key` 方法有直接的调用关系。`key` 方法用于获取对象的键值,这是对象在缓存或其他数据结构中的唯一标识符。在 `__repr__` 方法中,通过调用 `key` 方法可以获取到这个键值,并将其包含在对象的字符串表示中。这样做有助于在日志记录或调试时快速识别对象。
**注意**: 在使用 `__repr__` 方法时,需要确保对象的 `_key``_obj` 属性已经被正确初始化,否则可能会导致错误。此外,考虑到 `__repr__` 方法的输出可能会被用于日志记录,应确保包含的信息既有用又不过于冗长。
**输出示例**: 假设对象的类名为 `ThreadSafeObject``_key` 属性的值为 `"example_key"``_obj` 属性的值为 `"example_object"`,那么调用 `__repr__` 方法将返回:
```
<ThreadSafeObject: key: example_key, obj: example_object>
```
***
### FunctionDef key(self)
**key**: 此函数的功能是获取对象的键值。
**参数**: 此函数没有参数。
**代码描述**: `key` 函数是一个简单但关键的部分,用于访问和返回对象的 `_key` 属性。这个属性通常代表了对象在缓存或其他数据结构中的唯一标识符。在多线程环境下,访问和管理这些键值是确保数据一致性和线程安全的重要机制。
从项目中的调用情况来看,`key` 函数被多个地方调用,显示其在对象表示(`__repr__` 方法)、资源获取(`acquire` 方法)、以及特定操作如保存和清空缓存(`save``clear` 方法)中的重要性。例如,在 `__repr__` 方法中,通过调用 `key` 函数来获取对象的键值,以构建并返回对象的字符串表示,这有助于调试和日志记录。在 `acquire` 方法中,`key` 函数的返回值用于日志记录,帮助追踪哪个线程正在操作哪个资源。在 `save``clear` 方法中,`key` 同样用于日志记录,提供操作的上下文信息。
**注意**: 使用此函数时,需要确保 `_key` 属性已经被正确初始化,否则可能会引发错误。此外,考虑到线程安全,访问 `_key` 属性时应当小心处理同步问题,尽管在此函数的实现中看似简单,但在多线程环境下使用时应当保持警惕。
**输出示例**: 假设 `_key` 属性的值为 `"example_key"`,那么调用 `key` 函数将返回:
```
"example_key"
```
***
### FunctionDef acquire(self, owner, msg)
**acquire**: 此函数的功能是安全地获取并操作对象资源。
**参数**:
- `owner`: 字符串类型,默认为空字符串,表示资源的拥有者。如果未提供,则默认使用当前线程的ID。
- `msg`: 字符串类型,默认为空字符串,用于附加额外的日志信息。
**代码描述**:
`acquire` 函数是一个上下文管理器,用于在多线程环境中安全地获取和释放资源。它首先尝试获取一个锁,以确保在操作对象资源时的线程安全。如果提供了`owner`参数,则使用该参数值作为资源的拥有者;如果未提供,则默认使用当前线程的ID作为拥有者。此外,如果存在`_pool`属性且不为`None`,则会调用`_pool._cache.move_to_end(self.key)`方法,将当前对象的键值移动到缓存的末尾,这通常用于维护缓存的LRU(最近最少使用)策略。
在成功获取锁并进行资源操作的前后,如果`log_verbose`为真,则会记录日志信息,包括操作的开始和结束,以及提供的`msg`信息。这有助于追踪资源的使用情况和调试。
`finally`块中,无论资源操作是否成功,都会释放之前获取的锁,确保资源的安全释放,避免死锁的发生。
**注意**:
- 使用`acquire`函数时,需要确保`_lock`属性已经被正确初始化为一个锁对象,否则在尝试获取锁时会引发异常。
- 在多线程环境下操作共享资源时,正确使用锁是非常重要的,以避免数据竞争和不一致的问题。
- `acquire`函数设计为一个上下文管理器,推荐使用`with`语句进行调用,以确保资源的正确获取和释放。
***
### FunctionDef start_loading(self)
**start_loading**: 此函数的功能是清除加载状态。
**参数**: 此函数没有参数。
**代码描述**: `start_loading` 函数是 `ThreadSafeObject` 类的一个方法,用于重置对象的加载状态。在这个方法中,通过调用 `self._loaded.clear()` 实现了这一功能。`_loaded` 是一个标志,用于指示对象的数据是否已经被加载。调用 `clear` 方法将这个标志重置,意味着对象的加载状态被清除,对象被视为未加载状态。这通常是为了在数据需要重新加载时准备对象,确保数据的最新状态可以被重新加载和使用。
**注意**: 使用 `start_loading` 方法时,需要确保任何依赖于对象加载状态的操作都能正确处理对象的未加载状态。此外,考虑到这是一个线程安全的对象,`start_loading` 方法的调用应该在适当的同步机制下进行,以避免并发访问导致的问题。
***
### FunctionDef finish_loading(self)
**finish_loading**: 此函数的功能是标记对象加载完成。
**参数**: 此函数没有参数。
**代码描述**: `finish_loading` 函数是`ThreadSafeObject`类的一个方法,用于在对象的加载或初始化过程完成后,通过设置一个内部的线程安全标志(例如,使用`threading.Event``set`方法),来通知其他可能在等待此对象加载完成的线程。在本项目中,`finish_loading`方法被多个地方调用,主要用于标记嵌入模型(Embeddings)或向量存储(Vector Store)加载完成的状态。
`load_embeddings`方法中,`finish_loading`被调用来标记一个嵌入模型对象加载完成。这个过程包括选择合适的嵌入模型,加载模型,并将模型对象赋值给`ThreadSafeObject`实例的`obj`属性,最后通过调用`finish_loading`方法来标记加载过程完成。
`load_vector_store`方法中,无论是在`KBFaissPool`还是`MemoFaissPool`类中,`finish_loading`同样被用于标记向量存储加载完成。加载向量存储的过程可能包括从磁盘加载现有的向量存储,或者创建一个新的空向量存储,然后将这个向量存储对象赋值给`ThreadSafeFaiss`实例的`obj`属性,并通过`finish_loading`方法来标记加载完成。
**注意**: 使用`finish_loading`方法时,需要确保在对象的加载或初始化逻辑正确完成后调用此方法。此外,调用此方法前,通常会有线程锁的操作,以确保线程安全。在调用`finish_loading`之后,其他线程可以通过检查相应的线程安全标志来确定对象是否已经加载完成,从而进行后续操作。
***
### FunctionDef wait_for_loading(self)
**wait_for_loading**: 此函数的功能是等待直到对象加载完成。
**参数**: 此函数没有参数。
**代码描述**: `wait_for_loading` 函数是 `ThreadSafeObject` 类的一个方法,用于在多线程环境中确保对象安全地完成加载。该方法通过调用 `_loaded` 属性(一个线程安全的事件对象)的 `wait` 方法来实现。当 `_loaded` 事件被设置时,表示对象已经完成加载,此时 `wait` 方法将停止阻塞,允许执行后续代码。如果 `_loaded` 事件尚未被设置,调用此方法的线程将被阻塞,直到事件被设置。这种机制确保了在对象未完全加载前,任何依赖于对象状态的操作都将被暂停,从而避免了潜在的数据不一致或竞态条件问题。
**注意**: 使用 `wait_for_loading` 方法时,需要确保 `_loaded` 事件在对象加载完成后被正确设置,否则调用此方法的线程可能会无限期地阻塞。此外,考虑到多线程编程的复杂性,开发者应当仔细管理线程间的同步和通信,以避免死锁或资源竞争等问题。
***
### FunctionDef obj(self)
**obj**: 此函数的功能是获取ThreadSafeObject对象中的_obj属性。
**参数**: 此函数没有参数。
**代码描述**: `obj`函数是一个简单的访问器(accessor),用于返回ThreadSafeObject实例中的`_obj`属性。在多线程环境下,ThreadSafeObject对象提供了线程安全的访问方式,确保在并发访问时,对象的状态保持一致性。在项目中,`obj`函数被用于多个场景,主要是在加载嵌入向量(embeddings)和向量存储(vector store)时,获取已经加载或创建的对象实例。
例如,在`load_embeddings`方法中,首先检查是否已经加载了指定模型和设备的嵌入向量,如果没有,则创建一个新的ThreadSafeObject实例,并通过`obj`函数设置嵌入向量对象。在`load_vector_store`方法中,同样的逻辑被应用于加载或创建向量存储实例。这种使用方式确保了在并发环境下,对嵌入向量和向量存储的访问是线程安全的。
**注意**: 在使用`obj`函数时,需要确保ThreadSafeObject实例的`_obj`属性已经被正确初始化。否则,返回的将是`None`或者是初始状态的对象,这可能会导致后续操作中出现错误。
**输出示例**: 假设ThreadSafeObject实例的`_obj`属性被设置为了一个嵌入向量对象,那么调用`obj`函数将返回这个嵌入向量对象。例如:
```python
embeddings = thread_safe_object_instance.obj()
```
这里,`embeddings`将是之前存储在ThreadSafeObject实例中的嵌入向量对象。
***
### FunctionDef obj(self, val)
**obj**: obj函数用于设置ThreadSafeObject实例的内部对象。
**参数**:
- `val`: 任意类型,表示要设置的值。
**代码描述**:
obj函数是ThreadSafeObject类的一个成员方法,其主要功能是将传入的参数`val`赋值给实例的`_obj`属性。这个方法是线程安全对象操作的基础,允许在多线程环境中安全地修改对象的状态。
在项目中,obj函数被用于不同的上下文中,主要涉及到加载和设置嵌入式对象或向量存储。例如,在`EmbeddingsPool``load_embeddings`方法中,obj函数用于将加载的嵌入式模型对象赋值给ThreadSafeObject实例。这样做可以确保在并发访问时,嵌入式模型对象的加载和访问是线程安全的。
同样,在`KBFaissPool``MemoFaissPool``load_vector_store`方法中,obj函数被用于设置加载或创建的向量存储对象。这些方法首先检查缓存中是否已存在所需的向量存储,如果不存在,则创建一个新的ThreadSafeFaiss实例,并通过obj函数将向量存储对象赋值给它。这确保了向量存储的加载和初始化过程是线程安全的。
**注意**:
- 使用obj函数时,需要确保传入的`val`参数是正确的类型,因为函数内部不进行类型检查。
- 在多线程环境中使用obj函数修改对象状态时,应注意同步和并发控制,以避免数据竞争和不一致性问题。虽然obj函数本身的操作是简单的赋值,但它在项目中的应用场景通常涉及到线程安全的上下文,因此正确的使用方式对于保持程序的稳定性和正确性至关重要。
***
## ClassDef CachePool
**CachePool**: CachePool 类的功能是提供一个线程安全的缓存池,用于存储和管理缓存对象。
**属性**:
- `_cache_num`: 缓存池中允许存储的最大缓存对象数量。如果设置为-1,则不限制数量。
- `_cache`: 一个有序字典,用于存储缓存对象。
- `atomic`: 一个线程锁,确保缓存操作的线程安全。
**代码描述**:
CachePool 类提供了一个线程安全的缓存池实现,允许用户存储、获取和管理缓存对象。它使用了一个有序字典 `_cache` 来存储缓存对象,其中键是缓存对象的标识符,值是缓存对象本身。通过 `atomic` 线程锁确保了对缓存操作的线程安全性。
- `__init__` 方法初始化缓存池,可以指定缓存池中允许的最大缓存对象数量。
- `keys` 方法返回当前缓存中所有键的列表。
- `_check_count` 方法检查当前缓存的数量,如果超过了设定的最大值,则移除最早添加的缓存对象。
- `get` 方法根据键获取缓存对象。如果对象存在,则等待对象加载完成后返回。
- `set` 方法将一个对象添加到缓存中,并根据需要移除最早的缓存对象以保持在最大数量限制内。
- `pop` 方法可以移除并返回指定键的缓存对象。如果没有指定键,则移除并返回最早添加的缓存对象。
- `acquire` 方法尝试获取指定键的缓存对象,并对其进行加锁处理,确保在并发环境下的数据一致性。
- `load_kb_embeddings` 方法用于加载知识库嵌入向量,它根据知识库名称、嵌入设备和默认嵌入模型加载嵌入向量。
CachePool 类在项目中被其他对象如 `EmbeddingsPool``_FaissPool` 调用,用于管理嵌入向量和向量存储的缓存。这些调用情况表明 CachePool 类在知识库嵌入向量和向量存储管理中起到了核心作用,为上层提供了缓存管理和线程安全的支持。
**注意**:
- 在多线程环境下操作缓存时,应确保正确使用 `atomic` 锁来避免数据竞争。
- 当设置 `_cache_num` 限制缓存数量时,需要注意缓存淘汰策略可能会影响到缓存对象的可用性。
**输出示例**:
由于 CachePool 主要提供缓存管理功能,其输出依赖于存储在缓存中的对象类型。例如,如果缓存中存储的是嵌入向量对象,那么 `get` 方法可能返回一个嵌入向量对象的实例。
### FunctionDef __init__(self, cache_num)
**__init__**: 此函数的功能是初始化CachePool对象。
**参数**:
- `cache_num`: 整型,表示缓存中允许的最大元素数量,默认值为-1,表示不限制数量。
- `self._cache`: 使用`OrderedDict`初始化,用于存储缓存数据,保持插入顺序。
- `self.atomic`: 使用`threading.RLock`初始化,提供一个基于线程的锁,用于控制对缓存数据的并发访问,确保线程安全。
**代码描述**:
此函数是`CachePool`类的构造函数,用于初始化一个缓存池对象。它接受一个参数`cache_num`,该参数指定了缓存中可以存储的最大元素数量。如果`cache_num`的值为-1,则表示缓存大小不受限制。函数内部首先将`cache_num`参数的值赋给对象的`_cache_num`属性,用于后续控制缓存大小。接着,使用`OrderedDict`初始化`_cache`属性,`OrderedDict`是一种特殊的字典,它可以记住元素被插入的顺序,这对于某些缓存淘汰策略(如最近最少使用LRU)是非常有用的。最后,通过`threading.RLock`创建一个可重入锁`atomic`,赋给对象的`atomic`属性。这个锁用于同步对缓存的访问,确保在多线程环境下对缓存的操作是线程安全的。
**注意**:
- 在多线程环境下操作缓存时,应确保正确使用`self.atomic`锁,以避免数据竞争和不一致的问题。
- `cache_num`的默认值为-1,意味着如果不特别指定,缓存大小不会受到限制。在实际应用中,根据需要合理设置此参数,以避免因缓存过大而消耗过多内存资源。
- `OrderedDict`虽然可以保持元素的插入顺序,但在处理大量数据时可能会比普通字典有更高的性能开销,因此在设计缓存策略时应考虑到这一点。
***
### FunctionDef keys(self)
**keys**: 此函数的作用是获取缓存中所有键的列表。
**参数**: 此函数没有参数。
**代码描述**: `keys` 函数是 `CachePool` 类的一个方法,它的主要作用是从缓存中检索所有的键,并将这些键作为字符串列表返回。在这个函数中,`self._cache.keys()` 调用会获取 `_cache` 字典中所有的键,然后通过 `list()` 函数将这些键转换成列表形式。这是一个非常基础但重要的功能,因为它允许其他部分的代码了解缓存中目前存储了哪些数据的键。
在项目中,这个函数被 `file_chat` 函数调用,以检查传入的 `knowledge_id` 是否存在于 `memo_faiss_pool` 缓存中。如果 `knowledge_id` 不在缓存的键中,`file_chat` 函数将返回一个错误响应,指出需要的临时知识库未找到。这表明 `keys` 函数在项目中用于验证和检索操作,确保在进行进一步处理之前,所需的数据已经被正确地存储在缓存中。
**注意**: 使用此函数时,需要确保 `_cache` 已经被正确初始化并且包含了所需的数据。此外,返回的键列表仅代表了函数被调用时刻缓存中的状态,缓存内容的后续更新不会反映在已返回的列表中。
**输出示例**: 假设缓存中存储了三个键,分别为 `"key1"`, `"key2"`, `"key3"`,那么调用 `keys` 函数将返回以下列表:
```python
["key1", "key2", "key3"]
```
***
### FunctionDef _check_count(self)
**_check_count**: 此函数的功能是检查缓存中的项目数量,并确保其不超过设定的最大值。
**参数**: 此函数没有参数。
**代码描述**: `_check_count` 函数是 `CachePool` 类的一个私有方法,用于维护缓存池中的项目数量不超过一个预设的最大值。这个函数首先检查成员变量 `_cache_num` 是否为整数且大于0。如果是,函数进入一个循环,循环的条件是缓存池 `_cache` 的长度大于 `_cache_num`。在循环内部,使用 `_cache.popitem(last=False)` 从缓存中移除最早添加的项目,直到缓存的大小不超过 `_cache_num`。这种机制确保了缓存池不会无限增长,从而有效管理内存使用。
在项目中,`_check_count``set` 方法调用。`set` 方法用于向缓存中添加一个新的项目,并在添加后立即调用 `_check_count` 来确保缓存池的大小不会超过预设的限制。这表明 `_check_count` 在缓存管理策略中起到了关键的作用,它通过限制缓存大小来防止内存溢出,确保了缓存系统的健壮性和稳定性。
**注意**: `_check_count` 是一个私有方法,意味着它仅在 `CachePool` 类内部使用,不应该被类外部直接调用。这种设计封装了缓存管理的细节,使得 `CachePool` 类的使用更加安全和方便。在使用 `CachePool` 类时,开发者无需直接管理缓存大小,而是通过设置 `_cache_num` 并使用 `set` 方法来间接控制。
***
### FunctionDef get(self, key)
**get**: 此函数的功能是从缓存池中获取与给定键关联的线程安全对象。
**参数**:
- `key`: 字符串类型,用于从缓存中检索对象的键。
**代码描述**:
`get` 函数首先尝试从缓存池 `_cache` 中使用给定的键 `key` 来获取一个对象。如果找到了对应的对象,该函数会调用该对象的 `wait_for_loading` 方法。这个方法的作用是阻塞当前线程,直到对象的加载状态被设置为完成。这确保了在返回对象之前,对象已经处于可用状态。如果缓存中没有找到对应的键,函数将不会返回任何值。
在项目中,`get` 函数被多个地方调用,包括但不限于加载嵌入向量、保存和卸载向量存储、以及在工作线程中操作向量存储。这些调用场景表明,`get` 函数是处理缓存对象的关键组件,特别是在需要确保对象加载完成后再进行操作的情况下。
**注意**:
- 使用 `get` 函数时,应确保提供的键 `key` 在缓存中确实存在,否则函数将返回 `None`
- 在多线程环境下,`get` 函数通过 `wait_for_loading` 方法确保了线程安全,避免了在对象加载完成前的竞态条件。
**输出示例**:
假设缓存中存在一个键为 `"example_key"``ThreadSafeObject` 实例,且该实例已完成加载。调用 `get("example_key")` 将返回该 `ThreadSafeObject` 实例。如果 `"example_key"` 不存在于缓存中,函数将返回 `None`
***
### FunctionDef set(self, key, obj)
**set**: 此函数的功能是将一个线程安全的对象添加到缓存池中,并返回该对象。
**参数**:
- `key`: 字符串类型,用于标识缓存中的对象。
- `obj`: `ThreadSafeObject` 类型,表示要添加到缓存中的线程安全对象。
**代码描述**: `set` 函数首先将传入的线程安全对象 `obj` 与其对应的键 `key` 存储在缓存池的内部字典 `_cache` 中。这一操作确保了对象可以通过键值快速检索。随后,函数调用 `_check_count` 方法来检查缓存池中的对象数量是否超过了预设的最大值,如果超过了,将自动移除最早添加的对象以保持缓存池的大小在限制之内。最后,函数返回刚刚添加的线程安全对象 `obj`
在项目中,`set` 函数被用于多个场景,包括但不限于加载嵌入向量(`load_embeddings`)、加载向量存储(`load_vector_store`)等。这些场景中,`set` 函数负责将新创建或加载的资源(如嵌入向量、向量存储)以线程安全的方式添加到缓存池中,确保后续可以高效、安全地访问这些资源。
**注意**:
- 使用 `set` 函数时,需要确保传入的键 `key` 在缓存池中唯一,以避免覆盖已有的缓存项。
- 由于 `set` 函数会检查缓存池的大小并在必要时移除最早的缓存项,开发者应当合理设置缓存池的最大容量 `_cache_num`,以平衡内存使用和性能需求。
- 在多线程环境下,`set` 函数保证了添加缓存项的线程安全性,但在使用缓存项时,仍需注意线程安全的访问和操作。
**输出示例**: 假设调用 `set` 函数添加了一个键为 `"example_key"`,对象为某个 `ThreadSafeObject` 实例的缓存项,函数将返回这个 `ThreadSafeObject` 实例。
***
### FunctionDef pop(self, key)
**pop**: 该函数用于从缓存池中移除并返回指定键的对象或最早添加的对象。
**参数**:
- `key`: 字符串类型,指定要移除对象的键。默认为 None,表示移除并返回最早添加的对象。
**代码描述**:
`pop` 函数是 `CachePool` 类的一个方法,用于根据给定的键从缓存中移除并返回相应的对象。如果调用时没有提供键(即 `key=None`),则函数会移除并返回缓存中最早被添加的对象。这是通过调用 `_cache` 字典的 `popitem` 方法实现的,其中 `last=False` 参数确保返回最早添加的项。如果提供了键,则通过 `_cache` 字典的 `pop` 方法尝试移除并返回与该键关联的对象。如果键不存在,则返回 `None`
在项目中,`pop` 方法被多个场景调用,例如在 `upload_temp_docs` 函数中,用于移除之前的临时文档;在 `unload_vector_store` 方法中,用于释放向量库;在 `do_clear_vs` 方法中,用于清除特定的向量存储;以及在 `drop_kb_summary` 方法中,用于删除知识库摘要。这些调用场景表明 `pop` 方法在管理缓存资源、维护缓存状态和释放不再需要的资源方面起着关键作用。
**注意**:
- 在使用 `pop` 方法时,应确保键的正确性和存在性,特别是在期望移除特定对象时。如果键不存在,方法将返回 `None`,而不是抛出异常。
- 当不需要指定键移除对象时,应注意 `pop` 方法将移除并返回最早添加的对象,这可能会影响缓存的使用逻辑。
**输出示例**:
假设缓存中存在键为 "example_key" 的 `ThreadSafeObject` 对象,调用 `pop("example_key")` 将返回该对象,并从缓存中移除。如果缓存为空或键不存在,调用 `pop("nonexistent_key")` 将返回 `None`
***
### FunctionDef acquire(self, key, owner, msg)
**acquire**: 此函数的功能是从缓存池中安全地获取与给定键关联的对象。
**参数**:
- `key`: 字符串或元组类型,用于从缓存中检索对象的键。
- `owner`: 字符串类型,默认为空字符串,表示请求对象的所有者。
- `msg`: 字符串类型,默认为空字符串,用于附加消息或说明。
**代码描述**:
`acquire` 函数首先通过调用 `get` 方法尝试从缓存池中获取与给定键 `key` 关联的对象。如果缓存中不存在该键对应的对象,函数将抛出 `RuntimeError` 异常,提示请求的资源不存在。如果成功获取到对象,并且该对象是 `ThreadSafeObject` 类型的实例,则会调用该对象的 `acquire` 方法来安全地获取对象的引用,并将其返回。这一过程涉及到线程安全的处理,确保在多线程环境下对对象的访问是安全的。如果获取到的对象不是 `ThreadSafeObject` 类型的实例,则直接返回该对象。
在项目中,`acquire` 函数被用于安全地获取缓存中的对象,以进行后续操作。例如,在 `knowledge_base_chat_iterator` 函数中,通过调用 `acquire` 方法来获取知识库中的向量存储对象,以执行相似度搜索等操作。
**注意**:
- 在使用 `acquire` 函数时,应确保提供的键 `key` 在缓存中确实存在,否则会抛出异常。
- 当获取到的对象是 `ThreadSafeObject` 类型的实例时,应通过 `with` 语句或其他方式确保在操作完成后释放锁,以避免潜在的死锁问题。
- `acquire` 方法的使用场景主要集中在需要线程安全访问和操作缓存对象的情况。
**输出示例**:
由于 `acquire` 函数的返回值取决于缓存中对象的类型,因此可能有不同的返回形式。如果缓存中的对象是 `ThreadSafeObject` 类型的实例,则返回值将是该对象的引用;如果是其他类型的对象,则直接返回该对象。例如,如果缓存中存在键为 `"example_key"``ThreadSafeObject` 实例,调用 `acquire("example_key")` 将返回该实例的引用。如果 `"example_key"` 对应的是非 `ThreadSafeObject` 类型的对象,则直接返回该对象。
***
### FunctionDef load_kb_embeddings(self, kb_name, embed_device, default_embed_model)
**load_kb_embeddings**: 此函数的功能是加载指定知识库名称的嵌入向量。
**参数**:
- `kb_name`: 字符串类型,指定要加载嵌入向量的知识库名称。
- `embed_device`: 字符串类型,默认值由`embedding_device`函数确定,用于指定计算设备。
- `default_embed_model`: 字符串类型,默认值为`EMBEDDING_MODEL`,用于指定默认的嵌入模型。
**代码描述**:
此函数首先从`knowledge_base_repository`中调用`get_kb_detail`函数,根据`kb_name`获取知识库的详细信息,包括嵌入模型名称。如果知识库详情中包含嵌入模型名称,则使用该名称;否则,使用传入的`default_embed_model`作为嵌入模型名称。接着,函数检查该嵌入模型是否在在线模型列表中,该列表由`list_online_embed_models`函数提供。如果嵌入模型存在于在线模型列表中,则通过`EmbeddingsFunAdapter`类创建一个嵌入向量适配器实例并返回。如果嵌入模型不在在线模型列表中,则调用`embeddings_pool``load_embeddings`方法,根据模型名称和设备类型加载嵌入向量,并返回加载的嵌入向量实例。
**注意**:
- 在调用此函数时,需要确保传入的`kb_name`是存在的知识库名称,且知识库中有对应的嵌入模型信息。
- `embed_device`参数应根据实际计算环境选择合适的设备类型,如`"cuda"``"mps"``"cpu"`
- 此函数依赖于`EmbeddingsFunAdapter`类和`embeddings_pool``load_embeddings`方法,因此在使用前应确保相关依赖正确配置。
**输出示例**:
假设知识库名称为"技术文档库",且该知识库使用的嵌入模型在在线模型列表中,则可能返回一个`EmbeddingsFunAdapter`实例。如果嵌入模型不在在线模型列表中,则可能返回由`load_embeddings`方法加载的嵌入向量实例,具体类型取决于加载的嵌入模型。
***
## ClassDef EmbeddingsPool
**EmbeddingsPool**: EmbeddingsPool 类的功能是管理和加载不同模型的嵌入向量。
**属性**:
- 无特定公开属性,继承自 CachePool 类的属性。
**代码描述**:
EmbeddingsPool 类继承自 CachePool 类,专门用于加载和管理嵌入向量。它提供了一个 `load_embeddings` 方法,该方法负责根据指定的模型和设备加载嵌入向量。方法首先尝试从缓存中获取嵌入向量,如果缓存中不存在,则根据模型类型创建相应的嵌入向量对象,并将其添加到缓存中。
在加载嵌入向量时,根据模型的不同,EmbeddingsPool 类会调用不同的嵌入向量类。例如,对于 OpenAI 的 "text-embedding-ada-002" 模型,它会使用 `OpenAIEmbeddings` 类;对于包含 "bge-" 的模型,它会根据模型语言选择 `HuggingFaceBgeEmbeddings` 类,并设置相应的查询指令;对于其他模型,它默认使用 `HuggingFaceEmbeddings` 类。
此外,`load_embeddings` 方法在加载嵌入向量之前会通过 `atomic` 锁确保线程安全,避免在并发环境下的数据竞争问题。加载完成后,嵌入向量对象会被存储在缓存中,以便后续快速获取。
**注意**:
- 使用 `load_embeddings` 方法时,需要确保传入的模型和设备参数正确,否则可能无法加载正确的嵌入向量。
- 在多线程环境下使用此类时,其内部的线程安全机制可以保护嵌入向量的加载过程,但调用者仍需注意线程安全的其他方面。
- 由于嵌入向量可能占用大量内存,应合理管理缓存大小,避免内存溢出。
**输出示例**:
调用 `load_embeddings` 方法可能返回的嵌入向量对象示例:
```python
embeddings = embeddings_pool.load_embeddings(model="text-embedding-ada-002", device="cuda")
```
此代码行将返回一个针对 "text-embedding-ada-002" 模型的 `OpenAIEmbeddings` 对象,该对象已配置好与 OpenAI API 交互所需的所有参数,并准备好在指定的设备上进行嵌入向量的计算。
### FunctionDef load_embeddings(self, model, device)
**load_embeddings**: 此函数的功能是加载并返回指定模型和设备上的嵌入向量对象。
**参数**:
- `model`: 字符串类型,指定要加载的嵌入模型名称。如果未提供,则使用默认的嵌入模型。
- `device`: 字符串类型,指定计算设备。如果未提供,则通过`embedding_device`函数自动检测并选择合适的设备。
**代码描述**:
函数首先尝试获取一个线程安全的锁,以确保在多线程环境下的操作安全。然后,根据提供的模型名称和设备类型构造一个键值对`key`,用于检索或存储嵌入向量对象。如果缓存中不存在对应的嵌入向量对象,函数将创建一个新的`ThreadSafeObject`实例,并根据模型名称加载相应的嵌入向量。
如果模型名称为`"text-embedding-ada-002"`,则加载OpenAI提供的嵌入模型。如果模型名称包含`"bge-"`,则根据模型名称中的语言标识(如`"zh"``"en"`)加载对应语言的HuggingFace Bge嵌入模型,并设置相应的查询指令。对于其他模型名称,将加载HuggingFace提供的嵌入模型。
加载完成后,将嵌入向量对象赋值给`ThreadSafeObject`实例的`obj`属性,并标记加载完成。如果缓存中已存在对应的嵌入向量对象,则直接返回该对象。
**注意**:
- 在使用此函数时,应确保提供的模型名称和计算设备类型正确,以便正确加载嵌入向量。
- 函数内部使用了多线程安全机制,包括锁和`ThreadSafeObject`,以确保在并发环境下的操作安全。
- 加载嵌入向量可能需要一定的时间,特别是首次加载时,因此在设计应用逻辑时应考虑到可能的延迟。
**输出示例**:
调用`load_embeddings(model="text-embedding-ada-002", device="cuda")`可能会返回一个`OpenAIEmbeddings`的实例,该实例已经加载了指定的OpenAI嵌入模型,并准备好在CUDA设备上进行嵌入向量的计算。
在项目中,`load_embeddings`函数被`load_kb_embeddings``load_local_embeddings`等函数调用,用于加载知识库嵌入向量或本地嵌入向量,以支持不同的应用场景,如文本相似度计算、文本检索等。
***
@@ -0,0 +1,302 @@
## FunctionDef _new_ds_search(self, search)
**_new_ds_search**: 此函数的功能是根据提供的搜索字符串查找并返回相应的文档或未找到的信息。
**参数**:
- `search`: 需要搜索的字符串,用于在内部字典中查找对应的文档。
**代码描述**:
此函数接收一个名为`search`的参数,该参数是一个字符串,用于在内部维护的字典`_dict`中查找对应的条目。函数首先检查`search`是否存在于`_dict`中。如果不存在,函数将返回一个格式化的字符串,指出给定的ID未找到。如果找到了对应的条目,函数将进一步检查这个条目是否是一个`Document`类型的实例。如果是,函数将在该文档的元数据中添加一个`id`字段,其值为`search`参数的值。最后,无论条目是否为`Document`实例,函数都将返回这个条目。
**注意**:
- 函数返回值的类型依赖于查找结果。如果未找到对应的条目,将返回一个字符串;如果找到了条目,返回值将是该条目本身,可能是`Document`类型或其他类型。
- 在使用此函数时,需要确保`_dict`已经被正确初始化并填充了相应的数据。
- 当返回的是`Document`类型的实例时,其`metadata`将包含一个额外的`id`字段,其值对应于搜索字符串。
**输出示例**:
- 如果搜索的ID未在`_dict`中找到,可能的返回值为:"ID 12345 not found."
- 如果搜索的ID在`_dict`中找到,并且对应的条目是一个`Document`实例,返回的将是这个被更新了`metadata``Document`实例。
## ClassDef ThreadSafeFaiss
**ThreadSafeFaiss**: ThreadSafeFaiss 类的功能是提供一个线程安全的封装,用于操作和管理 FAISS 向量库。
**属性**:
- `key`: 对象的键,用于标识特定的向量库。
- `_obj`: 存储实际 FAISS 向量库的对象。
- `docs_count`: 表示向量库中文档的数量。
**代码描述**:
ThreadSafeFaiss 类继承自 ThreadSafeObject,增加了与 FAISS 向量库相关的特定功能。这个类主要用于在多线线程环境中安全地操作 FAISS 向量库,包括文档计数、保存到磁盘和清空向量库等操作。
- `__repr__` 方法提供了类的字符串表示,包括类名、键、对象以及文档数量。
- `docs_count` 方法返回向量库中文档的数量,这是通过查询 `_obj.docstore._dict` 的长度来实现的。
- `save` 方法用于将向量库保存到指定的磁盘路径。如果路径不存在且 `create_path` 参数为真,则会创建该路径。保存操作完成后,会记录一条日志信息。
- `clear` 方法用于清空向量库中的所有文档。清空操作完成后,会记录一条日志信息。
**注意**:
- 在使用 `save``clear` 方法时,会通过 `acquire` 方法获取锁,以确保线程安全。这意味着在这些操作执行期间,其他线程将无法访问该向量库对象。
- 修改 `_obj` 属性时,应通过 `obj` 属性的 setter 方法,以确保线程安全。
- 在多线程环境下操作向量库时,使用 ThreadSafeFaiss 可以有效避免数据竞争和其他并发问题。
**输出示例**:
假设有一个 ThreadSafeFaiss 实例,其 `key` 为 "example_key"`_obj` 为某个 FAISS 向量库对象,且向量库中有 100 个文档。调用 `__repr__` 方法可能会返回如下字符串:
`"<ThreadSafeFaiss: key: example_key, obj: <FAISS向量库对象的表示>, docs_count: 100>"`
通过这个类,开发者可以在多线程环境中安全高效地管理和操作 FAISS 向量库,无需担心线程安全问题。
### FunctionDef __repr__(self)
**__repr__**: 此函数的功能是生成并返回对象的字符串表示形式。
**参数**: 此函数没有参数。
**代码描述**: `__repr__` 方法是 `ThreadSafeFaiss` 类的一个特殊方法,用于提供对象的官方字符串表示。这种表示形式通常用于调试和日志记录,使得开发者可以更容易地理解对象的状态。在这个方法中,首先通过 `type(self).__name__` 获取对象的类名,然后通过访问对象的 `key` 属性和 `_obj` 属性,以及调用 `docs_count` 方法来获取文档数量,构造出一个格式化的字符串。这个字符串包含了对象的类名、键值、对应的对象以及文档数量,这些信息对于理解和调试 `ThreadSafeFaiss` 对象的状态非常有用。
`key` 属性提供了对象在缓存或其他数据结构中的唯一标识符,是通过访问对象的 `_key` 属性来获取的。`docs_count` 方法返回文档存储中文档的数量,是通过计算 `_obj.docstore._dict` 的长度来实现的。这里的 `_obj` 属性指向一个文档存储对象,`_dict` 是该存储对象中用于保存文档的字典。
通过这种方式,`__repr__` 方法为 `ThreadSafeFaiss` 对象提供了一个详细且易于理解的字符串表示,包括了关键的状态信息,如对象的键值和存储中的文档数量。
**注意**: 在使用 `__repr__` 方法时,需要确保 `_obj` 属性和 `_key` 属性已经被正确初始化,并且 `_obj.docstore._dict` 中包含了需要计数的文档。如果这些属性或字典未被正确初始化,可能会影响到字符串表示的准确性。
**输出示例**: 假设一个 `ThreadSafeFaiss` 对象的类名为 `ThreadSafeFaiss`,其键值为 `"example_key"`,对应的 `_obj` 属性指向一个包含3个文档的文档存储对象,那么调用 `__repr__` 方法可能返回如下字符串:
```
"<ThreadSafeFaiss: key: example_key, obj: <文档存储对象>, docs_count: 3>"
```
***
### FunctionDef docs_count(self)
**docs_count**: 此函数的功能是返回文档存储中文档的数量。
**参数**: 此函数没有参数。
**代码描述**: `docs_count` 函数是 `ThreadSafeFaiss` 类的一个方法,用于获取当前对象中文档存储 `_dict` 的长度,即文档的数量。这里,`self._obj.docstore` 指向一个文档存储对象,而 `_dict` 是该存储对象中用于保存文档的字典。通过调用 `len` 函数计算 `_dict` 的长度,可以得到存储中文档的总数。此方法在 `ThreadSafeFaiss` 类的实例化对象中被调用,特别是在其 `__repr__` 方法中,用于生成对象的字符串表示,其中包括了文档数量的信息。这样,当需要展示或记录 `ThreadSafeFaiss` 对象的状态时,可以直接通过其字符串表示来获取关键信息,包括文档数量。
**注意**: 使用此函数时,需要确保 `self._obj.docstore._dict` 已经正确初始化并包含了需要计数的文档。如果 `_dict` 是空的或者未被正确初始化,此函数将返回 `0`
**输出示例**: 假设 `_dict` 中存储了3个文档,那么 `docs_count()` 的返回值将是 `3`
***
### FunctionDef save(self, path, create_path)
**save**: 此函数的功能是将向量库保存到指定路径。
**参数**:
- `path`: 字符串类型,表示向量库保存的目标路径。
- `create_path`: 布尔类型,默认为True,指示如果目标路径不存在,是否创建该路径。
**代码描述**:
`save` 函数首先通过调用 `acquire` 方法来安全地获取资源,确保在多线程环境下的操作不会引起数据竞争或不一致的问题。在成功获取资源后,函数检查`path`参数指定的路径是否存在,如果不存在且`create_path`参数为True,则会创建该路径。随后,函数调用 `_obj.save_local` 方法将向量库保存到指定的路径。在保存过程中,会通过日志记录功能输出保存操作的信息,包括向量库的键值(通过调用 `key` 方法获取)和保存的目标路径。完成保存操作后,释放之前获取的资源,并返回 `_obj.save_local` 方法的返回值。
**注意**:
- 在使用此函数时,需要确保提供的`path`参数是有效的文件系统路径,且当前运行环境有足够的权限在该路径下创建文件夹或写入文件。
- 如果`create_path`参数设置为False,而指定的路径不存在,则不会创建新路径,可能会导致保存操作失败。
- 此函数在多线程环境下安全使用,但调用者应确保正确处理任何可能的异常,以避免资源泄露或其他意外情况。
**输出示例**: 由于此函数的主要作用是保存文件到磁盘,其返回值取决于 `_obj.save_local` 方法的实现,通常不直接输出信息。但在日志中,可以看到类似以下的信息:
```
已将向量库 example_key 保存到磁盘
```
这表明键值为`example_key`的向量库已成功保存到磁盘。
***
### FunctionDef clear(self)
**clear**: 此函数的功能是清空向量库。
**参数**: 此函数没有参数。
**代码描述**: `clear` 函数负责清空当前对象所代表的向量库。它首先创建一个空列表 `ret`,用于存储删除操作的返回结果。通过使用 `with self.acquire()` 上下文管理器,函数确保在多线程环境下安全地访问和操作向量库。在这个上下文管理器内部,首先获取向量库中所有文档的ID列表,然后检查这个列表是否非空。如果非空,调用 `_obj.delete(ids)` 方法删除这些文档,并将返回结果存储到 `ret` 中。此外,函数通过断言 `assert len(self._obj.docstore._dict) == 0` 确保所有文档都已被删除,向量库被成功清空。最后,记录一条日志信息,表明已经清空了特定的向量库,其中 `self.key` 用于获取向量库的唯一标识符。
从功能角度来看,`clear` 函数与其调用的对象 `acquire``key` 密切相关。`acquire` 函数提供了一个线程安全的环境,确保在执行删除操作时不会发生数据竞争。`key` 函数则用于获取向量库的唯一标识符,这在日志记录时非常有用,帮助开发者和维护者追踪是哪个向量库被清空了。
**注意**: 在使用 `clear` 函数时,需要确保向量库的 `_obj` 属性已经被正确初始化,并且 `_obj.docstore._dict` 能够正确反映向量库中文档的存储状态。此外,考虑到函数中使用了断言来验证向量库是否被成功清空,因此在生产环境中使用时应当确保这一点,以避免因断言失败而导致的异常。
**输出示例**: 假设向量库中原本存储了若干文档,调用 `clear` 函数后,如果删除成功,函数将返回一个包含删除操作结果的列表。例如,如果删除成功,可能返回如下列表:
```
[True, True, ...]
```
如果向量库原本为空,或者在删除过程中没有实际删除任何文档,则返回一个空列表:
```
[]
```
***
## ClassDef _FaissPool
**_FaissPool**: _FaissPool 类的功能是管理和操作基于FAISS库的向量存储。
**属性**:
- 该类继承自 `CachePool`,因此拥有 `CachePool` 的所有属性和方法。
**代码描述**:
_FaissPool 类提供了三个主要方法来管理向量存储:`new_vector_store``save_vector_store``unload_vector_store`
1. `new_vector_store` 方法用于创建一个新的向量存储。它接受嵌入模型名称和嵌入设备作为参数,使用 `EmbeddingsFunAdapter` 来适配不同的嵌入模型,并创建一个文档对象 `doc` 作为初始化数据。然后,它使用 `FAISS.from_documents` 方法根据这个文档对象和嵌入模型创建一个新的FAISS向量存储,同时设置L2归一化和距离策略。创建后,它会删除这个初始化文档对象,以便返回一个空的向量存储。
2. `save_vector_store` 方法用于保存指定名称的向量存储到磁盘。如果在缓存中找到了对应名称的向量存储,它会调用向量存储的 `save` 方法将其保存到指定路径。
3. `unload_vector_store` 方法用于从缓存中卸载并释放指定名称的向量存储。如果在缓存中找到了对应名称的向量存储,它会先从缓存中移除该向量存储,然后记录一条日志信息表示向量库已成功释放。
**注意**:
- 在使用 `new_vector_store` 方法创建向量存储时,需要确保传入的嵌入模型名称和嵌入设备是有效的,因为这将影响向量存储的创建和后续的向量检索性能。
- 使用 `save_vector_store` 方法保存向量存储时,如果没有提供保存路径,则需要确保向量存储对象已经配置了默认的保存路径。
- 在调用 `unload_vector_store` 方法卸载向量存储之前,应确保没有其他操作正在使用该向量存储,以避免数据丢失或访问冲突。
**输出示例**:
由于这些方法主要进行向量存储的管理操作,它们的输出通常不直接返回数据给用户。例如,`new_vector_store` 方法返回一个初始化后的空的FAISS向量存储对象,而 `save_vector_store``unload_vector_store` 方法则没有返回值,它们的执行结果主要通过日志信息和向量存储的状态变化来体现。
### FunctionDef new_vector_store(self, embed_model, embed_device)
**new_vector_store**: 此函数的功能是创建一个新的向量存储空间。
**参数**:
- `embed_model`: 字符串类型,默认值为 `EMBEDDING_MODEL`。用于指定嵌入模型的名称。
- `embed_device`: 字符串类型,默认值为 `embedding_device()` 函数的返回值。用于指定嵌入计算的设备类型。
**代码描述**:
`new_vector_store` 函数首先通过 `EmbeddingsFunAdapter` 类实例化一个嵌入模型适配器,该适配器根据传入的 `embed_model` 参数来处理文本嵌入转换。接着,函数创建一个包含初始化内容和元数据的 `Document` 对象。此后,利用 `FAISS.from_documents` 方法,以该文档对象、嵌入模型适配器、L2归一化以及内积距离策略作为参数,创建一个新的FAISS向量存储实例。创建过程中,会先向该向量存储中添加一个文档,然后立即删除,目的是初始化一个空的向量存储空间。最后,函数返回这个初始化后的向量存储实例。
**注意**:
- 在使用此函数之前,需要确保 `embed_model` 指定的嵌入模型已经存在且可用。
- `embed_device` 参数应根据实际运行环境的硬件配置来设置,以确保嵌入计算能在最适合的设备上执行(如GPU、MPS或CPU)。
- 此函数创建的向量存储实例是空的,即没有包含任何文档的向量数据。通常用于初始化向量存储空间,后续需要通过其他方法向其中添加具体的文档向量。
**输出示例**:
由于此函数返回一个FAISS向量存储实例,而具体的实例内容依赖于运行时的环境和参数,因此不易提供一个具体的输出示例。但可以预期,返回的向量存储实例是一个初始化状态的FAISS对象,准备好接收和管理文档向量数据。
***
### FunctionDef save_vector_store(self, kb_name, path)
**save_vector_store**: 此函数的功能是保存向量存储。
**参数**:
- `kb_name`: 字符串类型,指定要保存的知识库名称。
- `path`: 字符串类型,可选参数,指定保存向量存储的路径。如果未提供,则使用默认路径。
**代码描述**:
`save_vector_store` 函数首先尝试通过调用 `get` 函数从缓存池中获取与给定知识库名称 (`kb_name`) 关联的线程安全对象。如果成功获取到对象,该函数将调用该对象的 `save` 方法,并将可选的路径参数 `path` 传递给它。这一过程实现了向量存储的保存操作。
从功能上看,`get` 函数是从缓存池中检索与给定键关联的线程安全对象的关键步骤。它确保了在进行保存操作之前,所需的对象已经被成功加载并处于可用状态。这一点对于确保数据的一致性和防止在保存过程中发生错误至关重要。
**注意**:
- 在使用 `save_vector_store` 函数时,应确保提供的知识库名称 (`kb_name`) 在缓存中存在。如果不存在,函数将不执行任何操作并返回 `None`
- 提供的保存路径 (`path`) 应确保是有效的,如果路径无效或未提供,可能会导致保存操作失败或使用默认路径。
**输出示例**:
假设存在一个名为 `"example_kb"` 的知识库对象,并且该对象已经被加载到缓存中。调用 `save_vector_store("example_kb", "/path/to/store")` 将会将该知识库对象的向量存储保存到指定的路径。如果 `"example_kb"` 不存在于缓存中,函数将不执行任何操作并返回 `None`
***
### FunctionDef unload_vector_store(self, kb_name)
**unload_vector_store**: 此函数的功能是从缓存池中卸载并释放指定的向量库。
**参数**:
- `kb_name`: 字符串类型,指定要卸载并释放的向量库的名称。
**代码描述**:
`unload_vector_store` 函数是 `_FaissPool` 类的一个方法,用于卸载并释放指定名称的向量库。该函数首先调用 `get` 方法尝试从缓存池中获取与给定名称 `kb_name` 关联的向量库对象。如果成功获取到对象,`get` 方法会确保该对象的加载状态已完成,这是通过对象的 `wait_for_loading` 方法实现的,从而确保在进行后续操作前,对象已经处于可用状态。
获取到对象后,函数接着调用 `pop` 方法,根据提供的向量库名称 `kb_name` 从缓存池中移除该对象。移除操作成功后,会通过日志记录一条信息,表明指定的向量库已成功释放。
在整个过程中,`get` 方法确保了只有在向量库对象确实存在且加载完成的情况下,才会进行卸载操作。而 `pop` 方法则负责实际的移除操作,并处理缓存池中对象的移除逻辑。
**注意**:
- 使用此函数时,应确保提供的向量库名称 `kb_name` 在缓存池中确实存在。如果不存在,函数将不执行任何操作。
- 此函数通过日志记录操作结果,有助于监控和调试向量库的卸载过程。
- 在多线程环境下,`get` 方法的线程安全机制确保了在进行卸载操作前,对象的加载状态已经完成,避免了潜在的竞态条件。
***
## ClassDef KBFaissPool
**KBFaissPool**: KBFaissPool 类的功能是管理和加载基于FAISS库的向量存储池。
**属性**:
- 继承自 `_FaissPool` 类,因此拥有 `_FaissPool` 的所有属性和方法。
**代码描述**:
KBFaissPool 类主要提供了 `load_vector_store` 方法,用于加载或创建向量存储。该方法接受知识库名称(`kb_name`)、向量名称(`vector_name`)、是否创建新的向量存储(`create`)、嵌入模型名称(`embed_model`)和嵌入设备(`embed_device`)作为参数。
1. 方法首先尝试从内部缓存中获取指定的向量存储。如果未找到,它将初始化一个新的 `ThreadSafeFaiss` 对象,并尝试从磁盘加载向量存储或根据参数创建一个新的向量存储。
2. 如果指定路径下存在 `index.faiss` 文件,则从磁盘加载向量存储,并使用指定的嵌入模型和设备加载知识库嵌入。加载过程中,会对向量进行L2归一化,并设置距离策略为内积。
3. 如果指定路径下不存在 `index.faiss` 文件且 `create` 参数为真,则会创建一个新的空向量存储,并保存到磁盘。
4. 如果既不存在 `index.faiss` 文件,`create` 参数也为假,则抛出异常,表示指定的知识库不存在。
在加载或创建向量存储后,方法会将 `ThreadSafeFaiss` 对象存入内部缓存,并返回该对象。
**注意**:
- 在调用 `load_vector_store` 方法时,需要确保传入的知识库名称和向量名称是有效的,以便正确地加载或创建向量存储。
- 如果指定的向量存储已存在于内部缓存中,则方法会直接返回该缓存对象,而不会重复加载或创建。
- 在创建新的向量存储时,需要确保嵌入模型和设备参数正确配置,以保证向量存储的性能和兼容性。
**输出示例**:
调用 `load_vector_store` 方法可能返回的示例输出为一个 `ThreadSafeFaiss` 对象,该对象封装了FAISS向量存储的操作和管理,允许线程安全地访问和修改向量存储。
### FunctionDef load_vector_store(self, kb_name, vector_name, create, embed_model, embed_device)
**load_vector_store**: 此函数用于加载或创建指定知识库的向量存储。
**参数**:
- `kb_name`: 字符串类型,指定要加载或创建向量存储的知识库名称。
- `vector_name`: 字符串类型,可选参数,默认为None。指定向量存储的名称。如果未提供,则使用嵌入模型名称作为向量名称。
- `create`: 布尔类型,可选参数,默认为True。指示如果指定的向量存储不存在时,是否创建一个新的向量存储。
- `embed_model`: 字符串类型,可选参数,默认为`EMBEDDING_MODEL`。用于指定嵌入模型的名称。
- `embed_device`: 字符串类型,可选参数,默认由`embedding_device()`函数确定。用于指定嵌入计算的设备类型。
**代码描述**:
此函数首先尝试获取一个互斥锁,以确保线程安全。然后,根据提供的知识库名称和向量名称(如果未提供向量名称,则使用嵌入模型名称)尝试从缓存中获取对应的向量存储。如果缓存中不存在该向量存储,则会根据`create`参数的值决定是创建一个新的向量存储还是抛出异常。创建向量存储的过程包括初始化一个`ThreadSafeFaiss`实例,并将其添加到缓存中。接着,根据向量存储是否已存在于磁盘上,选择是从磁盘加载向量存储还是创建一个新的空向量存储。加载或创建完成后,会将向量存储实例赋值给`ThreadSafeFaiss`实例的`obj`属性,并标记加载完成。如果向量存储已存在于缓存中,则直接释放互斥锁。最后,函数返回缓存中的向量存储实例。
**注意**:
- 在多线程环境下使用此函数时,内部的互斥锁确保了线程安全。
- 如果`create`参数为False且指定的向量存储不存在,则会抛出运行时错误。
- 在调用此函数之前,应确保`kb_name``vector_name`(如果提供)正确无误,因为它们直接影响向量存储的加载和创建。
- 此函数依赖于`embedding_device()`函数来确定嵌入计算的设备类型,因此需要确保相关硬件和软件配置正确。
**输出示例**:
由于此函数返回一个`ThreadSafeFaiss`实例,而具体的实例内容依赖于运行时的环境和参数,因此不易提供一个具体的输出示例。但可以预期,返回的向量存储实例是一个初始化状态的`ThreadSafeFaiss`对象,准备好接收和管理文档向量数据。
***
## ClassDef MemoFaissPool
**MemoFaissPool**: MemoFaissPool 类的功能是在内存中加载和管理基于FAISS库的向量存储池。
**属性**:
- 继承自 `_FaissPool` 类,因此拥有 `_FaissPool` 的所有属性和方法。
**代码描述**:
`MemoFaissPool` 类通过继承 `_FaissPool` 类,提供了一种高效管理FAISS向量存储的方式。它主要通过 `load_vector_store` 方法来加载或初始化向量存储。
1. `load_vector_store` 方法接受三个参数:`kb_name`(知识库名称),`embed_model`(嵌入模型,默认为 `EMBEDDING_MODEL`),和 `embed_device`(嵌入设备,默认由 `embedding_device()` 函数确定)。该方法首先尝试从缓存中获取指定名称的向量存储。如果未找到,它将创建一个新的 `ThreadSafeFaiss` 对象,并将其添加到缓存中。在这个过程中,它使用了线程安全的锁机制来确保操作的原子性。
2. 在初始化 `ThreadSafeFaiss` 对象时,会调用 `_FaissPool` 类的 `new_vector_store` 方法来创建一个空的向量存储。这个过程涉及到使用指定的嵌入模型和设备来创建向量存储,确保了向量存储的创建与配置的灵活性和可定制性。
3. 完成向量存储的加载后,`load_vector_store` 方法会通过调用 `finish_loading` 方法来标记向量存储的加载状态,确保向量存储已经准备好被使用。
**注意**:
- 在使用 `load_vector_store` 方法时,需要确保传入的知识库名称、嵌入模型和嵌入设备参数正确无误,因为这些参数直接影响向量存储的创建和性能。
- 该类使用了线程安全的锁机制来保护向量存储的加载过程,避免了并发访问和修改时可能出现的数据不一致问题。
- 由于 `MemoFaissPool` 类继承自 `_FaissPool`,在使用该类之前,需要对 `_FaissPool` 类及其方法有一定的了解。
**输出示例**:
由于 `load_vector_store` 方法的主要作用是加载或初始化向量存储,其直接的返回值是一个 `ThreadSafeFaiss` 对象。这个对象代表了一个已加载或新创建的向量存储,可以被进一步用于向量的检索或管理操作。例如,如果成功加载了名为 "knowledge_base" 的向量存储,那么返回的 `ThreadSafeFaiss` 对象将包含这个向量存储的所有相关信息和操作接口。
### FunctionDef load_vector_store(self, kb_name, embed_model, embed_device)
**load_vector_store**: 此函数的功能是加载或初始化一个向量存储库,并确保其线程安全。
**参数**:
- `kb_name`: 字符串类型,用于指定知识库的名称。
- `embed_model`: 字符串类型,默认值为 `EMBEDDING_MODEL`。用于指定嵌入模型的名称。
- `embed_device`: 字符串类型,默认值为 `embedding_device()` 函数的返回值。用于指定嵌入计算的设备类型。
**代码描述**:
此函数首先尝试获取一个原子锁,以确保线程安全。接着,尝试从缓存中获取与`kb_name`对应的向量存储对象。如果未找到,即`cache``None`,则会创建一个新的`ThreadSafeFaiss`实例,并将其与`kb_name`关联后设置到缓存中。在这个过程中,会初始化一个新的向量存储空间,这是通过调用`new_vector_store`函数实现的,该函数根据指定的嵌入模型和计算设备创建向量存储。完成向量存储的初始化后,会调用`finish_loading`方法标记加载过程完成。如果在缓存中找到了对应的向量存储对象,则直接释放原子锁。最后,函数返回从缓存中获取的向量存储对象。
**注意**:
- 在多线程环境下使用此函数时,通过原子锁确保了操作的原子性和线程安全。
- 在初始化向量存储时,需要确保指定的嵌入模型和计算设备已经准备就绪,以避免在后续操作中出现错误。
- 此函数在向量存储对象不存在时会进行创建并加载,这可能是一个耗时操作,因此在设计应用逻辑时应考虑到这一点。
**输出示例**:
由于此函数返回的是一个`ThreadSafeFaiss`实例,具体的实例内容依赖于运行时的环境和参数,因此不易提供一个具体的输出示例。但可以预期,返回的向量存储实例是一个经过初始化,准备好接收和管理文档向量数据的`ThreadSafeFaiss`对象。
在项目中,`load_vector_store`函数被`upload_temp_docs`函数调用,用于在上传文件并进行向量化处理时,加载或初始化临时向量库。这确保了上传的文档能够被正确地添加到向量库中,以支持后续的搜索和检索操作。
***
## FunctionDef worker(vs_name, name)
**worker**: 此函数用于处理向量存储中文档的添加、搜索和删除操作。
**参数**:
- `vs_name`: 字符串类型,指定向量存储的名称。
- `name`: 字符串类型,表示执行当前操作的工作线程或用户的名称。
**代码描述**:
`worker`函数首先将`vs_name`参数的值设置为"samples",这意味着所有操作都将在名为"samples"的向量存储中进行。接着,函数通过调用`load_local_embeddings`函数加载本地嵌入向量。这一步骤是必要的,因为无论是添加文档还是搜索文档,都需要使用到嵌入向量。
函数随机选择一个整数`r`,根据`r`的值决定执行添加文档、搜索文档还是删除文档的操作。具体来说,如果`r`等于1,则执行添加文档操作;如果`r`等于2,则执行搜索文档操作;如果`r`等于3,则执行删除文档操作。
在执行添加或搜索操作时,函数通过`kb_faiss_pool.load_vector_store(vs_name).acquire(name)`获取向量存储的上下文管理器,并确保操作的线程安全。在此上下文管理器内,根据`r`的值执行相应的操作。添加文档时,使用`add_texts`方法将文本和对应的嵌入向量添加到向量存储中,并打印添加的文档ID。搜索文档时,使用`similarity_search_with_score`方法根据提供的文本和嵌入向量搜索最相似的文档,并打印搜索结果。
如果`r`等于3,即执行删除文档操作,则在上下文管理器外部调用`kb_faiss_pool.get(vs_name).clear()`方法,清除指定向量存储中的所有文档。此操作通过日志记录执行删除操作的信息。
**注意**:
- 在使用`worker`函数时,需要确保`vs_name``name`参数正确无误,因为它们直接影响向量存储的操作。
- `load_local_embeddings`函数的调用依赖于正确的嵌入模型配置和计算设备设置,因此在执行`worker`函数之前,应确保相关配置正确。
- `worker`函数通过随机选择操作类型(添加、搜索或删除文档),模拟了一个简单的向量存储操作场景。在实际应用中,可以根据具体需求调整操作逻辑。
- 在多线程环境下使用`worker`函数时,通过`acquire`方法获取的上下文管理器确保了操作的线程安全。
@@ -0,0 +1,417 @@
## FunctionDef search_docs(query, knowledge_base_name, top_k, score_threshold, file_name, metadata)
**search_docs**: 此函数的功能是根据用户输入的查询条件,在指定的知识库中搜索相关文档。
**参数**:
- `query`: 字符串类型,默认为空字符串,表示用户的查询输入。
- `knowledge_base_name`: 字符串类型,必填,表示要搜索的知识库名称。
- `top_k`: 整型,表示返回的匹配向量数目。
- `score_threshold`: 浮点型,取值范围在0-1之间,表示知识库匹配相关度阈值。SCORE越小,相关度越高,取到1相当于不筛选。
- `file_name`: 字符串类型,默认为空字符串,表示文件名称,支持sql通配符。
- `metadata`: 字典类型,默认为空字典,表示根据metadata进行过滤,仅支持一级键。
**代码描述**:
函数首先通过`KBServiceFactory.get_service_by_name`方法获取指定知识库的服务实例。如果知识库服务实例存在,函数将根据是否提供了`query`参数来决定搜索逻辑。如果提供了`query`参数,函数将调用知识库服务实例的`search_docs`方法进行搜索,并将搜索结果转换为`DocumentWithVSId`对象列表返回。如果没有提供`query`但提供了`file_name``metadata`参数,函数将调用知识库服务实例的`list_docs`方法列出文档。最终,函数返回一个包含`DocumentWithVSId`对象的列表。
**注意**:
- 在使用此函数时,确保传入的知识库名称在系统中已存在,否则将无法获取知识库服务实例,导致搜索失败。
- `score_threshold`参数用于过滤搜索结果,较低的值意味着更高的相关性要求,可根据实际需求调整。
-`query`参数为空时,可以通过`file_name``metadata`参数来列出知识库中的文档,这在需要根据特定条件获取文档列表时非常有用。
**输出示例**:
假设在知识库中搜索"技术文档",并且设置`top_k=2``score_threshold=0.5`,可能得到如下输出:
```python
[
DocumentWithVSId(id="doc1", score=0.45, metadata={"title": "技术文档介绍", "author": "张三"}),
DocumentWithVSId(id="doc2", score=0.48, metadata={"title": "技术文档使用手册", "author": "李四"})
]
```
此输出示例展示了根据查询条件返回的前两个最相关的文档对象列表,每个对象包含文档的唯一标识符、匹配得分以及元数据信息。
## FunctionDef update_docs_by_id(knowledge_base_name, docs)
**update_docs_by_id**: 按照文档 ID 更新文档内容。
**参数**:
- `knowledge_base_name`: 知识库名称,类型为字符串。此参数用于指定要更新文档的知识库。
- `docs`: 要更新的文档内容,类型为字典,形如 `{id: Document, ...}`。字典的键为文档的 ID,值为 `Document` 对象。
**代码描述**:
`update_docs_by_id` 函数首先通过 `KBServiceFactory.get_service_by_name` 方法,根据传入的知识库名称 `knowledge_base_name` 获取对应的知识库服务实例。如果指定的知识库不存在,函数将返回一个 `BaseResponse` 对象,其 `code` 属性设置为500`msg` 属性表示指定的知识库不存在的错误信息。如果知识库存在,函数将调用知识库服务实例的 `update_doc_by_ids` 方法,尝试更新传入的文档。如果更新成功,函数返回一个 `BaseResponse` 对象,其 `msg` 属性表示文档更新成功的信息;如果更新失败,返回的 `BaseResponse` 对象的 `msg` 属性将表示文档更新失败的信息。
**注意**:
- 在调用此函数之前,确保传入的 `knowledge_base_name` 在系统中存在,否则将无法找到对应的知识库进行操作。
- `docs` 参数中的 `Document` 对象应包含要更新的文档内容。确保文档 ID 与知识库中现有文档的 ID 匹配,以便正确更新。
- 此函数的执行结果(成功或失败)将通过返回的 `BaseResponse` 对象的 `msg` 属性反馈。因此,调用此函数后应检查返回值,以确认操作结果。
**输出示例**:
如果指定的知识库名称不存在,函数可能返回如下的 `BaseResponse` 对象:
```python
BaseResponse(code=500, msg="指定的知识库 不存在")
```
如果文档更新成功,函数将返回:
```python
BaseResponse(msg="文档更新成功")
```
如果文档更新失败,函数将返回:
```python
BaseResponse(msg="文档更新失败")
```
此函数是项目中知识库管理功能的一部分,允许通过 API 直接根据文档 ID 更新知识库中的文档内容。它在 `server/api.py` 文件中通过 `mount_knowledge_routes` 函数注册为 API 路由,使得前端或其他服务可以通过发送 HTTP 请求来调用此功能,实现知识库文档的更新操作。
## FunctionDef list_files(knowledge_base_name)
**list_files**: 此函数用于列出指定知识库中的所有文件名。
**参数**:
- `knowledge_base_name`: 字符串类型,表示要查询文件列表的知识库名称。
**代码描述**: `list_files` 函数首先验证传入的知识库名称的合法性,如果名称不合法(例如包含潜在的安全风险字符),则返回一个403状态码和错误信息。之后,函数对知识库名称进行URL解码处理,以确保能够正确处理经过URL编码的知识库名称。接着,通过 `KBServiceFactory.get_service_by_name` 方法获取对应知识库的服务实例。如果该知识库不存在,则返回一个404状态码和错误信息。如果知识库存在,函数将调用知识库服务实例的 `list_files` 方法获取所有文件名,并将这些文件名作为数据返回给客户端。
**注意**:
- 在调用此函数之前,需要确保传入的知识库名称是经过URL编码的,以避免潜在的URL解析错误。
- 此函数依赖于 `KBServiceFactory.get_service_by_name` 方法来获取知识库服务实例,因此需要确保知识库名称在系统中是存在的。
- 返回的文件名列表是通过 `ListResponse` 类封装的,这意味着除了文件名列表数据外,还会包含响应的状态码和状态消息。
**输出示例**:
假设存在一个名为 "技术文档库" 的知识库,其中包含三个文件 "doc1.docx", "doc2.pdf", "doc3.txt",调用 `list_files("技术文档库")` 将返回如下响应体:
```
{
"code": 200,
"msg": "success",
"data": ["doc1.docx", "doc2.pdf", "doc3.txt"]
}
```
如果传入的知识库名称不合法或知识库不存在,将返回相应的错误状态码和消息,例如:
```
{
"code": 403,
"msg": "Don't attack me",
"data": []
}
```
```
{
"code": 404,
"msg": "未找到知识库 技术文档库",
"data": []
}
```
## FunctionDef _save_files_in_thread(files, knowledge_base_name, override)
**_save_files_in_thread**: 该函数的功能是通过多线程将上传的文件保存到对应知识库目录内。
**参数**:
- `files`: 一个`UploadFile`对象列表,表示需要保存的文件。
- `knowledge_base_name`: 字符串,指定要保存文件的知识库名称。
- `override`: 布尔值,指示如果文件已存在是否覆盖原文件。
**代码描述**:
`_save_files_in_thread`函数主要通过内部定义的`save_file`函数来处理单个文件的保存逻辑。对于每个上传的文件,它会首先检查目标路径是否存在同名文件,如果存在且不允许覆盖,或者文件大小相同,则记录一条警告日志并返回一个包含错误代码404的字典。如果文件不存在或允许覆盖,函数会创建必要的目录结构,并将文件内容写入目标路径。在写入文件的过程中,如果遇到异常,则记录一条错误日志并返回一个包含错误代码500的字典。
此函数使用`run_in_thread_pool`来并发执行`save_file`函数,以提高文件保存的效率。`run_in_thread_pool`接受一个函数和一个参数列表,其中每个参数都是一个字典,包含了`save_file`所需的参数。这样,`_save_files_in_thread`可以同时处理多个文件的保存操作,每个文件的保存操作在一个独立的线程中执行。
**注意**:
- 在使用此函数时,需要确保`knowledge_base_name`是有效的,且对应的知识库目录具有写入权限。
- 由于使用了多线程,需要注意线程安全问题,尤其是在写文件和创建目录时。
- 函数返回一个生成器,每次迭代返回一个文件的保存结果,因此调用此函数时需要适当处理这些结果。
**输出示例**:
```python
{
"code": 200,
"msg": "成功上传文件 example.txt",
"data": {
"knowledge_base_name": "sample_kb",
"file_name": "example.txt"
}
}
```
此示例展示了一个成功保存文件的返回值,其中包含了状态码、消息以及文件的相关信息。
### FunctionDef save_file(file, knowledge_base_name, override)
**save_file**: 此函数的功能是保存上传的单个文件到指定的知识库中。
**参数**:
- file: UploadFile类型,表示需要上传的文件。
- knowledge_base_name: 字符串类型,表示目标知识库的名称。
- override: 布尔类型,指示如果文件已存在是否覆盖原文件。
**代码描述**:
`save_file` 函数首先从上传的文件中提取文件名,并使用 `get_file_path` 函数构造目标文件的存储路径。此路径是基于知识库名称和文件名动态生成的,确保文件能够被正确地保存在对应的知识库目录下。
函数接着读取上传文件的内容。在尝试保存文件之前,会检查目标路径上的文件是否已存在,以及是否设置了不覆盖已存在文件的选项(`override` 参数)。如果文件已存在且不允许覆盖,函数将记录一条警告日志,并返回一个包含错误代码和消息的字典。
如果目标文件夹不存在,函数会创建必要的目录结构。然后,以二进制写入模式打开目标文件路径,将上传的文件内容写入其中。
在文件成功保存后,函数返回一个包含成功代码和消息的字典。如果在文件保存过程中发生异常,函数会捕获异常,记录一条错误日志,并返回一个包含错误代码和消息的字典。
**注意**:
- 在使用此函数之前,确保传入的 `file` 参数是一个有效的 `UploadFile` 对象,且 `knowledge_base_name` 参数正确指向一个存在的知识库。
- 如果设置 `override` 参数为 `False`,而目标文件已存在且文件大小与上传文件相同,则不会进行文件覆盖,而是返回文件已存在的消息。
- 异常处理是此函数的重要组成部分,确保了文件操作过程中的稳定性和可靠性。
**输出示例**:
成功上传文件时,可能的返回值为:
```
{
"code": 200,
"msg": "成功上传文件 example.docx",
"data": {
"knowledge_base_name": "my_knowledge_base",
"file_name": "example.docx"
}
}
```
如果文件已存在且不覆盖,返回值可能为:
```
{
"code": 404,
"msg": "文件 example.docx 已存在。",
"data": {
"knowledge_base_name": "my_knowledge_base",
"file_name": "example.docx"
}
}
```
在文件上传失败时,返回值可能为:
```
{
"code": 500,
"msg": "example.docx 文件上传失败,报错信息为: [具体错误信息]",
"data": {
"knowledge_base_name": "my_knowledge_base",
"file_name": "example.docx"
}
}
```
***
## FunctionDef upload_docs(files, knowledge_base_name, override, to_vector_store, chunk_size, chunk_overlap, zh_title_enhance, docs, not_refresh_vs_cache)
**upload_docs**: 此函数用于上传文件到知识库,并可选择进行文件的向量化处理。
**参数**:
- `files`: 上传的文件列表,支持多文件上传。
- `knowledge_base_name`: 知识库名称,指定要上传文件的目标知识库。
- `override`: 布尔值,指示是否覆盖已有文件。
- `to_vector_store`: 布尔值,指示上传文件后是否进行向量化处理。
- `chunk_size`: 知识库中单段文本的最大长度。
- `chunk_overlap`: 知识库中相邻文本的重合长度。
- `zh_title_enhance`: 布尔值,指示是否开启中文标题加强功能。
- `docs`: 自定义的docs,需转为json字符串格式。
- `not_refresh_vs_cache`: 布尔值,指示是否暂不保存向量库(用于FAISS)。
**代码描述**:
函数首先验证知识库名称的合法性,如果不合法,则返回403状态码并提示错误信息。接着,根据知识库名称获取对应的知识库服务实例。如果实例获取失败,则返回404状态码并提示未找到知识库。
函数继续执行,将上传的文件保存到磁盘,并记录保存失败的文件。对于需要进行向量化处理的文件,函数将调用`update_docs`函数进行处理,并更新失败文件列表。如果`not_refresh_vs_cache``False`,则会保存向量库。
最后,函数返回包含操作结果的响应,其中包括失败文件列表。
**注意**:
- 确保传入的知识库名称在系统中已存在。
- 上传的文件将被保存到指定的知识库目录中,如果`override`参数为`False`,则不会覆盖已存在的同名文件。
- 如果选择进行向量化处理,需要考虑服务器的性能和资源限制。
- 自定义的docs需要正确格式化为json字符串,以确保能够被正确解析和处理。
**输出示例**:
```json
{
"code": 200,
"msg": "文件上传与向量化完成",
"data": {
"failed_files": {
"error_file.txt": "文件保存失败的错误信息"
}
}
}
```
此示例展示了函数执行成功的情况,其中`failed_files`字段列出了处理失败的文件及其错误信息。
## FunctionDef delete_docs(knowledge_base_name, file_names, delete_content, not_refresh_vs_cache)
**delete_docs**: 此函数用于从知识库中删除指定的文件。
**参数**:
- `knowledge_base_name`: 知识库的名称,类型为字符串,示例值为["samples"]。
- `file_names`: 需要删除的文件名称列表,类型为字符串列表,示例值为[["file_name.md", "test.txt"]]。
- `delete_content`: 布尔值,指定是否从磁盘中删除文件内容,默认为`False`
- `not_refresh_vs_cache`: 布尔值,指定是否暂不保存向量库(用于FAISS),默认为`False`,描述为"暂不保存向量库(用于FAISS"。
**代码描述**:
函数首先验证知识库名称的合法性,如果不合法,则返回403状态码和错误消息"Don't attack me"。之后,对知识库名称进行URL解码,并尝试获取对应的知识库服务实例。如果知识库服务实例不存在,则返回404状态码和错误消息,指出未找到知识库。
对于每个指定的文件名,函数检查文件是否存在于知识库中。如果文件不存在,将其添加到失败文件列表中。对于存在的文件,尝试删除文件,包括从知识库中删除记录和可选的从磁盘中删除文件内容。如果删除过程中发生异常,将异常信息记录到失败文件列表中,并记录错误日志。
如果`not_refresh_vs_cache``False`,则调用`save_vector_store`方法保存向量库。最后,函数返回200状态码和包含失败文件列表的响应。
**注意**:
- 在调用此函数之前,确保传入的知识库名称和文件名列表正确,且知识库存在。
- `delete_content`参数应谨慎使用,因为一旦从磁盘删除文件内容,该操作是不可逆的。
- `not_refresh_vs_cache`参数用于控制是否立即保存向量库的状态,这在批量删除文件时可以用来优化性能。
**输出示例**:
如果所有指定的文件都成功删除,且没有需要刷新的向量库,函数可能返回如下响应:
```json
{
"code": 200,
"msg": "文件删除完成",
"data": {
"failed_files": {}
}
}
```
如果存在未找到或删除失败的文件,响应中的`failed_files`将包含这些文件的名称和相关错误信息。
## FunctionDef update_info(knowledge_base_name, kb_info)
**update_info**: 此函数用于更新知识库的介绍信息。
**参数**:
- `knowledge_base_name`: 知识库的名称,类型为字符串。此参数是必需的,用于指定要更新介绍信息的知识库。
- `kb_info`: 知识库的介绍信息,类型为字符串。此参数是必需的,用于提供新的知识库介绍。
**代码描述**:
首先,`update_info` 函数通过调用 `validate_kb_name` 函数验证传入的知识库名称是否合法。如果知识库名称不合法(例如包含潜在的安全风险字符),函数将返回一个状态码为403的 `BaseResponse` 对象,消息为"Don't attack me",表示请求被拒绝。
如果知识库名称验证通过,函数接着尝试通过 `KBServiceFactory.get_service_by_name` 方法获取对应知识库的服务实例。如果指定的知识库不存在(即服务实例为None),函数将返回一个状态码为404的 `BaseResponse` 对象,消息为"未找到知识库 {knowledge_base_name}",表示未找到指定的知识库。
当知识库服务实例成功获取后,函数调用该实例的 `update_info` 方法,传入新的知识库介绍信息 `kb_info` 进行更新。
最后,函数返回一个状态码为200的 `BaseResponse` 对象,消息为"知识库介绍修改完成",并在数据字段中返回更新后的知识库介绍信息,表示知识库介绍信息更新成功。
**注意**:
- 在调用此函数之前,确保传入的知识库名称在系统中已存在且合法,否则可能会导致更新失败。
- 更新知识库介绍信息的操作可能会受到知识库服务实例类型的限制,确保知识库服务支持信息更新操作。
**输出示例**:
如果更新操作成功,函数可能返回如下的 `BaseResponse` 对象示例:
```
{
"code": 200,
"msg": "知识库介绍修改完成",
"data": {
"kb_info": "这是一个更新后的知识库介绍"
}
}
```
如果知识库名称不合法,返回的 `BaseResponse` 对象示例可能如下:
```
{
"code": 403,
"msg": "Don't attack me",
"data": null
}
```
如果未找到指定的知识库,返回的 `BaseResponse` 对象示例可能如下:
```
{
"code": 404,
"msg": "未找到知识库 {knowledge_base_name}",
"data": null
}
```
## FunctionDef update_docs(knowledge_base_name, file_names, chunk_size, chunk_overlap, zh_title_enhance, override_custom_docs, docs, not_refresh_vs_cache)
**update_docs**: 此函数用于更新知识库中的文档。
**参数**:
- `knowledge_base_name`: 知识库名称,字符串类型,必填参数。
- `file_names`: 文件名称列表,支持多文件,列表中每个元素为字符串类型。
- `chunk_size`: 知识库中单段文本最大长度,整数类型。
- `chunk_overlap`: 知识库中相邻文本重合长度,整数类型。
- `zh_title_enhance`: 是否开启中文标题加强,布尔类型。
- `override_custom_docs`: 是否覆盖之前自定义的docs,布尔类型,默认为False。
- `docs`: 自定义的docs,需要转为json字符串,字典类型。
- `not_refresh_vs_cache`: 暂不保存向量库(用于FAISS),布尔类型,默认为False。
**代码描述**:
此函数首先验证传入的知识库名称是否合法,如果不合法,则返回403状态码和错误信息。接着,通过知识库名称获取对应的知识库服务实例。如果实例获取失败,则返回404状态码和错误信息。
函数继续执行,生成需要加载docs的文件列表。对于每个文件,首先检查该文件是否使用了自定义docs,如果是且不覆盖自定义docs,则跳过该文件。否则,尝试将文件添加到待处理列表中。如果在此过程中出现异常,则记录错误信息。
接下来,函数将文件列表中的文件转换为docs,并进行向量化处理。这一步骤利用多线程在后台执行,以提高处理效率。处理完成后,如果指定了不刷新向量库缓存,则不立即保存向量库;否则,调用知识库服务的`save_vector_store`方法保存向量库。
最后,函数返回200状态码和处理结果,包括处理失败的文件列表。
**注意**:
- 在使用此函数时,确保传入的知识库名称在系统中已存在。
- 如果需要对文件进行自定义docs处理,确保`docs`参数格式正确,并且文件名与`file_names`中的文件名匹配。
- 此函数支持批量处理文件,但需要注意服务器资源和性能限制。
**输出示例**:
```json
{
"code": 200,
"msg": "更新文档完成",
"data": {
"failed_files": {
"error_file.txt": "加载文档时出错"
}
}
}
```
此示例展示了函数执行成功的情况,其中`failed_files`字段列出了处理失败的文件及其错误信息。
## FunctionDef download_doc(knowledge_base_name, file_name, preview)
**download_doc**: 此函数用于下载知识库中的文档。
**参数**:
- `knowledge_base_name`: 知识库名称,用于指定从哪个知识库下载文档。
- `file_name`: 文件名称,指定要下载的文件名。
- `preview`: 是否预览,布尔值,指示用户是希望在浏览器中预览文件还是直接下载文件。
**代码描述**:
`download_doc` 函数首先通过调用 `validate_kb_name` 函数验证传入的知识库名称是否合法。如果知识库名称不合法,函数将返回一个带有403状态码的 `BaseResponse` 对象,提示用户不要进行攻击。接着,函数尝试通过 `KBServiceFactory.get_service_by_name` 方法获取对应知识库的服务实例。如果找不到对应的知识库服务实例,将返回一个带有404状态码的 `BaseResponse` 对象,提示未找到指定的知识库。
根据 `preview` 参数的值,函数设置 `content_disposition_type`。如果 `preview``True`,则设置为 `"inline"`,允许在浏览器中预览文件;否则,`content_disposition_type``None`,表示文件将被下载。
然后,函数创建一个 `KnowledgeFile` 实例,用于表示和处理知识库中的文件。如果文件存在于磁盘上,函数将返回一个 `FileResponse` 对象,允许用户下载或预览文件。如果在尝试读取文件时发生异常,函数将记录错误信息并返回一个带有500状态码的 `BaseResponse` 对象,提示读取文件失败。
**注意**:
- 在调用此函数之前,确保传入的知识库名称和文件名称是正确的。
- 如果知识库名称不合法或文件不存在,函数将返回错误响应。
- 此函数支持文件预览和下载功能,通过 `preview` 参数控制。
**输出示例**:
假设存在一个名为 "samples" 的知识库,其中包含一个名为 "test.txt" 的文件。如果调用 `download_doc(knowledge_base_name="samples", file_name="test.txt", preview=False)`,函数将返回一个 `FileResponse` 对象,允许用户下载 "test.txt" 文件。如果指定的文件不存在,将返回一个带有404状态码的 `BaseResponse` 对象,提示未找到文件。
## FunctionDef recreate_vector_store(knowledge_base_name, allow_empty_kb, vs_type, embed_model, chunk_size, chunk_overlap, zh_title_enhance, not_refresh_vs_cache)
**recreate_vector_store**: 该函数用于根据内容文件夹中的文档重建向量库。
**参数**:
- `knowledge_base_name`: 知识库名称,类型为字符串,默认示例为“samples”。
- `allow_empty_kb`: 是否允许空的知识库,布尔类型,默认为True。
- `vs_type`: 向量库类型,字符串类型,默认值为`DEFAULT_VS_TYPE`
- `embed_model`: 嵌入模型名称,字符串类型,默认值为`EMBEDDING_MODEL`
- `chunk_size`: 知识库中单段文本的最大长度,整数类型,默认值为`CHUNK_SIZE`
- `chunk_overlap`: 知识库中相邻文本的重合长度,整数类型,默认值为`OVERLAP_SIZE`
- `zh_title_enhance`: 是否开启中文标题加强功能,布尔类型,默认值为`ZH_TITLE_ENHANCE`
- `not_refresh_vs_cache`: 是否暂不保存向量库(用于FAISS),布尔类型,默认为False。
**代码描述**:
`recreate_vector_store`函数主要用于在用户直接将文件复制到内容文件夹而不是通过网络上传输的情况下,从这些内容文件中重建向量库。默认情况下,只有在`info.db`中存在且包含文档文件的知识库才会被返回。通过将`allow_empty_kb`设置为True,可以使该函数也适用于那些在`info.db`中不存在或没有文档的空知识库。函数内部首先尝试获取指定的知识库服务,如果知识库不存在且不允许空的知识库,则返回404错误。如果知识库存在,则清除现有的向量库并重新创建。随后,函数遍历内容文件夹中的所有文件,并将它们转换为文档,同时考虑文本的分块大小、重合长度以及是否开启中文标题加强功能。每处理完一个文件,就会生成一个包含处理状态的JSON对象,并通过生成器返回。如果在添加文件到知识库时出现错误,则记录错误并跳过该文件。最后,如果不是设置为不刷新向量库缓存,则保存向量库。
在项目中,`recreate_vector_store`函数通过`server/api.py/mount_knowledge_routes`被注册为FastAPI的一个POST路由。这意味着该函数可以通过HTTP POST请求被调用,用于在用户通过其他方式将文件直接放入内容文件夹后,重新构建知识库的向量库。这在管理知识库时特别有用,尤其是在需要批量更新文档内容而不想逐个上传时。
**注意**:
- 确保在调用此函数之前,内容文件夹中的文件格式和内容符合知识库的要求。
- 函数的执行时间可能会根据内容文件夹中的文件数量和大小而有很大差异。
**输出示例**:
```json
{
"code": 200,
"msg": "(1 / 10): example.docx",
"total": 10,
"finished": 1,
"doc": "example.docx"
}
```
此JSON对象表示第一个文件处理成功,总共有10个文件需要处理,当前已完成1个。
### FunctionDef output
**output**: 此函数的功能是重建知识库的向量存储,并输出处理过程中的状态信息。
**参数**: 此函数不接受任何外部参数。
**代码描述**:
`output` 函数首先通过 `KBServiceFactory.get_service` 方法获取对应知识库的服务实例,该实例根据知识库名称、向量存储类型和嵌入模型来确定。如果指定的知识库不存在且不允许创建空的知识库,则函数会生成并返回一个包含错误代码404和相应错误信息的JSON对象。如果知识库存在,函数会先清除知识库中的向量存储,然后重新创建知识库。
接下来,函数通过 `list_files_from_folder` 方法列出知识库文件夹中的所有文件,并为每个文件创建一个 `KnowledgeFile` 实例。这些文件实例随后被批量处理,通过 `files2docs_in_thread` 方法将文件内容转换为文档,并添加到知识库中。在文件转换过程中,函数会逐个生成并返回包含处理状态的JSON对象,这些对象包含了处理进度、文件名等信息。
如果在文件转换过程中遇到错误,函数会记录错误信息并生成包含错误代码500和相应错误信息的JSON对象。所有文件处理完成后,如果不需要刷新向量存储缓存,则会调用 `save_vector_store` 方法保存向量库。
**注意**:
- 在调用此函数之前,需要确保 `KBServiceFactory.get_service` 能够根据提供的参数正确返回知识库服务实例。
- `list_files_from_folder` 方法用于列出知识库文件夹中的所有文件,确保知识库文件夹路径正确。
- `files2docs_in_thread` 方法负责将文件内容转换为文档并添加到知识库中,该过程是多线程执行的,需要注意线程安全问题。
- `save_vector_store` 方法用于保存向量库,确保在调用此方法之前,所有需要保存的数据已经正确处理完毕。
- 此函数通过生成器返回处理状态信息,调用方需要适当处理这些生成的JSON对象,以实现状态监控或错误处理。
***
@@ -0,0 +1,940 @@
## FunctionDef normalize(embeddings)
**normalize**: 此函数的功能是对输入的嵌入向量进行L2范数归一化处理。
**参数**:
- **embeddings**: 一个列表的列表,其中每个内部列表包含浮点数,代表一个嵌入向量。
**代码描述**:
`normalize`函数接受一个嵌入向量列表作为输入,这些嵌入向量可以是文档或查询的表示。它首先计算每个嵌入向量的L2范数,然后将每个向量的元素分别除以其L2范数,以实现归一化。这个过程确保了所有的嵌入向量都被规范化到单位球上,这在很多向量空间模型中是一个常见的预处理步骤,有助于提高后续处理的效果和稳定性。
在项目中,`normalize`函数被`EmbeddingsFunAdapter`类中的`embed_documents``embed_query``aembed_documents``aembed_query`方法调用。这些方法分别负责同步和异步地嵌入文档和查询,然后使用`normalize`函数对嵌入结果进行归一化处理。这表明归一化步骤是嵌入过程的一个重要组成部分,无论是处理文档还是查询,都需要进行归一化以确保嵌入向量的质量。
**注意**:
- 输入的嵌入向量列表需要确保每个向量的维度相同,因为归一化过程涉及到按元素的运算。
- 该函数依赖于`numpy`库进行矩阵运算,因此在使用前需要确保已经安装了`numpy`
**输出示例**:
假设输入的嵌入向量列表为`[[1.0, 2.0], [2.0, 3.0]]`,则函数的返回值可能如下所示:
```
[[0.4472136 0.89442719]
[0.5547002 0.83205029]]
```
这个输出展示了两个经过L2范数归一化的二维向量。
## ClassDef SupportedVSType
**SupportedVSType**: SupportedVSType的功能是定义支持的向量存储类型。
**属性**:
- FAISS: 代表使用FAISS作为向量存储服务。
- MILVUS: 代表使用MILVUS作为向量存储服务。
- DEFAULT: 代表使用默认的向量存储服务。
- ZILLIZ: 代表使用ZILLIZ作为向量存储服务。
- PG: 代表使用PostgreSQL (PG) 作为向量存储服务。
- ES: 代表使用Elasticsearch (ES) 作为向量存储服务。
- CHROMADB: 代表使用ChromaDB作为向量存储服务。
**代码描述**:
SupportedVSType类是一个枚举类,它定义了在知识库服务中支持的各种向量存储类型。这些类型包括FAISS、MILVUS、ZILLIZ、PostgreSQL、Elasticsearch和ChromaDB等,以及一个默认选项。这个类在项目中的主要作用是在知识库服务工厂(KBServiceFactory)中,根据传入的向量存储类型字符串,动态选择并实例化对应的知识库服务实现。例如,如果指定了FAISS作为向量存储类型,那么KBServiceFactory将实例化并返回一个FaissKBService对象。
在项目中,SupportedVSType类通过KBServiceFactory的get_service方法被调用,以确定并实例化相应的知识库服务。此外,各个具体的知识库服务类(如FaissKBService、MilvusKBService等)也通过实现vs_type方法,返回其对应的SupportedVSType值,以标识它们支持的向量存储类型。
**注意**:
- 在使用SupportedVSType时,应确保传入的向量存储类型字符串与SupportedVSType中定义的属性名称一致,以避免在动态解析时发生错误。
- DEFAULT类型通常用于指定一个默认的向量存储服务,具体实现可能会根据项目配置或环境而变化。
- 在扩展项目以支持新的向量存储服务时,应在SupportedVSType中添加相应的属性,并在KBServiceFactory中实现相应的逻辑以支持新的服务类型。
## ClassDef KBService
**KBService**: KBService 类是用于管理和操作知识库的抽象基类,提供了一系列对知识库进行操作的方法。
**属性**:
- `kb_name`: 知识库名称。
- `kb_info`: 知识库信息,如果在`KB_INFO`中找不到对应的知识库名称,则显示为"关于xxx的知识库"。
- `embed_model`: 嵌入模型名称,默认为`EMBEDDING_MODEL`
- `kb_path`: 知识库路径。
- `doc_path`: 文档路径。
**代码描述**:
KBService 类定义了一系列方法用于管理知识库,包括创建知识库、删除知识库、向知识库添加文档、从知识库删除文档、更新知识库信息、文档搜索等。它是一个抽象基类(ABC),意味着它不能直接实例化,而是需要通过继承它的子类来实现具体的功能。这样的设计允许不同类型的知识库服务(如Faiss、Milvus、Elasticsearch等)实现相同的接口,从而提供一致的操作方式。
KBService 类在项目中被多个子类继承,每个子类代表一种特定类型的知识库服务,例如`FaissKBService``MilvusKBService`等。这些子类实现了KBService类中定义的抽象方法,以适应不同知识库的具体操作需求。
此外,KBService 类还与`KBServiceFactory`类相关联,`KBServiceFactory`类提供了`get_service``get_service_by_name`方法,用于根据知识库名称和向量存储类型动态创建相应的知识库服务实例。这种工厂模式的设计使得在不同知识库服务之间切换变得更加灵活和方便。
**注意**:
- 由于KBService是一个抽象基类,直接实例化KBService会引发错误。应该通过继承KBService并实现其抽象方法的方式来创建子类。
- 在使用KBService的子类时,需要确保已经正确配置了知识库的相关信息,如知识库名称、嵌入模型名称等。
- 在进行知识库操作(如添加文档、搜索文档等)时,需要注意操作的具体实现可能会依赖于所使用的知识库服务类型。
**输出示例**:
由于KBService是一个抽象基类,它本身不直接产生输出。具体的输出将取决于继承KBService的子类以及实现的方法。例如,一个可能的搜索文档的输出示例为:
```python
[
{"id": "doc1", "text": "文档1的内容", "score": 0.95},
{"id": "doc2", "text": "文档2的内容", "score": 0.90}
]
```
这表示在执行搜索操作时,返回了两个文档及其相关性得分。
### FunctionDef __init__(self, knowledge_base_name, embed_model)
**__init__**: 此函数的功能是初始化KBService类的实例。
**参数**:
- knowledge_base_name: 字符串类型,指定知识库的名称。
- embed_model: 字符串类型,默认值为EMBEDDING_MODEL,指定嵌入模型的名称。
**代码描述**:
`__init__` 方法是 `KBService` 类的构造函数,负责初始化该类的实例。在这个方法中,首先将传入的知识库名称(`knowledge_base_name`)赋值给实例变量 `self.kb_name`。然后,使用 `KB_INFO.get` 方法尝试从一个预定义的字典 `KB_INFO` 中获取与 `knowledge_base_name` 对应的知识库信息,如果未找到,则使用默认信息(`"关于{knowledge_base_name}的知识库"`)。接下来,将传入的嵌入模型名称(`embed_model`)赋值给实例变量 `self.embed_model`
此外,`__init__` 方法调用了 `get_kb_path``get_doc_path` 函数,分别用于获取知识库的存储路径和文档存储路径,并将这些路径分别赋值给实例变量 `self.kb_path``self.doc_path`。这两个函数分别位于 `server/knowledge_base/utils.py` 文件中,`get_kb_path` 函数负责构造并返回知识库的文件路径,而 `get_doc_path` 函数则负责获取知识库文档的存储路径。
最后,`__init__` 方法调用了 `do_init` 方法,这是一个在 `KBService` 类中定义的方法,用于执行进一步的初始化操作。当前,`do_init` 方法的实现可能为空(使用 `pass` 关键字),但它的存在表明在初始化 `KBService` 实例时可能需要执行的额外步骤或特定的初始化逻辑。
**注意**:
- 在使用 `KBService` 类之前,确保 `KB_INFO` 字典已经被正确定义,且包含了所有可能的知识库名称及其对应的信息。
- `EMBEDDING_MODEL` 应为一个有效的嵌入模型名称,默认值应在类或模块的其他部分被定义。
- `do_init` 方法的具体实现应根据实际需求进行添加,以完成知识库服务的特定初始化需求。
***
### FunctionDef __repr__(self)
**__repr__**: 此函数的功能是生成对象的官方字符串表示。
**参数**: 此函数没有参数。
**代码描述**: `__repr__` 方法是一个特殊方法,用于定义对象的“官方”字符串表示。在 Python 中,当我们尝试使用 `repr()` 函数或者在解释器中直接查询对象时,会调用此方法。在本例中,`__repr__` 方法返回一个格式化的字符串,该字符串包含了两个对象属性:`kb_name``embed_model`。这意味着当此方法被调用时,它会返回一个包含知识库名称 (`kb_name`) 和嵌入模型 (`embed_model`) 的字符串,两者通过 "@" 符号连接。这种表示方式有助于快速识别对象的关键信息,特别是在调试和日志记录中非常有用。
**注意**: 使用 `__repr__` 方法时,应确保返回的字符串尽可能明确地反映对象的关键信息。此外,返回的字符串应该尽量遵循 Python 对象表示的惯例,即可能的话,应该能够通过执行这个字符串来重新创建该对象的一个相似实例。
**输出示例**: 假设一个 `KBService` 对象的 `kb_name` 属性值为 `"KnowledgeBase1"``embed_model` 属性值为 `"ModelX"`,那么调用此对象的 `__repr__` 方法将返回字符串 `"KnowledgeBase1 @ ModelX"`。这提供了一个直观的方式来理解对象的主要属性。
***
### FunctionDef save_vector_store(self)
**save_vector_store**: 此函数的功能是保存向量库。
**参数**: 此函数没有参数。
**代码描述**: `save_vector_store` 函数是`KBService`类的一个方法,它的主要作用是将向量库的数据持久化保存。在具体实现中,此函数根据不同的向量库类型(如FAISS、Milvus等)采取不同的保存策略。例如,对于FAISS类型的向量库,数据可能会被保存到磁盘上的文件中;而对于Milvus类型的向量库,数据则会被保存到数据库中。需要注意的是,当前代码示例中此函数的实现为空,这意味着具体的保存逻辑需要根据实际的向量库类型和需求来完成。
在项目中,`save_vector_store`函数被多个地方调用,以确保在进行文档的上传、删除、更新或向量库重建等操作后,向量库的状态能够被正确地保存。这些调用场景包括:
- 文档上传(`upload_docs`):在上传文档并进行向量化处理后,根据`not_refresh_vs_cache`参数的值决定是否立即保存向量库。
- 文档删除(`delete_docs`):在删除指定的文档后,根据`not_refresh_vs_cache`参数的值决定是否立即保存向量库。
- 文档更新(`update_docs`):在更新文档内容并进行向量化处理后,根据`not_refresh_vs_cache`参数的值决定是否立即保存向量库。
- 向量库重建(`recreate_vector_store``output`方法):在重建向量库的过程中,完成所有文档的向量化处理后,根据`not_refresh_vs_cache`参数的值决定是否立即保存向量库。
- 数据库文档清理(`prune_db_docs`):在从数据库中删除不存在于本地文件夹中的文档后,保存向量库以确保向量库与数据库的一致性。
**注意**: 在使用`save_vector_store`函数时,需要根据实际使用的向量库类型(如FAISS、Milvus等)来实现具体的保存逻辑。此外,考虑到向量库可能包含大量数据,保存操作可能会涉及到较大的I/O开销,因此在设计调用此函数的策略时应当考虑到性能影响,合理安排保存向量库的时机。
***
### FunctionDef create_kb(self)
**create_kb**: 此函数的功能是创建知识库。
**参数**: 此函数没有参数。
**代码描述**: `create_kb` 方法是 `KBService` 类的一个核心方法,负责知识库的创建流程。该方法首先检查指定的文档路径是否存在,如果不存在,则创建该路径。接着,调用 `do_create_kb` 方法,这是一个预留给开发者的扩展点,允许在知识库创建的基础流程中插入自定义逻辑。之后,该方法会调用 `add_kb_to_db` 函数,将知识库的名称、简介、向量库类型和嵌入模型等信息添加到数据库中。`add_kb_to_db` 函数的执行结果(状态)会被返回,表示知识库创建操作的成功与否。
在整个创建流程中,`do_create_kb` 方法提供了一个扩展点,允许开发者根据具体需求实现特定的知识库创建逻辑,而 `add_kb_to_db` 函数则负责将知识库信息持久化到数据库中。这种设计模式不仅提高了代码的可扩展性,也确保了知识库创建过程的灵活性和可维护性。
**注意**:
- 在调用 `create_kb` 方法之前,确保已经正确设置了 `KBService` 类的 `doc_path``kb_name``kb_info``vs_type()``embed_model` 属性,因为这些属性会在知识库创建过程中被使用。
- `do_create_kb` 方法默认不执行任何操作,需要在继承 `KBService` 类的子类中根据具体需求重写此方法。
- `add_kb_to_db` 函数的调用需要确保传入的知识库名称是唯一的,以避免不必要的信息覆盖。
**输出示例**: 该方法返回一个布尔值,表示知识库创建操作的成功与否。例如,如果知识库成功创建并添加到数据库中,方法将返回 `True`
***
### FunctionDef clear_vs(self)
**clear_vs**: 此函数的功能是删除向量库中所有内容。
**参数**: 此函数不接受任何外部参数。
**代码描述**: `clear_vs` 方法是 `KBService` 类的一个成员方法,主要负责清除知识库中的向量数据。该方法首先调用 `do_clear_vs` 方法,执行删除向量数据之前的预处理操作,尽管在当前的实现中,`do_clear_vs` 方法的具体实现为空,但它为未来可能的逻辑扩展提供了接口。接下来,`clear_vs` 方法通过调用 `delete_files_from_db` 函数,传入知识库名称(`self.kb_name`),从数据库中删除与该知识库相关的所有文件记录。`delete_files_from_db` 函数的执行结果(布尔值)将作为 `clear_vs` 方法的返回值,指示操作是否成功完成。
**注意**:
- 在调用 `clear_vs` 方法之前,确保知识库名称已正确设置在 `KBService` 实例的 `kb_name` 属性中。
- 该方法会永久删除知识库中的所有文件记录,此操作不可逆,请谨慎使用。
- 虽然当前 `do_clear_vs` 方法的实现为空,但开发者在未来的开发中可以在此方法中添加删除向量数据之前需要执行的特定逻辑(如日志记录、数据备份、权限检查等)。
**输出示例**:
如果操作成功完成,`clear_vs` 方法将返回 `True`。例如,在成功删除知识库中所有内容后,方法返回值为:
```
True
```
此方法在项目中的调用场景包括但不限于知识库的删除操作(`delete_kb` 函数)、知识库向量存储的重建操作(`recreate_vector_store` 函数的 `output` 方法)、以及知识库迁移操作中的向量库重建(`folder2db` 函数)。这些场景均涉及到需要先清除知识库中现有的向量数据,再进行后续的操作,确保知识库的数据状态是最新的。
***
### FunctionDef drop_kb(self)
**drop_kb**: 此函数的功能是删除知识库。
**参数**: 此函数不接受任何外部参数。
**代码描述**: `drop_kb` 方法是 `KBService` 类的一个成员方法,负责实现知识库的删除操作。该方法首先调用 `do_drop_kb` 方法来执行删除知识库的具体逻辑。`do_drop_kb` 方法是一个可由子类实现的方法,用于在删除知识库之前执行特定的逻辑,比如清理相关资源等。接着,`drop_kb` 方法调用 `delete_kb_from_db` 函数,该函数从数据库中删除指定名称的知识库。`delete_kb_from_db` 函数接受一个知识库名称作为参数,并返回一个布尔值,表示操作是否成功。最后,`drop_kb` 方法返回 `delete_kb_from_db` 函数的返回值,作为删除操作的最终状态。
**注意**:
- 在调用 `drop_kb` 方法之前,应确保知识库名称已正确设置在 `KBService` 实例的 `kb_name` 属性中。
- `do_drop_kb` 方法在 `KBService` 类中默认不执行任何操作,具体的删除逻辑需要在子类中根据实际需求实现。
- 删除知识库的操作不会自动提交数据库事务。调用 `drop_kb` 方法的代码需要根据实际情况决定是否提交事务。
**输出示例**: 由于 `drop_kb` 方法返回的是 `delete_kb_from_db` 函数的返回值,而该函数始终返回 `True`,因此在成功执行删除操作后,`drop_kb` 方法的返回值将为 `True`
在项目中,`drop_kb` 方法的调用场景包括但不限于通过 API 删除知识库、在自动化测试中验证知识库删除功能等。例如,在 `delete_kb` API 方法中,会根据提供的知识库名称创建 `KBService` 实例,并调用其 `drop_kb` 方法来删除知识库。此外,自动化测试 `test_delete_db``test_drop_kb` 也通过调用 `drop_kb` 方法来测试知识库的删除功能是否正常工作。这些调用示例说明了 `drop_kb` 方法在知识库管理功能中的重要作用,以及如何在不同场景下使用该方法来实现知识库的删除。
***
### FunctionDef _docs_to_embeddings(self, docs)
**_docs_to_embeddings**: 该函数的功能是将文档对象列表转化为向量存储系统可以接受的参数格式。
**参数**:
- `docs`: 需要转化为向量的文档对象列表,类型为`List[Document]`
**代码描述**:
`_docs_to_embeddings`函数是`KBService`类的一个私有方法,用于将文档对象列表转化为向量形式,以便后续存储或查询操作。该函数内部调用了`embed_documents`函数,传入文档对象列表`docs`、嵌入模型`embed_model`以及一个标志位`to_query``embed_model``KBService`类的一个属性,指定了用于文档向量化的模型。`to_query`参数在此处被设置为`False`,意味着向量化的结果不是用于查询操作。`embed_documents`函数负责实际的文档向量化过程,包括文本提取、向量化以及元数据处理,最终返回一个包含向量化结果的字典。
**注意**:
- 确保传入的`docs`参数是有效的文档对象列表,且每个文档对象都应包含必要的内容和元数据。
- `_docs_to_embeddings`函数依赖于`embed_model`属性指定的嵌入模型,因此在使用前应确保嵌入模型已正确设置。
- 该函数设计为KBService类的内部方法,不建议直接从类外部调用。
**输出示例**:
调用`_docs_to_embeddings(docs=[Document1, Document2])`可能会返回如下字典:
```python
{
"texts": ["文档1的内容", "文档2的内容"],
"embeddings": [[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]],
"metadatas": [{"title": "文档1标题"}, {"title": "文档2标题"}]
}
```
这个字典包含了文档的原始内容(`texts`)、向量化结果(`embeddings`)以及文档的元数据信息(`metadatas`),为后续的文档存储或查询操作提供了必要的数据结构。
***
### FunctionDef add_doc(self, kb_file, docs)
**add_doc**: 此函数用于向知识库添加文件。
**参数**:
- `kb_file`: `KnowledgeFile`类型的对象,表示要添加到知识库的文件。
- `docs`: `Document`类型的列表,默认为空列表。这些是要添加到知识库的文档。
- `**kwargs`: 接收额外的关键字参数,这些参数将传递给内部方法。
**代码描述**:
`add_doc`函数首先检查`docs`参数是否已提供。如果提供了`docs`,则将`custom_docs`标志设置为`True`,并为每个文档的元数据中添加`source`字段,其值为`kb_file`的文件名。如果没有提供`docs`,则调用`kb_file``file2text`方法将文件内容转换为文档列表,并将`custom_docs`标志设置为`False`
接下来,如果`docs`列表不为空,函数会尝试将每个文档的`source`字段中的绝对路径转换为相对于`self.doc_path`的相对路径。然后,调用`delete_doc`方法删除知识库中与`kb_file`相对应的旧文档。
随后,调用`do_add_doc`方法将文档添加到知识库中,该方法需要在子类中具体实现。`do_add_doc`方法的执行结果(`doc_infos`)将用于调用`add_file_to_db`函数,将文件信息添加到数据库中。此过程中,会根据`custom_docs`标志和文档数量更新数据库中的文件条目。
最后,函数根据操作结果返回一个状态值,如果文档列表为空,则直接返回`False`
**注意**:
- 在使用`add_doc`函数时,需要确保传入的`kb_file`对象正确实例化,并且其代表的文件确实存在。
- 如果提供了`docs`参数,则这些文档将直接添加到知识库中,不会对文件内容进行向量化处理。
- `**kwargs`参数提供了额外的灵活性,允许在不修改`add_doc`函数签名的情况下,传递额外的参数给内部方法。
**输出示例**:
由于`add_doc`函数的主要作用是执行添加操作,其返回值主要用于指示操作是否成功。例如,如果文件成功添加到知识库并更新数据库,函数可能返回`True`。如果在添加过程中遇到任何问题,可能返回`False`
***
### FunctionDef delete_doc(self, kb_file, delete_content)
**delete_doc**: 此函数的功能是从知识库中删除指定的文件。
**参数**:
- `kb_file`: `KnowledgeFile`类型的对象,表示需要从知识库中删除的文件。
- `delete_content`: 布尔值,指定是否从磁盘中删除文件内容。默认为`False`,即不删除文件内容。
- `**kwargs`: 接收额外的关键字参数,这些参数将传递给`do_delete_doc`方法。
**代码描述**:
`delete_doc`函数首先调用`do_delete_doc`方法,该方法需要在子类中根据具体逻辑进行实现,用于执行删除文件的自定义操作。随后,函数调用`delete_file_from_db`函数,从数据库中删除指定的知识文件,并更新相关知识库的文件计数。如果`delete_content`参数为`True`,且文件在磁盘上存在,则使用`os.remove`方法从磁盘中删除该文件。最后,函数返回删除操作的状态,该状态由`delete_file_from_db`函数的返回值决定。
**注意**:
- 在调用`delete_doc`函数之前,需要确保传入的`kb_file`对象正确实例化,且其代表的文件确实存在于知识库中。
- `delete_content`参数应谨慎使用,因为一旦从磁盘删除文件内容,该操作是不可逆的。
- `**kwargs`参数提供了额外的灵活性,允许在不修改`delete_doc`函数签名的情况下,传递额外的参数给`do_delete_doc`方法。
**输出示例**:
由于`delete_doc`函数的主要作用是执行删除操作,其返回值主要用于指示操作是否成功。例如,如果文件成功从数据库和(可选的)磁盘中删除,函数可能返回`True`。如果在删除过程中遇到任何问题,根据`delete_file_from_db`函数的实现,可能返回`False`或抛出异常。
***
### FunctionDef update_info(self, kb_info)
**update_info**: 此函数的功能是更新知识库的介绍信息。
**参数**:
- `kb_info`: 字符串类型,表示要更新的知识库介绍信息。
**代码描述**:
`update_info`函数主要用于更新知识库的介绍信息。它接收一个字符串参数`kb_info`,该参数包含了知识库的新介绍信息。函数首先将这个新的介绍信息赋值给`self.kb_info`,以更新当前知识库服务实例的介绍信息。随后,函数调用`add_kb_to_db`方法,将更新后的知识库信息(包括知识库名称`self.kb_name`、介绍信息`self.kb_info`、向量库类型`self.vs_type()`和嵌入模型`self.embed_model`)添加到数据库中。这里的`self.vs_type()`是通过调用`vs_type`方法获取的,该方法需要在`KBService`类的子类中具体实现,以返回正确的向量库类型。
`add_kb_to_db`函数负责将知识库信息添加或更新到数据库中。如果数据库中不存在具有相同名称的知识库,则会创建一个新的知识库记录;如果已存在,则更新该知识库的介绍信息、向量库类型和嵌入模型信息。`add_kb_to_db`函数最终返回一个布尔值,表示操作是否成功。
**注意**:
- 在调用`update_info`函数之前,确保知识库名称`self.kb_name`已经正确设置,因为它是更新数据库记录的关键标识。
- `vs_type`方法需要在`KBService`类的子类中实现,以确保能够提供正确的向量库类型信息。
- 调用`update_info`函数后,需要根据`add_kb_to_db`函数的返回值来判断更新操作是否成功。
**输出示例**:
由于`update_info`函数的返回值是由`add_kb_to_db`函数决定的,因此在成功更新知识库信息后,`update_info`函数将返回`True`。例如,如果更新操作成功完成,函数调用将返回`True`
***
### FunctionDef update_doc(self, kb_file, docs)
**update_doc**: 此函数用于使用指定的文件更新知识库中的文档。
**参数**:
- `kb_file`: `KnowledgeFile`类型的对象,表示要更新的知识库文件。
- `docs`: `Document`类型的列表,表示自定义的文档列表。默认为空列表。
- `**kwargs`: 接收额外的关键字参数,这些参数将传递给内部的`delete_doc``add_doc`方法。
**代码描述**:
`update_doc`函数首先检查`kb_file`指定的文件路径是否存在。如果文件存在,则调用`delete_doc`方法删除知识库中与该文件对应的旧文档。随后,调用`add_doc`方法将新的文档添加到知识库中。如果在调用过程中指定了`docs`参数,则这些自定义文档将被添加到知识库中,并且数据库中对应的条目会被标记为`custom_docs=True`,表示这些文档是自定义的。如果没有指定`docs`,则`add_doc`方法会根据`kb_file`中的文件内容生成文档并添加到知识库中。
**注意**:
- 在使用`update_doc`函数时,需要确保传入的`kb_file`对象已正确初始化,并且其代表的文件确实存在于磁盘上。
- 如果提供了`docs`参数,则这些文档将直接添加到知识库中,而不会对`kb_file`中的文件内容进行再次处理或向量化。
- `**kwargs`参数提供了额外的灵活性,允许在不修改`update_doc`函数签名的情况下,传递额外的参数给`delete_doc``add_doc`方法。
**输出示例**:
由于`update_doc`函数的主要作用是更新知识库中的文档,其没有直接的返回值。但是,通过调用`delete_doc``add_doc`方法,可以间接获得关于删除和添加操作的状态。例如,如果文档成功删除并添加到知识库,则这两个方法可能会返回操作成功的状态值。如果在更新过程中遇到任何问题,根据这两个方法的实现,可能会返回错误信息或抛出异常。
在项目中,`update_doc`函数被`update_docs`方法调用,用于处理来自API请求的知识库文档更新操作。这包括从文件生成文档、处理自定义文档以及更新知识库中的文档向量等任务。通过这种方式,`update_doc`函数在知识库管理系统中扮演了重要的角色,确保知识库内容的准确性和最新性。
***
### FunctionDef exist_doc(self, file_name)
**exist_doc**: 此函数用于检查指定的文件是否已存在于知识库中。
**参数**:
- `file_name`: 字符串类型,表示要检查是否存在的文件名。
**代码描述**:
`exist_doc` 函数通过接收一个文件名 (`file_name`) 作为参数,来检查该文件是否已经存在于知识库中。函数内部首先创建了一个 `KnowledgeFile` 对象,该对象包含了知识库的名称 (`kb_name`) 和文件名 (`file_name`)。然后,调用 `file_exists_in_db` 函数,将这个 `KnowledgeFile` 对象传递给它,以检查数据库中是否存在与之对应的文件记录。如果 `file_exists_in_db` 函数返回 `True`,表示文件已存在于数据库中;如果返回 `False`,则表示文件不存在。
**注意**:
- 确保传入的 `file_name` 是正确的文件名,并且该文件名不应包含路径信息,只有文件名本身。
- `exist_doc` 函数依赖于 `KnowledgeFile` 类和 `file_exists_in_db` 函数,因此在使用前需要确保这些依赖项正确实现且可用。
- 此函数不会对数据库进行任何修改操作,仅用于检查文件的存在性。
**输出示例**:
假设知识库中已存在名为 "example.pdf" 的文件,当调用 `exist_doc("example.pdf")` 时,函数将返回 `True`。如果文件 "new_document.txt" 不存在于知识库中,调用 `exist_doc("new_document.txt")` 将返回 `False`
***
### FunctionDef list_files(self)
**list_files**: 此函数的功能是列出属于特定知识库的所有文件名。
**参数**: 此函数不接受任何外部参数,但依赖于类实例中的`kb_name`属性。
**代码描述**: `list_files`函数是`KBService`类的一个方法,它的主要作用是调用`list_files_from_db`函数,以获取属于特定知识库的所有文件名。在调用`list_files_from_db`时,它传递了`self.kb_name`作为参数,这意味着它将列出与当前实例的`kb_name`属性相匹配的所有文件名。`list_files_from_db`函数进一步通过数据库会话查询`KnowledgeFileModel`模型,筛选出`kb_name`字段与给定知识库名称相匹配的记录,并返回这些记录的文件名列表。
**注意**:
- 确保在调用`list_files`方法之前,`KBService`类的实例已正确初始化,并且`kb_name`属性已经被赋予了一个有效的知识库名称。
- 此方法的执行结果直接依赖于数据库中的数据,因此确保数据库已正确填充了相关知识库的文件信息。
- 由于`list_files_from_db`函数使用了`ilike`方法进行查询,查询对大小写不敏感,但这可能会在某些情况下影响性能。
**输出示例**: 假设当前实例的`kb_name`属性值为"GeneralKB",并且数据库中存在属于"GeneralKB"的文件名为"document1.pdf"和"report2.docx"的文件,那么调用`list_files`方法将返回以下列表:
```
["document1.pdf", "report2.docx"]
```
此方法在项目中的使用场景包括但不限于获取知识库文件列表以供进一步处理,如在`get_kb_file_details`方法中获取文件列表以合并文件夹和数据库中的文件信息,在`folder2db`方法中用于确定需要更新或增量添加到数据库的文件列表,以及在测试用例中验证迁移、增量更新或数据库清理操作的正确性。
***
### FunctionDef count_files(self)
**count_files**: 此函数的功能是统计指定知识库中的文件数量。
**参数**: 此函数不直接接受任何参数,但它依赖于`KBService`类的实例属性。
**代码描述**: `count_files`方法是`KBService`类的一个成员方法,它的主要作用是调用`count_files_from_db`函数来统计特定知识库中的文件数量。在调用`count_files_from_db`时,它传递了`self.kb_name`作为参数,其中`self.kb_name``KBService`类实例化时指定的知识库名称。这意味着`count_files`方法将返回该知识库中的文件总数。`count_files_from_db`函数通过数据库查询来实现此功能,具体地,它使用ORM模型`KnowledgeFileModel`来过滤特定知识库的文件,并计算满足条件的文件数量。
**注意**: 在使用`count_files`方法时,需要确保`KBService`类的实例已正确初始化,且`kb_name`属性已经被赋予了正确的知识库名称。此外,由于`count_files_from_db`函数使用了不区分大小写的匹配来查找知识库名称,因此在指定知识库名称时应注意其准确性,以避免统计结果的偏差。
**输出示例**: 假设存在一个名为"DefaultKB"的知识库,且其中包含10个文件。如果`KBService`类的实例的`kb_name`属性被设置为"DefaultKB",那么调用其`count_files`方法将返回整数`10`,表示"DefaultKB"知识库中的文件数量为10。
通过`count_files`方法,可以方便地获取特定知识库中的文件总数,这对于知识库管理和数据分析等功能是非常有用的。此方法的设计充分考虑了模块化和代码重用,通过与`count_files_from_db`函数的交互,实现了功能的高效执行。
***
### FunctionDef search_docs(self, query, top_k, score_threshold)
**search_docs**: 此函数的功能是在知识库中搜索与查询字符串最相关的文档。
**参数**:
- `query`: 字符串类型,用户的搜索查询。
- `top_k`: 整型,默认值为`VECTOR_SEARCH_TOP_K`,表示返回的最相关文档的最大数量。
- `score_threshold`: 浮点型,默认值为`SCORE_THRESHOLD`,表示只有得分高于此阈值的文档才会被返回。
**代码描述**:
`search_docs`方法是`KBService`类中的一个方法,旨在提供一个高层次的接口,用于执行知识库的搜索操作。该方法首先调用`do_search`方法,根据用户提供的查询字符串`query`,返回的最大文档数量`top_k`,以及得分阈值`score_threshold`,执行搜索操作。`do_search`方法负责具体的搜索逻辑,包括查询处理、文档检索和得分计算等。`search_docs`方法通过调用`do_search`,获取搜索结果后,直接将这些结果返回给调用者。这样的设计使得`search_docs`方法可以专注于处理搜索操作的高层次逻辑,如参数的默认值设置,而具体的搜索逻辑则由`do_search`方法负责。
**注意**:
- 在使用`search_docs`方法时,需要注意`query`参数不能为空,且`top_k``score_threshold`参数应根据实际需求合理设置,以确保搜索结果的相关性和精确度。
- 该方法返回的是一个文档列表,每个文档都是搜索结果中与查询字符串相关性较高的文档。调用方需要根据自己的需求处理这些文档,例如展示给用户。
**输出示例**:
```python
[
Document(id="1", title="文档标题1", content="文档内容1"),
Document(id="2", title="文档标题2", content="文档内容2"),
...
]
```
在项目中,`search_docs`方法被多个测试用例调用,包括`test_faiss_kb.py``test_milvus_db.py``test_pg_db.py`中的`test_search_db`函数。这些测试用例通过调用`search_docs`方法,验证不同知识库实现下的搜索功能是否正常工作,确保搜索结果的数量大于0。这表明`search_docs`方法是项目中用于执行知识库搜索操作的关键接口之一,其正确性和性能对于整个知识库服务的质量至关重要。
***
### FunctionDef get_doc_by_ids(self, ids)
**get_doc_by_ids**: 此函数的功能是根据提供的文档ID列表检索对应的文档对象列表。
**参数**:
- ids: 一个字符串列表,包含需要检索的文档的ID。
**代码描述**:
`get_doc_by_ids` 函数是 `KBService` 类的一个方法,旨在根据给定的文档ID列表检索相应的文档对象。当前实现中,此函数返回一个空列表,这意味着它需要进一步的实现来完成其功能。在项目中,此函数被其他对象调用,以实现特定的业务逻辑。
例如,在 `list_docs` 方法中,通过文件名或元数据检索文档信息后,会使用 `get_doc_by_ids` 方法根据检索到的文档ID获取具体的文档对象。这一过程表明,`get_doc_by_ids` 方法是连接数据库检索与文档对象处理流程的关键一环。
另一个调用示例是在 `summary_doc_ids_to_vector_store` 函数中,该函数根据文档ID列表,使用 `get_doc_by_ids` 方法获取文档对象,进而进行文档摘要和向量存储的相关处理。这显示了 `get_doc_by_ids` 在文档处理和分析流程中的重要作用。
**注意**:
- 当前函数实现返回一个空列表,这表明需要根据实际的数据库或存储结构来完成此函数的具体实现。
- 在使用此函数时,需要确保传入的ID列表中的每个ID都是有效的,并且能够在数据库或存储系统中找到对应的文档。
**输出示例**:
假设函数已经实现,并且数据库中存在对应的文档,那么对于输入 `["doc1", "doc2"]`,一个可能的返回值示例为:
```python
[
Document(id="doc1", title="文档1标题", content="文档1内容"),
Document(id="doc2", title="文档2标题", content="文档2内容")
]
```
这个示例展示了函数在成功检索到文档后可能返回的文档对象列表的结构。
***
### FunctionDef del_doc_by_ids(self, ids)
**del_doc_by_ids**: 该函数的功能是根据提供的文档ID列表删除对应的文档。
**参数**:
- ids: 一个字符串列表,包含需要删除的文档的ID。
**代码描述**:
`del_doc_by_ids` 函数接受一个字符串列表作为参数,这个列表包含了需要被删除的文档的ID。函数的主体抛出了一个`NotImplementedError`异常,这表明该函数是一个抽象方法,需要在子类中被具体实现。在当前的上下文中,这个设计模式通常用于定义一个接口,强制继承该类的子类实现这个方法。
在项目中,`del_doc_by_ids` 函数被`update_doc_by_ids` 方法调用。`update_doc_by_ids` 方法的功能是更新给定ID的文档。如果传入的文档ID对应的文档不存在或者文档的`page_content`为空,则会调用`del_doc_by_ids`方法来删除这些文档。这种设计体现了一种先清理再更新的策略,确保在添加或更新文档之前,移除所有无效或不再需要的文档。
**注意**:
- `del_doc_by_ids` 方法是一个抽象方法,调用时需要注意在具体的子类中实现其功能。
- 在使用`del_doc_by_ids`方法之前,确保已经正确处理和筛选了需要删除的文档ID列表,避免误删除重要文档。
- 考虑到该方法可能会影响数据库或存储中的数据持久性,实现时应当谨慎处理异常和错误,确保数据的一致性和完整性。
***
### FunctionDef update_doc_by_ids(self, docs)
**update_doc_by_ids**: 此函数的功能是根据文档ID更新或删除文档。
**参数**:
- `docs`: 一个字典,键为文档ID,值为`Document`对象。
**代码描述**:
`update_doc_by_ids` 方法接收一个包含文档ID和对应`Document`对象的字典作为参数。此方法首先调用`del_doc_by_ids`方法,尝试删除所有传入的文档ID对应的文档。随后,方法初始化一个空列表用于存储有效的文档对象和对应的ID。接着,遍历传入的字典,检查每个`Document`对象的有效性:如果`Document`对象为`None`或其`page_content`属性为空(或仅包含空白字符),则该文档被视为无效,不会被添加到有效文档列表中。对于有效的文档,其ID和对象分别被添加到之前初始化的列表中。最后,调用`do_add_doc`方法,将有效的文档重新添加到知识库中。此过程实现了对指定ID的文档进行更新或删除的功能。
**注意**:
- 在调用此方法之前,确保传入的`docs`参数格式正确,即键为文档ID,值为对应的`Document`对象。
- 此方法假设`del_doc_by_ids``do_add_doc`方法已在子类中具体实现。因此,在使用`update_doc_by_ids`方法之前,需要确保这两个方法能够正常工作。
- 由于此方法内部调用了删除和添加文档的操作,可能会对知识库的数据产生重大影响。因此,在生产环境中使用时,应确保充分测试,并考虑实施适当的错误处理和日志记录机制,以便追踪操作结果。
**输出示例**:
调用`update_doc_by_ids`方法总是返回`True`,表示更新操作已被执行。然而,实际上是否成功更新或删除文档,需要依赖于`del_doc_by_ids``do_add_doc`方法的具体实现及其返回值。
***
### FunctionDef list_docs(self, file_name, metadata)
**list_docs**: 此函数的功能是通过文件名或元数据检索文档。
**参数**:
- `file_name`: 字符串类型,可选参数,默认为None,指定要查询的文件名称。
- `metadata`: 字典类型,可选参数,默认为空字典,用于根据文档的元数据进行过滤查询。
**代码描述**: `list_docs` 函数首先调用 `list_docs_from_db` 函数,根据提供的知识库名称、文件名和元数据参数从数据库中检索文档信息。检索到的文档信息是一个包含文档ID和元数据的字典列表。随后,函数遍历这个列表,对每个文档ID调用 `get_doc_by_ids` 方法获取具体的文档对象。如果文档对象非空,则创建一个 `DocumentWithVSId` 实例,并将其添加到结果列表中。这个过程允许函数根据文件名或元数据过滤条件,返回一组经过向量化处理的文档对象。
**注意**:
- 在调用此函数时,应确保提供的知识库名称是有效的,以便正确检索文档。
- 默认情况下,`metadata` 参数为空字典,如果需要根据特定元数据过滤文档,应显式传入相应的键值对。
- 函数处理空文档对象的情况,即如果 `get_doc_by_ids` 方法返回空,则当前迭代会跳过,不会向结果列表中添加任何对象。
**输出示例**:
假设数据库中存在两条记录,其字段值分别为:
- id: "docA", metadata: {"author": "张三", "year": "2021"}
- id: "docB", metadata: {"author": "李四", "year": "2022"}
调用 `list_docs(file_name="文件A.pdf")` 可能返回以下列表:
```python
[
DocumentWithVSId(id="docA", metadata={"author": "张三", "year": "2021"}, score=3.0),
DocumentWithVSId(id="docB", metadata={"author": "李四", "year": "2022"}, score=3.0)
]
```
此输出示例展示了函数如何根据指定的文件名返回该文件下所有文档的向量化处理对象列表。
***
### FunctionDef do_create_kb(self)
**do_create_kb**: 此函数的功能是创建知识库的子类实现逻辑。
**参数**: 此函数没有参数。
**代码描述**: `do_create_kb` 函数是 `KBService` 类中的一个方法,设计用于被子类重写,以实现特定的知识库创建逻辑。在 `KBService` 类的上下文中,`do_create_kb` 方法提供了一个扩展点,允许开发者在不修改 `create_kb` 方法逻辑的情况下,添加或修改知识库创建时的行为。具体来说,当 `create_kb` 方法被调用时,它首先检查指定的文档路径是否存在,如果不存在则创建该路径。之后,`create_kb` 方法会调用 `do_create_kb`,这一步骤是预留给开发者的扩展点,允许在创建知识库的基础流程中插入自定义逻辑。完成这些步骤后,`create_kb` 方法会继续执行,将知识库信息添加到数据库中,并返回操作的状态。
在实际使用中,开发者应该通过继承 `KBService` 类并重写 `do_create_kb` 方法来实现特定的知识库创建逻辑。这种设计模式提高了代码的可扩展性和可维护性,允许不同的知识库实现具有不同的创建逻辑,而不必修改公共的 `create_kb` 方法。
**注意**: `do_create_kb` 方法默认不执行任何操作,因为它是设计给子类用于重写的。如果在不重写此方法的情况下直接使用,它将不会对知识库的创建过程产生任何影响。因此,开发者在使用 `KBService` 类时,需要根据具体需求重写 `do_create_kb` 方法,以实现所需的知识库创建逻辑。
***
### FunctionDef list_kbs_type
**list_kbs_type**: 此函数的功能是列出所有知识库类型。
**参数**: 此函数不接受任何参数。
**代码描述**: `list_kbs_type` 函数的主要作用是从一个名为 `kbs_config` 的字典中获取所有的键,并将这些键作为一个列表返回。这里的 `kbs_config` 字典预期包含了不同知识库类型的配置信息,其中字典的键代表了各个知识库的类型。通过调用 `keys()` 方法,我们可以获取到一个包含所有键的视图,然后通过 `list()` 函数将这个视图转换成列表。这样,最终返回的就是一个包含所有知识库类型名称的列表。
**注意**: 使用此函数时,需要确保 `kbs_config` 字典已经被正确初始化并且包含了至少一个知识库类型的配置信息。如果 `kbs_config` 是空的,那么此函数将返回一个空列表。
**输出示例**:
假设 `kbs_config` 字典如下所示:
```python
kbs_config = {
"type1": {...},
"type2": {...},
"type3": {...}
}
```
调用 `list_kbs_type()` 函数将返回:
```python
["type1", "type2", "type3"]
```
这表示当前配置中存在三种类型的知识库。
***
### FunctionDef list_kbs(cls)
**list_kbs**: 此函数的功能是从数据库中列出满足特定条件的知识库名称列表。
**参数**: 此函数不接受任何外部参数。
**代码描述**: `list_kbs` 函数是 `KBService` 类的一个方法,它通过调用 `list_kbs_from_db` 函数来实现其功能。`list_kbs_from_db` 函数负责从数据库中检索并返回满足特定条件(如文件数量大于某个最小值)的知识库名称列表。`list_kbs` 函数作为一个接口,简化了从数据库获取知识库名称列表的过程,使得其他函数或服务可以轻松地获取这些信息而无需直接与数据库交互。
**注意**:
- `list_kbs` 函数的实现依赖于 `list_kbs_from_db` 函数,因此在使用 `list_kbs` 函数之前,需要确保 `list_kbs_from_db` 函数已正确实现并能够成功从数据库中检索信息。
- 此函数不接受任何参数,因此调用时不需要提供额外信息。它将返回数据库中所有符合条件的知识库名称列表,具体的筛选条件(如文件数量的最小值)是在 `list_kbs_from_db` 函数内部定义的。
**输出示例**: 假设数据库中存在多个知识库,且根据 `list_kbs_from_db` 函数的筛选条件,有两个知识库满足条件。那么 `list_kbs` 函数的返回值可能如下:
```
['知识库A', '知识库B']
```
这表示在满足特定条件下,数据库中的知识库A和知识库B被成功检索并返回。
通过 `list_kbs` 函数,`KBService` 类为其他服务或函数提供了一个简洁的接口来获取数据库中的知识库名称列表,进一步促进了项目中不同组件之间的解耦和协作。
***
### FunctionDef exists(self, kb_name)
**exists**: 此函数的功能是检查指定名称的知识库是否存在。
**参数**:
- `kb_name`: 可选参数,字符串类型,表示要检查的知识库名称。如果未提供,则使用对象自身的`kb_name`属性。
**代码描述**:
`exists`函数用于判断给定名称的知识库是否存在于数据库中。函数首先检查是否提供了`kb_name`参数,如果没有提供,则使用对象自身的`kb_name`属性作为要检查的知识库名称。然后,函数调用`kb_exists`函数,传入知识库名称作为参数,`kb_exists`函数会查询数据库,检查是否存在具有该名称的知识库。如果存在,则`kb_exists`函数返回`True`,否则返回`False`。最终,`exists`函数返回`kb_exists`的返回值,即表示知识库是否存在的布尔值。
**注意**:
- 在调用`exists`函数时,如果已知知识库名称,可以通过`kb_name`参数直接提供。如果不提供`kb_name`参数,则默认使用对象自身的`kb_name`属性。
- 确保在调用此函数之前,对象的`kb_name`属性已正确设置,以避免查询错误的知识库名称。
- 此函数的返回值是布尔类型,可以直接用于条件判断,例如在决定是否创建新知识库或执行其他依赖于知识库存在性的操作时。
**输出示例**:
假设数据库中存在名为"技术文档库"的知识库,调用`exists(kb_name="技术文档库")`将返回`True`。如果查询一个不存在的知识库名称,如`exists(kb_name="不存在的库")`,则会返回`False`
在项目中,`exists`函数被多个场景调用,包括在重建向量存储、生成知识库摘要向量存储、向知识库添加文档前的存在性检查等。这些调用场景表明,`exists`函数是知识库管理流程中的一个重要环节,用于确保操作的目标知识库确实存在,从而保证数据的一致性和操作的有效性。
***
### FunctionDef vs_type(self)
**vs_type**: 此函数的功能是获取知识库的类型。
**参数**: 此函数没有参数。
**代码描述**: `vs_type` 函数设计用于返回一个字符串,该字符串代表知识库的类型。在当前的代码实现中,函数体是空的,这意味着需要由继承`KBService`类的子类来具体实现`vs_type`方法,以返回正确的知识库类型。在项目中,`vs_type`函数被`create_kb``update_info`两个方法调用。这两个方法分别用于创建和更新知识库,它们通过调用`vs_type`来获取知识库的类型,并将这个类型信息作为参数之一传递给`add_kb_to_db`函数,以便将知识库的相关信息添加到数据库中。这表明`vs_type`函数在知识库创建和更新流程中扮演着关键的角色,确保了知识库类型的信息能够正确地存储和管理。
**注意**: 虽然当前`vs_type`函数的实现为空,但在实际使用时,开发者需要在继承`KBService`类的子类中重写此方法,以返回具体的知识库类型。这是因为不同类型的知识库可能需要不同的处理逻辑和存储方式,因此正确地识别和返回知识库的类型对于知识库的管理至关重要。
***
### FunctionDef do_init(self)
**do_init**: 此函数的功能是初始化知识库服务。
**参数**: 此函数没有参数。
**代码描述**: `do_init` 函数是 `KBService` 类的一个方法,目前其内部实现为空(即使用 `pass` 关键字),这意味着它是一个待实现的功能或者是一个占位符。在 `KBService` 类的构造函数 `__init__` 中,`do_init` 被调用,这表明在创建 `KBService` 对象的过程中,`do_init` 函数被设计为完成知识库服务的初始化工作。具体来说,`__init__` 函数首先设置了知识库的名称、知识库信息、嵌入模型、知识库路径和文档路径等属性,然后调用 `do_init` 来进行进一步的初始化操作。虽然当前 `do_init` 函数的实现为空,但它的存在暗示了在知识库服务初始化过程中可能需要执行的额外步骤或者特定的初始化逻辑,这些逻辑在未来可以在 `do_init` 函数中实现。
**注意**: 虽然当前 `do_init` 函数内部为空,但开发者在未来可能会在此函数中添加具体的初始化逻辑。因此,在修改或扩展 `KBService` 类的功能时,应当考虑到 `do_init` 函数的潜在作用和可能的实现内容。此外,调用 `do_init` 的方式表明它是类初始化过程的一部分,因此任何对 `do_init` 的修改都应当谨慎进行,以避免影响 `KBService` 类对象的正常创建和初始化。
***
### FunctionDef do_drop_kb(self)
**do_drop_kb**: 此函数的功能是执行删除知识库的具体逻辑。
**参数**: 此函数不接受任何参数。
**代码描述**: `do_drop_kb` 函数是 `KBService` 类中定义的一个方法,用于实现删除知识库的具体逻辑。在该方法的当前实现中,它仅包含一个 `pass` 语句,这意味着它是一个空方法,需要由继承 `KBService` 类的子类来具体实现删除知识库的逻辑。此方法的设计初衷是允许不同的知识库子类根据自己的需求实现具体的删除逻辑,从而提供了一种灵活的方式来扩展知识库服务的功能。
在项目中,`do_drop_kb` 方法被 `drop_kb` 方法调用。`drop_kb` 方法的主要职责是删除知识库,它首先调用 `do_drop_kb` 方法来执行特定的删除逻辑,然后调用 `delete_kb_from_db` 函数来从数据库中删除知识库,最后返回操作的状态。这种设计模式允许在删除知识库的过程中插入额外的逻辑,而不仅仅是从数据库中删除记录,从而提供了更大的灵活性和可扩展性。
**注意**: 由于 `do_drop_kb` 方法在 `KBService` 类中默认不执行任何操作,因此在使用 `KBService` 类或其子类进行知识库删除操作时,需要确保根据具体需求重写 `do_drop_kb` 方法,以实现所需的删除逻辑。此外,开发者在扩展或继承 `KBService` 类时,应当注意保持 `do_drop_kb` 方法与知识库删除流程的一致性和完整性。
***
### FunctionDef do_search(self, query, top_k, score_threshold)
**do_search**: 此函数的功能是执行知识库的搜索操作。
**参数**:
- `query`: 字符串类型,表示搜索查询的内容。
- `top_k`: 整型,指定返回的最相关文档的最大数量。
- `score_threshold`: 浮点型,设定的分数阈值,只有得分高于此阈值的文档才会被返回。
**代码描述**:
`do_search`函数是`KBService`类的一个方法,旨在根据给定的查询参数,在知识库中搜索并返回最相关的文档。该方法接受三个参数:`query`为用户的查询字符串,`top_k`限定了返回结果的数量,而`score_threshold`则是过滤结果的得分阈值,只有当文档的相关性得分超过这个阈值时,该文档才会被考虑为搜索结果的一部分。函数返回一个列表,列表中的每个元素是一个元组,包含一个文档和该文档的得分。
在项目中,`do_search`方法被`search_docs`方法调用。`search_docs`方法同样位于`KBService`类中,它提供了一个更高层次的接口,用于执行搜索操作。`search_docs`方法通过调用`do_search`,利用其提供的底层搜索逻辑,然后返回搜索结果。这种设计允许`do_search`方法专注于执行搜索逻辑,而`search_docs`方法则处理与搜索相关的其他逻辑,如参数的默认值设置等。
**注意**:
- `do_search`方法是一个抽象方法,意味着它需要在子类中被具体实现。在不同的知识库实现中,根据具体的搜索需求和知识库的结构,`do_search`方法的实现可能会有所不同。
- 调用此方法时,需要确保传入的参数类型和值是正确的,特别是`top_k``score_threshold`,这两个参数直接影响搜索结果的质量和数量。
- 由于`do_search`方法返回的是包含文档和得分的元组列表,因此调用方需要根据自己的需求处理这些结果,例如展示给用户等。
***
### FunctionDef do_add_doc(self, docs)
**do_add_doc**: 此函数的功能是向知识库添加文档。
**参数**:
- `docs`: 需要添加到知识库中的文档列表,类型为`List[Document]`
- `**kwargs`: 接受可变数量的关键字参数,用于扩展或自定义功能。
**代码描述**:
`do_add_doc`函数是`KBService`类的一个方法,设计用于将文档添加到知识库中。该方法接受一个文档列表`docs`作为参数,每个文档都是`Document`类型的实例,此外还可以接受多个关键字参数`**kwargs`,以提供更多的灵活性和扩展性。函数体内的具体实现逻辑需要由子类根据具体需求来完成,因为在基类中,此方法仅以`pass`占位,暗示这是一个待子类实现的抽象方法。
在项目中,`do_add_doc`方法被`add_doc``update_doc_by_ids`两个方法调用。`add_doc`方法用于向知识库添加文件,如果指定了`docs`参数,则直接调用`do_add_doc`方法添加这些文档,而不再进行文本向量化处理;`update_doc_by_ids`方法则是用于根据文档ID更新知识库中的文档,如果文档内容有效,则会调用`do_add_doc`方法重新添加这些文档。这两种调用方式都体现了`do_add_doc`方法在知识库文档管理中的核心作用,即作为一个接口,允许不同的上层逻辑向知识库中添加或更新文档。
**注意**:
- 由于`do_add_doc`方法在基类中没有具体实现,因此在使用时需要确保其子类已经根据具体的业务逻辑重写了这个方法。
- 调用此方法时,需要确保传入的`docs`参数是一个`Document`类型的实例列表,且每个实例都应该包含了要添加到知识库的文档信息。
- 通过`**kwargs`参数,可以灵活地为方法传入额外的参数,但使用时应注意检查子类实现中对这些参数的处理逻辑,以避免出现意外的行为。
***
### FunctionDef do_delete_doc(self, kb_file)
**do_delete_doc**: 此函数的功能是从知识库中删除指定的文档。
**参数**:
- `kb_file`: 表示要删除的知识库文件的KnowledgeFile对象。
**代码描述**: `do_delete_doc`函数是KBService类中用于删除知识库中文档的方法。它接收一个KnowledgeFile类型的参数`kb_file`,该参数封装了需要删除的文件的相关信息。此函数的实现需要子类根据具体逻辑进行重写。在当前的实现中,函数体内部仅包含一个`pass`语句,意味着默认情况下此函数不执行任何操作。实际的删除逻辑应由继承KBService类的子类根据具体需求实现。
**注意**:
- 在使用`do_delete_doc`函数时,需要确保传入的`kb_file`参数正确实例化,且其代表的文件确实存在于知识库中。否则,可能无法正确执行删除操作。
- 由于`do_delete_doc`函数默认不执行任何操作,开发者需要在子类中重写此方法,添加具体的删除逻辑。
- 此函数通常与`delete_doc`方法配合使用。`delete_doc`方法调用`do_delete_doc`进行文件的删除操作,并根据参数决定是否从磁盘和数据库中删除文件内容。这意味着`do_delete_doc`负责执行删除操作的自定义部分,而`delete_doc`则处理更广泛的删除流程,包括可选的从磁盘删除文件和更新数据库状态。
***
### FunctionDef do_clear_vs(self)
**do_clear_vs**: 此函数的功能是从知识库删除全部向量子类实自己逻辑。
**参数**: 此函数不接受任何参数。
**代码描述**: `do_clear_vs` 函数是 `KBService` 类中的一个方法,其主要作用是在知识库服务中执行删除所有向量数据的前置逻辑。具体来说,该函数被设计为在删除向量库中所有内容之前,执行必要的清理或准备工作。然而,根据提供的代码片段,`do_clear_vs` 方法的实现目前为空(使用了 `pass` 语句),这意味着它没有执行任何操作。这可能表明该方法是为了未来可能的扩展而保留的,或者是等待进一步的实现。
在项目中,`do_clear_vs` 方法被 `clear_vs` 方法调用。`clear_vs` 方法的文档说明了其功能是“删除向量库中所有内容”。在执行具体的删除操作之前,`clear_vs` 首先调用 `do_clear_vs` 方法。这表明 `do_clear_vs` 方法的设计初衷是作为执行实际删除操作前的一个预处理步骤。在 `do_clear_vs` 方法调用之后,`clear_vs` 方法继续调用 `delete_files_from_db` 函数,传入知识库名称作为参数,来完成向量库中所有内容的删除操作,并返回操作的状态。
**注意**: 虽然当前 `do_clear_vs` 方法的实现为空,但在未来的开发中,如果需要在删除向量数据之前执行特定的逻辑(如日志记录、数据备份、权限检查等),可以在此方法中添加相应的代码。因此,开发者在使用或修改此方法时,应考虑到其在整个删除流程中的定位和作用,避免破坏已有的调用关系和逻辑顺序。
***
## ClassDef KBServiceFactory
**KBServiceFactory**: KBServiceFactory 类的功能是提供一个静态方法工厂,用于根据不同的参数创建并返回不同类型的知识库服务实例。
**属性**:该类没有定义属性,所有功能都通过静态方法实现。
**代码描述**
KBServiceFactory 类提供了三个静态方法,分别用于根据不同的条件获取知识库服务实例。
1. `get_service` 方法接受知识库名称(kb_name)、向量存储类型(vector_store_type)、嵌入模型名称(embed_model)作为参数。该方法首先会检查向量存储类型是否为字符串,如果是,则将其转换为 `SupportedVSType` 枚举类型。根据向量存储类型的不同,方法会动态导入并返回对应的知识库服务实例,如 FaissKBService、PGKBService、MilvusKBService 等。这些服务实例都继承自 KBService 基类,但具体实现根据向量存储的不同而有所差异。
2. `get_service_by_name` 方法接受知识库名称(kb_name)作为参数,通过调用数据库加载函数 `load_kb_from_db` 来获取知识库的向量存储类型和嵌入模型名称,然后调用 `get_service` 方法来获取对应的知识库服务实例。如果数据库中不存在该知识库,则返回 None。
3. `get_default` 方法不接受任何参数,直接返回一个默认向量存储类型为 `SupportedVSType.DEFAULT` 的知识库服务实例。
在项目中,KBServiceFactory 被多个模块调用,用于创建、删除、更新、搜索知识库中的文档,以及上传和下载文档等操作。例如,在 `knowledge_base_chat.py` 中,通过 KBServiceFactory 获取知识库服务实例来搜索知识库中的文档;在 `kb_api.py` 中,通过 KBServiceFactory 创建新的知识库或删除现有知识库。
**注意**
- 在使用 `get_service` 方法时,需要确保传入的向量存储类型是支持的类型之一,否则可能会抛出异常。
- `get_service_by_name` 方法依赖于数据库中的知识库配置信息,如果数据库中不存在指定的知识库名称,将返回 None。
- 默认情况下,`get_default` 方法返回的知识库服务实例使用的向量存储类型为 `SupportedVSType.DEFAULT`,具体实现可能会根据项目需求进行调整。
**输出示例**
由于 KBServiceFactory 类主要提供静态方法来获取知识库服务实例,而不直接产生输出,因此没有具体的输出示例。返回的知识库服务实例根据不同的向量存储类型,将具有不同的方法和属性,用于执行知识库的相关操作。
### FunctionDef get_service(kb_name, vector_store_type, embed_model)
**get_service**: `get_service` 函数用于根据知识库名称、向量存储类型和嵌入模型名称动态获取对应的知识库服务实例。
**参数**:
- `kb_name`: 知识库名称,类型为 `str`
- `vector_store_type`: 向量存储类型,可以是 `str` 类型的向量存储类型名称或 `SupportedVSType` 枚举类型。
- `embed_model`: 嵌入模型名称,默认值为 `EMBEDDING_MODEL`,类型为 `str`
**代码描述**:
此函数首先判断 `vector_store_type` 参数的类型,如果是字符串,则将其转换为 `SupportedVSType` 枚举类型。接着,根据向量存储类型的不同,动态导入并返回对应的知识库服务类的实例。支持的向量存储类型包括 FAISS、Milvus、Zilliz、PostgreSQL、Elasticsearch、ChromaDB 等,以及一个默认的向量存储类型。如果指定的向量存储类型为默认类型,则会根据 `model_config.kbs_config` 中的配置返回 MilvusKBService 实例。每种向量存储类型对应的知识库服务类都继承自 `KBService` 基类,并实现了相应的方法以支持知识库的操作。
**注意**:
- 在使用 `get_service` 函数时,需要确保传入的向量存储类型名称与 `SupportedVSType` 中定义的类型名称一致,否则可能会引发错误。
- 如果项目中新增了向量存储类型,需要在 `SupportedVSType` 枚举类中添加相应的类型,并在 `get_service` 函数中添加相应的逻辑以支持新的向量存储类型。
- 在调用此函数获取知识库服务实例后,可以使用该实例执行创建知识库、添加文档、搜索文档等操作。
**输出示例**:
由于 `get_service` 函数返回的是知识库服务实例,而不是具体的数据,因此没有直接的输出示例。返回的实例类型取决于传入的向量存储类型参数。例如,如果传入的向量存储类型为 `FAISS`,则函数将返回一个 `FaissKBService` 类的实例。
***
### FunctionDef get_service_by_name(kb_name)
**get_service_by_name**: 此函数的功能是根据知识库名称获取对应的知识库服务实例。
**参数**:
- `kb_name`: 知识库的名称,类型为字符串。
**代码描述**: `get_service_by_name` 函数首先调用 `load_kb_from_db` 函数,根据传入的知识库名称 `kb_name` 从数据库中加载知识库的信息,包括知识库的名称、向量库类型和嵌入模型名称。如果数据库中不存在指定名称的知识库,`load_kb_from_db` 将返回三个 `None` 值,此时 `get_service_by_name` 函数也将返回 `None`。如果成功从数据库中加载到知识库信息,`get_service_by_name` 函数将使用加载到的知识库名称、向量库类型和嵌入模型名称作为参数,调用 `KBServiceFactory.get_service` 方法,动态获取并返回对应的知识库服务实例。
**注意**:
- 在调用此函数之前,确保传入的知识库名称在数据库中存在,否则函数将返回 `None`
- 此函数依赖于 `load_kb_from_db` 函数从数据库中加载知识库信息,因此需要确保数据库连接正常且知识库信息已正确录入数据库。
- 返回的知识库服务实例类型取决于知识库的向量库类型,例如,如果向量库类型为 `FAISS`,则返回的实例将是 `FaissKBService` 类的实例。
**输出示例**:
假设数据库中存在一个名为 "技术文档库" 的知识库,其向量库类型为 "FAISS",嵌入模型名称为 "BERT",调用 `get_service_by_name("技术文档库")` 将返回一个 `FaissKBService` 类的实例,该实例用于管理和操作名为 "技术文档库" 的知识库。如果数据库中不存在名为 "不存在的库" 的知识库,调用 `get_service_by_name("不存在的库")` 将返回 `None`
***
### FunctionDef get_default
**get_default**: `get_default` 函数的功能是获取默认的知识库服务实例。
**参数**: 此函数不接受任何参数。
**代码描述**: `get_default` 函数通过调用 `KBServiceFactory.get_service` 方法,传入 `"default"` 作为知识库名称和 `SupportedVSType.DEFAULT` 作为向量存储类型,来获取默认的知识库服务实例。在这个过程中,`SupportedVSType.DEFAULT` 指代默认的向量存储服务类型,其具体实现可能会根据项目配置或环境而变化。根据 `KBServiceFactory.get_service` 的实现逻辑,如果向量存储类型为 `SupportedVSType.DEFAULT`,则会返回一个 `MilvusKBService` 实例,除非项目配置指定了不同的默认服务。这意味着,如果没有特别指定,默认的知识库服务将使用 Milvus 作为向量存储后端。
**注意**:
- 使用 `get_default` 函数时,不需要传递任何参数,这使得它非常适合于需要快速获取默认知识库服务实例的场景。
- 返回的知识库服务实例类型可能会根据项目的配置或环境设置而有所不同。默认情况下,它返回的是 `MilvusKBService` 实例,但这一行为是可配置的。
- 在实际应用中,应确保项目配置正确,以便 `get_default` 能够返回预期的知识库服务实例。
**输出示例**: 由于 `get_default` 函数的返回值取决于项目配置,因此没有固定的输出示例。但在大多数情况下,如果项目使用 Milvus 作为默认的向量存储服务,那么该函数可能返回类似于以下的实例表示:
```python
<MilvusKBService object at 0x7f8b2d4c1e50>
```
这表示 `get_default` 成功返回了一个 `MilvusKBService` 的实例,可以用于执行知识库相关的操作,如创建知识库、添加文档、搜索文档等。
***
## FunctionDef get_kb_details
**get_kb_details**: 此函数的功能是获取所有知识库的详细信息列表。
**参数**: 此函数不接受任何参数。
**代码描述**: `get_kb_details` 函数首先调用 `list_kbs_from_folder` 函数来获取文件夹中的知识库列表,然后调用 `KBService.list_kbs` 方法获取数据库中的知识库列表。对于文件夹中的每个知识库,函数初始化一个包含基本信息的字典,并将其添加到结果字典中。接下来,对于数据库中的每个知识库,函数通过调用 `get_kb_detail` 函数获取其详细信息,并更新结果字典中相应知识库的信息。如果数据库中的知识库在结果字典中不存在,则将其添加到结果字典中,并标记为不在文件夹中。最后,函数将结果字典中的值转换为列表,并为每个知识库分配一个序号,然后返回这个列表。
**注意**:
- 确保 `list_kbs_from_folder``KBService.list_kbs` 方法能够正确执行,且数据库连接正常,以便能够获取完整的知识库列表。
- `get_kb_detail` 函数需要能够正确返回知识库的详细信息,包括知识库名称、简介、向量库类型、嵌入模型名称、文件数量和创建时间等。
**输出示例**:
假设文件夹和数据库中各有两个知识库,函数可能返回如下列表:
```python
[
{
"No": 1,
"kb_name": "知识库1",
"vs_type": "ElasticSearch",
"kb_info": "知识库1的简介",
"embed_model": "BERT",
"file_count": 100,
"create_time": "2023-04-01T12:00:00",
"in_folder": True,
"in_db": True
},
{
"No": 2,
"kb_name": "知识库2",
"vs_type": "Faiss",
"kb_info": "知识库2的简介",
"embed_model": "RoBERTa",
"file_count": 50,
"create_time": "2023-04-02T12:00:00",
"in_folder": False,
"in_db": True
}
]
```
这个列表包含了两个知识库的详细信息,每个知识库都有一个序号、名称、向量库类型、简介、嵌入模型名称、文件数量、创建时间以及它们是否存在于文件夹和数据库中的标记。
## FunctionDef get_kb_file_details(kb_name)
**get_kb_file_details**: 此函数用于获取指定知识库中的文件详细信息列表。
**参数**:
- `kb_name`: 字符串类型,指定要查询的知识库名称。
**代码描述**: `get_kb_file_details` 函数首先通过 `KBServiceFactory.get_service_by_name` 方法根据知识库名称获取对应的知识库服务实例。如果该实例不存在,则直接返回空列表。接着,函数调用 `list_files_from_folder` 函数列出知识库文件夹中的所有文件,并通过知识库服务实例的 `list_files` 方法获取数据库中记录的所有文件名。然后,函数遍历文件夹中的文件,为每个文件构建一个包含文件基本信息的字典,并将其添加到结果字典中。对于数据库中存在的文件,函数通过调用 `get_file_detail` 函数获取其详细信息,并更新到结果字典中。最后,函数将结果字典中的值转换为列表,并为每个元素添加一个序号字段,然后返回这个列表。
**注意**:
- 确保传入的 `kb_name` 在系统中是存在的,否则函数将返回空列表。
- 此函数整合了文件夹和数据库中的文件信息,如果文件同时存在于文件夹和数据库中,数据库中的文件信息将覆盖文件夹中的同名文件信息。
- 返回的列表中的每个字典都包含了文件的多个属性,如文件名、扩展名、版本等,这些信息有助于进一步处理和管理知识库中的文件。
**输出示例**:
```json
[
{
"No": 1,
"kb_name": "技术文档库",
"file_name": "document1.pdf",
"file_ext": ".pdf",
"file_version": 0,
"document_loader": "",
"docs_count": 0,
"text_splitter": "",
"create_time": null,
"in_folder": true,
"in_db": false
},
{
"No": 2,
"kb_name": "技术文档库",
"file_name": "report2.docx",
"file_ext": ".docx",
"file_version": 1,
"document_loader": "WordLoader",
"docs_count": 10,
"text_splitter": "SpacyTextSplitter",
"create_time": "2023-04-01 12:00:00",
"in_folder": false,
"in_db": true
}
]
```
此示例展示了当查询到文件时,`get_kb_file_details` 函数返回的信息列表。列表中的每个元素都是一个字典,包含了文件所属的知识库名称、文件名、文件扩展名、文件版本、文档加载器名称、文本分割器名称、文件的创建时间、是否存在于文件夹中、是否存在于数据库中等信息。
## ClassDef EmbeddingsFunAdapter
**EmbeddingsFunAdapter**: EmbeddingsFunAdapter类的功能是对文本进行嵌入表示的转换,支持同步和异步两种方式。
**属性**:
- `embed_model`: 嵌入模型的名称,用于指定使用哪个预训练模型进行文本嵌入。
**代码描述**:
EmbeddingsFunAdapter类继承自Embeddings类,主要提供了文本嵌入表示的功能。它包含以下几个关键方法:
- `__init__`: 构造函数,接收一个嵌入模型名称作为参数,默认使用预定义的EMBEDDING_MODEL。
- `embed_documents`: 接收一个文本列表,返回这些文本的嵌入表示。该方法首先使用指定的嵌入模型将文本转换为嵌入向量,然后对这些向量进行归一化处理。
- `embed_query`: 接收单个文本字符串,返回该文本的嵌入表示。与`embed_documents`方法类似,但是专门针对单个查询文本进行处理,并将结果转换为一维数组返回。
- `aembed_documents`: 异步版本的`embed_documents`方法,功能相同但适用于异步调用场景。
- `aembed_query`: 异步版本的`embed_query`方法,功能相同但适用于异步调用场景。
在项目中,EmbeddingsFunAdapter类被多个模块调用,用于处理不同场景下的文本嵌入需求。例如,在知识库聊天迭代器、知识库缓存加载、以及各种知识库服务中,都可以看到EmbeddingsFunAdapter的身影。这些调用场景表明,EmbeddingsFunAdapter是处理文本嵌入表示的核心组件,支持多种知识库服务的文本相似度查询功能。
**注意**:
- 在使用EmbeddingsFunAdapter进行文本嵌入转换时,需要确保传入的嵌入模型名称是有效且已经预训练好的。
- 异步方法`aembed_documents``aembed_query`需要在异步环境下调用,以避免阻塞主线程。
**输出示例**:
```python
# 使用embed_query方法的输出示例
embeddings = embed_func.embed_query("这是一个示例文本")
# 输出: [0.01, -0.02, 0.03, ..., 0.05] # 假设的嵌入向量列表
# 使用aembed_documents方法的输出示例
embeddings = await embed_func.aembed_documents(["文本1", "文本2"])
# 输出: [[0.01, -0.02, 0.03, ..., 0.05], [0.02, -0.03, 0.04, ..., 0.06]] # 假设的嵌入向量列表
```
在实际应用中,嵌入向量的维度和具体数值将取决于所使用的嵌入模型。
### FunctionDef __init__(self, embed_model)
**__init__**: 该函数用于初始化EmbeddingsFunAdapter类的实例。
**参数**:
- **embed_model**: 字符串类型,默认值为EMBEDDING_MODEL。该参数用于指定嵌入模型。
**代码描述**:
`__init__`方法是`EmbeddingsFunAdapter`类的构造函数,负责初始化类的实例。在这个方法中,接收一个名为`embed_model`的参数,该参数用于指定将要使用的嵌入模型。如果调用时没有指定`embed_model`参数,则会使用`EMBEDDING_MODEL`作为默认值。这里的`EMBEDDING_MODEL`是在类外部定义的一个常量,代表默认的嵌入模型名称。
在方法体内,将传入的`embed_model`参数值赋给实例变量`self.embed_model`。这样,每个`EmbeddingsFunAdapter`类的实例都会拥有一个`embed_model`实例变量,用于存储该实例所使用的嵌入模型名称。
**注意**:
- 在使用`EmbeddingsFunAdapter`类创建实例时,可以根据需要传入不同的`embed_model`参数值,以指定不同的嵌入模型。如果不指定,将使用默认的嵌入模型。
- 确保传入的`embed_model`参数值是有效的,且对应的嵌入模型已经正确安装和配置,以避免在后续使用过程中出现错误。
***
### FunctionDef embed_documents(self, texts)
**embed_documents**: 该函数的功能是将文本列表转换为归一化的嵌入向量列表。
**参数**:
- `texts`: 需要转换为嵌入向量的文本字符串列表。
**代码描述**:
`embed_documents`函数首先调用`embed_texts`函数,将文本列表`texts`和嵌入模型`self.embed_model`作为参数传递,以获取文本的嵌入向量。`embed_texts`函数负责将文本向量化,可以处理本地或在线的嵌入模型,并返回一个包含向量化结果的`BaseResponse`对象。接着,`embed_documents`函数使用`normalize`函数对嵌入向量进行L2范数归一化处理,以确保所有向量都规范化到单位球上。这一步骤对于后续的向量空间模型处理非常重要,有助于提高模型的效果和稳定性。最后,函数将归一化的嵌入向量转换为列表格式并返回。
在整个过程中,`embed_documents`函数依赖于`embed_texts`函数进行文本的向量化处理,并依赖于`normalize`函数进行向量的归一化处理,这两个函数是实现文本嵌入和归一化的关键步骤。
**注意**:
- 确保传入的`texts`参数是有效的文本列表,且`self.embed_model`已正确指定,以便函数能够找到并使用正确的嵌入模型进行文本向量化处理。
- 归一化步骤是必要的,它确保了嵌入向量的质量,对于后续的处理非常重要。
**输出示例**:
假设调用`embed_documents`函数,传入文本列表`["你好", "世界"]`,可能会返回如下归一化的嵌入向量列表:
```
[[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]]
```
这表示两个文本"你好"和"世界"被成功转换为嵌入向量,并且这些向量已经过归一化处理。
***
### FunctionDef embed_query(self, text)
**embed_query**: 该函数的功能是对输入的文本进行向量化处理,并返回归一化后的向量列表。
**参数**:
- `text`: 需要进行向量化处理的文本,数据类型为字符串。
**代码描述**:
`embed_query`函数首先调用`embed_texts`函数,将输入的文本`text`转换为向量化表示。在这个过程中,`embed_texts`函数接收一个文本列表(本例中为单个文本构成的列表)、嵌入模型名称以及一个标志位`to_query`,后者指示该文本是作为查询使用。得到的向量化结果是一个包含单个向量的列表,该向量代表输入文本的嵌入表示。
接下来,函数将这个向量转换为二维数组,以满足后续处理的需求。这是通过`np.reshape`实现的,其中`query_embed`是原始的一维向量,`query_embed_2d`是转换后的二维数组。
然后,使用`normalize`函数对二维数组进行L2范数归一化处理。归一化是向量空间模型中的一个常见预处理步骤,有助于提高模型的效果和稳定性。归一化后的结果是一个二维数组,其中包含了归一化后的嵌入向量。
最后,函数将归一化后的二维数组转换回一维数组,并将其转换为列表格式返回。这样,返回的结果便是输入文本的归一化嵌入表示,可以直接用于后续的查询或其他处理。
**注意**:
- 输入文本`text`应为有效的字符串,不应为空或非文本类型。
- 该函数依赖于`embed_texts``normalize`两个函数,因此在使用前需要确保这些依赖函数正确实现且可用。
- 归一化处理依赖于`numpy`库,使用前需确保已安装`numpy`
**输出示例**:
假设输入文本为"你好世界",且嵌入模型将该文本向量化为`[0.1, 0.2, 0.3]`,则归一化后的输出可能如下所示:
```
[0.26726124, 0.53452248, 0.80178373]
```
这表示输入文本"你好世界"的归一化嵌入向量为上述列表。
***
### FunctionDef aembed_documents(self, texts)
**aembed_documents**: 此函数的功能是异步地将一系列文本向量化,并返回归一化后的向量列表。
**参数**:
- `texts`: 需要进行向量化处理的文本列表,类型为List[str]。
**代码描述**:
`aembed_documents`函数是`EmbeddingsFunAdapter`类的一个方法,它接受一个文本列表作为输入,使用`aembed_texts`函数异步地将这些文本转换为嵌入向量。这一过程涉及到调用`aembed_texts`函数,该函数根据指定的嵌入模型(`embed_model`)对文本进行向量化处理,并返回一个包含向量化结果的`BaseResponse`对象。在获得向量化结果后,`aembed_documents`方法进一步调用`normalize`函数对嵌入向量进行L2范数归一化处理,以确保向量在同一规范化空间内,这对于后续的向量相似度计算等操作是非常重要的。最后,该方法将归一化后的嵌入向量转换为列表格式并返回。
从功能角度看,`aembed_documents`方法与其调用的`aembed_texts`函数和`normalize`函数共同构成了文本向量化和归一化处理的完整流程。其中,`aembed_texts`负责文本的异步向量化处理,而`normalize`负责对向量化结果进行归一化,以优化向量的表示和后续使用。
**注意**:
- 在调用此方法时,需要确保传入的`texts`参数是有效的文本列表。
- 该方法的执行效率和效果依赖于`embed_model`的选择和配置,以及`aembed_texts`函数和`normalize`函数的实现。
- 由于该方法涉及到异步调用,因此在使用时需要配合`await`关键字或在异步环境中调用。
**输出示例**:
假设调用`await aembed_documents(texts=["你好", "世界"])`,可能会返回如下归一化后的向量列表:
```
[[0.4472136, 0.89442719], [0.5547002, 0.83205029]]
```
这表示两个文本"你好"和"世界"被成功向量化并归一化,向量化结果分别为`[0.4472136, 0.89442719]``[0.5547002, 0.83205029]`
***
### FunctionDef aembed_query(self, text)
**aembed_query**: 此函数的功能是对给定文本进行异步向量化处理,并返回归一化后的向量列表。
**参数**:
- `text`: 需要进行向量化处理的文本,类型为str。
**代码描述**:
`aembed_query`函数首先调用`aembed_texts`函数,对输入的文本`text`进行异步向量化处理。该过程涉及将文本封装成列表,并指定使用的嵌入模型`embed_model`以及将`to_query`参数设置为True,以优化向量化结果的使用场景。向量化处理后,返回的结果是一个包含向量化结果的`BaseResponse`对象。
接下来,函数从`BaseResponse`对象中提取出第一个(也是唯一一个,因为输入文本为单个字符串)向量化结果,并将其从一维数组转换为二维数组。这一步骤是为了满足后续归一化处理的需求。
随后,函数调用`normalize`函数对二维数组进行L2范数归一化处理。归一化是向量空间模型中的一个常见预处理步骤,有助于提高后续处理的效果和稳定性。归一化处理后,函数将归一化后的二维数组转换回一维数组,并将其作为最终结果返回。
**注意**:
- 在调用此函数时,需要确保传入的`text`参数是有效的文本字符串。
- 函数的执行结果依赖于`embed_model`指定的嵌入模型的有效性和可用性,因此在使用前应确认模型配置正确且模型可用。
- 归一化处理是基于`numpy`库实现的,因此在使用此函数前需要确保已经安装了`numpy`库。
**输出示例**:
假设调用`await aembed_query(text="你好")`,可能会返回如下归一化后的向量列表:
```python
[0.1, 0.2, 0.3, 0.4]
```
这表示文本"你好"被成功向量化并归一化,向量化结果为一个一维数组。
在项目中,`aembed_query`函数被用于处理需要异步进行文本向量化的场景,如在聊天文件中对用户查询进行异步向量化以支持快速的文本查询和相似度计算。此外,它也支持通过在线API进行文本向量化,为项目提供了灵活的向量化解决方案。
***
## FunctionDef score_threshold_process(score_threshold, k, docs)
**score_threshold_process**: 此函数的功能是根据给定的分数阈值和文档相似度,筛选出符合条件的文档,并返回前k个文档。
**参数**:
- score_threshold: 分数阈值,用于筛选相似度高于此阈值的文档。
- k: 返回的文档数量上限。
- docs: 包含文档及其相似度分数的列表。
**代码描述**:
`score_threshold_process` 函数接收三个参数:`score_threshold`(分数阈值),`k`(返回的文档数量上限),以及`docs`(包含文档及其相似度分数的列表)。如果`score_threshold`不为`None`,则函数会使用`operator.le`(小于等于比较操作符)来筛选出相似度分数小于等于`score_threshold`的文档。之后,函数返回筛选后的文档列表中的前`k`个文档。
在项目中,`score_threshold_process`函数被多个知识库服务(如`MilvusKBService``PGKBService``ZillizKBService`)中的`do_search`方法调用。这些服务通过不同的后端(如Milvus、PostgreSQL、Zilliz等)执行相似度搜索,并使用`score_threshold_process`函数来根据分数阈值筛选和限制返回的结果数量。这样,无论底层使用哪种搜索技术,都能通过统一的方式控制搜索结果的质量和数量。
**注意**:
- 如果`score_threshold``None`,则不会进行分数阈值筛选,直接返回前`k`个文档。
- 函数的返回值依赖于输入的`docs`列表和`k`值,因此在调用此函数前,确保`docs`列表已按相似度分数排序。
**输出示例**:
假设有以下输入:
- score_threshold = 0.5
- k = 3
- docs = [("doc1", 0.6), ("doc2", 0.4), ("doc3", 0.7), ("doc4", 0.5)]
调用`score_threshold_process(score_threshold, k, docs)`后,返回值可能为:
- [("doc1", 0.6), ("doc3", 0.7), ("doc4", 0.5)]
这表示在给定的文档中,有三个文档的相似度分数满足小于等于分数阈值的条件,并且根据要求返回了前3个文档。
@@ -0,0 +1,306 @@
## FunctionDef _get_result_to_documents(get_result)
**_get_result_to_documents**: 该函数的功能是将`GetResult`类型的查询结果转换为`Document`对象列表。
**参数**:
- `get_result`: `GetResult`类型,表示从数据库查询得到的结果。
**代码描述**:
`_get_result_to_documents`函数主要用于处理从数据库查询得到的结果,并将这些结果转换为`Document`对象列表。首先,函数检查`get_result`中的`documents`字段是否为空,如果为空,则直接返回空列表。如果不为空,则继续处理。
接下来,函数检查`get_result`中的`metadatas`字段。如果`metadatas`字段存在且不为空,则使用该字段的值;如果不存在或为空,则创建一个与`documents`字段长度相同的空字典列表。这一步确保了每个文档都有对应的元数据,即使某些文档没有元数据也会分配一个空字典。
然后,函数遍历`documents``metadatas`列表,将它们的元素打包成`Document`对象,并添加到一个新的列表`document_list`中。这里,`Document`对象是通过关键字参数`page_content``metadata`构造的,分别对应每个文档的内容和元数据。
最后,函数返回构造好的`Document`对象列表。
在项目中,`_get_result_to_documents`函数被`ChromaKBService`类的`get_doc_by_ids`方法调用。`get_doc_by_ids`方法负责根据给定的ID列表从数据库中查询文档,并使用`_get_result_to_documents`函数将查询结果转换为`Document`对象列表,以便进一步处理或响应客户端请求。
**注意**:
- 确保传入的`get_result`参数格式正确,特别是`documents``metadatas`字段,以避免运行时错误。
- 该函数不直接与数据库交互,而是处理已经查询得到的结果。
**输出示例**:
```python
[
Document(page_content="文档内容1", metadata={"作者": "张三"}),
Document(page_content="文档内容2", metadata={"作者": "李四"})
]
```
此示例展示了当`_get_result_to_documents`函数处理包含两个文档内容和对应元数据的查询结果时,返回的`Document`对象列表的可能形态。
## FunctionDef _results_to_docs_and_scores(results)
**_results_to_docs_and_scores**: 该函数的功能是将搜索结果转换为文档和分数的列表。
**参数**:
- `results`: 任意类型,预期为包含文档内容、元数据和距离的搜索结果。
**代码描述**:
`_results_to_docs_and_scores` 函数接收一个包含搜索结果的参数 `results`,这个参数预期是一个字典,其中包含三个键:`"documents"``"metadatas"``"distances"`。每个键对应的值都是一个列表,列表中的每个元素分别代表搜索到的文档内容、文档的元数据和文档与查询之间的距离(通常用于表示相似度或相关性的分数)。
函数通过对这三个列表进行并行迭代(使用 `zip` 函数),为每个搜索结果创建一个元组,其中包含一个 `Document` 对象和一个浮点数。`Document` 对象由文档内容和元数据构成,而浮点数则是该文档与查询之间的距离。这个过程生成了一个元组列表,每个元组代表一个搜索结果及其相关性分数。
在项目中,`_results_to_docs_and_scores` 函数被 `ChromaKBService` 类的 `do_search` 方法调用。`do_search` 方法负责执行搜索查询,并使用 `_results_to_docs_and_scores` 函数处理查询结果,将其转换为更易于处理和展示的格式。这种设计模式允许将搜索逻辑与结果处理逻辑分离,提高了代码的可读性和可维护性。
**注意**:
- 确保传入的 `results` 参数格式正确,即包含 `"documents"``"metadatas"``"distances"` 三个键,且每个键对应的值都是列表格式。
- 该函数依赖于 `Document` 类的正确实现。`Document` 类需要能够接受页面内容和元数据作为参数,并将它们封装为一个对象。
**输出示例**:
```python
[
(Document(page_content="文档内容1", metadata={"作者": "张三"}), 0.95),
(Document(page_content="文档内容2", metadata={"作者": "李四"}), 0.89)
]
```
此输出示例展示了函数返回值的可能形式,其中包含了两个元组,每个元组都包含一个 `Document` 对象和一个表示与查询相似度的分数。
## ClassDef ChromaKBService
**ChromaKBService**: ChromaKBService 类是用于操作和管理基于 ChromaDB 的知识库服务。
**属性**:
- `vs_path`: 向量存储路径。
- `kb_path`: 知识库路径。
- `client`: ChromaDB 客户端实例。
- `collection`: 当前知识库的集合。
**代码描述**:
ChromaKBService 类继承自 KBService 类,专门用于处理基于 ChromaDB 的知识库操作。它提供了一系列方法来初始化服务、创建知识库、删除知识库、添加文档、删除文档、清空向量存储、以及执行文档搜索等操作。
- `vs_type` 方法返回当前知识库服务使用的向量存储类型,即 ChromaDB。
- `get_vs_path``get_kb_path` 方法分别用于获取向量存储和知识库的路径。
- `do_init` 方法初始化 ChromaDB 客户端和集合。
- `do_create_kb` 方法创建一个新的知识库,实际上是在 ChromaDB 中创建一个新的集合。
- `do_drop_kb` 方法删除知识库,即删除 ChromaDB 中的集合。
- `do_search` 方法执行文档搜索,返回与查询最相关的文档列表和它们的得分。
- `do_add_doc` 方法向知识库添加文档,包括文档的文本、嵌入向量和元数据。
- `get_doc_by_ids``del_doc_by_ids` 方法分别根据文档 ID 获取文档和删除文档。
- `do_clear_vs` 方法清空向量存储,通过删除并重新创建集合来实现。
- `do_delete_doc` 方法根据提供的知识文件删除文档。
**注意**:
- 在使用 ChromaKBService 之前,需要确保 ChromaDB 环境已经正确设置并可用。
- 在调用 `do_add_doc` 方法添加文档时,需要确保文档数据包含有效的文本、嵌入向量和元数据。
- 删除操作(`do_drop_kb``del_doc_by_ids``do_delete_doc`)应谨慎使用,以避免意外丢失数据。
**输出示例**:
```python
# 搜索文档的示例输出
[
(Document(text="文档内容示例", metadata={"author": "作者示例"}), 0.95),
(Document(text="另一个文档内容示例", metadata={"author": "另一个作者示例"}), 0.90)
]
```
这个示例展示了执行文档搜索操作后,可能返回的文档列表和它们的相关性得分。每个元组包含一个 Document 实例和一个得分,Document 实例包含文档的文本和元数据。
### FunctionDef vs_type(self)
**vs_type**: vs_type函数的功能是返回当前知识库服务支持的向量存储类型。
**参数**: 该函数没有参数。
**代码描述**: vs_type函数是ChromaKBService类的一个方法,它的作用是指明该知识库服务实例支持的向量存储类型。在这个具体实现中,vs_type方法通过返回SupportedVSType枚举类中的CHROMADB值,明确表示ChromaKBService支持ChromaDB作为其向量存储服务。SupportedVSType枚举类定义了一系列项目中支持的向量存储类型,包括但不限于FAISS、MILVUS、ZILLIZ、PostgreSQL、Elasticsearch等,其中CHROMADB代表使用ChromaDB作为向量存储服务。这种设计允许知识库服务在项目中以一种灵活的方式来指定和使用不同的向量存储解决方案,同时也便于在KBServiceFactory中根据需要动态选择和实例化相应的知识库服务实现。
**注意**:
- 在使用vs_type方法时,开发者不需要传递任何参数,该方法将自动返回ChromaKBService所支持的向量存储类型。
- 返回的向量存储类型应与SupportedVSType枚举类中定义的类型一致,以确保知识库服务的正确实例化和使用。
- 当扩展项目以支持新的向量存储服务时,应在SupportedVSType枚举类中添加新的类型,并确保知识库服务类正确实现vs_type方法以反映这一变化。
**输出示例**:
```python
'chromadb'
```
在这个示例中,vs_type方法将返回一个字符串'chromadb',表示ChromaKBService类支持使用ChromaDB作为其向量存储服务。
***
### FunctionDef get_vs_path(self)
**get_vs_path**: 此函数的功能是获取向量空间的路径。
**参数**: 此函数没有显式参数,但依赖于对象的`kb_name``embed_model`属性。
**代码描述**: `get_vs_path`函数是`ChromaKBService`类的一个方法,用于返回知识库的向量空间路径。它通过调用全局函数`get_vs_path`实现,该全局函数接受两个参数:知识库名称(`kb_name`)和嵌入模型(`embed_model`)。这两个参数是`ChromaKBService`对象的属性,分别代表当前知识库的名称和使用的嵌入模型。此方法的返回值是一个字符串,表示向量空间的文件路径。
在项目中,`get_vs_path`方法被`do_init`方法调用。在`do_init`方法中,首先通过调用`get_kb_path`获取知识库的路径,然后调用`get_vs_path`获取向量空间的路径,并使用此路径初始化`PersistentClient`对象。这表明`get_vs_path`方法在知识库初始化过程中起到了关键作用,它确保了向量空间的路径可以被正确获取并用于后续的数据库客户端和集合的创建。
**注意**: 使用`get_vs_path`方法时,需要确保`ChromaKBService`对象的`kb_name``embed_model`属性已经被正确设置,因为这两个属性直接影响向量空间路径的生成。
**输出示例**: 假设知识库名称为`example_kb`,嵌入模型为`model_v1`,则`get_vs_path`可能返回的路径示例为`/path/to/vector_space/example_kb_model_v1.vs`
***
### FunctionDef get_kb_path(self)
**get_kb_path**: 此函数的功能是获取知识库的路径。
**参数**: 此函数没有参数。
**代码描述**: `get_kb_path` 函数是 `ChromaKBService` 类的一个方法,它的主要作用是返回知识库的路径。这个方法通过调用 `get_kb_path` 函数,并传递 `self.kb_name` 作为参数,来实现这一功能。在这里,`self.kb_name``ChromaKBService` 类的一个属性,它存储了当前知识库的名称。通过这种方式,`get_kb_path` 方法能够根据知识库的名称动态地获取其路径。
在项目中,`get_kb_path` 方法被 `do_init` 方法调用。在 `do_init` 方法中,首先通过调用 `get_kb_path` 方法来获取知识库路径,并将其存储在 `self.kb_path` 属性中。这一步骤是初始化过程的一部分,确保了后续操作能够基于正确的知识库路径进行。此外,`do_init` 方法还涉及到获取视图存储路径和初始化持久化客户端等操作,这些都是基于知识库服务正常运行所必需的步骤。
**注意**: 在使用 `get_kb_path` 方法时,需要确保 `self.kb_name` 已经被正确赋值,因为这将直接影响到获取路径的结果。
**输出示例**: 假设当前知识库的名称为 "example_kb",那么 `get_kb_path` 方法的返回值可能看起来像这样:
```
"/path/to/knowledge_bases/example_kb"
```
***
### FunctionDef do_init(self)
**do_init**: 此函数的功能是初始化ChromaKBService对象。
**参数**: 此函数没有参数。
**代码描述**: `do_init`方法是`ChromaKBService`类的一个关键方法,负责初始化知识库服务的核心组件。这个方法首先调用`get_kb_path`方法来获取知识库的路径,并将这个路径存储在`self.kb_path`属性中。接着,它调用`get_vs_path`方法来获取向量空间的路径,并将这个路径用于初始化`PersistentClient`对象,该对象存储在`self.client`属性中。最后,通过`self.client``get_or_create_collection`方法,使用`self.kb_name`属性(即知识库的名称)来获取或创建一个集合,并将这个集合对象存储在`self.collection`属性中。
从功能上看,`do_init`方法通过组合`get_kb_path``get_vs_path`方法的功能,确保了知识库服务可以正确地访问知识库路径和向量空间路径。这两个路径对于后续的知识库操作至关重要,因为它们分别确定了知识库数据的存储位置和向量空间数据的存储位置。通过`PersistentClient`对象,`do_init`方法进一步确保了知识库服务能够进行持久化操作,如数据的存储和检索。此外,`self.collection`的初始化为知识库中数据的管理提供了基础,使得数据的增删查改操作可以在此基础上进行。
**注意**: 在调用`do_init`方法之前,需要确保`ChromaKBService`对象的`kb_name``embed_model`属性已经被正确设置,因为这些属性会影响到`get_vs_path`方法的执行结果,进而影响到整个知识库服务的初始化过程。此外,`do_init`方法的成功执行是后续所有知识库操作能够正常进行的前提,因此在知识库服务的启动流程中,这个方法的调用是不可或缺的一步。
***
### FunctionDef do_create_kb(self)
**do_create_kb**: 此函数的功能是在ChromaDB中创建一个知识库(KB)。
**参数**: 此函数不接受任何外部参数。
**代码描述**: `do_create_kb`函数是`ChromaKBService`类的一个方法,用于在ChromaDB中创建一个新的知识库。在ChromaDB中,知识库的概念与集合(collection)相对应。因此,此函数的主要任务是创建或获取一个与知识库名称(`self.kb_name`)相对应的集合。这一过程通过调用`self.client.get_or_create_collection(self.kb_name)`实现,其中`self.client`是指向ChromaDB客户端的引用,而`self.kb_name`则是需要创建或获取的集合的名称。如果指定名称的集合已经存在,则此操作将返回现有集合的引用;如果不存在,则创建一个新的集合并返回其引用。操作完成后,集合的引用被存储在`self.collection`属性中,以便后续操作可以使用。
**注意**: 使用`do_create_kb`方法时,需要确保`self.client`已经正确初始化并且可以连接到ChromaDB服务器。此外,`self.kb_name`应该是一个有效的集合名称,遵循ChromaDB对集合名称的任何限制或规则。在调用此方法之前,最好确认这些条件已经满足,以避免运行时错误。
***
### FunctionDef do_drop_kb(self)
**do_drop_kb**: 此函数的功能是删除ChromaDB中的一个集合。
**参数**: 此函数没有参数。
**代码描述**: `do_drop_kb`函数负责在ChromaDB数据库中删除一个名为`kb_name`的集合。这个过程首先尝试通过调用`self.client.delete_collection`方法来实现,其中`self.kb_name`作为参数传递,指定了要删除的集合的名称。如果在删除过程中遇到`ValueError`异常,并且异常信息不是因为集合不存在(即错误信息不是"Collection {self.kb_name} does not exist."),那么这个异常将会被重新抛出,以便调用者可以处理这个异常情况。这种设计确保了只有在遇到预期之外的错误时,才会中断程序的执行,而对于集合不存在这种可能预期的情况,则不会影响程序的继续执行。
在项目中,`do_drop_kb`函数被`do_clear_vs`函数调用,作为清空向量存储的一部分操作。在`do_clear_vs`函数中,调用`do_drop_kb`可以理解为在清空向量存储之前,先删除对应的集合,这可能是因为在某些情况下,直接删除集合比尝试清空其内容来得更为高效或者更符合业务逻辑。
**注意**: 在使用`do_drop_kb`函数时,需要确保`self.kb_name`已经正确设置为目标集合的名称,并且调用者应当准备好处理可能抛出的`ValueError`异常,特别是在集合可能不存在的情况下。此外,考虑到删除集合是一个不可逆的操作,应当谨慎使用此函数,确保其调用是在适当的上下文中,并且符合业务逻辑的需求。
***
### FunctionDef do_search(self, query, top_k, score_threshold)
**do_search**: 该函数的功能是执行文本查询,并返回与查询最相关的文档及其相关性分数。
**参数**:
- `query`: 需要进行搜索的查询文本,数据类型为字符串。
- `top_k`: 返回的最相关文档的数量,数据类型为整数。
- `score_threshold`: 相关性分数的阈值,默认为SCORE_THRESHOLD,只有分数高于此阈值的文档才会被返回,数据类型为浮点数。
**代码描述**:
`do_search`函数首先通过`EmbeddingsFunAdapter`类的实例化,使用`self.embed_model`作为嵌入模型来创建一个嵌入函数`embed_func`。然后,使用`embed_func.embed_query(query)`方法将查询文本`query`转换为嵌入向量`embeddings`。这一步骤是通过将文本转换为向量化表示,以便后续进行相似度计算。
接下来,函数调用`self.collection.query`方法,传入查询嵌入向量`embeddings`和结果数量`n_results`等于`top_k`,执行查询操作。此方法返回一个`QueryResult`对象,包含了查询的结果。
最后,函数调用`_results_to_docs_and_scores(query_result)`,将查询结果转换为文档和分数的列表。这一步骤通过解析`QueryResult`对象,提取出每个文档及其与查询文本的相似度分数,然后将这些信息封装成元组列表返回。
在整个过程中,`do_search`函数通过与`EmbeddingsFunAdapter``_results_to_docs_and_scores`等函数的交互,实现了从文本查询到获取相关文档及其分数的完整流程。
**注意**:
- 确保`query`参数是有效的查询文本,且`top_k`参数正确设置以返回期望数量的结果。
- 函数的性能和准确性依赖于嵌入模型的质量和查询处理机制,因此选择合适的嵌入模型和调整查询参数对于获得有用的搜索结果至关重要。
- 默认的`score_threshold`是SCORE_THRESHOLD,可以根据需要调整以过滤掉低相关性的结果。
**输出示例**:
```python
[
(Document(page_content="文档内容1", metadata={"作者": "张三"}), 0.95),
(Document(page_content="文档内容2", metadata={"作者": "李四"}), 0.89)
]
```
此输出示例展示了函数返回值的可能形式,其中包含了两个元组,每个元组都包含一个`Document`对象和一个表示与查询相似度的分数。这样的输出格式便于后续处理和展示搜索结果。
***
### FunctionDef do_add_doc(self, docs)
**do_add_doc**: 该函数的功能是将文档列表添加到数据库中,并返回包含文档ID和元数据的信息列表。
**参数**:
- `docs`: 需要添加到数据库的文档对象列表,类型为`List[Document]`
- `**kwargs`: 接受可变数量的关键字参数,用于扩展或自定义功能。
**代码描述**:
`do_add_doc`函数首先调用`_docs_to_embeddings`私有方法,将文档对象列表转化为向量化的数据,包括文本内容、向量化结果和元数据。这一步是为了准备将文档存储到向量数据库中,便于后续的检索和分析操作。
接下来,函数为每个文档生成一个唯一的ID(使用`uuid.uuid1()`方法),并通过遍历每个文档的向量化数据,调用`collection.add`方法将文档的ID、向量化结果、元数据和文本内容添加到数据库的集合中。每次添加操作后,函数会将文档的ID和元数据收集到`doc_infos`列表中。
最后,函数返回`doc_infos`列表,其中包含了每个添加到数据库中的文档的ID和元数据信息,为后续的文档管理和检索提供了便利。
**注意**:
- 确保传入的`docs`参数是有效的文档对象列表,且每个文档对象都应包含必要的内容和元数据。
- `_docs_to_embeddings`方法依赖于特定的文档向量化模型,因此在使用`do_add_doc`函数之前,应确保相关的向量化模型已经被正确设置和初始化。
- 生成的文档ID是基于时间戳的UUID,保证了每个文档的唯一性。
**输出示例**:
调用`do_add_doc(docs=[Document1, Document2])`可能会返回如下列表:
```python
[
{"id": "文档1的UUID", "metadata": {"title": "文档1标题"}},
{"id": "文档2的UUID", "metadata": {"title": "文档2标题"}}
]
```
这个列表包含了每个添加到数据库中的文档的唯一ID和元数据信息,便于后续的文档管理和检索操作。
***
### FunctionDef get_doc_by_ids(self, ids)
**get_doc_by_ids**: 该函数的功能是根据一组ID从数据库中查询并返回对应的文档对象列表。
**参数**:
- `ids`: `List[str]`类型,表示需要查询的文档ID列表。
**代码描述**:
`get_doc_by_ids`方法是`ChromaKBService`类的一部分,负责根据给定的ID列表从数据库中检索文档。该方法首先调用集合的`get`方法,传入ID列表作为参数,以从数据库中获取对应的文档数据。获取的结果是`GetResult`类型,随后该方法调用`_get_result_to_documents`函数,将`GetResult`类型的查询结果转换为`Document`对象列表。
`_get_result_to_documents`函数详细处理了如何从`GetResult`类型的查询结果中提取文档内容和元数据,并将它们封装成`Document`对象。这一过程包括检查查询结果中的`documents``metadatas`字段,确保每个文档都能正确地与其元数据对应,并最终生成一个包含所有查询到的文档的`Document`对象列表。
通过这种方式,`get_doc_by_ids`方法能够提供一个高效且方便的接口,用于根据文档ID查询并获取文档内容及其元数据,进而支持后续的文档处理或响应客户端请求。
**注意**:
- 传入的ID列表应确保有效,以避免查询不到文档或产生异常。
- 该方法依赖于`_get_result_to_documents`函数正确处理查询结果,因此需要保证`GetResult`类型的数据结构与预期匹配。
**输出示例**:
```python
[
Document(page_content="文档内容1", metadata={"作者": "张三"}),
Document(page_content="文档内容2", metadata={"作者": "李四"})
]
```
此示例展示了当根据给定的ID列表查询数据库并处理结果时,`get_doc_by_ids`方法可能返回的`Document`对象列表的形态。每个`Document`对象包含了文档的内容(`page_content`)和元数据(`metadata`)。
***
### FunctionDef del_doc_by_ids(self, ids)
**del_doc_by_ids**: 此函数的功能是根据提供的ID列表删除数据库中的文档。
**参数**:
- ids: 一个字符串列表,包含要删除的文档的ID。
**代码描述**:
`del_doc_by_ids`函数接受一个参数`ids`,这是一个字符串列表,每个字符串代表一个需要从数据库中删除的文档的ID。函数内部调用`self.collection.delete`方法,将`ids`作为参数传递给该方法,以便删除对应的文档。完成删除操作后,函数返回`True`,表示文档已成功删除。
**注意**:
- 确保传递给`del_doc_by_ids`函数的`ids`列表中的每个ID都是有效且存在于数据库中的,否则可能会导致删除操作失败或不完全。
- 此函数总是返回`True`,即使某些ID可能因为不存在而没有被实际删除。因此,调用者可能需要额外的逻辑来验证删除操作的实际效果。
**输出示例**:
由于此函数返回的是一个布尔值,因此调用`del_doc_by_ids(['123', '456'])`后,预期的返回值为:
```
True
```
这表示指定的文档已被成功删除。
***
### FunctionDef do_clear_vs(self)
**do_clear_vs**: 此函数的功能是清空向量存储。
**参数**: 此函数没有参数。
**代码描述**: `do_clear_vs`函数是ChromaKBService类中的一个方法,其主要作用是清空向量存储。在实现上,它通过调用`do_drop_kb`方法来达到清空向量存储的目的。根据`do_drop_kb`方法的文档描述,我们知道`do_drop_kb`的功能是删除ChromaDB中的一个集合。因此,`do_clear_vs`通过删除集合的方式来清空向量存储,这可能是因为直接删除集合比尝试清空其内容来得更为高效或者更符合业务逻辑。在调用`do_drop_kb`时,会尝试删除一个名为`kb_name`的集合,如果在删除过程中遇到`ValueError`异常,并且异常信息不是因为集合不存在,则这个异常将会被重新抛出。这种设计确保了只有在遇到预期之外的错误时,才会中断程序的执行。
**注意**: 在使用`do_clear_vs`函数时,需要确保`self.kb_name`已经正确设置为目标集合的名称。此外,考虑到删除集合是一个不可逆的操作,应当谨慎使用此函数,确保其调用是在适当的上下文中,并且符合业务逻辑的需求。由于`do_clear_vs`函数的实现依赖于`do_drop_kb`,因此在使用`do_clear_vs`时也应当准备好处理可能由`do_drop_kb`抛出的`ValueError`异常,特别是在集合可能不存在的情况下。
***
### FunctionDef do_delete_doc(self, kb_file)
**do_delete_doc**: 此函数用于删除知识库中的指定文件。
**参数**:
- `kb_file`: KnowledgeFile对象,代表要删除的知识库文件。
- `**kwargs`: 接收额外的关键字参数,可用于扩展功能或传递额外信息。
**代码描述**:
`do_delete_doc`函数是`ChromaKBService`类的一个方法,负责从知识库中删除指定的文件。该方法接收一个`KnowledgeFile`对象作为参数,该对象包含了要删除文件的详细信息,包括文件的路径等。函数内部通过调用`self.collection.delete`方法来执行删除操作,其中`where`参数用于指定删除条件,本例中以文件的路径(`kb_file.filepath`)作为删除的依据。
在项目的层次结构中,`KnowledgeFile`对象由`server/knowledge_base/utils.py`中定义,它封装了与知识库文件相关的信息和操作。`do_delete_doc`方法通过使用这个对象,可以精确地定位并操作知识库中的特定文件,实现了文件的删除功能。
此方法的实现依赖于`collection`对象的`delete`方法,该方法是对数据库操作的抽象,允许通过指定条件来删除记录。在本项目中,`collection`很可能代表了一个封装了数据库操作的类实例,用于管理知识库中的数据记录。
**注意**:
- 在调用`do_delete_doc`方法时,需要确保传入的`kb_file`对象有效,并且其`filepath`属性正确指向了要删除的文件路径。
- 该方法的执行结果依赖于`collection.delete`方法的实现,因此在不同的数据库或数据存储方案中,其具体行为可能会有所不同。
- 删除操作是不可逆的,因此在执行前应确保文件确实不再需要,以避免数据丢失。
**输出示例**:
由于`do_delete_doc`方法的主要作用是从数据库中删除记录,其返回值取决于`collection.delete`方法的实现。通常,该方法可能会返回一个表示删除操作结果的对象或布尔值。例如,如果删除成功,可能会返回`True`或者一个包含删除成功信息的对象;如果删除失败,可能会返回`False`或者一个包含错误信息的对象。
***
@@ -0,0 +1,138 @@
## ClassDef DefaultKBService
**DefaultKBService**: DefaultKBService 类是用于提供默认的知识库服务实现。
**属性**:
此类继承自KBService,因此继承了KBService的所有属性,包括知识库名称(kb_name)、知识库信息(kb_info)、嵌入模型名称(embed_model)、知识库路径(kb_path)和文档路径(doc_path)等。
**代码描述**:
DefaultKBService 类是KBService的一个具体实现,提供了对知识库的基本操作,包括创建知识库、删除知识库、向知识库添加文档、清空知识库、获取知识库类型、初始化知识库、搜索知识库、批量插入知识、单个插入知识和删除文档等方法。这些方法在DefaultKBService中大多以空方法(pass)的形式存在,意味着需要由继承DefaultKBService的子类来具体实现这些方法的功能。
DefaultKBService通过继承KBService类,确保了与其他知识库服务实现相同的接口,这样做的目的是为了提供一种默认的知识库服务实现,方便在没有指定具体知识库服务类型时使用。
**注意**:
- DefaultKBService类本身大多数方法未具体实现(使用pass),需要通过继承此类并重写这些方法来提供具体的功能。
- 在使用DefaultKBService或其子类时,需要确保已经正确配置了知识库的相关信息,如知识库名称、嵌入模型名称等。
- DefaultKBService类的实例化通常由KBServiceFactory类的get_service方法根据配置动态完成,而不是直接在代码中实例化。
**输出示例**:
由于DefaultKBService类的方法大多未具体实现,因此没有直接的输出示例。具体的输出将取决于继承DefaultKBService的子类以及这些子类实现的方法。例如,如果子类实现了do_search方法,那么搜索文档的输出示例可能如下:
```python
[
{"id": "doc1", "text": "文档1的内容", "score": 0.95},
{"id": "doc2", "text": "文档2的内容", "score": 0.90}
]
```
这表示在执行搜索操作时,返回了两个文档及其相关性得分。
### FunctionDef do_create_kb(self)
**do_create_kb**: 此函数的功能是创建知识库。
**参数**: 此函数没有参数。
**代码描述**: `do_create_kb` 函数是 `DefaultKBService` 类的一个方法,旨在创建一个知识库。在当前的代码实现中,此函数体为空,这意味着它尚未实现具体的功能。在实际应用中,开发者需要在此函数中添加创建知识库的逻辑,例如初始化知识库的结构,存储知识库的数据,或者配置知识库的相关设置等。此函数作为一个框架或者占位符存在,供将来扩展和具体实现使用。
**注意**: 使用此函数时,需要注意以下几点:
- 由于当前函数体为空,直接调用此函数不会有任何效果。开发者需要根据具体需求,实现知识库的创建逻辑。
- 在实现函数逻辑时,应考虑知识库的安全性、可扩展性和性能等因素,确保知识库的稳定和高效运行。
- 如果项目中已经有现成的知识库服务或框架,开发者应评估是否直接使用或扩展现有服务,以避免重复工作和提高开发效率。
***
### FunctionDef do_drop_kb(self)
**do_drop_kb**: 此函数的功能是删除知识库。
**参数**: 此函数没有参数。
**代码描述**: `do_drop_kb` 函数是 `DefaultKBService` 类的一个方法,用于实现知识库的删除操作。在当前的代码实现中,此函数体为空(使用了 `pass` 语句),这意味着它没有执行任何操作。在实际应用中,开发者需要在此函数中添加逻辑来实现知识库的具体删除操作,例如从数据库中删除知识库相关的数据或清理知识库使用的资源等。
**注意**: 虽然当前的实现为空,但开发者在使用此函数时应当注意,删除知识库是一个重要操作,可能会对系统中存储的数据产生不可逆的影响。因此,在实现和调用此函数时,应确保有充分的权限检查和必要的数据备份机制,以防止数据丢失或错误删除。此外,考虑到操作的敏感性,可能还需要实现相应的日志记录功能,以便于问题的追踪和审计。
***
### FunctionDef do_add_doc(self, docs)
**do_add_doc**: 此函数的功能是向知识库中添加文档。
**参数**:
- `docs`: 需要添加到知识库中的文档列表,类型为`List[Document]`
**代码描述**:
`do_add_doc`函数是`DefaultKBService`类的一个方法,旨在实现将一系列文档(`docs`)添加到知识库中的功能。该方法接受一个参数`docs`,这是一个`Document`对象的列表。每个`Document`对象代表了一个需要被添加到知识库的文档。
在当前的代码实现中,`do_add_doc`方法的具体逻辑尚未实现,仅提供了方法的定义和参数接收的框架。这意味着,如果你需要使用这个方法来向知识库添加文档,你需要在此基础上实现具体的添加文档到知识库的逻辑。
**注意**:
- 在实际使用`do_add_doc`方法之前,需要确保每个`Document`对象都已经正确构造,并包含了所有必要的信息,以便能够被成功添加到知识库中。
- 由于当前的实现是空的,调用此方法不会有任何实际效果,直到你实现了添加文档到知识库的具体逻辑。
- 在实现具体逻辑时,需要考虑如何处理文档添加过程中可能出现的异常情况,例如文档格式不正确或添加到知识库失败等。
***
### FunctionDef do_clear_vs(self)
**do_clear_vs**: 此函数的功能是清除视图状态。
**参数**: 此函数没有参数。
**代码描述**: `do_clear_vs`函数是`DefaultKBService`类的一个成员方法,目前其内部实现为空,即该方法被调用时不会执行任何操作。在`DefaultKBService`类中,此方法可能被设计为用于清除或重置与知识库服务相关的某些视图状态,但具体的实现细节尚未提供。这种设计通常用于在需要时重置服务的状态,或者在某些操作完成后清理资源。
**注意**: 虽然当前`do_clear_vs`方法的实现为空,但开发者在使用此方法时应注意其未来可能的更新或实现。在调用此方法之前,建议检查相关的文档或更新日志,以了解其最新的功能和使用方式。此外,由于该方法目前不执行任何操作,开发者应避免在生产环境中不必要地调用它,以免在未来的版本中引入潜在的副作用或性能问题。
***
### FunctionDef vs_type(self)
**vs_type函数功能**: 返回当前知识库服务的类型。
**参数**: 此函数不接受任何参数。
**代码描述**: `vs_type`函数是`DefaultKBService`类的一个方法,用于标识当前使用的知识库服务类型。在这个上下文中,它被设计为返回一个字符串值`"default"`,意味着如果没有特别指定,将使用默认的知识库服务类型。这个设计允许在系统中可能存在多种知识库服务类型时,能够灵活地指定和使用不同的服务类型。通过返回一个明确的字符串标识符,系统的其他部分可以根据这个标识符来决定如何与知识库服务交互。
**注意**: 在使用`vs_type`方法时,需要注意它是如何与系统中其他部分的逻辑配合工作的。因为它返回一个固定的字符串值,如果系统扩展了更多的知识库服务类型,可能需要更新此方法以反映新的服务类型。
**输出示例**:
```python
"default"
```
这个输出示例展示了调用`vs_type`方法时会收到的返回值。在当前的实现中,每次调用此方法都会返回字符串`"default"`,表示使用默认的知识库服务类型。
***
### FunctionDef do_init(self)
**do_init**: 此函数的功能是初始化DefaultKBService类的实例。
**参数**: 此函数没有参数。
**代码描述**: `do_init`函数是`DefaultKBService`类中的一个方法,目前其内部实现为空,即没有执行任何操作。这通常意味着该方法是为了将来的扩展而预留的,或者作为一个接口的一部分,具体的实现将在子类中完成。在面向对象编程中,这样的设计允许开发者在不修改现有代码的情况下,通过继承和重写方法来扩展功能。
**注意**: 虽然当前`do_init`方法没有执行任何操作,但在将来的开发中,如果需要对`DefaultKBService`类的实例进行初始化设置,比如配置参数的加载、资源的分配等,都可以在此方法中实现。因此,开发者在使用`DefaultKBService`类时,应当注意到`do_init`方法可能会在未来包含重要的初始化逻辑,应当在创建实例后调用它,以确保对象正确地被初始化。
***
### FunctionDef do_search(self)
**do_search**: 此函数的功能是执行搜索操作。
**参数**: 此函数目前没有定义任何参数。
**代码描述**: `do_search` 函数是 `DefaultKBService` 类的一个成员方法,旨在实现搜索功能。根据函数体的实现,当前此函数体为空,即它未执行任何操作。这通常意味着该函数是一个待实现的功能桩,预留给开发者后续根据具体需求实现搜索逻辑。在实际应用中,开发者可能需要根据特定的搜索需求,如关键词搜索、模糊搜索或其他高级搜索功能,来填充此函数体。例如,可以通过查询数据库、调用外部搜索服务或应用搜索算法来实现具体的搜索逻辑。
**注意**: 虽然当前 `do_search` 函数未具体实现任何逻辑,但在将来的开发中,开发者应确保为其添加适当的参数和返回值,以满足搜索功能的需求。此外,考虑到性能和准确性是搜索功能的关键,开发时应注意优化搜索算法和处理大量数据的能力。在实现具体逻辑之前,建议先定义好函数的输入输出规范,以及可能涉及的错误处理机制。
***
### FunctionDef do_insert_multi_knowledge(self)
**do_insert_multi_knowledge**: 此函数的功能是批量插入多条知识数据。
**参数**: 此函数目前不接受任何参数。
**代码描述**: `do_insert_multi_knowledge` 函数是 `DefaultKBService` 类的一个方法,设计用于处理批量插入知识数据的操作。当前,该函数的实现为空(使用了 `pass` 语句),这意味着它尚未实现具体的功能。在未来的开发中,此函数可能会被扩展以接受参数,如知识数据列表,并将这些数据批量插入到知识库中。这种批量插入操作通常比单条插入更高效,特别是当需要向知识库中添加大量数据时。
**注意**:
- 由于当前 `do_insert_multi_knowledge` 函数的实现为空,调用此函数不会产生任何效果。开发者在使用此函数之前需要实现具体的插入逻辑。
- 在实现批量插入逻辑时,需要考虑到数据的一致性和事务管理,确保数据的准确性和完整性。
- 开发者在扩展此函数以实现具体功能时,应考虑到性能优化,例如,使用批处理技术减少数据库访问次数,提高数据插入效率。
- 此函数在未来可能会更新以接受参数和返回值,开发者在使用时应关注相关文档的更新,以便正确使用。
***
### FunctionDef do_insert_one_knowledge(self)
**do_insert_one_knowledge**: 此函数的功能是插入单条知识记录。
**参数**: 此函数目前不接受任何参数。
**代码描述**: `do_insert_one_knowledge` 函数是 `DefaultKBService` 类的一个成员方法,旨在向知识库中插入一条新的知识记录。当前版本的函数体为空,这意味着它尚未实现具体的插入逻辑。在未来的版本中,此函数可能会被扩展以包含与数据库交互的代码,用于实际将知识记录插入到后端存储系统中。这可能涉及到构造数据库查询、处理数据模型以及管理数据库连接和事务等操作。
**注意**:
- 由于当前函数体为空,调用此函数不会产生任何效果。开发者在使用此函数时需要注意其实现状态,避免在生产环境中直接使用尚未完成的功能。
- 在未来的实现中,开发者可能需要关注函数参数的设计,以便能够灵活地传递要插入的知识记录数据。
- 此外,考虑到数据的一致性和完整性,实现此功能时可能需要处理错误和异常情况,确保知识记录的正确插入。
***
### FunctionDef do_delete_doc(self)
**do_delete_doc**: 此函数的功能是删除文档。
**参数**: 此函数没有参数。
**代码描述**: `do_delete_doc` 函数是 `DefaultKBService` 类的一个方法,目前其内部实现为空,即函数体中没有任何执行代码。这通常意味着该方法是一个待实现的功能占位符,或者在当前版本的代码中,删除文档的具体逻辑尚未被定义。在面向对象编程中,这种做法常用于定义接口或抽象类,预留方法供子类实现具体功能。然而,根据此函数所在的上下文——位于`default_kb_service.py`文件中的`DefaultKBService`类,我们可以推断`do_delete_doc`方法旨在提供一个删除知识库中特定文档的功能。在未来的版本中,开发者可能会在此方法中添加代码来实现从数据库或存储系统中删除特定文档的逻辑。
**注意**: 虽然当前`do_delete_doc`方法的实现为空,但在使用此方法之前,开发者应确保理解其预期的功能和实现逻辑。如果你是负责扩展或维护`DefaultKBService`类的开发者,那么在实现`do_delete_doc`方法时,需要考虑如何安全有效地从你的知识库服务中删除数据,包括处理可能的依赖关系和确保数据一致性等问题。此外,考虑到数据的重要性,实现删除功能时应提供充分的错误处理和日志记录,以便跟踪和恢复意外删除的数据。
***
@@ -0,0 +1,282 @@
## ClassDef ESKBService
**ESKBService**: ESKBService 类用于实现基于 Elasticsearch 的知识库服务。
**属性**:
- `kb_path`: 知识库路径。
- `index_name`: Elasticsearch 索引名称。
- `IP`: Elasticsearch 服务的 IP 地址。
- `PORT`: Elasticsearch 服务的端口号。
- `user`: 连接 Elasticsearch 服务的用户名。
- `password`: 连接 Elasticsearch 服务的密码。
- `dims_length`: 向量的维度。
- `embeddings_model`: 本地加载的嵌入模型。
- `es_client_python`: Elasticsearch 的 Python 客户端实例。
- `db_init`: 用于初始化和创建索引的 ElasticsearchStore 实例。
**代码描述**:
ESKBService 类继承自 KBService 类,专门用于操作和管理基于 Elasticsearch 的知识库。它提供了一系列方法来初始化服务、创建知识库、添加文档、删除文档、搜索文档等。
- `do_init` 方法用于初始化 Elasticsearch 客户端,包括连接到 Elasticsearch 服务、创建索引等。
- `get_kb_path``get_vs_path` 静态方法用于获取知识库路径和向量存储路径。
- `do_create_kb` 方法用于创建知识库,如果知识库路径不存在,则创建之。
- `vs_type` 方法返回支持的向量存储类型,即 Elasticsearch。
- `_load_es` 方法用于将文档加载到 Elasticsearch 中。
- `do_search` 方法用于执行文本相似性搜索。
- `get_doc_by_ids` 方法根据文档 ID 获取文档。
- `del_doc_by_ids` 方法根据文档 ID 删除文档。
- `do_delete_doc` 方法用于从知识库中删除指定的文档。
- `do_add_doc` 方法用于向知识库添加文档。
- `do_clear_vs` 方法用于从知识库中删除所有向量。
- `do_drop_kb` 方法用于删除整个知识库。
**注意**:
- 在使用 ESKBService 类之前,需要确保 Elasticsearch 服务已经启动并可访问。
- 用户名和密码是可选的,如果 Elasticsearch 服务没有设置认证,可以不提供。
- 创建索引时,需要指定向量的维度,这对于后续的向量搜索非常重要。
**输出示例**:
由于 ESKBService 类主要与 Elasticsearch 交互,它的方法通常不直接返回具体的输出,而是影响 Elasticsearch 中的数据。例如,`do_add_doc` 方法成功执行后,将在 Elasticsearch 中创建或更新文档,但不会返回具体的输出。搜索方法 `do_search` 可能会返回如下格式的文档列表:
```python
[
{"id": "doc1", "text": "文档1的内容", "score": 0.95},
{"id": "doc2", "text": "文档2的内容", "score": 0.90}
]
```
这表示在执行搜索操作时,返回了两个文档及其相关性得分。
### FunctionDef do_init(self)
**do_init**: 此函数的功能是初始化ESKBService类的实例,包括配置知识库路径、索引名称、连接Elasticsearch服务的参数以及加载本地嵌入模型。
**参数**: 此函数不接受任何外部参数。
**代码描述**: `do_init` 方法首先通过调用 `get_kb_path` 方法获取知识库的完整路径,并从该路径中提取索引名称。然后,它根据 `vs_type` 方法返回的向量存储类型,从配置文件中获取Elasticsearch服务的主机地址、端口、用户、密码和向量维度长度。接着,`do_init` 方法使用 `load_local_embeddings` 函数加载本地嵌入模型,以支持后续的向量搜索功能。
此外,`do_init` 方法尝试建立与Elasticsearch服务的连接。如果提供了用户名和密码,则使用基本认证;否则,发出警告并尝试无认证连接。连接成功后,尝试创建Elasticsearch索引,如果遇到BadRequestError异常,则记录错误信息。
最后,`do_init` 方法尝试通过 `ElasticsearchStore` 类的实例 `db_init` 初始化Elasticsearch连接和索引,这一步骤同样考虑了认证信息。如果在任何连接尝试中遇到 `ConnectionError` 或其他异常,将记录错误信息并抛出异常。
**注意**:
- 在调用 `do_init` 方法之前,确保已经正确配置了Elasticsearch服务的相关参数,包括主机地址、端口、用户、密码等。
- `do_init` 方法在ESKBService类的实例化过程中自动调用,用于准备Elasticsearch服务的连接和配置,因此在使用ESKBService类之前不需要手动调用此方法。
- 如果在连接Elasticsearch服务或创建索引时遇到问题,`do_init` 方法将记录错误信息并抛出异常,调用方应捕获并处理这些异常。
- `do_init` 方法依赖于 `load_local_embeddings` 函数加载的本地嵌入模型,确保嵌入模型与Elasticsearch服务的向量搜索功能兼容。
***
### FunctionDef get_kb_path(knowledge_base_name)
**get_kb_path**: 此函数的功能是获取知识库的完整路径。
**参数**:
- knowledge_base_name: 字符串类型,代表知识库的名称。
**代码描述**:
`get_kb_path` 函数接受一个参数 `knowledge_base_name`,这是一个字符串,代表知识库的名称。函数使用 `os.path.join` 方法将 `KB_ROOT_PATH`(一个在代码中预定义的常量,代表知识库根目录的路径)与 `knowledge_base_name` 拼接,从而构造出该知识库的完整路径。这个函数在项目中被用于构建知识库路径,以便于其他操作(如初始化、索引创建等)能够在正确的位置进行。
在项目中,`get_kb_path` 函数被 `do_init` 方法调用,用于确定知识库的存储路径,并据此设置索引名称和其他与 Elasticsearch 服务相关的配置。此外,它还被 `get_vs_path` 方法调用,后者进一步在知识库路径的基础上添加 "vector_store" 子目录,用于特定的向量存储操作。这表明 `get_kb_path` 函数是连接知识库基础设施与 Elasticsearch 服务操作的关键环节。
**注意**:
- 确保 `KB_ROOT_PATH` 已经正确设置,且指向一个有效的文件系统路径,否则构建的知识库路径可能无效。
- 在调用此函数之前,应确保传入的 `knowledge_base_name` 是唯一的,以避免路径冲突。
**输出示例**:
如果 `KB_ROOT_PATH` 设置为 "/data/knowledge_bases",且传入的 `knowledge_base_name` 为 "my_kb",则函数返回的路径将会是 "/data/knowledge_bases/my_kb"。
***
### FunctionDef get_vs_path(knowledge_base_name)
**get_vs_path**: 此函数的功能是获取知识库中向量存储的完整路径。
**参数**:
- knowledge_base_name: 字符串类型,代表知识库的名称。
**代码描述**:
`get_vs_path` 函数是用于构建知识库中向量存储位置的路径。它接受一个参数 `knowledge_base_name`,这是一个字符串,指定了知识库的名称。函数首先调用 `get_kb_path` 方法,该方法根据传入的知识库名称构建出知识库的根路径。然后,`get_vs_path` 函数使用 `os.path.join` 方法将这个根路径与 "vector_store" 字符串拼接,从而生成并返回向量存储的完整路径。
从功能角度来看,`get_vs_path` 函数与其调用的 `get_kb_path` 函数紧密相关。`get_kb_path` 提供了知识库的基础路径,而 `get_vs_path` 在此基础上进一步定位到知识库中用于存储向量数据的特定子目录。这种设计使得知识库的结构更加清晰,同时也便于管理和访问知识库中的向量数据。
**注意**:
- 在使用 `get_vs_path` 函数之前,应确保传入的知识库名称 `knowledge_base_name` 是准确且存在的,因为这将直接影响到向量存储路径的正确性。
- 由于 `get_vs_path` 函数依赖于 `get_kb_path` 函数来获取知识库的根路径,因此需要保证 `get_kb_path` 函数能够正常工作,包括确保知识库根目录的路径(`KB_ROOT_PATH`)已经被正确设置。
**输出示例**:
假设知识库的根目录路径为 "/data/knowledge_bases",且传入的知识库名称为 "my_kb",那么 `get_vs_path` 函数将返回的路径将会是 "/data/knowledge_bases/my_kb/vector_store"。这个路径指向了 "my_kb" 知识库中用于存储向量数据的子目录。
***
### FunctionDef do_create_kb(self)
**do_create_kb**: 此函数的功能是创建知识库所需的向量存储目录。
**参数**: 此函数没有参数。
**代码描述**: `do_create_kb` 函数首先检查文档路径(`self.doc_path`)是否存在。如果该路径存在,函数将继续检查知识库路径(`self.kb_path`)下是否存在名为 "vector_store" 的目录。如果 "vector_store" 目录不存在,则函数会在 `self.kb_path` 下创建该目录。如果 "vector_store" 目录已经存在,则会记录一条警告日志,提示目录已经存在。这个过程确保了知识库的向量存储目录被正确创建,以便后续操作可以在其中存储和管理知识库的向量数据。
**注意**:
- 确保在调用此函数之前,`self.doc_path``self.kb_path` 已经被正确设置,并且指向有效的文件系统路径。
- 如果在创建 "vector_store" 目录时遇到文件系统权限问题,可能会导致目录创建失败。因此,确保应用程序具有足够的权限来创建和写入指定的路径。
- 记录的警告信息可以帮助开发者了解知识库的当前状态,特别是在调试或者排查问题时。
***
### FunctionDef vs_type(self)
**vs_type**: vs_type函数的功能是返回当前知识库服务支持的向量存储类型。
**参数**: 该函数不接受任何参数。
**代码描述**: vs_type函数是ESKBService类的一个方法,它的主要作用是指明Elasticsearch (ES) 作为向量存储服务。该函数通过返回SupportedVSType枚举类中的ES属性值来实现这一点。在ESKBService类中,vs_type方法的返回值被用于配置和初始化Elasticsearch客户端,包括连接信息、索引名称、认证信息等。此外,vs_type方法的返回值还决定了向量维度长度、嵌入模型等配置的获取。这意味着,通过vs_type方法,ESKBService类能够明确其向量存储服务的类型,并据此进行相应的初始化和配置。
**注意**:
- 在使用vs_type方法时,需要确保SupportedVSType枚举类中已定义了返回的向量存储类型,否则可能会影响知识库服务的初始化和配置。
- vs_type方法的返回值直接影响到Elasticsearch客户端的配置,因此在修改该方法时应谨慎,以避免对知识库服务的正常操作产生不利影响。
**输出示例**: "es"
***
### FunctionDef _load_es(self, docs, embed_model)
**_load_es**: 该函数的功能是将文档(docs)写入到Elasticsearch中。
**参数**:
- docs: 需要写入Elasticsearch的文档列表。
- embed_model: 用于生成文档嵌入向量的模型。
**代码描述**:
`_load_es` 函数主要负责将一组文档(docs)通过嵌入模型(embed_model)处理后,写入到Elasticsearch数据库中。该函数首先检查是否提供了用户认证信息(用户名和密码),如果提供了,则使用这些信息来建立与Elasticsearch的安全连接。接着,根据是否提供了用户信息,选择相应的方式来初始化`ElasticsearchStore`对象,该对象负责将文档和它们的嵌入向量存储到指定的Elasticsearch索引中。在存储过程中,会设置一些参数,如索引名(`index_name`)、距离策略(`distance_strategy`)、查询字段(`query_field`)和向量查询字段(`vector_query_field`)等。
在存储文档到Elasticsearch的过程中,如果遇到连接错误(`ConnectionError`),会打印错误信息并记录日志。对于其他类型的异常,也会记录错误日志并打印异常信息。
该函数被`do_add_doc`方法调用,用于在向知识库添加文档的过程中,将文档写入Elasticsearch。`do_add_doc`方法首先打印待写入文档的数量,然后调用`_load_es`函数进行文档的写入操作。文档写入成功后,`do_add_doc`方法会继续执行一系列的操作,包括验证写入的文档是否能够被成功检索等。
**注意**:
- 确保在调用`_load_es`函数之前,`docs`参数中的文档已经准备好,并且`embed_model`模型能够正确生成文档的嵌入向量。
- 在使用`_load_es`函数时,需要确保Elasticsearch服务是可用的,并且提供的用户认证信息(如果有的话)是正确的。
- 该函数中捕获并处理了连接错误,但在实际使用中,还需要注意处理其他可能的异常情况,以确保系统的稳定性。
***
### FunctionDef do_search(self, query, top_k, score_threshold)
**do_search**: 此函数用于执行基于文本相似性的搜索。
**参数**:
- `query`: 字符串类型,表示搜索查询的文本。
- `top_k`: 整型,指定返回的最相似文档数量。
- `score_threshold`: 浮点型,设定的相似度分数阈值,用于过滤结果。
**代码描述**:
`do_search` 函数通过接收一个查询字符串 `query`、一个整数 `top_k` 和一个浮点数 `score_threshold` 作为参数,执行文本相似性搜索。它首先调用 `db_init` 对象的 `similarity_search_with_score` 方法,该方法根据提供的查询 `query` 和指定的返回文档数量 `k=top_k` 来检索最相似的文档。此方法返回一个包含文档的列表,这些文档根据与查询的相似度得分进行排序。
**注意**:
- 确保 `db_init` 已正确初始化并且可以访问相应的数据库或索引,以便执行相似性搜索。
- `top_k` 应为正整数,表示需要返回的文档数量。
- `score_threshold` 参数在此代码段中未直接使用,但可能在 `similarity_search_with_score` 方法内部用于过滤相似度得分低于某一阈值的文档。
**输出示例**:
```python
[
{'doc_id': '123', 'score': 0.95},
{'doc_id': '456', 'score': 0.93},
...
]
```
此输出示例展示了一个可能的返回值,其中包含了文档的ID和与查询的相似度得分。返回的文档数量和具体得分取决于查询内容、`top_k` 的值以及数据库中存储的文档。
***
### FunctionDef get_doc_by_ids(self, ids)
**get_doc_by_ids**: 此函数的功能是根据提供的文档ID列表从Elasticsearch中检索文档。
**参数**:
- `ids`: 一个字符串列表,包含需要检索的文档的ID。
**代码描述**:
`get_doc_by_ids` 函数接收一个文档ID列表作为输入参数,返回一个包含检索到的文档的列表。函数内部,通过遍历ID列表,使用Elasticsearch客户端的`get`方法根据每个ID检索文档。检索到的文档信息存储在变量`response`中,其中包含文档的源数据(`_source`)。函数假设每个文档包含`context``metadata`字段,分别用于存储文档的文本内容和元数据。如果检索成功,函数将创建一个`Document`对象,其中包含文档的文本内容和元数据,并将此对象添加到结果列表中。如果在检索过程中遇到异常,会通过日志记录错误信息,但不会中断整个检索过程。
**注意**:
- 函数假设Elasticsearch中的文档具有`context``metadata`字段。如果文档结构不同,需要相应地调整源代码中的字段名称。
- 在检索文档时遇到的任何异常都会被捕获并记录日志,但不会导致函数终止执行。这意味着即使某些文档ID可能因为错误而未能检索到文档,函数仍会继续尝试检索其余的文档ID。
- 函数返回的是一个`Document`对象列表,每个对象包含一个文档的文本内容和元数据。如果某个文档ID检索失败,该ID对应的文档将不会出现在返回的列表中。
**输出示例**:
假设有两个文档ID分别为"doc1"和"doc2",且这两个文档在Elasticsearch中成功检索到,函数可能返回如下列表:
```python
[
Document(page_content="文档1的文本内容", metadata={"作者": "张三", "发布日期": "2023-01-01"}),
Document(page_content="文档2的文本内容", metadata={"作者": "李四", "发布日期": "2023-02-01"})
]
```
如果"doc2"的检索失败,那么返回的列表将只包含"doc1"对应的`Document`对象。
***
### FunctionDef del_doc_by_ids(self, ids)
**del_doc_by_ids**: 此函数的功能是根据提供的文档ID列表删除Elasticsearch中的相应文档。
**参数**:
- `ids`: 一个字符串列表,包含要从Elasticsearch中删除的文档的ID。
**代码描述**:
`del_doc_by_ids`函数接收一个字符串列表`ids`作为参数,这个列表包含了需要从Elasticsearch索引中删除的文档的ID。函数遍历这个ID列表,对于列表中的每一个ID,它尝试使用`es_client_python.delete`方法从指定的索引`self.index_name`中删除对应的文档,并且设置`refresh=True`以确保删除操作立即生效。
如果在删除操作过程中遇到任何异常,函数会捕获这些异常并通过`logger.error`记录错误信息,包括异常的详细信息。这样做可以帮助开发者在出现问题时迅速定位和解决问题。
**注意**:
- 确保在调用此函数之前,`self.es_client_python`已经被正确初始化,并且已经设置了正确的索引名称`self.index_name`
- 删除操作会立即影响Elasticsearch索引的状态,因此请谨慎使用此函数,确保不会误删除重要文档。
- 如果提供的ID列表中包含不存在于索引中的ID,对应的删除操作将会被忽略,不会影响其他有效删除操作的执行。
- 异常处理机制确保了函数的健壮性,但开发者应注意检查日志文件以了解是否有删除操作失败的情况,并根据需要采取相应措施。
***
### FunctionDef do_delete_doc(self, kb_file)
**do_delete_doc**: 此函数的功能是从Elasticsearch索引中删除与给定知识库文件相关的文档。
**参数**:
- `kb_file`: 需要删除的知识库文件对象,此对象应包含一个`filepath`属性,该属性用于在Elasticsearch中定位相关文档。
- `**kwargs`: 关键字参数,用于提供额外的配置选项,虽然在当前实现中未直接使用,但保留了扩展性。
**代码描述**:
此函数首先检查Elasticsearch中是否存在指定的索引。如果索引存在,它将构造一个查询,该查询使用`kb_file.filepath`作为关键字,查找所有与给定知识库文件路径匹配的文档。查询时,注意设置查询返回的文档数量`size`为50,这是为了确保能够找到所有相关的文档,而不是默认的前10个。
接下来,函数会从查询结果中提取文档的ID,并将这些ID存储在`delete_list`列表中。如果`delete_list`为空,即没有找到任何匹配的文档,函数将返回`None`。如果找到了匹配的文档,函数将遍历`delete_list`中的每个文档ID,并使用Elasticsearch的`delete`方法逐一删除这些文档。在删除过程中,如果遇到任何异常,将通过日志记录错误信息。
**注意**:
- 确保`kb_file`对象有一个有效的`filepath`属性,因为它是定位和删除Elasticsearch中文档的关键。
- 删除操作会即时刷新索引(通过`refresh=True`参数),这可能会对性能有一定影响,特别是在处理大量文档时。请根据实际情况评估是否需要即时刷新。
- 异常处理部分仅记录错误信息,不会中断程序执行。开发者需要关注日志输出,以便了解删除操作是否遇到问题。
**输出示例**:
此函数没有明确的返回值(在成功删除文档或没有找到匹配文档时返回`None`)。因此,函数的主要作用是执行操作,而不是返回数据。
***
### FunctionDef do_add_doc(self, docs)
**do_add_doc**: 该函数的功能是向知识库添加文档。
**参数**:
- docs: 文档列表,每个文档都是一个Document对象。
- **kwargs: 接收可变数量的关键字参数。
**代码描述**:
`do_add_doc` 函数首先打印输入的文档(docs)数量,然后调用 `_load_es` 方法将这些文档写入Elasticsearch。在文档写入过程中,会使用到`embeddings_model`模型来处理文档数据。文档成功写入后,函数会检查Elasticsearch索引是否存在,如果存在,则根据文档的`source`路径构造一个查询,以检索与该路径相匹配的文档。此查询默认返回最多50个结果。如果没有检索到任何文档,函数会抛出一个`ValueError`异常。最后,函数会从检索结果中提取文档的ID和元数据(metadata),并将这些信息以列表的形式返回。
该函数与 `_load_es` 方法的关系是,`do_add_doc` 调用 `_load_es` 方法来实现文档的写入操作。`_load_es` 方法负责将文档通过嵌入模型处理后,写入到Elasticsearch数据库中。这一步是`do_add_doc`实现其功能的关键部分。
**注意**:
- 在调用`do_add_doc`函数之前,确保传入的`docs`参数中的文档已经准备好。
- 该函数依赖于Elasticsearch的索引设置和查询功能,因此在使用前需要确保Elasticsearch服务是可用的,并且相关索引已经正确设置。
- 函数中的错误处理包括检查召回元素个数是否为0,这是为了确保写入的文档能够被成功检索。在实际应用中,可能还需要考虑其他的异常情况。
**输出示例**:
```python
[
{"id": "文档ID1", "metadata": {"source": "文档源路径1", "其他元数据": ""}},
{"id": "文档ID2", "metadata": {"source": "文档源路径2", "其他元数据": ""}},
...
]
```
此输出示例展示了函数返回值的可能形式,即一个包含多个字典的列表,每个字典代表一个文档的ID和元数据信息。
***
### FunctionDef do_clear_vs(self)
**do_clear_vs**: 该函数的功能是从知识库删除全部向量。
**参数**: 此函数不接受任何外部参数。
**代码描述**: `do_clear_vs` 函数是 `ESKBService` 类的一个方法,用于从Elasticsearch知识库中删除所有的向量数据。首先,该函数通过调用 `self.es_client_python.indices.exists` 方法检查指定的索引(即知识库名称,存储在 `self.kb_name` 中)是否存在。如果索引存在,那么通过调用 `self.es_client_python.indices.delete` 方法删除该索引及其包含的所有数据。这一操作将清空知识库中存储的全部向量数据,实现知识库的初始化或清理。
**注意**:
- 在执行此函数之前,确保已经正确设置了 `self.es_client_python``self.kb_name` 属性。`self.es_client_python` 应为一个有效的Elasticsearch客户端实例,而 `self.kb_name` 应为一个字符串,表示要操作的Elasticsearch索引名称。
- 删除索引是一个不可逆的操作,一旦执行,索引中的所有数据将被永久删除。因此,在调用此函数之前,请确保已经做好了相应的数据备份或确认不再需要索引中的数据。
- 由于这个操作会影响到整个知识库的数据,建议在执行此操作前进行充分的测试和评估,确保其对系统的影响是可接受的。
***
### FunctionDef do_drop_kb(self)
**do_drop_kb**: 此函数用于删除知识库。
**参数**: 此函数不接受任何外部参数。
**代码描述**: `do_drop_kb` 函数是 `ESKBService` 类的一个方法,旨在删除指定的知识库目录。该函数首先检查 `self.kb_path`(知识库路径)是否存在。如果该路径存在,则使用 `shutil.rmtree` 方法删除该路径及其下的所有内容。这里的 `self.kb_path` 是一个类属性,代表了知识库文件存储的路径。
具体步骤如下:
1. 通过 `self.kb_path` 获取知识库的存储路径。
2. 使用 `os.path.exists` 函数检查该路径是否存在。
3. 如果路径存在,调用 `shutil.rmtree` 函数删除该路径及其包含的所有文件和子目录。
**注意**: 在使用此函数删除知识库之前,确保已经做好了相应的数据备份,以防不小心删除重要数据。此外,此操作不可逆,请谨慎操作。
***
@@ -0,0 +1,327 @@
## ClassDef FaissKBService
**FaissKBService**: FaissKBService 类是用于通过 FAISS 实现知识库服务的具体类。
**属性**:
- `vs_path`: 向量存储路径。
- `kb_path`: 知识库路径。
- `vector_name`: 向量名称,默认为 None。
**代码描述**:
FaissKBService 类继承自 KBService 类,专门用于处理基于 FAISS 的向量搜索服务。它提供了一系列方法来管理和操作 FAISS 知识库,包括知识库的创建、删除、文档的添加、删除以及搜索等。
- `vs_type` 方法返回支持的向量存储类型,即 FAISS。
- `get_vs_path``get_kb_path` 方法分别用于获取向量存储路径和知识库路径。
- `load_vector_store` 方法加载向量存储,返回一个线程安全的 FAISS 实例。
- `save_vector_store` 方法将向量存储保存到指定路径。
- `get_doc_by_ids` 方法根据文档 ID 获取文档。
- `del_doc_by_ids` 方法根据文档 ID 删除文档。
- `do_init` 方法在类初始化时设置向量名称、知识库路径和向量存储路径。
- `do_create_kb` 方法创建知识库,如果向量存储路径不存在,则创建该路径。
- `do_drop_kb` 方法删除知识库,包括清除向量存储和删除知识库路径。
- `do_search` 方法实现了基于 FAISS 的文档搜索功能。
- `do_add_doc` 方法向知识库添加文档,并将文档转化为向量存储。
- `do_delete_doc` 方法从知识库中删除指定的文档。
- `do_clear_vs` 方法清除向量存储中的所有内容。
- `exist_doc` 方法检查指定文件名的文档是否存在。
**注意**:
- 使用 FaissKBService 类之前,需要确保 FAISS 环境已正确安装和配置。
- 在调用 `do_add_doc``do_delete_doc` 等方法修改知识库内容时,应注意操作的原子性和线程安全性。
- `do_search` 方法中的 `score_threshold` 参数用于过滤搜索结果,只返回得分高于此阈值的文档。
**输出示例**:
```python
# 假设执行搜索操作,返回两个文档及其相关性得分
[
(Document(id="doc1", text="文档1的内容"), 0.95),
(Document(id="doc2", text="文档2的内容"), 0.90)
]
```
这表示在执行搜索操作时,返回了两个文档及其相关性得分。
### FunctionDef vs_type(self)
**vs_type**: vs_type的功能是返回当前知识库服务使用的向量存储类型。
**参数**: 此函数不接受任何参数。
**代码描述**: vs_type函数是FaissKBService类的一个方法,其主要作用是标识FaissKBService类实例所使用的向量存储类型。在这个具体实现中,vs_type方法通过返回SupportedVSType.FAISS,明确指出FaissKBService使用FAISS作为其向量存储服务。SupportedVSType是一个枚举类,定义了项目支持的所有向量存储类型,包括但不限于FAISS、MILVUS、ZILLIZ、PostgreSQL、Elasticsearch和ChromaDB等。通过返回SupportedVSType.FAISSvs_type方法使得知识库服务工厂(KBServiceFactory)能够识别并实例化FaissKBService作为向量存储服务的具体实现。这种设计允许项目动态地根据配置或需求,选择不同的向量存储服务实现,增强了项目的灵活性和可扩展性。
**注意**:
- 在使用vs_type方法时,无需传递任何参数,该方法将直接返回FaissKBService所支持的向量存储类型。
- 该方法的返回值应与SupportedVSType中定义的向量存储类型一致,以确保知识库服务工厂能够正确识别并实例化相应的服务。
- 当扩展项目以支持新的向量存储服务时,应在SupportedVSType枚举类中添加新的类型,并确保相应的知识库服务类实现了vs_type方法,返回其支持的向量存储类型。
**输出示例**:
```python
'faiss'
```
在这个示例中,vs_type方法返回一个字符串'faiss',表明FaissKBService使用FAISS作为其向量存储服务。
***
### FunctionDef get_vs_path(self)
**get_vs_path**: 此函数的功能是获取向量存储路径。
**参数**: 此函数没有显式参数,它依赖于对象的内部状态。
**代码描述**: `get_vs_path` 函数是 `FaissKBService` 类的一个方法,用于获取向量存储(vector storage)的路径。它通过调用全局的 `get_vs_path` 函数实现,此全局函数需要两个参数:`kb_name``vector_name`。这两个参数分别代表知识库的名称和向量的名称,它们是 `FaissKBService` 对象的属性。这意味着,当 `get_vs_path` 方法被调用时,它会使用当前对象的知识库名称和向量名称作为参数来获取向量存储的路径。
在项目中,`get_vs_path` 方法被 `do_init` 方法调用。在 `do_init` 方法中,首先通过一系列初始化操作设置了 `vector_name``kb_path`,然后调用 `get_vs_path` 方法获取向量存储的路径,并将其存储在 `vs_path` 属性中。这表明 `get_vs_path` 方法是在对象初始化过程中,用于确定向量存储位置的关键步骤。
**注意**: 使用此函数时,确保 `kb_name``vector_name` 属性已经被正确设置,因为这两个属性直接影响到向量存储路径的获取结果。
**输出示例**: 假设知识库名称为 "my_kb",向量名称为 "my_vector",则此函数可能返回的路径示例为 "/path/to/my_kb/my_vector_storage"。
***
### FunctionDef get_kb_path(self)
**get_kb_path**: 此函数的功能是获取知识库的路径。
**参数**: 此函数没有参数。
**代码描述**: `get_kb_path`函数是`FaissKBService`类的一个方法,用于返回知识库文件的路径。它通过调用`get_kb_path`函数并传入`self.kb_name`作为参数来实现。这里的`self.kb_name`是在`FaissKBService`类的实例化过程中定义的,代表了知识库的名称。此方法的设计意图是为了提供一种灵活的方式来获取知识库文件的路径,这对于知识库的存储和访问至关重要。
在项目中,`get_kb_path`方法被`do_init`方法调用。在`do_init`方法中,首先通过`self.get_kb_path()`获取知识库路径并将其赋值给`self.kb_path`,然后继续获取向量存储路径并赋值给`self.vs_path`。这表明`get_kb_path`方法在`FaissKBService`类的初始化过程中起到了关键作用,它确保了知识库路径的正确设置,从而为后续的知识库操作提供了基础。
**注意**: 使用`get_kb_path`方法时,需要确保`self.kb_name`已经被正确赋值,因为这直接影响到知识库路径的获取。此外,确保调用此方法的环境中有对应的`get_kb_path`函数定义,且能正确处理传入的知识库名称参数。
**输出示例**: 假设`self.kb_name`的值为"example_kb",则`get_kb_path`方法可能返回的路径示例为`"/path/to/knowledge_bases/example_kb"`。这个返回值代表了知识库文件存储的具体路径。
***
### FunctionDef load_vector_store(self)
**load_vector_store**: 此函数的功能是加载并返回一个线程安全的FAISS向量库实例。
**参数**: 此函数没有显式参数,它通过`self`访问类实例的属性。
**代码描述**: `load_vector_store`函数通过调用`kb_faiss_pool.load_vector_store`方法来加载一个FAISS向量库。它传递了三个参数:`kb_name``vector_name``embed_model`,这些参数分别代表知识库的名称、向量的名称以及嵌入模型。这些参数都是`FaissKBService`类实例的属性,用于指定加载哪个向量库以及使用哪个嵌入模型。加载的向量库是一个`ThreadSafeFaiss`实例,这保证了在多线程环境下对FAISS向量库的操作是安全的。
**注意**:
- 使用此函数前,确保`kb_name``vector_name``embed_model`属性已正确设置,因为它们决定了将加载哪个向量库。
- 返回的`ThreadSafeFaiss`实例支持线程安全的操作,包括文档的增加、删除、搜索等,适用于多线程环境。
**输出示例**: 假设`kb_name`为"my_kb"`vector_name`为"my_vector"`embed_model`为"bert",则此函数可能返回一个表示如下的`ThreadSafeFaiss`实例:
```
<ThreadSafeFaiss: key: my_kb_my_vector, obj: <FAISS向量库对象>, docs_count: 100>
```
这表示加载了一个名为"my_kb_my_vector"的FAISS向量库,其中包含100个文档。
在项目中,`load_vector_store`函数被多个方法调用,包括`save_vector_store``get_doc_by_ids``del_doc_by_ids``do_create_kb``do_search``do_add_doc``do_delete_doc`。这些方法利用`load_vector_store`加载的向量库执行各种操作,如保存向量库到磁盘、通过ID获取文档、删除指定ID的文档、创建知识库、执行搜索、添加文档和删除文档等。这体现了`load_vector_store``FaissKBService`类中的核心作用,它为管理和操作FAISS向量库提供了基础。
***
### FunctionDef save_vector_store(self)
**save_vector_store**: 此函数的功能是保存当前加载的向量库到磁盘。
**参数**: 此函数没有显式参数。
**代码描述**: `save_vector_store`方法首先调用`load_vector_store`方法来加载当前的向量库,确保操作的向量库是最新的。加载的向量库是一个线程安全的FAISS向量库实例,这一点由`load_vector_store`方法保证。加载完成后,通过调用向量库实例的`save`方法,将其保存到`self.vs_path`指定的路径。这个路径是`FaissKBService`类实例化时确定的,代表向量库在磁盘上的存储位置。
在保存向量库的过程中,`save`方法会检查目标路径是否存在,如果不存在且其`create_path`参数为True(默认值),则会创建该路径。这一过程确保了即使目标路径在之前未创建,向量库也能被成功保存。保存操作完成后,会在日志中记录向量库保存的相关信息,包括向量库的键值和保存的目标路径。
**注意**:
- 在调用`save_vector_store`方法之前,确保`self.vs_path`已正确设置,因为它决定了向量库将被保存到哪个路径。
- 由于`save_vector_store`方法依赖于`load_vector_store`来加载向量库,因此需要确保相关的属性(如`kb_name``vector_name``embed_model`)已经被正确设置,以便能够加载正确的向量库。
- 此方法在多线程环境下安全使用,但在保存向量库时,应确保没有其他操作正在修改向量库,以避免数据不一致的问题。
- 如果在保存向量库的过程中遇到路径不存在且无法创建路径的情况,操作可能会失败。因此,调用此方法时应确保应用程序具有足够的权限来创建目录或写入文件。
***
### FunctionDef get_doc_by_ids(self, ids)
**get_doc_by_ids**: 此函数的功能是根据提供的ID列表获取对应的文档对象列表。
**参数**:
- `ids`: 字符串列表,表示需要获取的文档的ID。
**代码描述**:
`get_doc_by_ids`函数首先通过调用`load_vector_store`方法加载一个线程安全的FAISS向量库实例。加载的向量库实例提供了一个上下文管理器,确保在多线程环境下安全地访问和操作向量库。在成功加载向量库实例后,函数使用Python列表推导式遍历提供的ID列表,通过访问向量库实例的`docstore`属性(一个字典类型的存储),使用`get`方法尝试获取每个ID对应的文档对象。如果某个ID在`docstore`中不存在,则返回值为`None`
此函数与`load_vector_store`方法的关系是,它依赖于`load_vector_store`方法提供的线程安全的向量库实例来安全、高效地获取文档对象。`load_vector_store`方法确保了在多线程环境下对FAISS向量库的操作是安全的,这对于`get_doc_by_ids`函数在执行文档检索时至关重要。
**注意**:
- 确保在调用此函数前,向量库已经被正确加载且包含了目标文档的向量数据,否则无法获取到文档对象。
- 返回的文档对象列表中可能包含`None`值,这表示某些提供的ID在向量库的文档存储中不存在。调用方需要对此进行适当的处理。
**输出示例**:
假设提供了ID列表`["doc1", "doc2", "doc3"]`,并且这些ID在向量库的文档存储中都存在对应的文档对象,则此函数可能返回如下的文档对象列表:
```
[<Document: id=doc1, content="文档1的内容">, <Document: id=doc2, content="文档2的内容">, <Document: id=doc3, content="文档3的内容">]
```
如果某个ID(如"doc3")在文档存储中不存在,则对应位置将返回`None`
```
[<Document: id=doc1, content="文档1的内容">, <Document: id=doc2, content="文档2的内容">, None]
```
***
### FunctionDef del_doc_by_ids(self, ids)
**del_doc_by_ids**: 此函数的功能是根据提供的ID列表删除向量库中的文档。
**参数**:
- `ids`: 一个字符串列表,包含要从向量库中删除的文档的ID。
**代码描述**:
`del_doc_by_ids`函数首先通过调用`load_vector_store`方法加载一个线程安全的FAISS向量库实例。这一步骤确保了在多线程环境下对向量库的操作是安全的。加载向量库实例后,使用`with`语句和`acquire`方法创建一个上下文管理器,这样可以安全地获取向量库资源进行操作。在这个上下文管理器内部,调用向量库实例的`delete`方法,传入参数`ids`,即可删除指定ID的文档。
从功能上看,`del_doc_by_ids`与其调用的`load_vector_store``acquire`方法紧密相关。`load_vector_store`负责加载并返回一个线程安全的向量库实例,这是进行任何向量库操作的前提。而`acquire`方法则提供了一个安全的环境,确保在执行删除操作时,不会因为多线程访问而导致数据竞争或不一致的问题。
**注意**:
- 在调用`del_doc_by_ids`函数之前,确保传入的ID列表中的每个ID都是向量库中实际存在的文档ID。如果尝试删除一个不存在的ID,根据FAISS库的具体实现,这可能会导致错误或者简单地忽略该操作。
- 由于`del_doc_by_ids`涉及到对向量库的修改操作,建议在执行此操作前后对向量库进行适当的备份,以防止意外数据丢失。
- 此函数适用于需要从向量库中批量删除文档的场景,例如在文档更新或清理过程中。
***
### FunctionDef do_init(self)
**do_init**: 此函数的功能是初始化FaissKBService对象。
**参数**: 此函数没有显式参数。
**代码描述**: `do_init` 方法是 `FaissKBService` 类的一个关键方法,用于完成对象的初始化工作。在这个方法中,首先会检查 `self.vector_name` 是否已经被赋值,如果没有,则将其设置为 `self.embed_model` 的值。这一步骤确保了向量名称的正确设置,是后续操作如向量存储路径的获取的基础。
接下来,`do_init` 方法调用 `self.get_kb_path()` 方法来获取知识库的路径,并将这个路径赋值给 `self.kb_path` 属性。这一步是为了确保知识库路径的正确设置,从而使得后续对知识库的操作能够基于正确的路径进行。
紧接着,`do_init` 方法调用 `self.get_vs_path()` 方法来获取向量存储的路径,并将这个路径赋值给 `self.vs_path` 属性。这一步是为了确保向量存储路径的正确设置,从而使得后续对向量的存储和访问能够基于正确的路径进行。
通过这些步骤,`do_init` 方法为 `FaissKBService` 对象的后续操作提供了必要的初始化设置,包括知识库路径和向量存储路径的设置,以及向量名称的确认。这些设置是后续操作正确进行的基础。
**注意**: 在使用 `do_init` 方法之前,确保 `self.embed_model` 已经被正确赋值,因为在向量名称未显式设置的情况下,`do_init` 方法会将 `self.embed_model` 作为向量名称。此外,`do_init` 方法的正确执行依赖于 `get_kb_path``get_vs_path` 方法的正确实现,因此在调用 `do_init` 方法之前,需要确保这两个方法能够正确返回知识库路径和向量存储路径。
***
### FunctionDef do_create_kb(self)
**do_create_kb**: 此函数的功能是创建知识库。
**参数**: 此函数没有显式参数,它通过`self`访问类实例的属性。
**代码描述**: `do_create_kb`函数首先检查由`self.vs_path`指定的路径是否存在,如果不存在,则创建该路径。这一步骤确保了存储向量数据的目录是可用的。接着,该函数调用`load_vector_store`方法。`load_vector_store`方法的作用是加载并返回一个线程安全的FAISS向量库实例,这一过程是通过访问`FaissKBService`类实例的`kb_name``vector_name``embed_model`属性来完成的,这些属性分别指定了要加载的知识库名称、向量名称以及嵌入模型。加载的向量库是线程安全的,支持在多线程环境下安全地进行文档的增加、删除和搜索等操作。
从功能角度看,`do_create_kb`函数通过确保向量存储路径的存在并加载向量库,为后续的知识库操作(如添加文档、搜索文档等)准备了必要的环境。这一过程是`FaissKBService`类管理和操作FAISS向量库的基础步骤之一。
**注意**:
- 在调用`do_create_kb`函数之前,确保`vs_path`属性已正确设置,因为它决定了向量数据存储的位置。
- 该函数依赖于`load_vector_store`方法来加载向量库,因此在使用前应确保`kb_name``vector_name``embed_model`属性已经被正确配置,以指定加载哪个向量库以及使用哪个嵌入模型。
***
### FunctionDef do_drop_kb(self)
**do_drop_kb**: 此函数的功能是删除知识库。
**参数**: 此函数不接受任何外部参数。
**代码描述**: `do_drop_kb` 方法是 `FaissKBService` 类的成员方法,主要负责删除整个知识库。该方法首先调用 `clear_vs` 方法来清除知识库中的向量数据。根据 `clear_vs` 方法的文档,这一步骤会删除向量库中的所有内容,并且是通过删除数据库中与知识库相关的所有文件记录来实现的。这是一个重要的预处理步骤,确保在物理删除知识库文件之前,相关的向量数据已经被清除。
接下来,`do_drop_kb` 方法尝试使用 `shutil.rmtree` 函数删除知识库的物理文件夹。这一步骤是通过传递 `self.kb_path` 作为参数来完成的,其中 `self.kb_path` 表示知识库文件夹的路径。如果在删除过程中遇到任何异常,该方法会捕获异常并不做进一步处理,这意味着异常情况下的具体处理逻辑可能需要在未来根据实际需求进行添加。
**注意**:
- 在调用 `do_drop_kb` 方法之前,请确保已经备份了重要数据。一旦执行此方法,知识库及其包含的所有数据将被永久删除,这一操作是不可逆的。
- 请确保 `self.kb_path` 已经正确设置,指向了需要被删除的知识库的物理路径。
- 考虑到异常处理目前尚未实现详细逻辑,开发者在使用此方法时应当注意异常情况的监控和处理,以避免潜在的问题。
此方法在项目中的主要应用场景包括知识库的重置或删除操作,特别是在知识库数据需要被彻底清除以释放存储空间或为新的知识库初始化时。通过先清除向量数据再删除物理文件夹的步骤,`do_drop_kb` 方法确保了知识库的彻底清除。
***
### FunctionDef do_search(self, query, top_k, score_threshold)
**do_search**: 此函数的功能是根据给定的查询字符串,执行相似度搜索并返回最相关的文档列表及其相应的分数。
**参数**:
- `query`: 需要进行搜索的查询字符串。
- `top_k`: 返回的最相关文档的数量。
- `score_threshold`: 分数阈值,只有当文档的相似度分数高于此阈值时,才会被包含在结果中。默认值为`SCORE_THRESHOLD`
**代码描述**:
`do_search`函数首先通过`EmbeddingsFunAdapter`类的实例化,使用`self.embed_model`作为嵌入模型,对查询字符串`query`进行向量化处理,得到查询的嵌入向量。`EmbeddingsFunAdapter`类是一个专门用于将文本转换为嵌入向量的适配器,它支持同步和异步两种方式进行文本的嵌入表示转换。
随后,函数调用`self.load_vector_store()`方法获取一个线程安全的FAISS向量库实例。`load_vector_store`方法负责加载并返回一个`ThreadSafeFaiss`实例,该实例封装了FAISS向量库的操作,确保在多线程环境下的线程安全性。加载的向量库包含了预先索引的文档向量,用于执行相似度搜索。
在成功获取向量库实例后,函数使用`acquire`方法以线程安全的方式访问向量库,并调用`similarity_search_with_score_by_vector`方法执行相似度搜索。该方法接受查询的嵌入向量、`top_k`参数指定的返回文档数量以及`score_threshold`分数阈值作为输入,返回与查询最相关的`top_k`个文档及其相似度分数。
最后,函数返回搜索结果,即最相关的文档列表及其相应的分数。
**注意**:
- 在使用`do_search`函数之前,确保`self.embed_model`已正确设置,因为它决定了查询字符串如何被向量化。
- `top_k`参数应为正整数,表示需要返回的最相关文档的数量。
- 分数阈值`score_threshold`用于过滤相似度分数低于该阈值的文档,可以根据实际需求调整。
**输出示例**:
假设对于查询字符串"人工智能",`top_k`设置为3`score_threshold`设置为0.5,函数可能返回如下结果:
```
[
(Document(id="doc1", title="人工智能基础", content="..."), 0.95),
(Document(id="doc2", title="人工智能应用", content="..."), 0.85),
(Document(id="doc3", title="人工智能未来", content="..."), 0.75)
]
```
这表示找到了三个与查询"人工智能"最相关的文档,它们的相似度分数分别为0.95、0.85和0.75。
***
### FunctionDef do_add_doc(self, docs)
**do_add_doc**: 此函数的功能是向知识库中添加文档,并返回添加的文档信息。
**参数**:
- `docs`: 需要添加到知识库中的文档对象列表,类型为`List[Document]`
- `**kwargs`: 关键字参数,可以包括`ids``not_refresh_vs_cache`等选项。
**代码描述**:
`do_add_doc`方法首先调用`_docs_to_embeddings`私有方法,将文档对象列表转化为向量和元数据的格式,这一步骤有助于减少向量库的锁定时间,提高效率。接着,通过`load_vector_store`方法加载线程安全的FAISS向量库实例,并使用`acquire`方法安全地获取向量库的操作权限。在这个上下文管理器中,使用`add_embeddings`方法将文档的文本、向量和元数据添加到向量库中,并根据`kwargs`中的`ids`参数指定的ID进行存储。如果`kwargs`中没有设置`not_refresh_vs_cache``True`,则会调用`save_local`方法将向量库的当前状态保存到本地路径`self.vs_path`。最后,构造并返回包含文档ID和元数据的信息列表。在方法的末尾,调用`torch_gc`函数清理PyTorch的缓存内存,以避免内存溢出或性能下降的问题。
**注意**:
- 确保传入的`docs`参数是有效的文档对象列表。
- 使用`kwargs`中的`ids`参数可以指定添加文档的ID,如果不指定,则向量库会自动生成ID。
- 如果不希望每次添加文档后都刷新向量库缓存,可以通过设置`kwargs`中的`not_refresh_vs_cache``True`来跳过保存向量库到本地的步骤。
- 调用`torch_gc`函数清理缓存是为了管理内存使用,特别是在处理大量数据时。
**输出示例**:
调用`do_add_doc(docs=[Document1, Document2], ids=[1, 2])`可能会返回如下列表:
```python
[
{"id": 1, "metadata": {"title": "文档1标题"}},
{"id": 2, "metadata": {"title": "文档2标题"}}
]
```
这个列表包含了每个添加到知识库中文档的ID和元数据信息。
***
### FunctionDef do_delete_doc(self, kb_file)
**do_delete_doc**: 此函数的功能是根据给定的知识库文件删除相应的文档向量。
**参数**:
- `kb_file`: KnowledgeFile对象,表示要删除的知识库文件。
- `**kwargs`: 关键字参数,用于提供额外的配置选项。
**代码描述**:
`do_delete_doc`函数首先通过调用`load_vector_store`方法加载一个线程安全的FAISS向量库实例。接着,它遍历向量库中的文档存储(`vs.docstore._dict`),寻找其元数据中`source`字段与`kb_file.filename`相匹配(不区分大小写)的文档ID。找到后,将这些ID存储在列表`ids`中。如果`ids`列表不为空,即存在需要删除的文档,那么调用`vs.delete(ids)`方法删除这些文档。
此外,函数检查关键字参数`not_refresh_vs_cache`。如果该参数不存在或其值为`False`,则调用`vs.save_local(self.vs_path)`方法,将更新后的向量库保存到本地路径。这一步骤确保了向量库的状态与实际文档保持一致。
最后,函数返回被删除的文档ID列表`ids`
**注意**:
- 在调用此函数之前,确保传入的`kb_file`对象正确表示了要删除的知识库文件,并且该文件已经存在于知识库中。
- 删除操作会直接影响向量库的内容,因此在执行此操作前应确保已经做好相应的备份或确认操作的必要性。
- `not_refresh_vs_cache`参数允许调用者控制是否立即更新本地向量库缓存,这在批量删除操作时可能有用,以避免频繁的磁盘写操作。
**输出示例**:
```python
# 假设删除操作找到并删除了两个文档,其ID分别为'123'和'456'
deleted_ids = do_delete_doc(kb_file)
print(deleted_ids) # 输出: ['123', '456']
```
在此示例中,`do_delete_doc`函数返回了一个包含被删除文档ID的列表。这表明两个文档已从向量库中成功删除。
***
### FunctionDef do_clear_vs(self)
**do_clear_vs**: 此函数的功能是清除特定向量存储。
**参数**: 此函数不接受任何外部参数。
**代码描述**: `do_clear_vs` 函数是 `FaissKBService` 类的一个方法,用于清除与特定知识库名称 (`kb_name`) 和向量名称 (`vector_name`) 相关联的向量存储。该函数首先通过 `kb_faiss_pool.atomic` 上下文管理器确保对 `kb_faiss_pool` 的操作是原子的,然后调用 `pop` 方法从 `kb_faiss_pool` 中移除指定的键值对。这里的键是由知识库名称和向量名称组成的元组 `(self.kb_name, self.vector_name)``pop` 方法的作用是从缓存池中移除并返回指定键的对象,如果键不存在,则不执行任何操作。
接下来,函数尝试删除向量存储的物理路径 `self.vs_path`。这是通过调用 `shutil.rmtree` 方法实现的,该方法会递归删除文件夹及其所有内容。如果在删除过程中遇到任何异常(例如路径不存在或权限问题),异常会被捕获并忽略,确保程序的稳定性。
最后,函数使用 `os.makedirs` 方法重新创建向量存储的路径,`exist_ok=True` 参数确保如果路径已经存在,则不会抛出异常。这一步骤是为了确保即使向量存储被清除,相关的路径结构仍然被保留,便于后续的向量存储操作。
**注意**:
- 在调用 `do_clear_vs` 函数之前,应确保知识库名称 (`kb_name`) 和向量名称 (`vector_name`) 已经正确设置,因为这些信息将用于定位需要清除的向量存储。
- 由于 `do_clear_vs` 函数会删除物理路径下的所有文件和文件夹,因此在调用此函数时应谨慎,以避免意外删除重要数据。
- 在多线程或多进程环境中使用 `do_clear_vs` 函数时,应注意同步和并发控制,以防止数据竞争或不一致的情况发生。
***
### FunctionDef exist_doc(self, file_name)
**exist_doc**: 此函数的功能是判断指定的文件名是否存在于知识库中。
**参数**:
- `file_name`: 需要查询的文件名,类型为字符串。
**代码描述**:
`exist_doc` 函数首先调用其父类的 `exist_doc` 方法来检查指定的文件名是否已经存在于数据库中。如果父类方法返回 `True`,表示文件已存在于数据库中,那么此函数将返回 `"in_db"` 字符串,表示文件存在于数据库。
如果文件不在数据库中,函数接着会检查文件是否存在于知识库的 `content` 文件夹内。这是通过拼接知识库路径 (`self.kb_path`) 和 `"content"` 子目录,然后检查拼接路径下是否有与 `file_name` 相对应的文件来实现的。如果文件确实存在于 `content` 文件夹中,函数将返回 `"in_folder"` 字符串,表示文件存在于文件夹中。
如果以上两种情况都不成立,即文件既不在数据库中也不在文件夹中,函数将返回 `False`,表示文件不存在于知识库中。
**注意**:
- 确保在调用此函数前,`self.kb_path` 已被正确设置,指向知识库的根目录。
- 此函数的返回值有三种可能:"in_db"、"in_folder" 和 `False`,分别表示文件存在于数据库中、存在于文件夹中和不存在于知识库中。
**输出示例**:
- 如果文件存在于数据库中: `"in_db"`
- 如果文件存在于文件夹中: `"in_folder"`
- 如果文件不存在于知识库中: `False`
***
@@ -0,0 +1,292 @@
## ClassDef MilvusKBService
**MilvusKBService**: MilvusKBService 类是用于在 Milvus 向量数据库中管理和操作知识库的服务。
**属性**:
- `milvus`: Milvus 实例,用于执行与 Milvus 数据库相关的操作。
**代码描述**:
MilvusKBService 类继承自 KBService 类,提供了一系列方法用于在 Milvus 向量数据库中管理和操作知识库。这包括文档的增加、删除、搜索以及知识库的创建、初始化、删除等操作。
- `get_collection` 静态方法用于获取 Milvus 中的集合(Collection)。
- `get_doc_by_ids` 方法根据文档ID列表检索文档,返回包含文档内容和元数据的 Document 对象列表。
- `del_doc_by_ids` 方法根据文档ID列表从知识库中删除文档。
- `search` 静态方法实现了基于内容的搜索功能,返回与搜索内容最相关的文档列表。
- `do_create_kb` 方法用于创建知识库,此方法在 MilvusKBService 类中为空实现,具体逻辑需在子类中定义。
- `vs_type` 方法返回知识库使用的向量存储类型,对于 MilvusKBService 类,始终返回 `SupportedVSType.MILVUS`
- `_load_milvus` 方法负责加载 Milvus 实例,包括设置嵌入函数、集合名称、连接参数等。
- `do_init` 方法初始化 Milvus 实例。
- `do_drop_kb` 方法删除知识库,包括释放和删除集合。
- `do_search` 方法实现了基于查询的搜索功能,返回与查询最相关的文档列表。
- `do_add_doc` 方法向知识库添加文档。
- `do_delete_doc` 方法根据 KnowledgeFile 对象从知识库中删除文档。
- `do_clear_vs` 方法清空知识库中的所有文档。
**注意**:
- 使用 MilvusKBService 类之前,需要确保 Milvus 服务已经启动并可连接。
- 在调用 `do_add_doc``do_delete_doc` 方法时,需要传入符合 Milvus 要求的文档格式。
- `get_collection` 方法需要确保传入的集合名称在 Milvus 中已存在。
**输出示例**:
```python
# 假设执行搜索操作后的返回示例
[
{"id": "123", "content": "文档内容示例", "score": 0.95},
{"id": "456", "content": "另一个文档内容示例", "score": 0.90}
]
```
这表示在执行搜索操作时,返回了两个文档及其相关性得分。
### FunctionDef get_collection(milvus_name)
**get_collection**: 此函数的功能是获取指定名称的Milvus集合。
**参数**:
- **milvus_name**: 需要获取的Milvus集合的名称。
**代码描述**:
`get_collection`函数是`MilvusKBService`类中用于获取Milvus数据库中特定名称的集合的方法。它通过`milvus_name`参数接收集合的名称,并使用`pymilvus`库中的`Collection`类来获取并返回这个集合的实例。这个函数在项目中的主要作用是为其他需要操作Milvus集合的方法提供集合实例,例如,在`search`方法中,它通过调用`get_collection`来获取集合实例,然后在这个集合上执行搜索操作。
`search`方法中,`get_collection`被用来获取一个集合实例,然后使用这个实例来执行搜索操作,其中包括指定搜索参数和返回字段。这显示了`get_collection`在项目中作为获取Milvus集合实例的基础功能的重要性。
**注意**:
- 确保传入的`milvus_name`参数正确,且对应的Milvus集合已经存在,否则`Collection`类可能会抛出异常。
- 使用`get_collection`函数需要先安装并正确配置`pymilvus`库。
**输出示例**:
调用`get_collection("example_collection")`可能会返回一个`Collection`类的实例,这个实例代表了名为`example_collection`的Milvus集合。具体的返回值依赖于Milvus数据库中该集合的状态和内容。
***
### FunctionDef get_doc_by_ids(self, ids)
**get_doc_by_ids**: 此函数的功能是根据提供的ID列表从Milvus数据库中检索文档。
**参数**:
- `ids`: 一个字符串列表,包含要检索的文档的ID。
**代码描述**:
`get_doc_by_ids` 函数接受一个ID列表作为参数,返回一个包含对应ID的文档列表。首先,函数检查Milvus数据库的集合是否存在。如果集合存在,函数将继续执行以下步骤:
1. 将输入的ID列表中的每个ID转换为整数,因为Milvus数据库中可能以整数形式存储这些ID。
2. 使用转换后的ID列表构造一个查询表达式,用于从Milvus数据库的集合中检索具有这些ID的文档。
3. 执行查询,检索包含所有指定字段的文档列表。这里的`output_fields=["*"]`表示检索文档的所有字段。
4. 遍历查询结果,从每个结果中提取文本内容,并将其余部分作为元数据存储。每个文档被封装为一个`Document`对象,其中包含页面内容(`page_content`)和元数据(`metadata`)。
5. 将所有`Document`对象收集到一个列表中,并返回这个列表。
**注意**:
- 确保传入的ID列表中的ID与Milvus数据库中存储的ID类型相匹配。如果数据库中的ID是整数类型,确保转换ID类型。
- 此函数依赖于Milvus数据库的连接实例(`self.milvus`)和其集合(`self.milvus.col`)。确保在调用此函数之前已正确配置这些连接。
**输出示例**:
假设有两个文档的ID分别为"1"和"2",调用`get_doc_by_ids(["1", "2"])`可能返回如下列表:
```python
[
Document(page_content="文档1的内容", metadata={"id": 1, "title": "文档1标题", ...}),
Document(page_content="文档2的内容", metadata={"id": 2, "title": "文档2标题", ...})
]
```
此示例展示了函数返回的`Document`对象列表,每个对象包含了对应文档的页面内容和元数据。
***
### FunctionDef del_doc_by_ids(self, ids)
**del_doc_by_ids**: 此函数的功能是根据提供的ID列表删除Milvus数据库中的文档。
**参数**:
- `ids`: 需要删除的文档的ID列表,类型为`List[str]`
**代码描述**:
`del_doc_by_ids`函数接受一个字符串列表`ids`作为参数,这个列表包含了需要从Milvus数据库中删除的文档的ID。函数内部,通过调用`self.milvus.col.delete`方法来执行删除操作。这个方法使用了一个表达式`expr=f'pk in {ids}'`,其中`pk`代表Milvus数据库中的主键字段,这个表达式的意思是选择所有主键在`ids`列表中的文档进行删除。
**注意**:
- 确保传入的`ids`列表中的ID是存在于Milvus数据库中的,否则删除操作不会影响任何文档。
- 删除操作是不可逆的,一旦执行,相应的文档将从数据库中永久移除,请谨慎使用此功能。
- 在执行删除操作前,建议先进行必要的数据备份,以防不慎删除重要数据。
- 此函数返回一个布尔值,表示删除操作是否成功执行,但需要注意的是,即使删除操作成功,也不代表所有指定的ID都被成功删除,因为某些ID可能本来就不存在于数据库中。
***
### FunctionDef search(milvus_name, content, limit)
**search**: 此函数的功能是在Milvus集合中执行向量搜索操作。
**参数**:
- **milvus_name**: 字符串类型,指定要搜索的Milvus集合的名称。
- **content**: 搜索内容,通常是向量或向量数组。
- **limit**: 整型,指定返回的最大结果数量,默认为3。
**代码描述**:
`search`函数是`MilvusKBService`类中用于在指定的Milvus集合中执行向量搜索操作的方法。它首先定义了一个搜索参数`search_params`,其中包括度量类型("L2")和其他搜索相关参数(如"nprobe": 10)。这些参数用于控制搜索过程中的行为,例如,"L2"指定了使用L2距离(欧几里得距离)作为相似度的衡量标准。
接下来,函数通过调用`get_collection`方法获取指定名称(`milvus_name`)的Milvus集合的实例。`get_collection`方法是`MilvusKBService`类中的一个重要方法,它负责连接到Milvus数据库并获取集合的实例,以便进行后续的操作,如本函数中的搜索操作。
一旦获得集合实例,函数使用该实例的`search`方法执行搜索操作。搜索操作的参数包括搜索内容(`content`)、搜索字段("embeddings")、搜索参数(`search_params`)、结果数量限制(`limit`)和输出字段(["content"])。这允许函数在指定的集合中根据给定的向量内容进行搜索,并返回与搜索内容最相似的几个结果。
**注意**:
- 确保`milvus_name`参数正确,且对应的Milvus集合已经存在,否则可能无法获取集合实例,导致搜索失败。
- 搜索参数`search_params`中的"metric_type"和"params"应根据实际搜索需求进行调整。
- `limit`参数控制返回结果的数量,根据实际需求调整此值。
**输出示例**:
调用`search("example_collection", some_vector, limit=2)`可能会返回如下格式的结果:
```python
[
{"content": "文档1的内容", "distance": 0.1},
{"content": "文档2的内容", "distance": 0.2}
]
```
这个示例显示了搜索操作返回的两个最相似的结果,每个结果包括了匹配内容和与搜索内容的距离(相似度的衡量)。
***
### FunctionDef do_create_kb(self)
**do_create_kb函数功能**: 此函数用于创建知识库。
**参数**: 此函数没有参数。
**代码描述**: `do_create_kb`函数是`MilvusKBService`类中的一个方法,目前其内部实现为空(使用了`pass`语句)。这意味着,函数被调用时不会执行任何操作。在实际应用中,该函数可能被设计为负责在Milvus向量数据库中创建一个新的知识库,包括但不限于初始化知识库的结构、配置知识库的存储参数等。由于当前代码中该函数的实现为空,开发者需要根据实际需求完成相应的功能实现。
**注意**:
- 由于`do_create_kb`函数当前未实现任何功能,直接调用它不会对系统产生任何影响。开发者在使用时需要添加具体的实现逻辑。
- 在为`do_create_kb`函数添加实现逻辑时,应确保理解Milvus向量数据库的相关API和知识库的需求,以确保正确和高效地创建知识库。
- 考虑到未来可能的需求变更和功能扩展,建议在实现具体逻辑时编写清晰、可维护的代码,并充分进行测试。
***
### FunctionDef vs_type(self)
**vs_type**: vs_type函数的功能是返回当前知识库服务支持的向量存储类型。
**参数**: 该函数不接受任何参数。
**代码描述**: vs_type函数是MilvusKBService类的一个方法,它的作用是标识该服务实例支持的向量存储类型。在这个具体实现中,vs_type方法通过返回SupportedVSType.MILVUS来明确指出,当前的知识库服务使用的是MILVUS作为其向量存储解决方案。SupportedVSType是一个枚举类,其中定义了一系列支持的向量存储类型,包括但不限于FAISS、MILVUS、ZILLIZ等。通过返回SupportedVSType.MILVUSvs_type方法为知识库服务工厂(KBServiceFactory)提供了必要的信息,以便在需要时能够正确地实例化和管理MilvusKBService对象。这种设计允许系统灵活地支持多种向量存储服务,同时保持了代码的模块化和可扩展性。
**注意**:
- 在使用vs_type方法时,不需要传递任何参数,它将返回一个字符串,表示支持的向量存储类型。
- 返回的向量存储类型应与SupportedVSType枚举类中定义的类型一致,以确保系统的一致性和可靠性。
- 当需要扩展知识库服务以支持更多的向量存储类型时,应首先在SupportedVSType枚举类中添加新的类型,然后在相应的知识库服务类中实现vs_type方法,以返回新增的类型。
**输出示例**:
```python
'milvus'
```
在这个示例中,vs_type方法返回了一个字符串'milvus',表明当前的知识库服务实例使用MILVUS作为其向量存储解决方案。
***
### FunctionDef _load_milvus(self)
**_load_milvus**: 此函数的功能是初始化Milvus服务的连接并配置相关参数。
**参数**: 此函数没有显式参数,但它依赖于类属性进行操作。
**代码描述**: `_load_milvus`函数负责创建一个Milvus实例,并通过该实例连接到Milvus服务。它使用`EmbeddingsFunAdapter`类来适配嵌入模型,该模型将用于文本的嵌入表示转换。此外,它还配置了Milvus集合的名称、连接参数、索引参数和搜索参数。这些参数从`kbs_config`配置对象中获取,其中包括:
- `embedding_function`:使用`EmbeddingsFunAdapter`类,它根据提供的嵌入模型(`embed_model`)来生成文本的嵌入表示。
- `collection_name`:指定Milvus中的集合名称,这里使用`self.kb_name`作为集合名称。
- `connection_args`:包含连接Milvus服务所需的参数,这些参数从`kbs_config.get("milvus")`中获取。
- `index_params``search_params`:分别用于配置Milvus索引的创建参数和搜索参数,这些参数通过`kbs_config.get("milvus_kwargs")`获取。
此函数是`MilvusKBService`类的私有方法,主要在类的初始化过程(`do_init`)和执行搜索操作(`do_search`)之前被调用,以确保Milvus服务的连接已经建立并配置好了相应的参数。
**注意**:
- 在调用`_load_milvus`之前,确保`kbs_config`配置对象中包含了正确的Milvus连接参数、索引参数和搜索参数。
- `EmbeddingsFunAdapter`类是一个关键组件,它负责将文本转换为嵌入向量,这些嵌入向量随后将用于Milvus中的相似度搜索。因此,确保`embed_model`属性已正确设置,并且所引用的嵌入模型是有效的。
- `_load_milvus`函数不应直接从类外部调用,而是通过类的公共方法(如`do_init``do_search`)间接调用。
***
### FunctionDef do_init(self)
**do_init**: 此函数的功能是初始化Milvus知识库服务。
**参数**: 此函数没有参数。
**代码描述**: `do_init`函数是`MilvusKBService`类的公共方法,其主要职责是调用`_load_milvus`私有方法来完成Milvus服务的初始化。在`_load_milvus`方法中,会创建一个Milvus实例,并通过该实例连接到Milvus服务,同时配置相关的参数,如嵌入模型、集合名称、连接参数、索引参数和搜索参数。这些参数的配置是基于`kbs_config`配置对象进行的。因此,`do_init`方法通过调用`_load_milvus`,间接完成了Milvus服务的连接和参数配置,为后续的知识库操作(如搜索)做好准备。
**注意**:
- `do_init`方法通常在`MilvusKBService`类实例化后立即调用,以确保Milvus服务的连接和配置正确完成。
- 在调用`do_init`方法之前,应确保`kbs_config`配置对象已正确设置,包括Milvus服务的连接信息和操作参数。
- 除了在类初始化时调用,`do_init`方法还可能在需要重新初始化Milvus服务连接时被调用,例如在`do_clear_vs`方法中,如果已存在的Milvus集合被清除,将会调用`do_init`来重新初始化服务。
- 由于`do_init`方法依赖于`_load_milvus`私有方法,因此在修改或维护代码时应注意这两个方法之间的关系和依赖。
***
### FunctionDef do_drop_kb(self)
**do_drop_kb**: 此函数的功能是释放并删除当前Milvus数据库中的集合。
**参数**: 此函数没有参数。
**代码描述**: `do_drop_kb`函数是`MilvusKBService`类的一个方法,用于处理与Milvus数据库中的集合相关的删除操作。当调用此函数时,首先会检查`self.milvus.col`(即当前操作的Milvus集合)是否存在。如果存在,该方法将执行两个步骤:首先,使用`release()`方法释放集合,这是为了确保在删除集合之前,所有的资源都被正确地释放;随后,调用`drop()`方法删除集合。这个过程确保了集合被安全且彻底地从Milvus数据库中移除。
在项目中,`do_drop_kb`函数被`do_clear_vs`方法调用。`do_clear_vs`方法的目的是清理视图状态,它通过调用`do_drop_kb`来删除相关的Milvus集合,然后通过调用`do_init`来重新初始化状态。这表明`do_drop_kb`在项目中扮演着重要的角色,它是处理数据清理和状态重置流程中不可或缺的一部分。
**注意**: 在使用`do_drop_kb`函数时,需要确保Milvus数据库的连接是正常的,并且调用此函数会永久删除集合及其所有数据,这是一个不可逆的操作。因此,在调用此函数之前,应该仔细考虑是否真的需要删除集合,以避免意外丢失重要数据。
***
### FunctionDef do_search(self, query, top_k, score_threshold)
**do_search**: 此函数的功能是执行文本查询,并返回与查询最相似的前k个文档及其相似度分数。
**参数**:
- `query`: 需要查询的文本,数据类型为字符串。
- `top_k`: 返回的文档数量上限,数据类型为整数。
- `score_threshold`: 分数阈值,用于筛选相似度高于此阈值的文档,数据类型为浮点数。
**代码描述**:
`do_search`函数首先调用`_load_milvus`方法来初始化Milvus服务的连接并配置相关参数,确保Milvus服务可以被正确访问。接着,使用`EmbeddingsFunAdapter`类的实例`embed_func`来处理输入的查询文本`query`,将其转换为嵌入向量。这一步是通过调用`embed_func.embed_query(query)`实现的,该方法返回查询文本的嵌入向量。
随后,函数利用`self.milvus.similarity_search_with_score_by_vector`方法,传入查询文本的嵌入向量和`top_k`参数,执行相似度搜索。该方法返回与查询最相似的前`top_k`个文档及其相似度分数。
最后,调用`score_threshold_process`函数,传入`score_threshold``top_k`和搜索结果`docs`作为参数,根据分数阈值筛选出符合条件的文档,并返回前`top_k`个文档及其相似度分数。这一步骤确保了最终返回的文档不仅与查询文本相似度高,而且其相似度分数超过了指定的阈值。
**注意**:
- 在调用`do_search`函数之前,确保Milvus服务已经正确配置并可以访问。
- `top_k`参数应根据实际需求合理设置,以避免返回过多不相关的结果。
- `score_threshold`参数用于进一步筛选相似度较高的文档,应根据实际情况调整其值。
**输出示例**:
假设输入查询为"最近的科技新闻",`top_k`为3`score_threshold`为0.5,可能的返回值为:
```
[
("doc1", 0.8),
("doc2", 0.75),
("doc3", 0.65)
]
```
这表示在所有文档中,有三个文档的相似度分数满足大于等于0.5的条件,并且是与查询"最近的科技新闻"最相似的前3个文档。
***
### FunctionDef do_add_doc(self, docs)
**do_add_doc**: 此函数的功能是向Milvus数据库中添加文档,并返回添加的文档信息。
**参数**:
- `docs`: 需要添加到Milvus数据库中的文档列表,每个文档都是一个Document对象。
- `**kwargs`: 接受可变数量的关键字参数,这些参数可以用于扩展或自定义功能。
**代码描述**:
此函数首先遍历输入的文档列表`docs`。对于每个文档,它会遍历文档的元数据`metadata`,将所有元数据的值转换为字符串类型。接着,它会检查Milvus数据库的字段,确保每个文档的元数据中都包含这些字段,如果缺少,则会添加空字符串作为默认值。此外,它会从元数据中移除特定的字段,这些字段通常是用于文本和向量数据的字段,因为它们可能不适合直接存储为元数据。
在处理完所有文档的元数据后,函数调用`self.milvus.add_documents(docs)`方法将文档添加到Milvus数据库中。此方法返回添加的文档的ID列表。
最后,函数构造一个包含文档ID和更新后的元数据的字典列表,并将此列表作为结果返回。
**注意**:
- 确保传入的文档列表`docs`中的每个文档都是有效的Document对象,并且已经正确设置了必要的元数据。
- 此函数不处理文本和向量字段的存储,调用此函数前请确保这些数据已经以适当的方式处理。
**输出示例**:
```python
[
{"id": "123456789", "metadata": {"title": "文档标题1", "author": "作者1"}},
{"id": "987654321", "metadata": {"title": "文档标题2", "author": "作者2"}}
]
```
此示例展示了函数返回值的可能形式,包含了每个添加到Milvus数据库中的文档的ID和更新后的元数据。
***
### FunctionDef do_delete_doc(self, kb_file)
**do_delete_doc**: 此函数的功能是删除指定知识库文件中的文档记录。
**参数**:
- `kb_file`: KnowledgeFile类型,表示要删除文档的知识库文件。
- `**kwargs`: 接收可变数量的关键字参数,用于扩展或自定义功能。
**代码描述**:
`do_delete_doc`函数主要用于删除Milvus向量数据库中,与指定知识库文件相关联的文档记录。首先,通过调用`list_file_num_docs_id_by_kb_name_and_file_name`函数,根据`kb_file`对象提供的知识库名称(`kb_name`)和文件名称(`filename`),获取该文件对应的所有文档ID列表。然后,如果Milvus的集合(`col`)存在,使用Milvus的`delete`方法,构造删除表达式`expr=f'pk in {id_list}'`,以此表达式为条件执行删除操作。这里的`pk`代表主键,即文档的唯一标识符,`id_list`是需要删除的文档ID列表。
此函数与`list_file_num_docs_id_by_kb_name_and_file_name`函数紧密相关,后者负责查询并返回指定文件中所有文档的ID,而`do_delete_doc`则使用这些ID来定位并删除Milvus数据库中对应的文档记录。这种设计使得文档的删除操作既准确又高效,确保了知识库的数据一致性和准确性。
**注意**:
- 在调用此函数之前,确保`kb_file`对象正确初始化,且其属性`kb_name``filename`准确无误,以匹配数据库中的记录。
- 此函数依赖于Milvus数据库的连接和配置正确设置,确保`self.milvus.col`指向有效的Milvus集合。
- 删除操作一旦执行,被删除的文档记录将无法恢复,请谨慎使用此功能以避免数据丢失。
***
### FunctionDef do_clear_vs(self)
**do_clear_vs**: 此函数的功能是清理Milvus知识库服务的视图状态。
**参数**: 此函数没有参数。
**代码描述**: `do_clear_vs`函数是`MilvusKBService`类的一个方法,用于清理Milvus知识库服务的视图状态。该方法首先检查`self.milvus.col`,即当前操作的Milvus集合是否存在。如果存在,则执行两个操作:首先调用`do_drop_kb`方法来释放并删除当前Milvus数据库中的集合,然后调用`do_init`方法来重新初始化Milvus知识库服务。
具体来说,`do_drop_kb`方法负责释放并删除Milvus数据库中的集合,确保集合被安全且彻底地从数据库中移除。随后,`do_init`方法被调用来重新初始化Milvus服务的连接和配置,为后续的知识库操作(如搜索)做好准备。这一过程表明`do_clear_vs`方法在处理数据清理和状态重置流程中扮演着重要的角色,它通过组合`do_drop_kb``do_init`两个方法的功能,实现了对Milvus知识库服务视图状态的彻底清理和重置。
**注意**:
- 在调用`do_clear_vs`方法之前,应确保Milvus服务的连接是正常的。
- 由于`do_clear_vs`方法会导致当前Milvus数据库中的集合被删除,这是一个不可逆的操作。因此,在执行此方法之前,应仔细考虑是否真的需要清理视图状态,以避免意外丢失重要数据。
- `do_clear_vs`方法的执行依赖于`do_drop_kb``do_init`两个方法,因此在修改或维护这些方法时,应注意它们之间的关系和依赖,确保整个流程的正确执行。
***
@@ -0,0 +1,254 @@
## ClassDef PGKBService
**PGKBService**: PGKBService 类是用于通过 PostgreSQL 实现知识库服务的具体类。
**属性**:
- `engine`: 通过 SQLAlchemy 创建的连接引擎,用于与 PostgreSQL 数据库进行交互。
- `pg_vector`: 用于存储和检索嵌入向量的 PGVector 实例。
**代码描述**:
PGKBService 类继承自 KBService 类,提供了与 PostgreSQL 数据库交互的具体实现。它使用 SQLAlchemy 作为 ORM 工具,通过 `engine` 属性与数据库建立连接。此类主要负责初始化向量存储、文档的增删查改、知识库的创建和删除等操作。
- `_load_pg_vector` 方法用于加载 PGVector 实例,该实例负责嵌入向量的存储和检索。
- `get_doc_by_ids` 方法通过文档 ID 获取文档内容和元数据。
- `del_doc_by_ids` 方法删除指定 ID 的文档,实际调用基类的同名方法。
- `do_init` 方法在类初始化时被调用,用于加载 PGVector 实例。
- `do_create_kb` 方法是创建知识库的具体实现,当前为空实现。
- `vs_type` 方法返回支持的向量存储类型,即 PostgreSQL。
- `do_drop_kb` 方法删除知识库,包括数据库中的相关记录和文件系统上的知识库路径。
- `do_search` 方法实现了基于查询的文档搜索功能,返回与查询最相关的文档列表。
- `do_add_doc` 方法向知识库添加文档,并返回添加的文档信息。
- `do_delete_doc` 方法从知识库删除指定的文档。
- `do_clear_vs` 方法清空向量存储中的所有内容,并重新创建集合。
**注意**:
- 使用 PGKBService 类之前,需要确保 PostgreSQL 数据库已经正确配置,并且 `kbs_config` 中的 `pg` 配置项包含了正确的数据库连接 URI。
- 在调用 `do_add_doc``do_delete_doc` 等方法修改数据库内容时,需要确保传入的参数符合预期格式,以避免执行错误或数据损坏。
- `do_drop_kb` 方法在删除知识库时会同时删除数据库中的记录和文件系统上的知识库路径,使用时需谨慎以防误删重要数据。
**输出示例**:
```python
# 假设调用 get_doc_by_ids 方法查询 ID 为 ['doc1', 'doc2'] 的文档
docs = pgkb_service.get_doc_by_ids(['doc1', 'doc2'])
# 可能的返回值为
[
Document(page_content="文档1的内容", metadata={"author": "作者1"}),
Document(page_content="文档2的内容", metadata={"author": "作者2"})
]
```
此示例展示了通过文档 ID 获取文档内容和元数据的过程及其可能的返回值。
### FunctionDef _load_pg_vector(self)
**_load_pg_vector**: 此函数的功能是加载PostgreSQL向量空间搜索引擎。
**参数**: 此函数没有显式参数,但它依赖于类实例的多个属性。
**代码描述**: `_load_pg_vector`函数负责初始化一个PGVector实例,该实例用于在PostgreSQL数据库中进行向量空间搜索。这个过程包括以下几个关键步骤:
1. 使用`EmbeddingsFunAdapter`类创建一个嵌入函数适配器。这个适配器基于类实例的`embed_model`属性,用于将文本转换为向量表示。`EmbeddingsFunAdapter`支持同步和异步两种文本嵌入方式,适用于不同的应用场景。
2. 指定向量空间搜索的集合名称,这里使用类实例的`kb_name`属性作为集合名称。
3. 设置距离策略为欧几里得距离(`DistanceStrategy.EUCLIDEAN`),用于计算向量之间的距离。
4. 使用`PGKBService.engine`作为数据库连接。这是一个类属性,表示与PostgreSQL数据库的连接引擎。
5. 通过`kbs_config.get("pg").get("connection_uri")`获取数据库连接字符串,这个字符串包含了数据库的地址、端口、用户名、密码等信息,用于建立数据库连接。
通过这些步骤,`_load_pg_vector`函数配置了一个用于向量空间搜索的PGVector实例,并将其保存在类实例的`pg_vector`属性中。这使得类的其他方法可以利用这个PGVector实例来执行向量空间搜索操作,例如查找与给定文本向量最相似的文档。
**注意**:
- 在调用`_load_pg_vector`函数之前,需要确保类实例的`embed_model``kb_name`属性已经被正确设置。这些属性对于初始化PGVector实例至关重要。
- `PGKBService.engine`需要预先配置好,确保能够成功连接到PostgreSQL数据库。
- 数据库连接字符串应该保密处理,避免泄露数据库的敏感信息。
此函数是在`do_init`方法中被调用的,`do_init`方法负责执行类的初始化操作,包括加载PostgreSQL向量空间搜索引擎。这表明`_load_pg_vector`函数是类初始化过程的一个重要组成部分,确保了向量空间搜索功能的可用性。
***
### FunctionDef get_doc_by_ids(self, ids)
**get_doc_by_ids**: 此函数的功能是根据提供的ID列表查询并返回相应的文档列表。
**参数**:
- ids: 一个字符串列表,包含需要查询的文档的ID。
**代码描述**:
`get_doc_by_ids` 函数接受一个字符串列表 `ids` 作为参数,这个列表包含了需要查询的文档的ID。函数内部首先使用 `Session` 上下文管理器创建一个会话,通过这个会话与数据库进行交互。接着,定义了一个SQL查询语句 `stmt`,这个语句用于从名为 `langchain_pg_embedding` 的表中选取 `document``cmetadata` 字段,条件是 `collection_id` 字段的值包含在参数 `ids` 提供的ID列表中。
通过执行这个查询语句并传入 `ids` 参数,函数会从数据库中检索出匹配的记录。每条记录都会被用来创建一个 `Document` 对象,这个对象包含了检索到的文档内容(`page_content`)和元数据(`metadata`)。所有这些 `Document` 对象随后被收集到一个列表中,并作为函数的返回值。
**注意**:
- 确保传入的ID列表 `ids` 不为空,且每个ID都是有效的,以确保查询能够正确执行。
- 此函数依赖于数据库表 `langchain_pg_embedding` 的结构,特别是它查询的字段。如果数据库结构发生变化,可能需要相应地更新此函数。
**输出示例**:
假设数据库中有两条记录的 `collection_id` 匹配给定的ID列表,函数可能返回如下的列表:
```python
[
Document(page_content="文档内容1", metadata={"作者": "张三", "发布日期": "2023-01-01"}),
Document(page_content="文档内容2", metadata={"作者": "李四", "发布日期": "2023-02-01"})
]
```
这个列表包含了两个 `Document` 对象,每个对象都包含了从数据库检索到的文档内容和元数据。
***
### FunctionDef del_doc_by_ids(self, ids)
**del_doc_by_ids**: 此函数的功能是根据提供的ID列表删除文档。
**参数**:
- ids: 一个字符串列表,包含要删除的文档的ID。
**代码描述**:
`del_doc_by_ids` 函数接受一个字符串列表 `ids` 作为参数,这个列表包含了需要从数据库中删除的文档的ID。函数通过调用其父类的 `del_doc_by_ids` 方法来实现删除操作,并将 `ids` 参数传递给该方法。这表明实际的删除逻辑被封装在父类的方法中,而当前函数主要负责将删除请求转发给父类处理。
**注意**:
- 确保传递给此函数的 `ids` 参数包含有效的文档ID,否则可能不会有任何文档被删除。
- 此函数返回一个布尔值,表示删除操作是否成功。但是,具体的成功与否依赖于父类方法的实现细节。
- 在使用此函数之前,应当了解父类中 `del_doc_by_ids` 方法的具体实现,以及它对于不同情况下删除操作的处理方式。
**输出示例**:
调用 `del_doc_by_ids(['doc1', 'doc2'])` 可能会返回 `True`,表示指定ID的文档已成功删除。如果操作失败,可能会返回 `False`。请注意,实际的返回值取决于父类方法的具体实现。
***
### FunctionDef do_init(self)
**do_init**: 此函数的功能是初始化PGKBService类的实例。
**参数**: 此函数没有参数。
**代码描述**: `do_init`方法是PGKBService类的一个初始化方法,它通过调用`_load_pg_vector`方法来加载PostgreSQL向量空间搜索引擎。这个过程是类实例化过程中的一个重要步骤,确保了类的实例能够正确地进行向量空间搜索操作。
`do_init`方法中,通过调用`_load_pg_vector`方法,完成了以下几个关键的初始化步骤:
1. 创建一个嵌入函数适配器`EmbeddingsFunAdapter`,该适配器基于类实例的`embed_model`属性,用于将文本转换为向量表示。
2. 指定向量空间搜索的集合名称,使用类实例的`kb_name`属性作为集合名称。
3. 设置距离策略为欧几里得距离,用于计算向量之间的距离。
4. 使用类属性`PGKBService.engine`作为数据库连接,这表示与PostgreSQL数据库的连接引擎。
5. 获取数据库连接字符串,用于建立数据库连接。
通过这些步骤,`_load_pg_vector`方法配置了一个用于向量空间搜索的PGVector实例,并将其保存在类实例的`pg_vector`属性中。这样,类的其他方法就可以利用这个PGVector实例来执行向量空间搜索操作,例如查找与给定文本向量最相似的文档。
**注意**:
- 在调用`do_init`方法之前,不需要进行特别的准备工作,因为它是类实例化过程中自动调用的初始化方法。
- 需要确保`embed_model``kb_name`属性在调用`_load_pg_vector`之前已经被正确设置,因为这些属性对于初始化PGVector实例至关重要。
- `PGKBService.engine`需要预先配置好,以确保能够成功连接到PostgreSQL数据库。
- 数据库连接字符串应该保密处理,避免泄露数据库的敏感信息。
总的来说,`do_init`方法通过调用`_load_pg_vector`方法,完成了PGKBService类实例的初始化,为后续的向量空间搜索操作做好了准备。
***
### FunctionDef do_create_kb(self)
**do_create_kb**: 此函数的功能是创建知识库。
**参数**: 此函数没有参数。
**代码描述**: `do_create_kb` 函数是 `PGKBService` 类的一个方法,负责创建知识库的具体逻辑。目前,此函数的实现为空(使用了 `pass` 语句),这意味着它不执行任何操作。在实际应用中,开发者需要在此函数中添加创建知识库的代码逻辑,例如连接数据库、执行数据库操作等。
**注意**: 虽然当前 `do_create_kb` 函数的实现为空,但在将来的开发中,当添加具体的实现逻辑时,需要确保数据库连接的正确性和操作的安全性。此外,考虑到知识库可能包含大量数据,还需要注意性能优化和错误处理。
***
### FunctionDef vs_type(self)
**vs_type**: vs_type函数的功能是返回当前知识库服务支持的向量存储类型。
**参数**: 该函数不接受任何参数。
**代码描述**: vs_type函数是PGKBService类的一个方法,它的主要作用是标识该知识库服务实例支持的向量存储类型。在这个具体实现中,vs_type方法通过返回SupportedVSType.PG,明确指出PostgreSQL(简称PG)是该服务实例使用的向量存储类型。SupportedVSType是一个枚举类,它定义了项目中支持的所有向量存储类型,包括但不限于FAISS、MILVUS、ZILLIZ、ElasticsearchES)、ChromaDB等,以及PG。通过返回SupportedVSType中的一个枚举值,vs_type方法为知识库服务的配置和实例化提供了必要的信息。这种设计使得知识库服务的管理和扩展更加灵活和方便,因为可以根据需要动态选择和切换不同的向量存储服务。
**注意**:
- 在使用PGKBService类及其vs_type方法时,应当了解SupportedVSType枚举类中定义的向量存储类型,以确保正确理解和使用该方法返回的向量存储类型信息。
- 由于vs_type方法返回的是一个枚举成员,因此在处理返回值时,应当注意枚举类型的使用方法,例如通过枚举成员的name或value属性获取具体的信息。
**输出示例**: 假设调用PGKBService实例的vs_type方法,可能的返回值为:
```
'pg'
```
这表示当前知识库服务实例使用PostgreSQL作为其向量存储服务。
***
### FunctionDef do_drop_kb(self)
**do_drop_kb**: 此函数的功能是删除与指定知识库名称相关联的数据库记录和文件系统中的知识库目录。
**参数**: 此函数没有显式参数,但它依赖于`self.kb_name``self.kb_path`这两个实例变量。
**代码描述**:
`do_drop_kb`函数是`PGKBService`类的一个方法,用于删除特定知识库相关的数据。该方法首先通过SQL语句删除数据库中与知识库相关联的记录,然后删除文件系统中对应的知识库目录。具体步骤如下:
1. 使用`Session`上下文管理器创建一个数据库会话,确保数据库操作在一个会话中完成,并且在操作结束后自动关闭会话。
2. 在会话中执行SQL删除操作。首先,删除`langchain_pg_embedding`表中所有`collection_id``langchain_pg_collection`表中`name`字段匹配`self.kb_name`的记录的`uuid`相匹配的记录。这意味着,所有与指定知识库名称相关联的嵌入信息将被删除。
3. 接着,删除`langchain_pg_collection`表中`name`字段与`self.kb_name`匹配的记录。这一步骤将删除知识库的集合记录。
4. 执行`session.commit()`提交数据库事务,确保上述删除操作被保存到数据库中。
5. 使用`shutil.rmtree`函数删除文件系统中的知识库目录。`self.kb_path`变量指定了知识库目录的路径,该函数将递归删除该目录及其所有内容。
**注意**:
- 在执行此函数之前,确保`self.kb_name``self.kb_path`已经正确设置,分别指向要删除的知识库的名称和路径。
- 该操作不可逆,一旦执行,相关的数据库记录和文件系统中的目录将被永久删除。因此,在调用此函数之前,请确保已经做好相应的备份或确认不再需要这些数据。
- 由于直接操作数据库和文件系统,确保执行此操作的用户具有相应的权限。
***
### FunctionDef do_search(self, query, top_k, score_threshold)
**do_search**: 此函数的功能是执行文本查询,并根据给定的分数阈值和返回的文档数量上限筛选出相似度最高的文档。
**参数**:
- `query`: 需要查询的文本,数据类型为字符串。
- `top_k`: 返回的文档数量上限,数据类型为整数。
- `score_threshold`: 分数阈值,用于筛选相似度高于此阈值的文档,数据类型为浮点数。
**代码描述**:
`do_search`函数首先通过`EmbeddingsFunAdapter`类的实例`embed_func`,调用`embed_query`方法将查询文本`query`转换为嵌入向量。这一步骤是通过将文本转换为向量化表示,以便后续进行相似度搜索。
接着,函数使用`self.pg_vector``similarity_search_with_score_by_vector`方法,传入上一步得到的嵌入向量和`top_k`参数,执行相似度搜索。此方法返回一个包含文档及其相似度分数的列表,列表中的文档是根据与查询向量的相似度排序的。
最后,函数调用`score_threshold_process`方法,传入`score_threshold``top_k`和相似度搜索的结果,根据分数阈值筛选出符合条件的文档,并返回前`top_k`个文档。这一步骤确保了返回的文档不仅与查询文本相似度高,而且其相似度分数超过了指定的阈值。
**注意**:
- 确保传入的`query`是有效的字符串,`top_k`是正整数,`score_threshold`是非负浮点数。
- `EmbeddingsFunAdapter``score_threshold_process`是此函数依赖的关键组件,确保它们的实现与预期一致。
- 此函数的性能和准确性依赖于嵌入模型的质量和相似度搜索算法的效率。
**输出示例**:
假设调用`do_search`函数,传入查询文本"示例查询",`top_k`为3`score_threshold`为0.5,可能的返回值为:
```
[("文档1", 0.8), ("文档3", 0.7), ("文档5", 0.6)]
```
这表示在所有文档中,有三个文档的相似度分数满足大于等于0.5的条件,并且是相似度最高的前三个文档。
***
### FunctionDef do_add_doc(self, docs)
**do_add_doc**: 此函数的功能是向数据库中添加文档,并返回包含文档ID和元数据的信息列表。
**参数**:
- `docs`: 需要添加到数据库中的文档列表,每个文档都是一个`Document`对象。
- `**kwargs`: 接受可变数量的关键字参数,这些参数可以根据需要传递给底层数据库操作。
**代码描述**:
`do_add_doc`函数首先调用`pg_vector`对象的`add_documents`方法,将`docs`列表中的文档添加到数据库中。`add_documents`方法返回一个包含每个文档ID的列表。然后,函数遍历这些ID和原始的`docs`列表,使用列表推导式创建一个新的列表`doc_infos`。这个新列表的每个元素都是一个字典,包含两个键:`id``metadata``id`键对应于文档的ID`metadata`键对应于文档的元数据。最后,函数返回`doc_infos`列表。
**注意**:
- 确保传递给`do_add_doc`函数的`docs`参数是一个`Document`对象的列表,且每个`Document`对象都应该有有效的元数据。
- 传递给`**kwargs`的关键字参数将直接影响底层数据库操作,因此请谨慎使用,确保了解这些参数的影响。
**输出示例**:
假设我们向`do_add_doc`函数传递了两个文档,且这两个文档成功添加到数据库中,函数可能返回如下列表:
```python
[
{"id": "doc1_id", "metadata": {"title": "Document 1 Title", "author": "Author Name"}},
{"id": "doc2_id", "metadata": {"title": "Document 2 Title", "author": "Another Author Name"}}
]
```
这个列表包含了每个文档的ID和元数据,可以用于进一步的处理或显示。
***
### FunctionDef do_delete_doc(self, kb_file)
**do_delete_doc**: 此函数用于从数据库中删除与指定知识文件相关联的文档向量。
**参数**:
- `kb_file`: KnowledgeFile对象,代表需要删除其文档向量的知识库文件。
- `**kwargs`: 接收额外的关键字参数,以便在未来的版本中扩展功能而不影响现有接口。
**代码描述**:
`do_delete_doc`函数首先通过`kb_file`参数获取知识库文件的完整路径。为了确保数据库查询语句中的文件路径字符串格式正确,它将路径中的所有反斜杠(`\`)替换为双反斜杠(`\\`)。这是因为在SQL查询中,反斜杠是一个特殊字符,需要进行转义。
接着,函数使用`Session`上下文管理器创建一个数据库会话,并执行一个SQL `DELETE`语句。这个`DELETE`语句的目的是从`langchain_pg_embedding`表中删除所有`cmetadata`字段(以JSONB格式存储)中`source`键对应的值与给定文件路径匹配的记录。这里,`cmetadata::jsonb @> '{"source": "filepath"}'::jsonb`是一个PostgreSQL的JSONB查询表达式,用于查找`cmetadata`中包含特定`source`键值对的记录。
在执行删除操作后,函数通过`session.commit()`提交更改,确保删除操作被保存到数据库中。
**注意**:
- 使用此函数时,需要确保传入的`kb_file`对象有效,且其`filepath`属性正确反映了文件在磁盘上的位置。
- 此函数直接操作数据库,执行删除操作。因此,在调用此函数之前,应确保已经对要删除的数据进行了适当的备份或确认,以防意外数据丢失。
- 由于此函数涉及数据库操作,其执行效率和影响范围可能会受到数据库当前状态和配置的影响。在处理大量数据或高负载情况下,建议监控数据库性能,以避免潜在的性能问题。
***
### FunctionDef do_clear_vs(self)
**do_clear_vs**: 此函数的功能是清除并重新创建向量空间。
**参数**: 此函数不接受任何参数。
**代码描述**: `do_clear_vs` 函数是 `PGKBService` 类的一个方法,用于管理向量空间的清除和重建过程。在这个函数中,首先调用 `self.pg_vector.delete_collection()` 方法来删除当前的向量空间集合。这一步骤是为了清除所有现有的数据,确保向量空间是空的。紧接着,通过调用 `self.pg_vector.create_collection()` 方法来重新创建一个新的向量空间集合。这样做的目的是为了在删除旧数据之后,提供一个全新的环境以便后续的数据插入和管理。
**注意**: 使用 `do_clear_vs` 函数时需要谨慎,因为这会导致所有现有的向量空间数据被永久删除,无法恢复。因此,在执行此操作之前,请确保已经做好了充分的数据备份或确认不再需要这些数据。此外,重新创建向量空间集合后,需要重新配置任何相关的设置或索引,以确保向量空间的正常使用和性能优化。
***
@@ -0,0 +1,280 @@
## ClassDef ZillizKBService
**ZillizKBService**: ZillizKBService 类是用于在 Zilliz 向量数据库中管理和操作知识库的服务。
**属性**:
- `zilliz`: Zilliz 实例,用于与 Zilliz 向量数据库进行交互。
**代码描述**:
ZillizKBService 类继承自 KBService 类,提供了一系列专门用于在 Zilliz 向量数据库中管理和操作知识库的方法。这些方法包括获取集合、通过 ID 获取文档、通过 ID 删除文档、搜索、创建知识库、初始化、删除知识库、添加文档、删除文档以及清除向量空间等。
- `get_collection` 静态方法用于获取指定名称的集合。
- `get_doc_by_ids` 方法根据提供的 ID 列表查询并返回文档列表。
- `del_doc_by_ids` 方法根据提供的 ID 列表删除文档。
- `search` 静态方法用于在指定的集合中搜索与给定内容相似的文档。
- `do_create_kb` 方法用于创建知识库,当前为空实现。
- `vs_type` 方法返回支持的向量存储类型,即 Zilliz。
- `_load_zilliz` 方法用于加载 Zilliz 实例。
- `do_init` 方法用于初始化服务,包括加载 Zilliz 实例。
- `do_drop_kb` 方法用于删除知识库。
- `do_search` 方法用于搜索知识库。
- `do_add_doc` 方法用于向知识库添加文档。
- `do_delete_doc` 方法用于从知识库删除指定的文档。
- `do_clear_vs` 方法用于清除向量空间。
**注意**:
- 在使用 ZillizKBService 之前,需要确保 Zilliz 向量数据库已正确配置并可用。
- 由于 ZillizKBService 继承自 KBService,部分方法的具体实现可能依赖于 KBService 类中定义的抽象方法。
- 在调用 `do_add_doc``do_delete_doc` 等方法时,需要注意传入的参数格式和类型。
**输出示例**:
```python
# 假设已经有一个 ZillizKBService 实例,名为 zilliz_service
# 搜索内容为 "example content" 的文档,限制返回结果为前3个
search_results = zilliz_service.search("example_collection", "example content", limit=3)
# 输出可能为:
[
{"content": "文档1内容", "score": 0.95},
{"content": "文档2内容", "score": 0.90},
{"content": "文档3内容", "score": 0.85}
]
```
此输出示例展示了使用 `search` 方法进行内容搜索的可能结果,包括每个匹配文档的内容和相似度得分。
### FunctionDef get_collection(zilliz_name)
**get_collection**: 此函数的功能是获取指定名称的集合。
**参数**:
- **zilliz_name**: 集合的名称。
**代码描述**:
`get_collection` 函数是`ZillizKBService`类中的一个方法,它的主要作用是通过传入的集合名称`zilliz_name`,使用`pymilvus`库中的`Collection`类来获取对应的集合对象。这个方法简洁明了,只涉及到从`pymilvus`导入`Collection`类并返回一个集合对象的过程。
在项目中,`get_collection`方法被`search`方法调用。在`search`方法中,首先通过`get_collection`获取到了一个指定名称的集合对象,然后使用这个集合对象执行搜索操作。这表明`get_collection`方法是搜索功能实现的基础,它确保了搜索操作能够在正确的集合上执行。
**注意**:
- 确保在调用此函数之前,指定的集合名称`zilliz_name`已经存在于Milvus数据库中,否则会导致获取集合失败。
- 使用此函数需要安装并正确配置`pymilvus`库。
**输出示例**:
调用`get_collection("example_collection")`可能会返回一个`pymilvus`库中的`Collection`对象,这个对象代表了名为"example_collection"的集合。
***
### FunctionDef get_doc_by_ids(self, ids)
**get_doc_by_ids**: 此函数的功能是根据提供的ID列表从Zilliz的集合中检索文档。
**参数**:
- `ids`: 一个字符串列表,包含要检索的文档的ID。
**代码描述**:
`get_doc_by_ids`函数接受一个ID列表作为参数,返回一个文档列表。这个函数首先检查`self.zilliz.col`是否存在,这是一个对Zilliz集合的引用。如果这个集合存在,函数将继续执行查询操作。
查询是通过调用`self.zilliz.col.query`方法实现的,该方法的`expr`参数设置为`'pk in {ids}'`,其中`{ids}`是传入的ID列表。这意味着函数将查询主键(pk)在给定ID列表中的所有记录。`output_fields=["*"]`参数指示查询返回所有字段的数据。
对于查询结果中的每条数据,函数将从数据中提取`text`字段,并将其余字段作为元数据。然后,它使用这些信息创建一个`Document`对象,其中`page_content`设置为提取的文本,`metadata`设置为剩余的数据字段。这些`Document`对象被收集到一个列表中,最后返回这个列表。
**注意**:
- 确保传入的ID列表中的ID是存在于Zilliz集合中的有效ID,否则查询将不会返回任何结果。
- 此函数依赖于`self.zilliz.col`的存在,这意味着在调用此函数之前,必须正确初始化并设置对应的Zilliz集合引用。
**输出示例**:
假设有两个文档的ID分别为"123"和"456",并且这些文档在Zilliz集合中存在。调用`get_doc_by_ids(['123', '456'])`可能会返回如下列表:
```python
[
Document(page_content="这是文档123的内容", metadata={'id': '123', 'title': '文档123标题', 'date': '2023-01-01'}),
Document(page_content="这是文档456的内容", metadata={'id': '456', 'title': '文档456标题', 'date': '2023-01-02'})
]
```
这个列表包含两个`Document`对象,每个对象都包含了从Zilliz集合中检索到的文档的内容和元数据。
***
### FunctionDef del_doc_by_ids(self, ids)
**del_doc_by_ids**: 此函数的功能是根据提供的ID列表删除对应的文档。
**参数**:
- ids: 一个字符串列表,包含需要删除的文档的ID。
**代码描述**:
`del_doc_by_ids`函数是`ZillizKBService`类的一个方法,用于从Zilliz的知识库服务中删除指定ID的文档。此函数接受一个参数`ids`,这是一个字符串列表,每个字符串代表一个需要删除的文档的ID。函数内部,通过调用`self.zilliz.col.delete`方法来执行删除操作,其中`expr=f'pk in {ids}'`是一个表达式,用于指定需要删除的文档的ID条件。这里`pk`代表文档的主键,`in {ids}`表示主键在提供的ID列表中的文档将被删除。
**注意**:
- 确保传入的ID列表中的每个ID都是有效的,并且对应于知识库中实际存在的文档。如果列表中包含无效或不存在的ID,这些ID将被忽略,不会影响其他有效ID的删除操作。
- 删除操作一旦执行,被删除的文档将无法恢复,请在执行删除操作前仔细确认。
- 此函数返回一个布尔值,表示删除操作是否成功执行。然而,具体的代码实现中没有明确返回值,这可能需要根据实际的业务逻辑进行相应的调整或补充。
***
### FunctionDef search(zilliz_name, content, limit)
**search**: 此函数的功能是在指定的集合中执行基于内容的搜索操作。
**参数**:
- **zilliz_name**: 指定的集合名称。
- **content**: 搜索的内容。
- **limit**: 返回的结果数量上限,默认值为3。
**代码描述**:
`search` 函数是`ZillizKBService`类中的一个方法,它用于在指定的集合中执行基于内容的搜索操作。首先,该函数定义了搜索参数`search_params`,其中包括度量类型("IP")和其他搜索相关的参数。接着,通过调用`get_collection`方法获取到指定名称的集合对象。最后,使用集合对象的`search`方法执行搜索操作,该操作基于`content`参数进行,搜索范围限定在"embeddings"字段中,同时指定了搜索参数`search_params`和结果数量上限`limit`。此外,还通过`output_fields`参数指定了搜索结果中需要包含的字段,本例中为["content"]。
从功能角度看,`get_collection`方法为`search`方法提供了执行搜索所需的集合对象,确保搜索操作能够在正确的集合上进行。这种设计体现了模块化和功能分离的原则,便于代码的维护和扩展。
**注意**:
- 在使用`search`函数之前,确保`zilliz_name`指定的集合已经存在,并且集合中的数据已经按照需要进行了索引。
- `limit`参数应根据实际需求调整,以平衡搜索结果的全面性和性能开销。
- 确保`pymilvus`库已正确安装并配置,因为`search`函数的实现依赖于此库。
**输出示例**:
调用`search("example_collection", "some search content")`可能会返回如下格式的搜索结果:
```python
[
{"content": "匹配的内容1"},
{"content": "匹配的内容2"},
{"content": "匹配的内容3"}
]
```
这个示例展示了当搜索限制为返回最多3个结果时,可能得到的搜索结果。每个结果包含了指定的输出字段"content",其中包含了与搜索内容匹配的集合中的数据。
***
### FunctionDef do_create_kb(self)
**do_create_kb**: 此函数的功能是创建知识库。
**参数**: 此函数没有参数。
**代码描述**: `do_create_kb` 函数是 `ZillizKBService` 类的一个方法,用于创建知识库。在当前的代码实现中,此函数体内没有具体的执行代码,仅包含一个 `pass` 语句。这意味着,此函数作为一个框架或者是占位符存在,等待后续的实现。在实际应用中,开发者需要根据具体需求,填充此函数以实现知识库的创建逻辑,比如初始化数据库连接、设置知识库的结构、数据导入等操作。
**注意**: 虽然当前 `do_create_kb` 函数没有实现具体的功能,但在将来的版本中,开发者可能会添加具体的实现代码。因此,在使用此函数时,需要关注其最新的实现状态和文档说明,以确保正确使用。同时,考虑到此函数的目的是创建知识库,开发者在实现时应确保有充分的权限和正确的配置信息,以避免潜在的权限问题或配置错误。
***
### FunctionDef vs_type(self)
**vs_type**: vs_type函数的功能是返回当前知识库服务支持的向量存储类型。
**参数**: 此函数没有参数。
**代码描述**: vs_type函数是ZillizKBService类的一个方法,它的作用是标识该知识库服务实例支持的向量存储类型。在这个具体实现中,vs_type方法通过返回SupportedVSType.ZILLIZ来明确指出,当前的知识库服务使用的是ZILLIZ作为其向量存储解决方案。SupportedVSType是一个枚举类,其中定义了项目支持的所有向量存储类型,包括但不限于FAISS、MILVUS、ZILLIZ等。ZILLIZ在这里被选定,意味着ZillizKBService专门为与ZILLIZ向量存储服务交互而设计。这种设计方式便于在知识库服务工厂(KBServiceFactory)中根据需要动态选择和实例化具体的知识库服务实现,从而提高了项目的灵活性和可扩展性。
**注意**:
- 在使用ZillizKBService类时,开发者应当了解其背后的向量存储类型是ZILLIZ,这对于理解如何配置和使用该服务至关重要。
- 如果项目需要支持其他类型的向量存储服务,应在SupportedVSType枚举类中添加相应的类型,并在知识库服务工厂中实现相应的逻辑以支持新的服务类型。
**输出示例**: 该函数调用将返回一个字符串值:"zilliz"。
***
### FunctionDef _load_zilliz(self)
**_load_zilliz**: 此函数的功能是加载Zilliz服务。
**参数**: 此函数没有显式参数,它通过类实例访问成员变量。
**代码描述**: `_load_zilliz`函数首先从配置中获取名为`zilliz`的参数,这些参数用于配置Zilliz服务的连接。然后,它创建一个`Zilliz`实例,该实例负责处理嵌入向量的存储和搜索。在创建`Zilliz`实例时,它使用`EmbeddingsFunAdapter`类将当前对象的`embed_model`属性作为嵌入函数传递给`Zilliz``EmbeddingsFunAdapter`是一个适配器类,用于将文本转换为嵌入向量,支持同步和异步两种方式。此外,`Zilliz`实例还接收知识库的名称(`kb_name`)和连接参数(`zilliz_args`)。这意味着,每当需要初始化或执行搜索操作时,都会通过`Zilliz`实例与Zilliz服务进行交互,以便处理嵌入向量的存储和相似度搜索。
**注意**:
- 在调用`_load_zilliz`函数之前,需要确保`kbs_config`中已经正确配置了`zilliz`参数,包括Zilliz服务的连接信息。
- `EmbeddingsFunAdapter`类的使用依赖于有效的嵌入模型名称(`embed_model`),该名称应指向一个预先训练好的模型,用于文本嵌入转换。
- `_load_zilliz`函数通常在知识库服务的初始化(`do_init`)和搜索(`do_search`)过程中被调用,以确保Zilliz服务的连接和配置在进行操作前已经就绪。
通过这种方式,`_load_zilliz`函数为知识库服务提供了一个核心功能,即配置和初始化与Zilliz服务的连接,这对于后续的文本嵌入存储和相似度搜索操作至关重要。
***
### FunctionDef do_init(self)
**do_init**: 此函数的功能是初始化Zilliz知识库服务。
**参数**: 此函数没有显式参数。
**代码描述**: `do_init`函数是`ZillizKBService`类的一个方法,用于初始化Zilliz知识库服务。它通过调用`_load_zilliz`方法来加载和配置Zilliz服务。`_load_zilliz`方法负责创建一个Zilliz实例,这个实例用于处理嵌入向量的存储和搜索。这一过程包括从配置中获取Zilliz服务的连接参数,以及使用`EmbeddingsFunAdapter`类将当前对象的`embed_model`属性作为嵌入函数传递给Zilliz实例。这确保了Zilliz服务能够根据预先训练好的模型将文本转换为嵌入向量,并进行存储和相似度搜索操作。
**注意**:
- 在调用`do_init`方法之前,应确保已经在`kbs_config`中正确配置了Zilliz服务的连接信息。
- `do_init`方法通常在知识库服务需要重新初始化时调用,例如在`do_clear_vs`方法中,如果检测到知识库集合已存在,则会先删除现有集合,然后通过调用`do_init`来重新初始化Zilliz服务。
- 此方法的成功执行对于后续的知识库操作(如文本嵌入存储和相似度搜索)是必要的,因为它确保了Zilliz服务的连接和配置已经就绪。
通过`do_init`方法,`ZillizKBService`类能够确保Zilliz知识库服务的正确初始化和配置,为后续的操作提供了基础。
***
### FunctionDef do_drop_kb(self)
**do_drop_kb**: 此函数的功能是释放并删除当前的知识库集合。
**参数**: 此函数不接受任何参数。
**代码描述**: `do_drop_kb` 函数是`ZillizKBService`类的一个方法,用于处理知识库集合的释放和删除操作。当`ZillizKBService`实例中的`zilliz.col`属性存在时,此方法首先调用`release`方法来释放集合,随后调用`drop`方法来删除集合。这个过程确保了知识库的集合被正确地清理,避免了资源泄露或是不必要的存储占用。
在项目中,`do_drop_kb`方法被`do_clear_vs`方法调用。`do_clear_vs`方法的目的是清理视图状态,在清理过程中,它首先调用`do_drop_kb`来释放并删除知识库集合,然后通过调用`do_init`方法重新初始化状态。这表明`do_drop_kb`在知识库管理流程中扮演着重要的角色,确保了知识库的集合在不再需要时能够被正确地处理。
**注意**: 使用`do_drop_kb`方法时,需要确保`zilliz.col`属性已经正确初始化,并且在调用此方法后,相关的集合资源将被释放和删除。因此,在调用此方法之前,应当确保不再需要对该集合进行任何操作。
***
### FunctionDef do_search(self, query, top_k, score_threshold)
**do_search**: 此函数的功能是执行文本查询的搜索操作,并返回符合条件的文档列表。
**参数**:
- `query`: 需要进行搜索的查询文本,数据类型为字符串。
- `top_k`: 返回的文档数量上限,数据类型为整数。
- `score_threshold`: 分数阈值,用于筛选相似度高于此阈值的文档,数据类型为浮点数。
**代码描述**:
`do_search`函数首先调用`_load_zilliz`方法来加载Zilliz服务,这一步骤确保了与Zilliz服务的连接已经建立,并且相关配置已经就绪。接下来,函数创建了一个`EmbeddingsFunAdapter`实例,该实例使用类中的`embed_model`属性作为嵌入模型。通过`EmbeddingsFunAdapter``embed_query`方法,将输入的查询文本`query`转换为嵌入向量。
得到嵌入向量后,函数调用`zilliz`实例的`similarity_search_with_score_by_vector`方法,执行相似度搜索操作。此方法接收嵌入向量、`top_k`参数,并返回一个包含文档及其相似度分数的列表。
最后,函数调用`score_threshold_process`方法,根据`score_threshold`参数筛选出相似度分数高于阈值的文档,并限制返回的文档数量不超过`top_k`。这一步骤确保了返回的文档列表既符合相似度要求,又满足数量上限的要求。
**注意**:
- 在调用`do_search`函数之前,需要确保`embed_model`已经正确配置,且指向一个有效的预训练嵌入模型。
- `score_threshold`参数允许调用者根据需要筛选相似度较高的文档,如果设置为较低的值,可能会返回更多的文档;如果设置为较高的值,则可能会返回较少的文档。
- `top_k`参数控制返回的文档数量上限,应根据实际需求合理设置。
**输出示例**:
假设输入查询文本为"人工智能",`top_k`为3`score_threshold`为0.5,且相似度搜索返回的文档及其相似度分数列表为[("doc1", 0.6), ("doc2", 0.4), ("doc3", 0.7), ("doc4", 0.5)]。经过`score_threshold_process`处理后,最终返回的文档列表可能为[("doc1", 0.6), ("doc3", 0.7), ("doc4", 0.5)],表示这三个文档的相似度分数满足大于等于0.5的条件,并且数量不超过3。
***
### FunctionDef do_add_doc(self, docs)
**do_add_doc**: 此函数的功能是将文档添加到知识库中,并返回包含文档ID和元数据的列表。
**参数**:
- `docs`: 需要添加到知识库中的文档列表,每个文档都是一个Document对象。
- `**kwargs`: 接收额外的关键字参数,用于扩展或自定义功能。
**代码描述**:
此函数首先遍历传入的文档列表`docs`。对于每个文档,它会遍历文档的元数据`metadata`,将所有元数据的值转换为字符串格式。接着,它会检查是否有缺失的字段,如果有,则为这些字段设置默认的空字符串值。此外,函数会从元数据中移除特定的字段,这些字段通常是用于文本和向量表示的字段,由`self.zilliz._text_field``self.zilliz._vector_field`指定。
在处理完所有文档的元数据后,函数调用`self.zilliz.add_documents(docs)`方法将文档添加到知识库中,并接收返回的文档ID列表。最后,函数构造一个包含文档ID和更新后的元数据的列表,并将其返回。
**注意**:
- 确保传入的文档列表中的每个文档都有`metadata`属性,且其值为字典类型。
- 此函数不处理文本和向量字段的添加,确保在调用此函数之前已经正确设置了这些字段。
- 传入的文档对象应该是已经准备好添加到知识库的,包括所有必要的元数据和内容。
**输出示例**:
```python
[
{"id": "123", "metadata": {"title": "文档标题1", "author": "作者1"}},
{"id": "456", "metadata": {"title": "文档标题2", "author": "作者2"}}
]
```
此示例展示了函数返回值的可能形式,包含了每个文档的ID和更新后的元数据。
***
### FunctionDef do_delete_doc(self, kb_file)
**do_delete_doc**: 此函数用于从知识库中删除指定文件的文档。
**参数**:
- `kb_file`: KnowledgeFile对象,代表需要删除的知识库文件。
- `**kwargs`: 接收可变数量的关键字参数,用于扩展或自定义功能。
**代码描述**:
`do_delete_doc`函数是`ZillizKBService`类的一个方法,负责删除知识库中与指定文件相关的文档。首先,该函数检查`zilliz`对象的`col`属性是否存在,`col`属性代表当前操作的数据库集合。如果集合存在,则继续执行删除操作。
函数通过`kb_file`参数接收一个`KnowledgeFile`对象,该对象包含了知识库文件的详细信息,如文件路径等。为了确保文件路径在数据库查询中正确使用,函数首先将文件路径中的反斜杠(`\`)替换为双反斜杠(`\\`),以适应数据库查询语法。
接着,函数使用`self.zilliz.col.query`方法查询与指定文件路径匹配的所有文档,并从查询结果中提取文档的主键(`pk`)列表。这一步是为了找出需要删除的文档的唯一标识符。
最后,函数通过`self.zilliz.col.delete`方法,使用提取的主键列表构造删除表达式,从数据库集合中删除这些文档。删除操作的表达式形式为`'pk in {delete_list}'`,其中`{delete_list}`是需要删除的文档主键的列表。
**注意**:
- 使用`do_delete_doc`函数时,需要确保传入的`kb_file`对象有效,并且该文件已经在知识库中注册。
- 删除操作依赖于`zilliz`对象的`col`属性,该属性必须指向一个有效的数据库集合。
- 文件路径的处理是为了适应数据库查询语法,确保查询和删除操作能够正确执行。
- 删除操作是基于文档的主键(`pk`)执行的,因此需要确保数据库中的文档有唯一的主键标识。
此函数与`KnowledgeFile`对象紧密相关,因为它使用`KnowledgeFile`对象提供的文件路径信息来定位和删除知识库中的文档。通过这种方式,`do_delete_doc`函数支持高效地管理知识库内容,允许用户根据文件信息快速删除相关文档,从而维护知识库的准确性和清洁度。
***
### FunctionDef do_clear_vs(self)
**do_clear_vs**: 此函数的功能是清理Zilliz知识库服务的视图状态。
**参数**: 此函数不接受任何参数。
**代码描述**: `do_clear_vs`函数是`ZillizKBService`类中的一个方法,用于在特定情况下清理Zilliz知识库服务的视图状态。该方法首先检查`ZillizKBService`实例的`zilliz.col`属性是否存在,这个属性代表当前的知识库集合。如果该属性存在,说明当前有一个活跃的知识库集合,那么`do_clear_vs`方法会进行两个步骤的操作:首先,调用`do_drop_kb`方法来释放并删除当前的知识库集合;其次,调用`do_init`方法来重新初始化Zilliz知识库服务。
`do_drop_kb`方法负责释放并删除知识库集合,确保在重新初始化之前,当前的集合资源被正确地清理。而`do_init`方法则用于重新加载和配置Zilliz服务,包括创建新的知识库集合和配置嵌入向量的处理。这一系列操作确保了Zilliz知识库服务可以在清理现有状态后,以正确的配置重新开始服务。
**注意**:
- 在调用`do_clear_vs`方法之前,应确保`ZillizKBService`实例已经正确初始化,特别是`zilliz.col`属性,它代表了当前的知识库集合。
- `do_clear_vs`方法的调用场景通常是在需要重置知识库服务状态时,例如在测试过程中或者在知识库数据结构需要更新时。
- 由于此方法会删除当前的知识库集合,因此在调用之前应确保不再需要集合中的数据,或者已经做好了数据备份。
- 此方法的执行会影响Zilliz知识库服务的状态,因此建议在知识库服务的使用低峰时段进行,以避免对正常服务造成影响。
***
@@ -0,0 +1,134 @@
## ClassDef KBSummaryService
**KBSummaryService**: KBSummaryService类的功能是管理和操作知识库摘要的生成、添加和删除。
**属性**:
- `kb_name`: 知识库的名称。
- `embed_model`: 嵌入模型的名称。
- `vs_path`: 向量存储的路径。
- `kb_path`: 知识库的路径。
**代码描述**:
KBSummaryService类是一个抽象基类(ABC),用于定义操作知识库摘要的基本方法和属性。它主要负责知识库摘要的创建、添加和删除。类的初始化方法接受知识库名称和嵌入模型名称作为参数,并根据这些参数设置知识库路径和向量存储路径。如果向量存储路径不存在,则会创建该路径。
- `get_vs_path`方法返回向量存储的完整路径。
- `get_kb_path`方法返回知识库的完整路径。
- `load_vector_store`方法负责加载或创建向量存储。
- `add_kb_summary`方法用于将文档摘要添加到向量存储和数据库中。
- `create_kb_summary`方法用于创建知识库摘要的存储空间,如果存储空间不存在则创建。
- `drop_kb_summary`方法用于删除知识库摘要的向量存储和数据库记录。
在项目中,`KBSummaryService`类被用于处理知识库摘要的生成和管理。例如,在`recreate_summary_vector_store``summary_file_to_vector_store`的场景中,通过`KBSummaryService`类的实例来重新创建或更新知识库的摘要信息。这涉及到从知识库中读取文档,生成摘要,然后将这些摘要添加到向量存储和数据库中。
**注意**:
- 在使用`KBSummaryService`类之前,确保已经正确设置了知识库的路径和嵌入模型。
- 在调用`add_kb_summary`方法之前,应确保摘要信息已经准备好,并且向量存储已经创建。
**输出示例**:
由于`KBSummaryService`类的方法主要进行数据处理和存储操作,它们的输出通常不直接返回给用户,而是通过日志记录或数据库状态反映操作结果。例如,当成功添加知识库摘要时,可能会在日志中记录相应的信息,如“知识库'example_kb'的摘要添加成功”。
### FunctionDef __init__(self, knowledge_base_name, embed_model)
**__init__**: 此函数的功能是初始化KBSummaryService类的实例。
**参数**:
- knowledge_base_name: 知识库的名称,类型为字符串。
- embed_model: 嵌入模型的名称,默认值为EMBEDDING_MODEL,类型为字符串。
**代码描述**: `__init__` 方法是 `KBSummaryService` 类的构造函数,用于初始化类的实例。在这个方法中,首先将传入的 `knowledge_base_name``embed_model` 参数分别赋值给实例变量 `self.kb_name``self.embed_model`。这两个实例变量分别存储了知识库的名称和使用的嵌入模型名称。
接下来,方法调用 `self.get_kb_path()``self.get_vs_path()` 分别获取知识库的完整路径和向量存储的完整路径,并将这些路径分别赋值给实例变量 `self.kb_path``self.vs_path``get_kb_path` 方法返回知识库文件的完整路径,而 `get_vs_path` 方法则基于 `get_kb_path` 方法返回的路径,进一步构造出向量存储的完整路径。
最后,通过检查 `self.vs_path` 指定的路径是否存在,如果不存在,则使用 `os.makedirs` 方法创建该路径。这一步骤确保了向量存储的目录在使用前已经被正确创建。
**注意**: 在使用 `__init__` 方法初始化 `KBSummaryService` 类的实例时,需要确保传入的 `knowledge_base_name` 是有效的,且对应的知识库在文件系统中存在。此外,考虑到不同操作系统的路径表示可能有所不同,`get_kb_path``get_vs_path` 方法内部使用了 `os.path.join` 来构造路径,以确保路径的正确性和兼容性。
***
### FunctionDef get_vs_path(self)
**get_vs_path**: 此函数的功能是获取向量存储的完整路径。
**参数**: 此函数没有参数。
**代码描述**: `get_vs_path` 函数是 `KBSummaryService` 类的一个方法,用于构造并返回知识库摘要向量存储的完整路径。它首先调用 `get_kb_path` 方法获取知识库的完整路径,然后使用 `os.path.join` 方法将此路径与字符串 "summary_vector_store" 拼接起来,从而生成向量存储的完整路径。这个方法在 `KBSummaryService` 类的初始化方法 `__init__` 中被调用,并将生成的路径赋值给实例变量 `self.vs_path`。如果检测到该路径不存在,则会创建对应的目录。
**注意**: 使用此函数时,需要确保 `get_kb_path` 方法能够正确返回知识库的路径,且该路径已经存在于文件系统中。此外,考虑到不同操作系统之间的路径表示差异,使用 `os.path.join` 方法可以确保路径的正确性和兼容性。
**输出示例**: 假设 `get_kb_path` 方法返回的路径为 "/data/knowledge_bases/tech_docs",那么此函数的返回值将会是 "/data/knowledge_bases/tech_docs/summary_vector_store"。这意味着向量存储将位于知识库 "tech_docs" 下的 "summary_vector_store" 目录中。
***
### FunctionDef get_kb_path(self)
**get_kb_path**: 此函数的功能是获取知识库的完整路径。
**参数**: 此函数没有参数。
**代码描述**: `get_kb_path` 函数是 `KBSummaryService` 类的一个方法,用于返回知识库文件的完整路径。它通过将 `KB_ROOT_PATH`(一个预定义的知识库根路径常量)与 `self.kb_name`(知识库的名称,是在类的初始化时通过参数传入的)使用 `os.path.join` 方法拼接起来,从而构造出知识库的完整路径。这个方法在 `KBSummaryService` 类的初始化方法 `__init__` 中被调用,用于设置实例变量 `self.kb_path`,即知识库路径。此外,它还被 `get_vs_path` 方法调用,作为构造向量存储路径的一部分。
在项目中,`get_kb_path` 方法的调用确保了知识库路径的一致性和正确性,无论是直接获取知识库路径还是作为其他路径(如向量存储路径)构建的基础,都能确保路径的准确性。
**注意**: 使用此函数时,需要确保 `KB_ROOT_PATH``self.kb_name` 已经正确设置,且 `KB_ROOT_PATH` 指向的目录存在于文件系统中。此外,考虑到操作系统的差异,`os.path.join` 方法能够确保路径的正确性,无论是在 Windows 还是在类 Unix 系统上。
**输出示例**: 假设 `KB_ROOT_PATH` 为 "/data/knowledge_bases",且 `self.kb_name` 为 "tech_docs",那么此函数的返回值将会是 "/data/knowledge_bases/tech_docs"。
***
### FunctionDef load_vector_store(self)
**load_vector_store**: 此函数的功能是加载一个线程安全的FAISS向量库实例。
**参数**: 此函数没有显式参数,但它依赖于`KBSummaryService`类的实例属性。
**代码描述**: `load_vector_store`函数通过调用`kb_faiss_pool.load_vector_store`方法来加载一个FAISS向量库。这个方法接受几个关键参数:`kb_name`(知识库的名称),`vector_name`(向量库的名称,这里固定为"summary_vector_store"),`embed_model`(嵌入模型),以及`create`(一个布尔值,指示如果向量库不存在时是否创建)。这些参数的值来源于`KBSummaryService`类的实例属性。函数返回一个`ThreadSafeFaiss`实例,这是一个线程安全的封装,用于操作和管理FAISS向量库。
**注意**: 使用`load_vector_store`函数时,需要确保`KBSummaryService`类的实例属性已正确设置,因为这些属性将直接影响向量库的加载过程。此外,返回的`ThreadSafeFaiss`实例支持线程安全的操作,适用于多线程环境。
**输出示例**: 假设`KBSummaryService`的实例属性已正确设置,调用`load_vector_store`可能会返回如下的`ThreadSafeFaiss`实例表示:
`<ThreadSafeFaiss: key: summary_vector_store, obj: <FAISS向量库对象的表示>, docs_count: 100>`
此函数在项目中的调用情况包括在`add_kb_summary`方法中,用于获取向量库实例以添加文档并将其保存到本地路径。这表明`load_vector_store`函数是知识库摘要服务中管理和操作FAISS向量库的关键组成部分,支持知识库摘要的添加和存储过程。
***
### FunctionDef add_kb_summary(self, summary_combine_docs)
**add_kb_summary**: 此函数的功能是将文档摘要添加到向量存储并更新数据库。
**参数**:
- `summary_combine_docs`: `List[Document]`类型,包含需要添加到向量存储和数据库中的文档摘要信息。
**代码描述**:
`add_kb_summary`函数首先通过调用`load_vector_store`方法加载一个线程安全的FAISS向量库实例。接着,使用`acquire`方法安全地获取向量库实例,并向其中添加文档摘要信息,这些信息来自于`summary_combine_docs`参数。添加完成后,向量库的状态会被保存到本地路径。
随后,函数构造一个包含摘要信息的列表`summary_infos`,每个摘要信息包括摘要内容、摘要ID、文档ID列表和元数据。这些信息是基于`summary_combine_docs`中每个文档的`page_content`、生成的ID、`metadata`中的`doc_ids``metadata`本身。
最后,`add_kb_summary`函数调用`add_summary_to_db`函数,将摘要信息添加到数据库中。此操作依赖于当前知识库服务实例的`kb_name`属性和构造的`summary_infos`列表。函数执行成功后,返回`add_summary_to_db`的执行结果,通常是一个表示操作成功的布尔值。
**注意**:
- 确保`summary_combine_docs`参数中的每个文档都包含必要的摘要信息和元数据。
- 在多线程环境下操作向量库和数据库时,函数内部已采取必要的线程安全措施,请避免在外部重复加锁。
- 函数执行成功并不直接返回摘要信息,而是通过数据库操作的结果来反映操作是否成功。
**输出示例**:
调用`add_kb_summary`函数通常不会直接返回具体的摘要信息,而是返回一个布尔值,例如`True`,表示所有摘要信息已成功添加到向量存储并更新到数据库中。
在项目中,`add_kb_summary`函数被用于处理知识库文档的摘要信息,支持知识库摘要的创建和更新流程。例如,在知识库摘要API中,通过处理文档文件生成摘要并调用此函数,将摘要信息添加到向量存储和数据库,从而实现知识库的动态更新和管理。
***
### FunctionDef create_kb_summary(self)
**create_kb_summary**: 此函数的功能是创建知识库摘要的存储路径。
**参数**: 此函数没有参数。
**代码描述**: `create_kb_summary` 函数是 `KBSummaryService` 类的一个方法,用于在指定的存储路径不存在时创建该路径。这个方法首先检查 `self.vs_path`(一个类属性,代表知识库摘要的存储路径)是否存在。如果该路径不存在,函数则会使用 `os.makedirs` 方法创建这个路径。这个功能在知识库摘要的生成和存储过程中非常关键,确保了存储知识库摘要的目录是存在的,从而可以顺利地保存摘要数据。
在项目中,`create_kb_summary` 函数被 `recreate_summary_vector_store``summary_file_to_vector_store` 两个方法调用。这两个方法分别位于 `kb_summary_api.py` 文件中,它们的共同点是都会在处理知识库摘要之前调用 `create_kb_summary` 函数来确保摘要数据的存储路径是存在的。无论是重新创建知识库摘要还是将单个文件的摘要信息保存到向量存储中,`create_kb_summary` 都是一个必要的步骤,以保证后续操作的顺利进行。
**注意**: 在使用 `create_kb_summary` 函数时,需要确保 `self.vs_path` 已经正确设置为期望的存储路径。此外,考虑到文件系统权限的问题,调用此函数的环境需要有相应的权限来创建目录。
**输出示例**: 由于 `create_kb_summary` 函数的主要作用是创建目录,它本身不返回任何值。但是,如果目录创建成功,指定的路径将会存在于文件系统中,这可以通过文件系统的检查工具(如在终端使用 `ls` 命令)来验证。如果之前路径不存在,调用此函数后,你将能够看到新创建的目录。
***
### FunctionDef drop_kb_summary(self)
**drop_kb_summary**: 该函数的功能是删除指定知识库的chunk summary。
**参数**: 此函数不接受任何外部参数。
**代码描述**: `drop_kb_summary` 函数是 `KBSummaryService` 类的一个方法,用于删除特定知识库的摘要信息。该方法首先通过 `kb_faiss_pool.atomic` 确保操作的原子性,接着使用 `kb_faiss_pool.pop(self.kb_name)` 从缓存池中移除指定知识库的摘要信息。紧接着,`shutil.rmtree(self.vs_path)` 调用用于删除与知识库相关的向量存储目录。最后,调用 `delete_summary_from_db(kb_name=self.kb_name)` 方法从数据库中删除该知识库的chunk summary信息。
在删除过程中,首先确保通过缓存池的原子操作来维护数据一致性,然后从缓存中移除知识库摘要信息,接着删除文件系统中的相关数据,最后从数据库中彻底清除该知识库的摘要信息。这一系列操作确保了知识库摘要的完全删除,避免了数据残留问题。
**注意**:
- 在执行此函数之前,确保 `self.kb_name``self.vs_path` 已正确设置,分别代表了知识库的名称和向量存储的路径。
- 由于该操作会从缓存、文件系统和数据库中删除数据,因此操作不可逆,请在调用前确保确实需要删除对应的知识库摘要信息。
- 该函数不返回任何值,但会影响系统中的缓存、文件系统和数据库状态。
**输出示例**: 该函数不提供输出示例,因为它不返回任何数据,而是直接对系统状态产生影响。
通过对 `drop_kb_summary` 函数的分析,开发者应能理解其在知识库管理中的重要作用,特别是在需要清理或重置知识库摘要信息时。务必谨慎使用此函数,以避免不必要的数据丢失。
***
@@ -0,0 +1,190 @@
## ClassDef SummaryAdapter
**SummaryAdapter**: SummaryAdapter类的功能是实现文档摘要的生成和处理。
**属性**:
- `_OVERLAP_SIZE`: 重叠大小,用于处理文档时去除重叠部分。
- `token_max`: 最大token数量,用于限制生成摘要的最大长度。
- `_separator`: 分隔符,默认为两个换行符,用于连接文档。
- `chain`: MapReduceDocumentsChain对象,用于执行文档的映射、规约和摘要合并操作。
**代码描述**:
SummaryAdapter类提供了文档摘要的生成、处理和优化的功能。它通过`form_summary`类方法创建实例,该方法接受两个基于语言模型的参数(`llm``reduce_llm`),用于生成摘要和合并摘要,以及`overlap_size``token_max`参数,分别控制重叠部分的大小和生成摘要的最大token数量。此外,该类还提供了`summarize``asummarize`方法,用于同步和异步生成文档摘要,以及`_drop_overlap``_join_docs`私有方法,用于处理文档中的重叠部分和连接文档。
从功能角度看,SummaryAdapter类在项目中被用于处理和生成知识库文档的摘要。它通过调用`form_summary`方法创建实例,并使用`summarize`方法生成文档摘要。这些摘要随后被用于更新或创建知识库的摘要信息,如在`kb_summary_api.py`文件中的`recreate_summary_vector_store``summary_file_to_vector_store`方法中所示。
**注意**:
- 在使用SummaryAdapter类时,需要确保提供的语言模型(`llm``reduce_llm`)能够有效地生成和合并文档摘要。
- `overlap_size``token_max`参数应根据实际需求和文档的特性进行调整,以优化摘要生成的效果。
- 在处理大量文档或需要高性能的场景下,应考虑使用`asummarize`方法进行异步摘要生成,以提高处理效率。
**输出示例**:
```python
[Document(page_content="这是生成的文档摘要。", metadata={"file_description": "文件描述", "summary_intermediate_steps": "摘要中间步骤", "doc_ids": "文档ID列表"})]
```
此输出示例展示了`summarize`方法返回的文档摘要列表,其中每个摘要包含了生成的摘要内容、文件描述、摘要生成的中间步骤和文档ID列表等元数据信息。
### FunctionDef __init__(self, overlap_size, token_max, chain)
**__init__**: 此函数的功能是初始化SummaryAdapter对象。
**参数**:
- `overlap_size`: 整型,表示文本块之间重叠的大小。
- `token_max`: 整型,表示处理的最大令牌数。
- `chain`: MapReduceDocumentsChain对象,用于处理文档的链式操作。
**代码描述**:
`__init__`方法是`SummaryAdapter`类的构造函数,用于初始化该类的实例。在这个方法中,首先将传入的`overlap_size`参数赋值给私有变量`_OVERLAP_SIZE`,这个变量定义了在文本摘要过程中,文本块之间应该有多大的重叠部分。这是为了确保在处理长文本时,可以平滑地过渡并保持上下文的连贯性。
其次,`token_max`参数被直接赋值给实例变量`token_max`,这个参数限制了在文本处理过程中,可以处理的最大令牌(例如,单词或字符)数量。这是为了控制处理的复杂度和资源消耗。
最后,`chain`参数是一个`MapReduceDocumentsChain`对象,它被赋值给实例变量`chain`。这个对象代表了一个处理文档的链式操作序列,允许对文档进行复杂的处理流程,如分词、摘要生成等。
**注意**:
- 在使用`SummaryAdapter`类时,需要确保传入的`overlap_size``token_max`参数是合理的,以避免处理时出现性能问题或结果不准确的情况。
- `chain`参数需要是一个有效的`MapReduceDocumentsChain`实例,这意味着在使用之前应该正确配置链式操作。
***
### FunctionDef form_summary(cls, llm, reduce_llm, overlap_size, token_max)
**form_summary**: 该函数用于形成文本摘要。
**参数**:
- **llm**: 用于生成摘要的语言模型。
- **reduce_llm**: 用于合并摘要的语言模型。
- **overlap_size**: 文本重叠部分的大小。
- **token_max**: 每个摘要块的最大token数量,默认为1300。
**代码描述**:
`form_summary`函数是`SummaryAdapter`类的一个方法,负责创建一个文本摘要的处理流程。该流程包括使用语言模型生成摘要、合并摘要以及处理文本块以确保每个摘要块的长度不超过指定的最大token数量。函数首先定义了文档格式化的模板,然后定义了一个处理链`llm_chain`,用于生成摘要。接着,定义了另一个处理链`reduce_llm_chain`,用于合并这些摘要。最后,通过`MapReduceDocumentsChain`将生成摘要和合并摘要的流程结合起来,返回一个配置好的摘要处理流程实例。
在项目中,`form_summary`函数被多个地方调用,包括重建知识库摘要向量存储、将文件摘要转换为向量存储以及根据文档ID将摘要转换为向量存储等场景。这些调用场景表明,`form_summary`函数是处理知识库文档摘要的核心功能,它能够根据不同的需求生成和合并文档摘要,为知识库的构建和更新提供支持。
**注意**:
- 确保传入的`llm``reduce_llm`参数是有效的语言模型实例。
- `overlap_size``token_max`参数应根据实际需求合理设置,以优化摘要生成的效果和性能。
- 该函数返回的是一个配置好的摘要处理流程实例,需要通过调用其`summarize`方法来执行摘要的生成和合并操作。
**输出示例**:
由于`form_summary`函数返回的是一个配置好的摘要处理流程实例,而非直接的摘要结果,因此没有直接的输出示例。但在使用返回的实例调用`summarize`方法后,可以得到如下格式的摘要结果:
```json
{
"code": 200,
"msg": "摘要生成成功",
"summarize": [
{
"doc_id": "文档ID1",
"summary": "这里是文档摘要内容..."
},
{
"doc_id": "文档ID2",
"summary": "这里是另一个文档的摘要内容..."
}
]
}
```
这个示例展示了摘要处理流程实例在处理完文档后返回的摘要结果格式,其中包含了文档的ID和对应的摘要内容。
***
### FunctionDef summarize(self, file_description, docs)
**summarize**: 此函数的功能是同步调用异步生成文档摘要的方法。
**参数**:
- `file_description`: 字符串类型,描述文件的内容。
- `docs`: `DocumentWithVSId` 类型的列表,默认为空列表。这些文档将被用来生成摘要。
**代码描述**:
`summarize` 函数是 `SummaryAdapter` 类的一个方法,用于同步调用异步方法 `asummarize` 生成文档的摘要。该函数首先根据 Python 版本检查来决定如何获取或创建事件循环。如果 Python 版本低于 3.10,它将使用 `asyncio.get_event_loop()` 来获取当前事件循环;对于 Python 3.10 及以上版本,它尝试使用 `asyncio.get_running_loop()` 获取正在运行的事件循环,如果失败,则创建一个新的事件循环并设置为当前事件循环。之后,函数通过事件循环的 `run_until_complete` 方法同步调用 `asummarize` 方法,并传入文件描述和文档列表作为参数,最终返回一个包含 `Document` 对象的列表。
**注意**:
- 该函数是一个同步包装器,用于在同步代码中调用异步方法 `asummarize`,确保异步方法能够在同步环境中正确执行。
- 如果传入的文档列表 `docs` 为空,`asummarize` 方法将直接返回一个空的 `Document` 对象列表。
- 在使用该函数时,需要注意 Python 版本的兼容性问题,以确保事件循环能够正确获取或创建。
**输出示例**:
调用 `summarize` 函数可能会返回如下格式的列表:
```python
[
Document(
page_content="这里是合并后的摘要内容。",
metadata={
"file_description": "文件描述信息",
"summary_intermediate_steps": "中间步骤的信息",
"doc_ids": "文档ID列表"
}
)
]
```
这个列表包含一个 `Document` 对象,其中 `page_content` 属性包含了生成的摘要内容,`metadata` 属性包含了文件描述、中间步骤的信息和文档ID列表。
***
### FunctionDef asummarize(self, file_description, docs)
**asummarize**: 此函数的功能是异步生成文档的摘要。
**参数**:
- `file_description`: 字符串类型,描述文件的内容。
- `docs`: `DocumentWithVSId` 类型的列表,默认为空列表。这些文档将被用来生成摘要。
**代码描述**:
`asummarize` 函数是`SummaryAdapter`类的一个异步方法,用于处理文档摘要的生成。该过程分为两个主要部分:首先,对每个文档进行处理,得到每个文档的摘要;其次,将这些摘要合并成一个最终的摘要,并且可以返回中间步骤的信息。
在处理文档摘要时,该函数首先记录开始生成摘要的日志信息。然后,通过调用`chain.combine_docs`方法,传入文档列表和任务简介,来生成文档的摘要。这个方法会返回合并后的摘要和中间步骤的信息。函数会打印出合并后的摘要和中间步骤的信息,以便于调试和查看。
函数还会记录文档ID,并将文件描述、中间步骤的信息以及文档ID作为元数据,与合并后的摘要一起封装成一个`Document`对象。最后,函数返回一个包含这个`Document`对象的列表。
**注意**:
- 该函数是异步的,需要在异步环境中调用。
- 如果传入的文档列表为空,函数将直接返回一个空的`Document`对象列表。
- 函数中有一段被注释的代码,说明在某些情况下可能需要重新生成摘要,这部分逻辑在当前版本中未被启用。
**输出示例**:
调用`asummarize`函数可能会返回如下格式的列表:
```python
[
Document(
page_content="这里是合并后的摘要内容。",
metadata={
"file_description": "文件描述信息",
"summary_intermediate_steps": "中间步骤的信息",
"doc_ids": "文档ID列表"
}
)
]
```
这个列表包含一个`Document`对象,其中`page_content`属性包含了生成的摘要内容,`metadata`属性包含了文件描述、中间步骤的信息和文档ID列表。
***
### FunctionDef _drop_overlap(self, docs)
**_drop_overlap**: 此函数的功能是去除文档列表中页面内容句子重叠的部分。
**参数**:
- `docs`: 一个包含DocumentWithVSId实例的列表,每个实例代表一个文档,其中包含页面内容。
**代码描述**:
`_drop_overlap` 函数接收一个文档列表作为输入,这些文档通过DocumentWithVSId类的实例表示,每个实例包含一个页面内容属性。该函数的目的是处理文档列表,去除其中页面内容句子重叠的部分,以便于后续的文档处理或摘要生成过程中,减少冗余信息的干扰。
函数首先初始化一个空列表`merge_docs`,用于存储处理后的文档内容。然后,通过遍历输入的文档列表`docs`,逐个处理每个文档。对于列表中的第一个文档,其页面内容直接被添加到`merge_docs`列表中,作为处理的起始点。对于后续的文档,函数检查当前文档的页面内容开头是否与前一个文档的页面内容结尾存在重叠部分。如果存在重叠,函数则从当前文档的页面内容中去除这部分重叠的内容,只将非重叠部分添加到`merge_docs`列表中。
重叠检测和去除的具体实现是通过迭代减少前一个文档页面内容的长度,并与当前文档页面内容的开头进行比较,直到找到重叠的部分或达到一定的迭代条件。这里使用了`self._OVERLAP_SIZE``self._separator`两个属性来辅助确定重叠检测的条件和处理逻辑。
**注意**:
- `_drop_overlap`函数依赖于`DocumentWithVSId`类的`page_content`属性来获取文档的页面内容。因此,确保传入的文档列表中的每个实例都包含有效的页面内容。
- 函数处理的效果和性能可能会受到`self._OVERLAP_SIZE``self._separator`值的影响,适当调整这些值可以优化处理结果。
**输出示例**:
假设有两个文档的页面内容分别为"今天天气不错,适合出去玩。适合出去玩,不要忘记带伞。"和"适合出去玩,不要忘记带伞。明天也是好天气。",经过`_drop_overlap`函数处理后,返回的`merge_docs`列表可能如下:
```
["今天天气不错,适合出去玩。适合出去玩,不要忘记带伞。", "明天也是好天气。"]
```
这表示第二个文档中与第一个文档重叠的部分已被成功去除。
***
### FunctionDef _join_docs(self, docs)
**_join_docs**: 此函数的功能是将字符串列表连接成一个字符串,并在必要时返回None。
**参数**:
- `docs`: 字符串列表,即要连接的文档列表。
**代码描述**:
`_join_docs` 函数接收一个字符串列表作为参数。它使用实例变量 `_separator` 作为分隔符,将这些字符串连接成一个新的字符串。然后,它会去除新字符串两端的空白字符。如果处理后的字符串为空(即长度为0),函数将返回 `None`;否则,返回处理后的字符串。
这个函数的设计考虑到了可能存在的空字符串或全空白字符的字符串列表,确保在这种情况下不会返回一个空字符串而是返回 `None`,这在很多情况下对于后续的逻辑判断是有帮助的。
**注意**:
- `_separator` 应该在类的其他部分被定义,它决定了如何在字符串之间插入分隔符。如果 `_separator` 没有被正确定义,这个函数可能不会按预期工作。
- 传入的 `docs` 列表不能为空,否则函数将返回 `None`
**输出示例**:
假设 `_separator` 被定义为逗号 `,`,并且 `docs` 参数为 `["Hello", "world", "!"]`,那么函数的返回值将是 `"Hello,world,!"`。如果 `docs` 为空列表,或者列表中的所有字符串都是空或者只包含空白字符,函数将返回 `None`
***
@@ -0,0 +1,169 @@
## FunctionDef recreate_summary_vector_store(knowledge_base_name, allow_empty_kb, vs_type, embed_model, file_description, model_name, temperature, max_tokens)
**recreate_summary_vector_store**: 此函数的功能是重建单个知识库文件摘要。
**参数**:
- `knowledge_base_name`: 知识库的名称,类型为字符串。
- `allow_empty_kb`: 是否允许空的知识库,布尔类型,默认为True。
- `vs_type`: 向量存储类型,字符串类型,默认值由`DEFAULT_VS_TYPE`变量决定。
- `embed_model`: 嵌入模型名称,字符串类型,默认值由`EMBEDDING_MODEL`变量决定。
- `file_description`: 文件描述,字符串类型,默认为空字符串。
- `model_name`: LLM模型名称,字符串类型,默认值为`LLM_MODELS`列表的第一个元素。
- `temperature`: LLM采样温度,浮点数类型,必须在0.0到1.0之间。
- `max_tokens`: 限制LLM生成Token的数量,整数类型或None,默认为None,代表使用模型的最大值。
**代码描述**:
`recreate_summary_vector_store`函数主要用于重建指定知识库的文件摘要。首先,通过`KBServiceFactory.get_service`方法获取知识库服务实例。如果指定的知识库不存在且不允许空的知识库,则返回404错误。否则,会先删除现有的知识库摘要,然后重新创建。接着,利用指定的LLM模型参数创建文本摘要适配器,并对知识库中的每个文件进行摘要处理。每处理完一个文件,就会向客户端发送一个包含处理状态的JSON消息。如果在处理某个文件时出错,则会记录错误信息并跳过该文件。
此函数通过`EventSourceResponse`返回一个生成器,该生成器会逐步产生处理每个文件的状态信息,使得客户端可以实时获取处理进度。
在项目中,`recreate_summary_vector_store`函数被`server/api.py/mount_filename_summary_routes`中的`mount_filename_summary_routes`函数调用,并注册为FastAPI的一个POST路由。这表明该函数主要用于处理HTTP POST请求,用于在Web服务中重建知识库文件摘要。
**注意**:
- 确保在调用此函数之前,已经正确设置了`DEFAULT_VS_TYPE``EMBEDDING_MODEL``LLM_MODELS`等全局变量。
- 函数处理过程中可能会产生大量日志,建议监控日志以便及时发现和解决问题。
- 调用此函数可能需要较长的处理时间,特别是当知识库文件数量较多时。
**输出示例**:
```json
{
"code": 200,
"msg": "(1 / 10): example_file.txt",
"total": 10,
"finished": 1,
"doc": "example_file.txt"
}
```
此JSON表示第一个文件`example_file.txt`已经处理完成,总共需要处理10个文件。
### FunctionDef output
**output**: 此函数的功能是输出知识库摘要的创建或更新过程中的状态信息。
**参数**: 此函数没有参数。
**代码描述**: `output` 函数是一个生成器,用于在知识库摘要的创建或更新过程中,逐步输出处理状态信息。首先,通过 `KBServiceFactory.get_service` 方法获取知识库服务实例。如果指定的知识库不存在且不允许空知识库,则生成并返回一个包含错误代码404和相应消息的字典。否则,会重新创建知识库摘要,包括删除旧的知识库摘要和创建新的知识库摘要。
接下来,函数初始化两个 `ChatOpenAI` 实例,`llm``reduce_llm`,用于生成和合并文本摘要。然后,通过 `SummaryAdapter.form_summary` 方法创建一个摘要适配器实例,用于处理文本摘要。
函数遍历知识库中的文件,对每个文件使用 `kb.list_docs` 方法获取文档信息,并通过摘要适配器的 `summary.summarize` 方法生成摘要。如果摘要成功添加到知识库摘要中,则输出一个包含成功状态的JSON字符串;如果在添加摘要过程中出错,则输出一个包含错误信息的JSON字符串。
此函数与项目中的其他组件紧密相关,特别是与知识库服务 (`KBServiceFactory`)、摘要生成 (`ChatOpenAI``SummaryAdapter`) 相关联。它通过调用这些组件的方法,实现了知识库摘要的自动化创建和更新过程,并通过生成器逐步返回处理状态,为知识库管理提供了实时反馈。
**注意**:
- 确保在调用此函数之前,知识库名称、嵌入模型等参数已正确配置,以确保能够正确初始化知识库服务和摘要生成器。
- 此函数作为生成器,需要在循环或迭代器中使用,以获取所有的状态信息。
- 在处理大量文件或大型知识库时,此函数可能需要较长时间执行,建议异步调用或在后台任务中执行。
***
## FunctionDef summary_file_to_vector_store(knowledge_base_name, file_name, allow_empty_kb, vs_type, embed_model, file_description, model_name, temperature, max_tokens)
**summary_file_to_vector_store**: 此函数的功能是根据文件名称对单个知识库进行摘要,并将摘要结果存储到向量存储中。
**参数**:
- `knowledge_base_name`: 知识库的名称,示例值为"samples"。
- `file_name`: 需要进行摘要的文件名称,示例值为"test.pdf"。
- `allow_empty_kb`: 是否允许空的知识库,默认为True。
- `vs_type`: 向量存储的类型,默认值由`DEFAULT_VS_TYPE`指定。
- `embed_model`: 嵌入模型的名称,默认值由`EMBEDDING_MODEL`指定。
- `file_description`: 文件的描述,默认为空字符串。
- `model_name`: LLM模型的名称,默认值为`LLM_MODELS`数组的第一个元素,用于指定使用的语言模型。
- `temperature`: LLM采样温度,取值范围为0.0至1.0,默认值由`TEMPERATURE`指定。
- `max_tokens`: 限制LLM生成的Token数量,若为None则代表使用模型的最大值,默认为None。
**代码描述**:
`summary_file_to_vector_store`函数主要负责将指定文件的内容进行摘要,并将摘要结果存储到向量存储中。首先,通过`KBServiceFactory.get_service`获取知识库服务实例。如果指定的知识库不存在且不允许空的知识库,则返回404错误。否则,使用`KBSummaryService`创建知识库摘要服务,并调用`create_kb_summary`方法重新创建知识库摘要。接着,初始化两个LLM模型实例用于生成摘要。通过`SummaryAdapter.form_summary`方法,结合LLM模型和文件描述,对文件内容进行摘要。最后,将摘要结果添加到知识库摘要中,并根据操作结果返回相应的状态码和信息。
在项目中,`summary_file_to_vector_store`函数被`server/api.py/mount_filename_summary_routes`对象调用,用于处理HTTP POST请求,实现根据文件名称对单个知识库进行摘要的API接口。这表明该函数是知识库管理功能中处理文件摘要的核心逻辑部分。
**注意**:
- 确保传入的`knowledge_base_name``file_name`有效,以避免处理不存在的知识库或文件。
- `allow_empty_kb`参数在知识库为空时特别有用,可以根据实际需求调整其值。
- 调用此函数时,需要注意`model_name``temperature``max_tokens`参数的设置,以确保摘要生成的效果符合预期。
**输出示例**:
```json
{
"code": 200,
"msg": "test.pdf 总结完成",
"doc": "test.pdf"
}
```
或在知识库不存在时:
```json
{
"code": 404,
"msg": "未找到知识库 samples"
}
```
### FunctionDef output
**output**: 此函数的功能是输出知识库摘要的处理结果。
**参数**: 此函数没有参数。
**代码描述**: `output` 函数是知识库摘要API中的一个关键组成部分,主要负责输出知识库摘要的处理结果。首先,通过 `KBServiceFactory.get_service` 方法获取知识库服务实例。如果指定的知识库不存在且不允许空知识库,则返回404状态码和相应的错误信息。如果知识库存在或允许空知识库,函数将继续执行以下步骤:
1. 使用 `KBSummaryService` 创建或更新知识库摘要。
2. 通过 `get_ChatOpenAI` 方法初始化两个语言模型实例,用于生成和优化文本摘要。
3. 使用 `SummaryAdapter.form_summary` 方法配置文本摘要的生成流程。
4. 通过 `KBService.list_docs` 方法获取指定文件的文档列表。
5. 调用 `SummaryAdapter.summarize` 方法生成文档摘要。
6. 将生成的文档摘要添加到知识库摘要中,并检查操作是否成功。
如果知识库摘要添加成功,函数将记录日志信息并返回200状态码、成功信息和文件名。如果在添加知识库摘要时发生错误,函数将记录错误信息并返回500状态码和错误信息。
**注意**:
- 在调用 `output` 函数之前,需要确保知识库名称、向量存储类型和嵌入模型等参数已经正确配置。
- `get_ChatOpenAI` 方法返回的语言模型实例用于生成和优化文本摘要,确保传入的模型名称、温度和最大token数量等参数符合预期。
- `SummaryAdapter.form_summary` 方法配置的文本摘要生成流程包括文档的格式化、摘要生成和摘要合并等步骤,需要根据实际需求调整参数。
- 在处理大量文档或执行复杂的摘要生成任务时,应注意性能和资源消耗,可能需要优化算法或调整系统资源。
此函数在知识库摘要API中扮演着核心角色,通过综合利用知识库服务、语言模型和文本摘要适配器等组件,实现了知识库文档摘要的自动化生成和更新。
***
## FunctionDef summary_doc_ids_to_vector_store(knowledge_base_name, doc_ids, vs_type, embed_model, file_description, model_name, temperature, max_tokens)
**summary_doc_ids_to_vector_store**: 此函数的功能是根据文档ID列表生成单个知识库的文档摘要,并将摘要信息存储到向量存储中。
**参数**:
- `knowledge_base_name`: 知识库名称,字符串类型,默认示例为"samples"。
- `doc_ids`: 文档ID列表,列表类型,默认为空列表,示例值为["uuid"]。
- `vs_type`: 向量存储类型,字符串类型,默认值由`DEFAULT_VS_TYPE`变量决定。
- `embed_model`: 嵌入模型名称,字符串类型,默认值由`EMBEDDING_MODEL`变量决定。
- `file_description`: 文件描述,字符串类型,默认为空字符串。
- `model_name`: LLM模型名称,字符串类型,默认值为`LLM_MODELS`列表的第一个元素,用于描述使用的语言模型。
- `temperature`: LLM采样温度,浮点数类型,用于控制生成文本的多样性,默认值由`TEMPERATURE`变量决定,取值范围为0.0至1.0。
- `max_tokens`: 限制LLM生成Token数量,整型或None,默认为None代表模型最大值。
**代码描述**:
函数首先通过`KBServiceFactory.get_service`方法获取知识库服务实例。如果指定的知识库不存在,则返回404状态码和相应的错误信息。否则,函数将初始化两个`ChatOpenAI`实例,分别用于生成文档摘要和合并摘要。接着,使用`SummaryAdapter.form_summary`方法创建文本摘要适配器,并通过知识库服务实例的`get_doc_by_ids`方法获取文档信息。然后,将文档信息转换为`DocumentWithVSId`对象,并调用摘要适配器的`summarize`方法生成文档摘要。最后,将生成的文档摘要转换为字典格式并返回,状态码为200,表示操作成功。
**注意**:
- 确保传入的知识库名称、文档ID列表和向量存储类型等参数正确无误,以避免查询错误或操作失败。
- 在调用此函数之前,请确保知识库服务已正确配置,包括知识库存在性、向量存储类型和嵌入模型等。
- 函数依赖于`ChatOpenAI`实例进行文档摘要的生成和合并,因此需要确保提供的模型名称、采样温度和Token数量限制等参数适合于所使用的语言模型。
**输出示例**:
调用`summary_doc_ids_to_vector_store`函数可能会返回如下格式的响应:
```json
{
"code": 200,
"msg": "总结完成",
"data": {
"summarize": [
{
"id": "文档ID1",
"page_content": "这里是文档摘要内容...",
"metadata": {
"file_description": "文件描述信息",
"summary_intermediate_steps": "摘要中间步骤信息",
"doc_ids": "文档ID列表"
}
},
{
"id": "文档ID2",
"page_content": "这里是另一个文档的摘要内容...",
"metadata": {
"file_description": "文件描述信息",
"summary_intermediate_steps": "摘要中间步骤信息",
"doc_ids": "文档ID列表"
}
}
]
}
}
```
此输出示例展示了函数在处理完文档后返回的摘要结果格式,其中包含了文档的ID、摘要内容和相关的元数据信息。
@@ -0,0 +1,166 @@
## FunctionDef create_tables
**create_tables**: 此函数的功能是创建数据库表。
**参数**: 此函数不接受任何参数。
**代码描述**: `create_tables` 函数是在数据库迁移过程中使用的关键函数,用于创建数据库中定义的所有表。它通过调用 `Base.metadata.create_all` 方法并将 `engine` 作为绑定参数来实现。这里的 `Base` 是一个ORM声明基类,它存储了所有模型(即表)的元数据,而 `engine` 是SQLAlchemy的连接引擎,用于执行对数据库的实际操作。
在项目中,`create_tables` 函数被多个对象调用,显示了其在不同场景下的重要性:
- 在初始化数据库(`init_database.py`)、服务器启动(`startup.py`)时,确保所需的表结构已经创建。
- 在重置表(`server/knowledge_base/migrate.py/reset_tables`)时,先删除所有表,然后重新调用此函数来创建表,用于测试或重置数据库环境。
- 在各种测试场景中(如`tests/kb_vector_db/test_faiss_kb.py/test_init``tests/kb_vector_db/test_milvus_db.py/test_init``tests/kb_vector_db/test_pg_db.py/test_init`),确保测试前数据库表结构正确设置。
**注意**: 使用此函数时,需要确保`Base``engine`已经正确初始化,且所有的表模型都已经通过`Base`定义。此外,调用此函数将会创建所有未存在的表,如果表已经存在,则不会对其进行修改,这意味着它不会更新或修改现有表结构。因此,在生产环境中使用时应谨慎,以避免数据丢失。
## FunctionDef reset_tables
**reset_tables**: 此函数的功能是重置数据库表。
**参数**: 此函数不接受任何参数。
**代码描述**: `reset_tables` 函数是数据库迁移过程中的一个重要环节,用于重置数据库环境。它首先调用 `Base.metadata.drop_all` 方法删除所有现有的表结构,然后通过调用 `create_tables` 函数重新创建表结构。这个过程通常用于测试或者在需要彻底清理数据库并重新设置表结构的场景下。
在这个函数中,`Base.metadata.drop_all(bind=engine)` 负责删除所有表,其中 `Base` 是ORM声明基类,存储了所有模型(即表)的元数据,`engine` 是SQLAlchemy的连接引擎,用于执行对数据库的实际操作。紧接着,`create_tables()` 被调用以重新创建数据库中定义的所有表。这确保了数据库环境可以被重置到一个干净的初始状态。
**注意**: 在调用 `reset_tables` 函数时,需要确保 `Base``engine` 已经被正确初始化,并且所有的表模型都已经通过 `Base` 定义。此外,由于此函数会删除所有现有的表并重新创建,因此在生产环境中使用时应格外小心,以避免不必要的数据丢失。在测试或开发环境中使用此函数可以帮助快速重置数据库状态,便于进行环境的清理和重建。
## FunctionDef import_from_db(sqlite_path)
**import_from_db**: 该函数的功能是从备份数据库中导入数据到 info.db。
**参数**:
- `sqlite_path`: 字符串类型,指定 SQLite 数据库的路径。默认为 None。
**代码描述**:
`import_from_db` 函数主要用于在知识库与向量库无变化的情况下,从备份的 SQLite 数据库中导入数据到当前的 info.db 数据库中。这种情况通常出现在版本升级时,info.db 的结构发生了变化,但数据本身不需要重新向量化处理。函数开始时,会导入必要的模块,包括 `sqlite3` 用于操作 SQLite 数据库,以及 `pprint` 用于打印数据。
函数内部首先获取数据库模型列表,然后尝试连接到指定的 SQLite 数据库。通过查询 SQLite 的 `sqlite_master` 表,获取并遍历所有表名。对于每一个模型对应的表,如果表存在于数据库中,则会进一步读取该表的所有数据。对于每一行数据,函数会根据模型定义的列名过滤出需要的字段,并特别处理 `create_time` 字段,将其解析为正确的时间格式。之后,使用 `session_scope` 上下文管理器自动管理数据库会话,将过滤并处理后的数据添加到会话中,最终提交到数据库。
如果在数据导入过程中遇到任何异常,函数会打印错误信息,并返回 False 表示导入失败。否则,在成功处理所有数据后关闭数据库连接,并返回 True 表示导入成功。
**注意**:
- 请确保传入的 `sqlite_path` 是正确的 SQLite 数据库文件路径。
- 确保备份数据库中的表名和字段名与当前数据库模型一致。
- 该函数目前仅支持 SQLite 数据库。
- 使用该函数导入数据时,应确保没有其他操作正在访问目标数据库,以避免数据冲突。
**输出示例**:
- 成功导入数据时,函数返回 `True`
- 如果无法读取备份数据库或遇到其他错误,函数返回 `False`
## FunctionDef file_to_kbfile(kb_name, files)
**file_to_kbfile**: 该函数的功能是将文件列表转换为KnowledgeFile对象列表。
**参数**:
- `kb_name`: 字符串类型,表示知识库的名称。
- `files`: 字符串列表,包含需要转换的文件名。
**代码描述**: `file_to_kbfile`函数接收知识库名称和文件名列表作为输入参数,遍历文件列表,为每个文件创建一个`KnowledgeFile`实例。在实例化`KnowledgeFile`过程中,如果遇到任何异常,该文件会被跳过,并且异常信息会被记录到日志中。函数最终返回一个`KnowledgeFile`对象的列表,这些对象包含了文件与知识库名称的关联信息以及其他由`KnowledgeFile`类提供的文件处理功能。
**注意**:
- 在调用此函数之前,需要确保传入的文件列表中的文件都存在于磁盘上。
- 如果文件格式不被支持,或者在创建`KnowledgeFile`实例的过程中出现其他问题,相关文件将被跳过,错误信息会被记录。
- 日志记录的详细程度取决于全局日志配置中`log_verbose`的设置。
**输出示例**:
假设有一个文件列表`["document1.md", "document2.txt"]`和知识库名称`"demo_kb"`,调用`file_to_kbfile("demo_kb", ["document1.md", "document2.txt"])`可能会返回如下`KnowledgeFile`对象列表(具体内容取决于文件内容和`KnowledgeFile`类的实现):
```python
[
KnowledgeFile(filename="document1.md", knowledge_base_name="demo_kb"),
KnowledgeFile(filename="document2.txt", knowledge_base_name="demo_kb")
]
```
这个列表中的每个`KnowledgeFile`对象都代表了一个与知识库`demo_kb`关联的文件,可以进一步用于知识库的文件处理、文档加载和文本分割等操作。
在项目中,`file_to_kbfile`函数被用于多个场景,包括但不限于将本地文件夹中的文件转换为知识库文件、更新知识库中的文件、从知识库中删除文件等。例如,在`folder2db`函数中,它被用来将指定文件夹中的文件转换为`KnowledgeFile`对象,然后这些对象可以用于向量库的创建或更新;在`prune_db_docs`函数中,它用于识别并删除那些在本地文件夹中已经不存在的知识库文件。
## FunctionDef folder2db(kb_names, mode, vs_type, embed_model, chunk_size, chunk_overlap, zh_title_enhance)
**folder2db**: 此函数的功能是使用本地文件夹中的现有文件来填充数据库和/或向量存储。
**参数**:
- `kb_names`: 知识库名称列表,类型为 `List[str]`
- `mode`: 迁移模式,可选值为 `"recreate_vs"`, `"update_in_db"`, `"increment"`,类型为 `Literal["recreate_vs", "update_in_db", "increment"]`
- `vs_type`: 向量存储类型,可选值为 `"faiss"`, `"milvus"`, `"pg"`, `"chromadb"`,默认值为 `DEFAULT_VS_TYPE`,类型为 `Literal["faiss", "milvus", "pg", "chromadb"]`
- `embed_model`: 嵌入模型名称,默认值为 `EMBEDDING_MODEL`,类型为 `str`
- `chunk_size`: 分块大小,默认值为 `CHUNK_SIZE`,类型为 `int`
- `chunk_overlap`: 分块重叠大小,默认值为 `OVERLAP_SIZE`,类型为 `int`
- `zh_title_enhance`: 是否增强中文标题,默认值为 `ZH_TITLE_ENHANCE`,类型为 `bool`
**代码描述**:
此函数根据提供的参数,从本地文件夹中读取文件,并根据指定的迁移模式将文件信息填充到数据库和/或向量存储中。支持的迁移模式包括:
- `recreate_vs`:重新创建所有向量存储,并使用本地文件夹中的现有文件填充数据库信息。
- `update_in_db`:使用数据库中已存在的本地文件更新向量存储和数据库信息。
- `increment`:为数据库中不存在的本地文件创建向量存储和数据库信息。
函数首先检查是否提供了知识库名称列表,如果没有,则调用 `list_kbs_from_folder` 函数获取所有知识库目录名称。然后,根据指定的向量存储类型和嵌入模型名称,通过 `KBServiceFactory.get_service` 方法获取相应的知识库服务实例。根据迁移模式的不同,函数执行相应的操作,如清除向量存储、创建知识库、更新向量存储等。
**注意**:
- 在使用此函数之前,确保本地文件夹中存在目标知识库的相关文件。
- 根据迁移模式的不同,操作可能会涉及到重建向量存储或更新数据库信息,这可能会对现有数据产生影响,请谨慎操作。
- 函数内部通过调用多个辅助函数和服务实例方法来完成具体的操作,确保这些辅助函数和方法已正确实现并可用。
在项目中,`folder2db` 函数被用于初始化数据库 (`init_database.py`) 和测试迁移功能 (`tests/test_migrate.py`),包括测试重新创建向量存储 (`test_recreate_vs`) 和增量更新 (`test_increment`)。这些调用情况表明,`folder2db` 函数是知识库迁移和管理流程中的关键组件,用于根据本地文件夹中的文件更新或重建数据库和向量存储。
### FunctionDef files2vs(kb_name, kb_files)
**files2vs**: 此函数的功能是将文件批量转换并添加到向量库中。
**参数**:
- `kb_name`: 字符串类型,表示知识库的名称。
- `kb_files`: `KnowledgeFile`对象的列表,表示要处理并添加到向量库的文件列表。
**代码描述**:
`files2vs`函数主要负责将给定的文件列表(`kb_files`)批量处理并添加到指定的知识库(`kb_name`)中。这个过程涉及以下几个步骤:
1. 调用`files2docs_in_thread`函数,该函数使用多线程将文件列表中的每个文件转换成文档列表。这个过程中,会根据文件的内容和一系列参数(如文档分块大小`chunk_size`、分块重叠大小`chunk_overlap`、是否增强中文标题`zh_title_enhance`等)进行处理。
2. 对于`files2docs_in_thread`函数的每个返回结果,首先检查转换是否成功。如果成功,会获取转换后的文件名和文档列表。
3. 对于每个成功转换的文件,创建一个新的`KnowledgeFile`实例,并将文件名、知识库名称以及分割处理后的文档列表(`splited_docs`)设置给这个实例。
4. 调用`KBService``add_doc`方法,将上一步创建的`KnowledgeFile`实例添加到知识库中。在这个过程中,不刷新向量库缓存(`not_refresh_vs_cache=True`)。
5. 如果转换失败,则打印错误信息。
此函数通过上述步骤,实现了将文件内容批量转换并添加到知识库的向量库中,以支持后续的搜索和检索功能。
**注意**:
- 在使用`files2vs`函数时,需要确保传入的`kb_name``kb_files`参数正确且有效。`kb_files`中的每个`KnowledgeFile`对象都应该是可以被正确处理的文件。
- `files2docs_in_thread`函数的多线程处理可以提高文件转换的效率,但在使用时也需要注意线程安全问题。
- `add_doc`方法的调用不刷新向量库缓存,这意味着在添加大量文档后,可能需要手动刷新缓存以确保向量库的数据是最新的。
***
## FunctionDef prune_db_docs(kb_names)
**prune_db_docs**: 此函数的功能是删除数据库中不存在于本地文件夹中的文档。
**参数**:
- `kb_names`: 字符串列表,包含需要进行清理操作的知识库名称。
**代码描述**: `prune_db_docs` 函数通过遍历传入的知识库名称列表 `kb_names`,对每一个知识库执行以下操作:
1. 使用 `KBServiceFactory.get_service_by_name` 方法根据知识库名称获取对应的知识库服务实例。如果该实例存在,则继续执行;如果不存在,则跳过当前知识库。
2. 调用知识库服务实例的 `list_files` 方法获取数据库中的文件列表。
3. 调用 `list_files_from_folder` 函数获取本地文件夹中的文件列表。
4. 计算出存在于数据库中但不在本地文件夹中的文件列表。
5. 使用 `file_to_kbfile` 函数将步骤4中得到的文件列表转换为 `KnowledgeFile` 对象列表。
6. 遍历 `KnowledgeFile` 对象列表,对每个对象调用知识库服务实例的 `delete_doc` 方法删除数据库中的文档,并打印成功删除的文档信息。
7. 调用知识库服务实例的 `save_vector_store` 方法保存向量库的状态。
**注意**:
- 确保在调用此函数之前,传入的知识库名称列表 `kb_names` 中的每个知识库都已经在数据库中注册并正确配置。
- 此函数用于同步本地文件夹和数据库中的文档状态,特别适用于用户在文件浏览器中删除了某些文档文件后,需要从数据库中也删除这些文档的场景。
- 在删除数据库中的文档时,`delete_doc` 方法的 `not_refresh_vs_cache` 参数被设置为 `True`,这意味着在删除操作后不立即刷新向量库缓存。向量库的状态将在所有删除操作完成后通过 `save_vector_store` 方法统一保存。
- 函数执行过程中,会打印每个成功删除的文档的信息,包括知识库名称和文件名,以便于跟踪操作结果。
通过以上步骤,`prune_db_docs` 函数能够有效地从数据库中删除那些已经不再存在于本地文件夹中的文档,从而保持数据库内容的准确性和最新性。
## FunctionDef prune_folder_files(kb_names)
**prune_folder_files**: 此函数的功能是删除本地文件夹中不存在于数据库中的文档文件,用于通过删除未使用的文档文件释放本地磁盘空间。
**参数**:
- `kb_names`: 一个字符串列表,表示需要处理的知识库的名称。
**代码描述**:
`prune_folder_files` 函数接收一个包含知识库名称的列表作为参数。对于列表中的每一个知识库名称,函数首先使用 `KBServiceFactory.get_service_by_name` 方法尝试获取对应的知识库服务实例。如果成功获取到服务实例,则继续执行以下步骤:
1. 调用知识库服务实例的 `list_files` 方法获取数据库中存储的文件列表。
2. 使用 `list_files_from_folder` 函数获取本地文件夹中的文件列表。
3. 通过集合运算找出存在于本地文件夹中但不在数据库文件列表中的文件,这些文件被认为是未使用的文件。
4. 对于每一个未使用的文件,使用 `os.remove` 方法删除该文件,并打印删除成功的消息。
此过程确保了本地存储空间不会被数据库中已经不存在的文件占用,从而优化了存储资源的使用。
**注意**:
- 在调用此函数之前,需要确保提供的知识库名称列表中的每个名称都是有效的,并且对应的知识库服务实例可以成功获取。
- 该函数依赖于 `KBServiceFactory.get_service_by_name``list_files_from_folder``get_file_path` 函数,因此需要确保这些依赖函数能够正常工作。
- 删除文件操作是不可逆的,因此在执行此函数之前应确保已经正确备份了重要数据。
- 函数执行过程中会打印每个被删除文件的信息,可以通过这些信息跟踪删除操作的执行情况。
@@ -0,0 +1,18 @@
## ClassDef DocumentWithVSId
**DocumentWithVSId**: DocumentWithVSId 类的功能是表示一个经过向量化处理的文档。
**属性**:
- `id`: 文档的唯一标识符,类型为字符串。
- `score`: 文档的评分,初始默认值为3.0,类型为浮点数。
**代码描述**:
DocumentWithVSId 类继承自 Document 类,用于表示一个经过向量化处理的文档。这个类主要用于知识库系统中,对文档进行向量化处理后,通过这个类的实例来表示处理结果。类中定义了两个属性:`id``score``id` 属性用于存储文档的唯一标识符,而 `score` 属性则用于存储文档在某些操作(如搜索或排序)中的评分或相关性度量。
在项目中,DocumentWithVSId 类的实例主要用于以下几个场景:
1. 在搜索知识库文档时,返回的搜索结果会包含一系列 DocumentWithVSId 实例,其中每个实例代表一个搜索到的文档,其 `score` 属性表示该文档与搜索查询的匹配程度。
2. 在列出知识库文档时,如果需要根据特定的文件名或元数据进行过滤,返回的结果也可能包含 DocumentWithVSId 实例。
3. 在文档摘要生成过程中,DocumentWithVSId 实例用于表示需要进行摘要处理的文档,其中 `id` 属性用于标识具体的文档。
**注意**:
- 在使用 DocumentWithVSId 类时,需要注意 `id` 属性的唯一性,确保每个实例能够准确地对应到知识库中的一个具体文档。
- `score` 属性的值可能会根据不同的操作或上下文环境有所变化,因此在使用时应注意其含义和计算方式。
@@ -0,0 +1,529 @@
## FunctionDef validate_kb_name(knowledge_base_id)
**validate_kb_name**: 此函数用于验证知识库名称的合法性。
**参数**:
- knowledge_base_id: 字符串类型,表示待验证的知识库名称。
**代码描述**:
`validate_kb_name` 函数接收一个字符串参数 `knowledge_base_id`,该参数代表知识库的名称。函数的主要目的是检查这个名称是否包含潜在的安全风险,具体来说,就是检查名称中是否包含 "../" 这样的子串。如果包含,函数返回 `False`,表示名称不合法或存在安全风险;如果不包含,函数返回 `True`,表示名称合法。这种验证机制主要是为了防止路径遍历攻击,确保系统的安全性。
在项目中,`validate_kb_name` 函数被多个地方调用,包括创建知识库、删除知识库、列出文件、上传文档、删除文档、更新知识库信息、更新文档和下载文档等API接口中。在这些接口中,函数用于在执行核心逻辑之前验证传入的知识库名称的合法性。如果名称不合法,API接口会直接返回错误响应,阻止后续的操作执行,从而增强了系统的安全性。
**注意**:
- 在使用此函数时,需要确保传入的参数是字符串类型。
- 函数的返回值是布尔类型,调用方需要根据返回值判断知识库名称是否合法,并据此执行相应的逻辑。
**输出示例**:
- 如果知识库名称合法,例如 "valid_kb_name",函数将返回 `True`
- 如果知识库名称不合法,例如包含 "../" 的 "invalid/../kb_name",函数将返回 `False`
## FunctionDef get_kb_path(knowledge_base_name)
**get_kb_path**: 此函数的功能是获取指定知识库的文件路径。
**参数**:
- knowledge_base_name: 字符串类型,表示知识库的名称。
**代码描述**:
`get_kb_path` 函数接受一个参数 `knowledge_base_name`,这是一个字符串,代表知识库的名称。函数的主要作用是构造并返回一个路径,这个路径是知识库名称与一个预定义的根路径 `KB_ROOT_PATH` 结合而成的完整文件路径。这里使用了 `os.path.join` 方法来确保路径的正确构造,无论是在不同的操作系统上,都能正确处理路径分隔符。
在项目中,`get_kb_path` 函数被多个地方调用,主要用于获取知识库相关文件的存储路径。例如,在 `KBService` 类的初始化方法中,通过调用 `get_kb_path` 来确定知识库文件的存储位置,并进一步使用这个位置来获取文档路径或向量存储路径。这表明 `get_kb_path` 函数是处理知识库文件路径的基础工具函数,为知识库服务的初始化和其他文件路径的获取提供了支持。
**注意**:
- 确保 `KB_ROOT_PATH` 已经被正确定义并指向了一个有效的文件系统路径,否则 `get_kb_path` 返回的路径可能无效。
- 调用此函数时传入的知识库名称应确保是唯一的,以避免路径冲突。
**输出示例**:
假设 `KB_ROOT_PATH` 被设置为 `/var/knowledge_bases`,且调用 `get_kb_path('my_knowledge_base')`,则函数将返回:
```
/var/knowledge_bases/my_knowledge_base
```
这个返回值表示了名为 `my_knowledge_base` 的知识库在文件系统中的存储路径。
## FunctionDef get_doc_path(knowledge_base_name)
**get_doc_path**: 此函数的功能是获取指定知识库的文档存储路径。
**参数**:
- knowledge_base_name: 字符串类型,表示知识库的名称。
**代码描述**:
`get_doc_path` 函数接受一个参数 `knowledge_base_name`,这是一个字符串,代表知识库的名称。函数通过调用 `get_kb_path` 函数获取知识库的根路径,然后将此根路径与字符串 "content" 结合,构造出知识库文档的存储路径。这里使用了 `os.path.join` 方法来确保路径的正确构造,无论是在不同的操作系统上,都能正确处理路径分隔符。
在项目中,`get_doc_path` 函数主要被用于确定知识库中文档的存储位置。例如,在 `KBService` 类的初始化方法中,通过调用 `get_doc_path` 来获取知识库文档的存储路径,并可能进一步使用这个路径来读取或存储文档数据。此外,`get_file_path``list_files_from_folder` 函数也调用了 `get_doc_path`,用于获取具体文档的路径或列出知识库文档目录下的所有文件,表明 `get_doc_path` 函数是处理知识库文档路径的基础工具函数,为知识库中文档的管理和操作提供了支持。
**注意**:
- 确保在调用此函数之前,`get_kb_path` 函数能够正确返回知识库的根路径,且该路径有效存在于文件系统中。
- 路径中的 "content" 是硬编码的,意味着知识库中存储文档的目录名称需要遵循这一约定。
**输出示例**:
假设 `get_kb_path('my_knowledge_base')` 返回的路径为 `/var/knowledge_bases/my_knowledge_base`,则调用 `get_doc_path('my_knowledge_base')` 将返回:
```
/var/knowledge_bases/my_knowledge_base/content
```
这个返回值表示了名为 `my_knowledge_base` 的知识库中文档存储的具体路径。
## FunctionDef get_vs_path(knowledge_base_name, vector_name)
**get_vs_path**: 此函数的功能是构造并返回知识库中向量存储的完整文件路径。
**参数**:
- knowledge_base_name: 字符串类型,表示知识库的名称。
- vector_name: 字符串类型,表示特定的向量名称。
**代码描述**:
`get_vs_path` 函数接受两个参数:`knowledge_base_name``vector_name`。这两个参数分别代表知识库的名称和向量的名称。函数首先调用 `get_kb_path` 函数,传入知识库名称 `knowledge_base_name` 来获取知识库的基础路径。然后,函数使用 `os.path.join` 方法将基础路径、字符串 "vector_store" 和向量名称 `vector_name` 连接起来,构造出向量存储的完整文件路径。这样做的目的是为了确保无论在哪种操作系统上,路径的构造都是正确的,避免了路径分隔符的问题。
在项目中,`get_vs_path` 函数主要被用于确定向量存储的位置。例如,在 `KBFaissPool` 类的 `load_vector_store` 方法中,通过调用 `get_vs_path` 来获取向量存储的路径,并根据这个路径来加载或创建向量存储。这表明 `get_vs_path` 函数是处理向量存储路径的关键工具函数,为向量存储的加载和创建提供了路径支持。
**注意**:
- 在调用此函数之前,确保 `knowledge_base_name``vector_name` 参数正确无误,因为它们直接影响到向量存储路径的构造。
- 此函数依赖于 `get_kb_path` 函数来获取知识库的基础路径,因此需要确保 `get_kb_path` 函数能够正常工作。
**输出示例**:
假设知识库名称为 `my_knowledge_base`,向量名称为 `my_vector``get_kb_path` 返回的路径为 `/var/knowledge_bases/my_knowledge_base`,则 `get_vs_path` 函数将返回:
```
/var/knowledge_bases/my_knowledge_base/vector_store/my_vector
```
这个返回值表示了名为 `my_vector` 的向量存储在文件系统中的完整路径。
## FunctionDef get_file_path(knowledge_base_name, doc_name)
**get_file_path**: 此函数的功能是构造并返回知识库中特定文档的完整文件路径。
**参数**:
- knowledge_base_name: 字符串类型,表示知识库的名称。
- doc_name: 字符串类型,表示文档的名称。
**代码描述**:
`get_file_path` 函数接受两个参数:`knowledge_base_name``doc_name`。这两个参数分别代表知识库的名称和文档的名称。函数首先调用 `get_doc_path` 函数,传入知识库名称以获取该知识库文档存储的根路径。然后,使用 `os.path.join` 方法将此根路径与文档名称 `doc_name` 结合,构造出完整的文件路径。这种方法确保了在不同操作系统上,路径分隔符能够被正确处理,从而生成有效的文件路径。
在项目中,`get_file_path` 函数被多个模块调用,用于获取知识库中特定文档的存储路径。例如,在文件上传、文档删除、文档检索等场景中,都需要先通过此函数获取文档的完整路径,然后进行后续的文件操作。这表明 `get_file_path` 函数是处理知识库中文档路径的关键工具函数,为知识库中文档的管理和操作提供了基础支持。
**注意**:
- 在调用 `get_file_path` 函数之前,需要确保 `get_doc_path` 函数能够正确返回知识库文档的根路径,并且该路径在文件系统中有效存在。
- 传入的文档名称 `doc_name` 应当是合法的文件名,避免包含可能导致路径构造失败的非法字符。
**输出示例**:
假设 `get_doc_path('my_knowledge_base')` 返回的路径为 `/var/knowledge_bases/my_knowledge_base/content`,且文档名称为 `example.docx`,则调用 `get_file_path('my_knowledge_base', 'example.docx')` 将返回:
```
/var/knowledge_bases/my_knowledge_base/content/example.docx
```
这个返回值表示了名为 `my_knowledge_base` 的知识库中名为 `example.docx` 文档的完整存储路径。
## FunctionDef list_kbs_from_folder
**list_kbs_from_folder**: 此函数的功能是列出知识库根路径下的所有目录。
**参数**: 此函数没有参数。
**代码描述**: `list_kbs_from_folder` 函数通过访问全局变量 `KB_ROOT_PATH`,使用 `os.listdir` 方法获取该路径下的所有文件和目录。然后,它通过列表推导式结合 `os.path.isdir` 方法筛选出所有的目录(即子文件夹),并将这些目录名称作为列表返回。这个函数在项目中主要被用于获取当前知识库根路径下存在的所有知识库目录名称,这对于知识库的管理和操作至关重要。
在项目中,`list_kbs_from_folder` 函数被多个地方调用:
-`get_kb_details` 函数中,它用于获取文件夹中的知识库列表,进而获取每个知识库的详细信息,包括它们是否存在于数据库中。
-`folder2db` 函数中,它用于获取所有需要迁移至数据库的知识库目录名称。根据迁移模式,这些知识库目录中的文件可能会被重新创建向量存储、更新数据库信息或仅对新增文件进行处理。
这些调用情况表明,`list_kbs_from_folder` 函数是知识库管理和迁移工作流中不可或缺的一部分,它提供了一个基础的目录检索功能,使得其他功能模块能够基于当前存在的知识库目录进行进一步的操作。
**注意**: 使用此函数时,需要确保 `KB_ROOT_PATH` 已被正确设置且指向一个有效的知识库根目录。此外,该函数仅返回目录名称,不包括任何文件或子目录的信息。
**输出示例**: 假设知识库根路径下存在两个目录 `kb1``kb2`,则函数的返回值可能如下:
```python
['kb1', 'kb2']
```
## FunctionDef list_files_from_folder(kb_name)
**list_files_from_folder**: 此函数的功能是列出指定知识库文件夹中的所有文件。
**参数**:
- kb_name: 字符串类型,表示知识库的名称。
**代码描述**:
`list_files_from_folder` 函数接受一个参数 `kb_name`,这是一个字符串,代表知识库的名称。函数首先通过调用 `get_doc_path` 函数获取知识库文档的存储路径。然后,它定义了两个内部函数 `is_skiped_path``process_entry` 用于过滤和处理文件夹中的条目。
- `is_skiped_path` 函数用于判断给定的路径是否应该被跳过,例如临时文件或隐藏文件。
- `process_entry` 函数递归地处理每一个文件夹条目,如果是符号链接,则解析目标路径并处理;如果是文件,则将其相对路径添加到结果列表中;如果是目录,则递归处理目录下的每一个条目。
最终,函数返回一个包含所有有效文件相对路径的列表,这些路径都是以 POSIX 格式表示的。
**注意**:
- 确保在调用此函数之前,`get_doc_path` 函数能够正确返回知识库文档的存储路径。
- 此函数会自动过滤掉临时文件、隐藏文件等不需要处理的文件。
- 返回的文件路径列表是基于知识库文档存储路径的相对路径,并且以 POSIX 格式表示。
**输出示例**:
假设知识库名为 "my_knowledge_base",且其文档存储路径下有三个文件 "doc1.txt", "doc2.txt", "tempfile.tmp",则调用 `list_files_from_folder('my_knowledge_base')` 将返回:
```
["doc1.txt", "doc2.txt"]
```
这个返回值表示了名为 "my_knowledge_base" 的知识库中有效文档文件的相对路径列表,注意 "tempfile.tmp" 被自动过滤掉了。
### FunctionDef is_skiped_path(path)
**is_skiped_path**: 此函数的功能是判断给定的路径是否应被跳过。
**参数**:
- path: 字符串类型,表示需要判断的文件或目录路径。
**代码描述**:
`is_skiped_path` 函数接收一个路径字符串作为参数,其目的是判断该路径是否指向一个应被忽略的文件或目录。函数首先使用 `os.path.basename` 方法获取路径的最后一部分(即文件名或目录名),并将其转换为小写,以便进行不区分大小写的比较。然后,函数遍历一个包含特定前缀的列表(如 "temp", "tmp", ".", "~$"),这些前缀被认为是应当被忽略的文件或目录的标志。如果路径的最后一部分以列表中的任何一个前缀开始,函数将返回 `True`,表示该路径应被跳过。如果遍历完列表后没有找到匹配的前缀,函数将返回 `False`,表示该路径不应被跳过。
在项目中,`is_skiped_path` 函数被 `process_entry` 函数调用,用于在处理文件系统条目(如文件或目录)时判断是否应忽略某些路径。这样做可以避免处理临时文件、隐藏文件或其他不需要处理的文件,从而提高处理效率和准确性。
**注意**:
- 在使用此函数时,需要确保传入的路径是字符串类型,并且是有效的文件系统路径。
- 函数的判断依据是路径的最后一部分(文件名或目录名)的前缀,因此在特定情况下可能需要根据实际需求调整忽略的前缀列表。
**输出示例**:
- 如果传入的路径为 "/path/to/tempfile.txt",函数将返回 `True`
- 如果传入的路径为 "/path/to/document.docx",函数将返回 `False`
***
### FunctionDef process_entry(entry)
**process_entry**: 此函数的功能是递归处理文件系统中的每一个条目,包括文件、目录和符号链接。
**参数**:
- entry: 一个代表文件系统条目的对象,该对象具有 `path` 属性以及 `is_symlink()`, `is_file()`, `is_dir()` 等方法,用于判断条目的类型。
**代码描述**:
`process_entry` 函数首先判断给定条目的路径是否应被跳过。这一判断通过调用 `is_skiped_path` 函数实现,如果该函数返回 `True`,则当前条目将被忽略,不进行进一步处理。这主要用于过滤掉临时文件、隐藏文件等不需要处理的文件或目录。
如果条目是一个符号链接(symlink),函数将解析该链接指向的实际路径,并对该路径下的所有条目递归调用 `process_entry` 函数。这确保了符号链接指向的目录或文件被正确处理。
如果条目是一个文件,函数将计算该文件的相对路径(相对于文档根目录 `doc_path`),并将其转换为 POSIX 格式的路径字符串。然后,这个路径字符串被添加到全局的 `result` 列表中,用于后续处理或输出。
如果条目是一个目录,函数将遍历该目录下的所有条目,并对每个条目递归调用 `process_entry` 函数。这样可以确保目录下的所有文件和子目录都被递归处理。
**注意**:
- 在使用此函数之前,需要确保 `doc_path``result` 已经被正确初始化。`doc_path` 应为一个字符串,表示文档的根目录路径;`result` 应为一个列表,用于收集处理结果。
- 该函数递归处理文件系统条目,因此对于具有大量文件和目录的文件系统,需要注意递归深度和性能问题。
- 函数依赖于 `os.scandir` 来遍历目录,这是一个高效的目录遍历方法,但需要确保运行环境支持。
**输出示例**:
由于 `process_entry` 函数主要作用是修改全局的 `result` 列表,而不是直接返回值,因此没有直接的返回值示例。但在函数执行后,`result` 列表将包含所有不被忽略的文件的相对路径(POSIX 格式),例如:
```python
['path/to/file1.txt', 'another/path/to/file2.jpg']
```
这个列表随后可以用于进一步的处理或输出。
***
## FunctionDef _new_json_dumps(obj)
**_new_json_dumps**: 该函数的功能是对对象进行JSON格式化,同时确保结果中的ASCII字符不会被转义。
**参数**:
- obj: 需要进行JSON格式化的对象。
- **kwargs: 接受可变数量的关键字参数,这些参数将直接传递给底层的JSON序列化函数。
**代码描述**:
`_new_json_dumps`函数是一个封装了JSON序列化过程的辅助函数。它接受一个Python对象`obj`和任意数量的关键字参数`**kwargs`。函数的主要作用是在调用原始的JSON序列化函数(假设为`_origin_json_dumps`)之前,强制设置`ensure_ascii`参数为`False`。这样做的目的是确保在序列化过程中,所有非ASCII字符(如中文字符)不会被转义成`\uXXXX`形式的ASCII字符串,而是保持原样输出。这对于需要保持数据可读性的场景特别有用。
**注意**:
- `_origin_json_dumps`应该是一个已经存在的JSON序列化函数,该函数能够接受`ensure_ascii`以及其他任何`json.dumps`支持的参数。
- 由于`ensure_ascii`被强制设置为`False`,在处理包含非ASCII字符的数据时,输出的JSON字符串将包含这些原生字符。使用者需要确保处理结果的环境支持这些字符。
- 该函数通过`**kwargs`接受额外的参数,这意味着用户可以传递任何`json.dumps`支持的参数来定制序列化行为,除了`ensure_ascii`,因为它已被预设。
**输出示例**:
假设有一个包含中文字符的对象`obj = {"name": "张三"}`,调用`_new_json_dumps(obj)`将返回一个字符串:`'{"name": "张三"}'`。注意,中文字符“张三”没有被转义,直接以原生形式出现在了结果字符串中。
## ClassDef JSONLinesLoader
**JSONLinesLoader**: JSONLinesLoader的功能是加载行式JSON文件,这些文件的扩展名为.jsonl。
**属性**:
- `_json_lines`: 一个布尔值,指示该加载器是否处理行式JSON数据。
**代码描述**:
JSONLinesLoader类是`langchain.document_loaders.JSONLoader`的子类,专门用于处理行式JSON(.jsonl)文件。行式JSON文件是一种特殊的JSON文件,其中每一行都是一个独立的JSON对象。这种格式特别适用于处理大量数据,因为它允许逐行读取,而不需要一次性加载整个文件到内存中。
构造函数`__init__`接受任意数量的位置参数和关键字参数,这些参数将被传递给父类`JSONLoader`的构造函数。在调用父类构造函数初始化基类属性之后,`JSONLinesLoader`类设置了一个内部属性`_json_lines``True`。这个属性的设置可能是用来标识该加载器实例为行式JSON数据的处理者,或者用于在内部逻辑中区分行式JSON和其他类型的JSON数据处理。
**注意**:
- 使用JSONLinesLoader时,需要确保传入的文件符合行式JSON格式,即文件的每一行都是一个完整的JSON对象。
- 由于JSONLinesLoader继承自`JSONLoader`,因此它也继承了父类的所有方法和属性。这意味着除了专门处理行式JSON数据的能力外,它还可以使用父类提供的任何功能,如加载和解析JSON数据。
- 在实际应用中,使用JSONLinesLoader可以有效地处理大型的行式JSON文件,因为它不需要一次性将整个文件加载到内存中,从而减少了内存消耗。
### FunctionDef __init__(self)
**__init__**: 该函数用于初始化JSONLinesLoader类的实例。
**参数**:
- *args: 可变位置参数,用于传递给父类的初始化方法。
- **kwargs: 可变关键字参数,用于传递给父类的初始化方法。
**代码描述**:
`__init__`方法是JSONLinesLoader类的构造函数,负责初始化类的实例。在这个方法中,首先通过`super().__init__(*args, **kwargs)`调用父类的构造函数,确保父类被正确初始化。这是面向对象编程中常见的做法,特别是在继承体系中,确保父类的初始化逻辑得到执行。
接下来,该方法设置了一个实例变量`_json_lines`,并将其值设为`True`。这个变量的存在表明,JSONLinesLoader类的实例将以处理JSON Lines格式的数据为主要功能。JSON Lines是一种便于处理大量结构化数据的格式,每一行都是一个独立的JSON对象,这种格式特别适合于数据流或数据湖场景。
**注意**:
- 在使用JSONLinesLoader类时,应当意识到它默认处理的是JSON Lines格式的数据。如果你的数据不是这种格式,可能需要进行相应的转换。
- 由于`__init__`方法中使用了`*args``**kwargs`,这意味着在实例化JSONLinesLoader类时,可以传递额外的参数给父类的构造函数。这提供了灵活性,但同时也要求开发者对父类的构造函数有一定的了解,以确保正确使用。
***
## FunctionDef get_LoaderClass(file_extension)
**get_LoaderClass**: 此函数的功能是根据文件扩展名返回相应的加载器类。
**参数**:
- **file_extension**: 文件扩展名,用于确定需要使用哪个加载器类。
**代码描述**:
`get_LoaderClass` 函数遍历一个名为 `LOADER_DICT` 的字典,该字典将加载器类映射到它们支持的文件扩展名列表。函数接收一个参数 `file_extension`,这是一个字符串,表示文件的扩展名。函数通过检查 `file_extension` 是否存在于 `LOADER_DICT` 字典的任一值(即支持的文件扩展名列表)中,来确定哪个加载器类支持该文件扩展名。如果找到匹配的文件扩展名,函数将返回相应的加载器类。
在项目中,`get_LoaderClass` 函数被 `KnowledgeFile` 类的构造函数调用,用于根据文件的扩展名确定如何加载文件内容。这是在处理知识库文件时的一个关键步骤,确保了文件能够被正确解析和处理,无论它们的格式如何。通过这种方式,系统能够灵活地支持多种文件格式,只要为这些格式提供了相应的加载器类。
**注意**:
- 确保 `LOADER_DICT` 字典在使用 `get_LoaderClass` 函数之前已经被正确定义和填充,且包含了所有支持的文件扩展名及其对应的加载器类。
- 如果传入的文件扩展名不在 `LOADER_DICT` 的任何值中,函数将返回 `None`。因此,调用此函数的代码需要能够处理这种情况,可能通过抛出异常或提供默认行为。
**输出示例**:
假设 `LOADER_DICT` 如下定义:
```python
LOADER_DICT = {
TextLoader: ['.txt', '.md'],
PDFLoader: ['.pdf']
}
```
如果调用 `get_LoaderClass('.pdf')`,则函数将返回 `PDFLoader` 类。
## FunctionDef get_loader(loader_name, file_path, loader_kwargs)
**get_loader**: 根据指定的加载器名称和文件路径或内容返回相应的文档加载器实例。
**参数**:
- **loader_name**: 字符串,指定要使用的加载器的名称。
- **file_path**: 字符串,指定要加载的文件的路径。
- **loader_kwargs**: 字典,可选参数,用于传递给加载器的额外参数。
**代码描述**:
`get_loader` 函数的主要功能是根据提供的加载器名称(`loader_name`)和文件路径(`file_path`),动态地导入并实例化相应的文档加载器。这个过程中,函数首先会根据加载器名称判断应该从哪个模块导入加载器类。如果加载器名称是`RapidOCRPDFLoader``RapidOCRLoader``FilteredCSVLoader``RapidOCRDocLoader``RapidOCRPPTLoader`中的任何一个,那么加载器将从`document_loaders`模块导入。否则,将从`langchain.document_loaders`模块导入。
在尝试导入加载器类时,如果遇到任何异常,将会记录错误信息,并改为导入默认的`UnstructuredFileLoader`加载器。
此外,函数还会根据不同的加载器名称对`loader_kwargs`参数进行特定的处理。例如,如果使用的是`UnstructuredFileLoader`,则会设置`autodetect_encoding``True`。如果是`CSVLoader`,则会尝试自动检测文件的编码类型,并设置相应的`encoding`参数。对于`JSONLoader``JSONLinesLoader`,则会设置默认的`jq_schema``text_content`参数。
最后,函数使用导入的加载器类和处理后的参数创建加载器实例,并返回该实例。
在项目中,`get_loader`函数被`file2docs`方法调用,用于根据文件路径和加载器名称动态加载文件内容,进而转换为文档对象。这种设计使得加载不同类型文件的过程更加灵活和可配置。
**注意**:
- 在使用`get_loader`函数时,需要确保传入的`loader_name`对应的加载器类已经正确实现,并且可以从指定的模块中导入。
- 对于`loader_kwargs`参数,应根据实际使用的加载器的需求,传入正确的参数值。
**输出示例**:
假设存在一个名为`RapidOCRLoader`的加载器类,调用`get_loader("RapidOCRLoader", "/path/to/file")`可能会返回一个`RapidOCRLoader`的实例,该实例已经被初始化,准备用于加载指定路径的文件。
## FunctionDef make_text_splitter(splitter_name, chunk_size, chunk_overlap, llm_model)
**make_text_splitter**: 此函数的功能是根据给定参数创建并返回一个特定的文本分词器实例。
**参数**:
- `splitter_name`: 字符串类型,默认为`TEXT_SPLITTER_NAME`。指定要创建的分词器名称。
- `chunk_size`: 整型,默认为`CHUNK_SIZE`。指定分词时每个文本块的大小。
- `chunk_overlap`: 整型,默认为`OVERLAP_SIZE`。指定分词时文本块之间的重叠大小。
- `llm_model`: 字符串类型,默认为`LLM_MODELS[0]`。指定使用的大型语言模型。
**代码描述**:
此函数首先根据`splitter_name`参数确定需要创建的文本分词器类型。如果未指定`splitter_name`,则默认使用`SpacyTextSplitter`。函数尝试根据分词器名称从用户自定义模块或`langchain.text_splitter`模块中导入相应的分词器类。对于特定的分词器,如`MarkdownHeaderTextSplitter`,会根据配置字典`text_splitter_dict`中的设置进行初始化。
根据分词器的来源(如`tiktoken``huggingface`),函数会采用不同的方式来创建分词器实例。例如,从`huggingface`加载时,会根据配置中的`tokenizer_name_or_path`来加载对应的分词器,并根据`chunk_size``chunk_overlap`参数进行初始化。如果在创建过程中遇到任何异常,函数会回退到使用`RecursiveCharacterTextSplitter`作为默认分词器。
此外,函数中包含了一些注释,指出如何使用GPU加速`SpacyTextSplitter`的分词过程,这对处理大规模文本数据特别有用。
**注意**:
- 确保在调用此函数之前,已经正确设置了`TEXT_SPLITTER_NAME``CHUNK_SIZE``OVERLAP_SIZE`等全局变量,以及`LLM_MODELS`列表。
- 如果需要从`tiktoken``huggingface`加载分词器,请确保相关的分词器名称或路径已经正确配置在`text_splitter_dict`字典中。
- 此函数依赖于`importlib`动态导入模块和类,因此需要确保目标分词器的模块已经安装在环境中。
**输出示例**:
调用`make_text_splitter(splitter_name="SpacyTextSplitter", chunk_size=100, chunk_overlap=20)`可能会返回一个`SpacyTextSplitter`的实例,该实例配置了每个文本块大小为100,文本块之间的重叠大小为20。
## ClassDef KnowledgeFile
**KnowledgeFile**: KnowledgeFile类用于表示和处理知识库中的文件。
**属性**:
- `kb_name`: 知识库的名称。
- `filename`: 文件的名称。
- `ext`: 文件的扩展名。
- `loader_kwargs`: 加载文件时使用的参数字典。
- `filepath`: 文件在磁盘上的完整路径。
- `docs`: 文件内容转换成的文档列表。
- `splited_docs`: 经过分割处理后的文档列表。
- `document_loader_name`: 用于加载文件内容的加载器类名。
- `text_splitter_name`: 用于分割文档文本的分割器名称。
**代码描述**:
KnowledgeFile类主要负责处理知识库中的文件,包括文件的加载、文档的提取和文本的分割等功能。它首先检查文件格式是否受支持,然后根据文件扩展名确定使用哪个文档加载器和文本分割器。通过`file2docs`方法,可以将文件内容加载为文档列表;通过`docs2texts`方法,可以将文档列表进一步处理成文本列表,支持中文标题加强和文本分块等功能;`file2text`方法则结合了加载和处理两个步骤,直接从文件生成处理后的文本列表。此外,该类还提供了检查文件存在性、获取文件修改时间和大小的方法。
在项目中,KnowledgeFile类被多个模块调用,用于处理上传的文件、更新知识库文档、删除知识库文档等场景。例如,在文件上传处理中,会创建KnowledgeFile实例来加载和处理上传的文件,然后将处理结果存储到知识库中;在知识库文档更新和删除操作中,也会通过KnowledgeFile实例来操作具体的文件。
**注意**:
- 在使用KnowledgeFile类时,需要确保传入的文件名和知识库名称正确,且文件必须存在于磁盘上。
- 文件处理过程中,如果文件格式不受支持或者文档加载器、文本分割器出现问题,可能会抛出异常。
- 在处理大量文件或大型文件时,应注意性能和内存使用情况。
**输出示例**:
```python
# 假设有一个Markdown文件"example.md",以下是创建KnowledgeFile实例并加载文档的示例代码
kb_file = KnowledgeFile(filename="example.md", knowledge_base_name="demo_kb")
docs = kb_file.file2docs()
print(docs) # 输出处理后的文档列表
```
### FunctionDef __init__(self, filename, knowledge_base_name, loader_kwargs)
**__init__**: 此函数的功能是初始化KnowledgeFile对象,用于处理知识库中的文件。
**参数**:
- **filename**: 字符串类型,指定了文件的名称。
- **knowledge_base_name**: 字符串类型,指定了知识库的名称。
- **loader_kwargs**: 字典类型,默认为空字典,用于传递给文件加载器的额外参数。
**代码描述**:
`__init__` 函数是 `KnowledgeFile` 类的构造函数,负责初始化处理知识库中文件的实例。首先,它将知识库名称存储在实例变量 `kb_name` 中。然后,使用 `Path` 类将文件名转换为POSIX风格的路径字符串,并存储在实例变量 `filename` 中。接着,通过 `os.path.splitext` 方法提取文件的扩展名,并转换为小写存储在实例变量 `ext` 中。如果文件扩展名不在支持的扩展名列表 `SUPPORTED_EXTS` 中,则抛出 `ValueError` 异常,提示文件格式不被支持。
此外,`__init__` 函数还负责根据知识库名称和文件名,通过调用 `get_file_path` 函数获取文件的完整路径,并存储在实例变量 `filepath` 中。这一步骤是文件处理的基础,确保了后续操作能够针对正确的文件路径进行。
函数还初始化了几个用于后续文档处理的实例变量,如 `docs``splited_docs`,它们分别用于存储加载的文档内容和分割后的文档内容,初始值均为 `None`
最后,`__init__` 函数根据文件扩展名,通过调用 `get_LoaderClass` 函数确定适合该文件格式的加载器类,并将其名称存储在实例变量 `document_loader_name` 中。同时,将文本分割器的名称存储在实例变量 `text_splitter_name` 中,为后续的文档加载和处理提供必要的信息。
**注意**:
- 在使用 `__init__` 函数初始化 `KnowledgeFile` 对象之前,确保传入的文件名和知识库名称是有效的,且文件必须存在于磁盘上。
- 文件的扩展名必须包含在 `SUPPORTED_EXTS` 列表中,否则会抛出异常。
- `loader_kwargs` 参数提供了一种灵活的方式,允许在加载文件时传递额外的参数给加载器类,但默认为空字典。在需要特殊处理文件加载行为时,可以通过此参数传递必要的信息。
***
### FunctionDef file2docs(self, refresh)
**file2docs**: 该函数用于加载并返回文件内容的文档对象。
**参数**:
- **refresh**: 布尔值,默认为False。如果设置为True,则强制重新加载文档。
**代码描述**:
`file2docs`方法主要负责根据文件路径加载文件内容,并将其转换为文档对象。当对象的`docs`属性为None或者`refresh`参数为True时,该方法会通过调用`get_loader`函数动态地获取一个文档加载器实例。加载器的选择依赖于对象的`document_loader_name`属性和`loader_kwargs`属性,这些属性分别指定了加载器的名称和传递给加载器的额外参数。加载器实例化后,会调用其`load`方法加载文件内容,并将加载的结果赋值给对象的`docs`属性。如果`docs`属性已经有值且`refresh`参数为False,则直接返回`docs`属性的值,不会重新加载文档。
在整个过程中,会有日志记录当前使用的加载器名称和文件路径,以便于跟踪和调试。
**注意**:
- 使用`file2docs`方法时,需要确保对象的`document_loader_name`属性已正确设置,且对应的加载器类能够被成功导入和实例化。
- `loader_kwargs`属性应根据实际使用的加载器的需求,提前正确设置。
- 如果需要重新加载文档,可以将`refresh`参数设置为True。
**输出示例**:
调用`file2docs(refresh=True)`可能会返回一个文档对象列表,这取决于文件内容和指定的加载器。例如,如果文件是一个PDF文档,且使用了`RapidOCRPDFLoader`加载器,那么返回的可能是包含PDF中每一页内容的文档对象列表。
***
### FunctionDef docs2texts(self, docs, zh_title_enhance, refresh, chunk_size, chunk_overlap, text_splitter)
**docs2texts**: 此函数的功能是将文档对象列表转换为文本列表,可选地增强中文标题,并支持文本的分块处理。
**参数**:
- `docs`: 文档对象列表,默认为None。如果未提供,则会调用`file2docs`方法获取文档对象列表。
- `zh_title_enhance`: 布尔值,指示是否增强中文标题,默认值取决于全局变量`ZH_TITLE_ENHANCE`
- `refresh`: 布尔值,指示是否强制刷新文档对象列表,默认为False。
- `chunk_size`: 整型,指定分块大小,默认值取决于全局变量`CHUNK_SIZE`
- `chunk_overlap`: 整型,指定分块之间的重叠大小,默认值取决于全局变量`OVERLAP_SIZE`
- `text_splitter`: 文本分割器实例,默认为None。如果未提供,则会根据`self.text_splitter_name`创建一个新的文本分割器实例。
**代码描述**:
此函数首先检查是否提供了`docs`参数,如果没有,则调用`file2docs`方法获取文档对象列表。接着,检查文档列表是否为空,如果为空,则直接返回空列表。对于非CSV文件类型,根据是否提供了`text_splitter`参数,使用`make_text_splitter`函数创建或使用提供的文本分割器实例进行文本分割。如果文本分割器名称为`MarkdownHeaderTextSplitter`,则仅分割第一个文档的页面内容;否则,对整个文档列表进行分割。分割后,如果启用了中文标题增强(`zh_title_enhance`为True),则对分割后的文档进行标题增强处理。最后,将分割(和可能增强)后的文档列表赋值给`self.splited_docs`属性,并返回该属性。
**注意**:
- 在调用此函数之前,确保相关的全局变量(如`ZH_TITLE_ENHANCE``CHUNK_SIZE``OVERLAP_SIZE`)已正确设置。
- 如果需要处理大量文档或大型文档,考虑合理设置`chunk_size``chunk_overlap`参数以优化性能和结果质量。
- 此函数支持通过`text_splitter`参数自定义文本分割器,使其能够灵活适应不同的文本处理需求。
**输出示例**:
调用`docs2texts(docs=my_docs, zh_title_enhance=True, refresh=True, chunk_size=200, chunk_overlap=50)`可能会返回一个文本列表,其中每个文本块的大小为200个字符,相邻文本块之间有50个字符的重叠,并且对于包含中文标题的文档,其标题已被增强处理。
***
### FunctionDef file2text(self, zh_title_enhance, refresh, chunk_size, chunk_overlap, text_splitter)
**file2text**: 此函数用于将文件内容转换为文本列表,支持中文标题增强、文档刷新、分块处理以及自定义文本分割器。
**参数**:
- `zh_title_enhance`: 布尔值,指示是否增强中文标题,默认值取决于全局变量`ZH_TITLE_ENHANCE`
- `refresh`: 布尔值,指示是否强制刷新文档对象列表,默认为False。
- `chunk_size`: 整型,指定分块大小,默认值取决于全局变量`CHUNK_SIZE`
- `chunk_overlap`: 整型,指定分块之间的重叠大小,默认值取决于全局变量`OVERLAP_SIZE`
- `text_splitter`: 文本分割器实例,默认为None。如果未提供,则会根据`self.text_splitter_name`创建一个新的文本分割器实例。
**代码描述**:
`file2text`函数首先检查对象的`splited_docs`属性是否为None或者是否需要刷新(`refresh`参数为True)。如果是,则调用`file2docs`方法加载文件内容并转换为文档对象列表。接着,调用`docs2texts`方法将文档对象列表转换为文本列表,同时可以选择是否增强中文标题、是否刷新文档对象列表、分块大小、分块之间的重叠大小以及是否使用自定义的文本分割器。最后,将转换得到的文本列表赋值给`splited_docs`属性,并返回该属性。
**注意**:
- 在调用`file2text`函数之前,确保相关的全局变量(如`ZH_TITLE_ENHANCE``CHUNK_SIZE``OVERLAP_SIZE`)已正确设置。
- 如果需要处理大量文档或大型文档,考虑合理设置`chunk_size``chunk_overlap`参数以优化性能和结果质量。
- 通过`text_splitter`参数可以自定义文本分割器,使其能够灵活适应不同的文本处理需求。
-`refresh`参数设置为True时,将强制重新加载文档并进行文本转换处理,这可能会增加处理时间。
**输出示例**:
调用`file2text(zh_title_enhance=True, refresh=True, chunk_size=200, chunk_overlap=50)`可能会返回一个文本列表,其中每个文本块的大小为200个字符,相邻文本块之间有50个字符的重叠,并且对于包含中文标题的文档,其标题已被增强处理。这个列表可以直接用于后续的文本分析或处理任务。
***
### FunctionDef file_exist(self)
**file_exist**: 此函数用于检查文件是否存在。
**参数**: 此函数不接受任何外部参数,但依赖于对象内的`filepath`属性。
**代码描述**: `file_exist`函数是`KnowledgeFile`类的一个方法,用于检查指定路径的文件是否存在。它通过调用`os.path.isfile`方法实现,该方法接受一个路径作为参数,并返回一个布尔值,指示该路径是否指向一个存在的文件。在这里,`self.filepath``KnowledgeFile`对象中存储文件路径的属性。如果文件存在于该路径,则函数返回`True`;如果文件不存在,则返回`False`
**注意**: 使用此函数前,请确保`KnowledgeFile`对象已正确初始化,并且`filepath`属性已经被赋予了一个有效的文件路径。此外,此函数的返回值依赖于操作系统对文件系统的访问权限,如果没有足够的权限访问指定的文件路径,可能会影响结果的准确性。
**输出示例**: 假设`self.filepath`指向的文件存在,那么`file_exist()`将返回`True`。反之,如果文件不存在,将返回`False`
***
### FunctionDef get_mtime(self)
**get_mtime**: 此函数的功能是获取文件的最后修改时间。
**参数**: 此函数没有参数。
**代码描述**: `get_mtime`函数是`KnowledgeFile`类的一个方法,用于获取与`KnowledgeFile`实例关联的文件的最后修改时间。它通过调用`os.path.getmtime`方法实现,该方法接受一个路径作为参数,并返回该路径所指文件的最后修改时间(以秒为单位,自1970年1月1日以来的时间)。在这个场景中,`self.filepath`代表了`KnowledgeFile`实例所关联的文件路径。此函数在项目中的主要作用是在更新或添加知识库文件到数据库时,获取文件的最新修改时间,以便进行相应的数据更新或记录。
`server/db/repository/knowledge_file_repository.py/add_file_to_db`方法中,`get_mtime`被用来获取一个知识库文件的最后修改时间。这个时间随后被用来更新数据库中对应文件的`file_mtime`字段,如果文件已存在,则更新该文件的信息和版本号;如果文件不存在,则添加新文件时记录该时间。这样确保了数据库中文件的修改时间是最新的,有助于跟踪文件的更新历史。
**注意**: 使用`get_mtime`函数时,需要确保`self.filepath`是有效的且指向的文件存在,否则`os.path.getmtime`将抛出`FileNotFoundError`异常。
**输出示例**: 假设某文件最后修改时间为2023年4月1日12时0分0秒,调用`get_mtime`函数将返回`1679856000.0`(这是一个示例值,实际值取决于文件的确切修改时间)。
***
### FunctionDef get_size(self)
**get_size**: 此函数的功能是获取文件的大小。
**参数**: 此函数没有参数。
**代码描述**: `get_size` 函数是 `KnowledgeFile` 类的一个方法,用于返回与该实例关联的文件的大小。它通过调用 `os.path.getsize` 方法实现,该方法接受一个文件路径作为参数,并返回该文件的大小(以字节为单位)。在这个场景中,`self.filepath` 表示的是 `KnowledgeFile` 实例所关联的文件路径。此功能在文件管理和处理中非常重要,尤其是在需要根据文件大小做出决策或进行优化的场景下。
在项目中,`get_size` 方法被 `add_file_to_db` 函数调用,用于获取待添加到数据库的知识文件的大小。这个大小信息随后被用于更新或创建数据库中的文件记录。具体来说,如果文件已存在于数据库中,则更新该文件的大小信息;如果文件不存在,则在创建新文件记录时包含文件大小信息。这样做可以确保数据库中的文件信息是最新的,同时也支持文件管理和版本控制的需求。
**注意**: 使用 `get_size` 方法时,需要确保 `self.filepath` 是有效的文件路径,且文件确实存在,否则 `os.path.getsize` 方法会抛出异常。
**输出示例**: 假设 `self.filepath` 指向的文件大小为 1024 字节,那么 `get_size` 方法的返回值将会是 `1024`
***
## FunctionDef files2docs_in_thread(files, chunk_size, chunk_overlap, zh_title_enhance)
**files2docs_in_thread**: 该函数的功能是利用多线程批量将磁盘文件转化成langchain Document。
**参数**:
- `files`: 文件列表,可以是`KnowledgeFile`实例、包含文件名和知识库名的元组,或者是包含文件信息的字典。
- `chunk_size`: 文档分块的大小,默认值为`CHUNK_SIZE`
- `chunk_overlap`: 文档分块之间的重叠大小,默认值为`OVERLAP_SIZE`
- `zh_title_enhance`: 是否开启中文标题加强,默认值为`ZH_TITLE_ENHANCE`
**代码描述**:
`files2docs_in_thread`函数主要通过多线程的方式,将文件转化为文档对象。函数首先会遍历`files`参数中的每个文件,根据文件的类型(`KnowledgeFile`实例、元组或字典),提取或设置文件的相关信息,并构造`KnowledgeFile`实例。接着,为每个文件设置转化为文档所需的参数,包括文件本身、分块大小、分块重叠大小和中文标题加强选项,并将这些参数存储在`kwargs_list`列表中。
之后,函数调用`run_in_thread_pool`函数,将`file2docs`函数和`kwargs_list`作为参数传入,以多线程的方式执行文件到文档的转化过程。`run_in_thread_pool`函数会返回一个生成器,该生成器按顺序产生每个文件转化结果的状态和结果(包括知识库名、文件名和文档列表或错误信息)。
在转化过程中,如果遇到任何异常,函数会捕获这些异常并记录错误信息,同时生成器会产生包含错误信息的结果。
**注意**:
- 传入的文件列表中的文件必须存在于磁盘上,否则在创建`KnowledgeFile`实例时会抛出异常。
- `run_in_thread_pool`函数的使用需要确保线程安全,因此在`file2docs`函数中进行的操作应避免线程安全问题。
- 由于函数返回值是一个生成器,调用此函数时需要通过迭代来获取所有文件的转化结果。
**输出示例**:
```python
# 假设files参数包含了多个文件信息
results = files2docs_in_thread(files=[("example.txt", "sample_kb"), {"filename": "demo.txt", "kb_name": "demo_kb"}])
for status, result in results:
if status:
print(f"成功处理文件: {result[1]},文档数量: {len(result[2])}")
else:
print(f"处理文件失败: {result[1]},错误信息: {result[2]}")
```
在这个示例中,`files2docs_in_thread`函数被用于处理两个文件,一个通过元组指定,另一个通过字典指定。函数返回的生成器被迭代,以打印每个文件处理的结果。成功处理的文件会打印文件名和文档数量,处理失败的文件会打印文件名和错误信息。
### FunctionDef file2docs
**file2docs**: 此函数的功能是将文件转换为文档列表。
**参数**:
- `file`: KnowledgeFile类型的对象,表示需要转换为文档的文件。
- `**kwargs`: 可变关键字参数,用于传递给`file.file2text`方法的额外参数。
**代码描述**:
`file2docs`函数接收一个`KnowledgeFile`对象作为参数,并尝试调用该对象的`file2text`方法来将文件内容转换为文本列表。这个过程中,`file2text`方法支持通过`**kwargs`传递额外的参数,以便在转换过程中进行定制化处理,例如中文标题增强、文档刷新、分块处理以及自定义文本分割器等。
如果转换成功,函数将返回一个元组,其中第一个元素为`True`,表示转换成功;第二个元素为另一个元组,包含知识库名称(`kb_name`)、文件名(`filename`)和转换得到的文档列表。
如果在转换过程中发生异常,函数将捕获异常并通过日志记录错误信息,然后返回一个元组,其中第一个元素为`False`,表示转换失败;第二个元素为另一个元组,包含知识库名称、文件名和错误信息。
此函数在项目中的作用是作为文件到文档转换过程的入口点,它依赖于`KnowledgeFile`对象的`file2text`方法来实现文件内容的读取和转换。这种设计使得文件到文档的转换过程可以灵活地适应不同类型的文件和处理需求。
**注意**:
- 在调用此函数之前,需要确保传入的`file`对象已经正确初始化,并且对应的文件确实存在。
- 转换过程中可能会因为文件格式不支持、文件内容问题或其他内部错误而失败,因此调用方需要检查返回值,以确定转换是否成功。
- 由于可能涉及到文件读取和文本处理,该过程可能会消耗一定的时间和资源,特别是处理大型文件时。
**输出示例**:
```python
# 假设转换成功
(True, ('知识库名称', '文件名.md', [文档对象1, 文档对象2, ...]))
# 假设转换失败
(False, ('知识库名称', '文件名.md', '加载文档时出错:错误信息'))
```
***