[开源项目推荐]privateGPT使用体验和修改

文章目录

  • 一.跑通简述
  • 二.解读ingest.py
    • 1.导入库和读取环境变量
    • 2.文档加载
    • 3.文档处理(调用文件加载函数和文本分割函数)
  • 三.injest.py效果演示
    • 1.main函数解读
    • 2.测试
  • 四.修改代码,使之适配多知识库需求
    • 1.修改配置文件:constants.py
    • 2.设置.env文件
    • 3.知识库选择函数
    • 4.修改main函数
    • 5.效果演示

一.跑通简述

  • 链接如下:https://github.com/imartinez/privateGPT/tree/main

  • 一开始是看到了gpt4all这个开源模型(苦于没有算力,据说这个能在低配置电脑上跑,就去看了),然后发现privateGPT这个开源项目,然后试了,果真能跑起来

  • 跟着项目中的readme来做即可
    在这里插入图片描述
    在CLI中输入问题,会显示答案和答案来源

  • 其中遇到的一些问题

    • 要把gpt4all下载下来,放到models路径下(也可以自己指定,和.env文件里面写的MODEL_PATH一致即可)
      在这里插入图片描述
  • 在使用ingest.py将本地知识库导入向量数据库的时候
    使用了langchain的HuggingFaceEmbeddings,也是可以在.env文件指定embedding模型,如果没有提前预下载好的话,那么会在运行程序的时候自动下载
    在这里插入图片描述在这里插入图片描述
    如果遇到和我一样下载失败的情况 在这里插入图片描述
    可以参考这篇博客,或者使用如下指令

$baseUri = "https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2/resolve/main/"
$outDir = "/data/pretrained_model/all-MiniLM-L6-v2/"
$files = @("pytorch_model.bin", "data_config.json", "config_sentence_transformers.json", "modules.json", "sentence_bert_config.json", "special_tokens_map.json", "tokenizer.json", "tokenizer_config.json", "train_script.py", "vocab.txt")foreach ($file in $files) {$url = $baseUri + $file$outFile = $outDir + $fileInvoke-WebRequest -Uri $url -OutFile $outFileWrite-Host "Downloaded $file"
}

然后就会下载到命令里面指定的路径了
在这里插入图片描述

二.解读ingest.py

  • 1.导入库和读取环境变量

import os
import glob
from typing import List
from dotenv import load_dotenv
from multiprocessing import Pool
from tqdm import tqdmfrom langchain.document_loaders import (CSVLoader,EverNoteLoader,PyMuPDFLoader,TextLoader,UnstructuredEmailLoader,UnstructuredEPubLoader,UnstructuredHTMLLoader,UnstructuredMarkdownLoader,UnstructuredODTLoader,UnstructuredPowerPointLoader,UnstructuredWordDocumentLoader,
)from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.docstore.document import Document
from constants import CHROMA_SETTINGSload_dotenv()# Load environment variables
persist_directory = os.environ.get('PERSIST_DIRECTORY')
source_directory = os.environ.get('SOURCE_DIRECTORY', 'source_documents')
embeddings_model_name = os.environ.get('EMBEDDINGS_MODEL_NAME')
chunk_size = 500
chunk_overlap = 50
  • 其中load_dotenv()挺常用的,用于从.env文件中读取环境变量

  • tqdm用于后面load文件的时候能看到进度条

  • chunk_sizechunk_overlap

    这有个关于这两个参数的解读博客写的挺好

    • chunk_size:这个参数表示文本分割的滑窗长度。它决定了每个分割后的文本块的大小。较大的 chunk_size 值会导致更大的文本块,而较小的值会导致更小的文本块。通常,较大的文本块可以提供更多的上下文信息,但也会增加模型的计算成本和内存需求。
    • chunk_overlap:这个参数表示重叠滑窗的长度。它决定了每个分割后的文本块之间的重叠部分。重叠滑窗可以提供文本块之间的上下文关联,使得模型能够更好地理解整个文本。较大的 chunk_overlap 值会导致更多的上下文关联,但也会增加计算成本。
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      (现在langchain官网支持对文档进行问答了)
  • persist_directory: 从环境中获取持久化目录的路径。

  • source_directory: 从环境中获取源文件目录的路径,如果没有设置则默认为 source_documents
    在这里插入图片描述

2.文档加载

  • langchain有超级强大且全面的各类文档加载器:https://python.langchain.com/docs/integrations/document_loaders

    在这里插入图片描述

  • 发现一篇很不错的博客:https://blog.csdn.net/weixin_42608414/article/details/131760937

    这篇博客也很清楚地介绍了chunk_size和chunk_overlap,这篇博客介绍了使用LangChain框架进行文档加载和切割的方法。还介绍了CharacterTextSplitter和RecursiveCharacterTextSplitter的区别

    在这里插入图片描述
    其中那个MyElmLoader就是继承了Langchain的邮件加载器,改了一些东西

  • 单个文档加载函数:load_single_document

    • 参数:这个函数接受一个file_path参数,它是要加载文档的文件路径。

    • 功能:

      • 从文件路径中获取文件扩展名。
      • 检查该扩展名是否存在于之前定义的LOADER_MAPPING字典中。
        • 如果存在,使用相应的加载器和参数从文件路径加载文档。
        • 如果不支持文件扩展名,抛出一个ValueError。
    • 返回值:返回一个文档列表

  • 文档加载函数:load_documents

    • 参数:
      • source_dir:来源目录的路径,其中包含要加载的所有文档。
      • ignored_files:一个默认为空的文件路径列表,指定哪些文件应该被忽略。
    • 功能:
      • 为所有在LOADER_MAPPING中定义的文件扩展名获取文件路径。
      • 使用glob模块的glob.glob函数,为每个扩展名获取文件路径,并将结果存储在all_files列表中。
      • 过滤掉ignored_files中的文件路径,得到filtered_files。
      • 使用多进程并行加载每个文件,使用系统的CPU核数作为进程数。为了提高效率,文件是无序加载的。
      • 使用pool.imap_unordered并行地调用load_single_document函数加载每个文件。
      • 使用tqdm显示加载进度。
      • 将从每个文件加载的所有文档扩展到结果列表中。
    • 返回值:这个函数返回所有加载的文档的列表。

在这里插入图片描述

  • glob.glob 用于查找匹配特定模式的文件路径。在这个函数中,我们使用 ** 来匹配任意深度的子目录,* 来匹配任意字符,ext 来匹配特定的文件扩展名。os.path.join 函数用于将目录路径和文件名组合成完整的文件路径。recursive=True 参数用于递归地查找子目录中的文件。最终,glob.glob 返回一个包含所有匹配文件路径的列表。
  • extend 是 Python 中的一个列表方法,用于将一个列表中的所有元素添加到另一个列表中。在这个函数中,all_files 是一个空列表,glob.glob 返回一个包含所有匹配文件路径的列表,extend 方法将这个列表中的所有元素添加到 all_files 列表中。这样,all_files 列表就包含了所有匹配文件的路径。
  • Pool 是 Python 中的一个类,它提供了一种简单的方式来并行处理大量的任务。它可以创建多个进程来执行函数,并将结果收集到一个列表中。在这个函数中, Pool 类用于异步地加载文档,以加快加载速度。processes 参数用于指定要创建的进程数,这里使用 os.cpu_count() 函数来获取系统上的 CPU 数量。imap_unordered 方法用于异步地加载每个文档,load_single_document 函数被应用于 filtered_files 列表中的每个文件路径。imap_unordered 方法返回一个迭代器,它可以用于获取每个文档的结果。
  • imap_unorderedmultiprocessing.Pool 类中的一个方法,用于异步地将一个可迭代对象中的元素应用于一个函数。它返回一个迭代器,可以用于获取函数的结果。与 imap 方法不同,imap_unordered 方法不保证返回结果的顺序与输入顺序相同。这个函数中,imap_unordered 方法用于异步地加载每个文档,以加快加载速度。load_single_document 函数被应用于 filtered_files 列表中的每个文件路径。imap_unordered 方法返回一个迭代器,它可以用于获取每个文档的结果。

3.文档处理(调用文件加载函数和文本分割函数)

process_documents函数加载并处理文档,返回分割后的文本块。而does_vectorstore_exist函数则检查指定的目录中是否存在有效的向量存储。

  1. 处理文档的函数: process_documents
    在这里插入图片描述

    功能:这个函数的主要任务是从指定的source_directory加载文档,然后将这些文档分割成较小的文本块。

    • 参数

      • ignored_files:默认为空的文件路径列表,这些文件在加载时会被忽略。
    • 步骤

      1. 输出一个信息,提示从source_directory开始加载文档。
      2. 调用load_documents函数来从source_directory加载文档,并同时考虑需要忽略的文件。
      3. 如果没有加载到任何新文档,它将输出提示信息并终止程序。
      4. 输出已加载的新文档的数量。
      5. 创建一个RecursiveCharacterTextSplitter对象,该对象负责将文档分割成较小的文本块。这里使用了之前定义的chunk_sizechunk_overlap作为参数。
      6. 使用text_splittersplit_documents方法将所有文档分割成文本块。
      7. 输出文本块的数量以及每个块的最大标记数量。
    • 返回值:函数返回分割后的文本块。

  2. 检查向量存储是否存在的函数: does_vectorstore_exist

在这里插入图片描述

功能:这个函数检查指定目录下是否存在一个有效的向量存储。

  • 参数

    • persist_directory:一个字符串,表示向量存储可能存在的目录路径。
  • 步骤

    1. 检查persist_directory下是否存在名为index的子目录。
    2. 检查是否存在文件chroma-collections.parquetchroma-embeddings.parquet
    3. 获取index目录下所有的.bin.pkl文件。
    4. 如果这些文件的数量超过3个,那么假定该向量存储是有效的。
  • 返回值:如果向量存储存在并且被认为是有效的,则返回True。否则,返回False

三.injest.py效果演示

1.main函数解读

def main():# Create embeddings# 创建嵌入embeddings = HuggingFaceEmbeddings(model_name=embeddings_model_name)# 如果vectorstore存在if does_vectorstore_exist(persist_directory):# Update and store locally vectorstoreprint(f"Appending to existing vectorstore at {persist_directory}")db = Chroma(persist_directory=persist_directory, embedding_function=embeddings, client_settings=CHROMA_SETTINGS)collection = db.get() # get是获取vectorstoretexts = process_documents([metadata['source'] for metadata in collection['metadatas']])print(f"Creating embeddings. May take some minutes...")db.add_documents(texts)else:# 创建并存储本地vectorstoreprint("Creating new vectorstore")texts = process_documents()print(f"Creating embeddings. May take some minutes...")db = Chroma.from_documents(texts, embeddings, persist_directory=persist_directory, client_settings=CHROMA_SETTINGS)db.persist()db = Noneprint(f"Ingestion complete! You can now query your documents")
  • 创建嵌入:
    使用HuggingFaceEmbeddings类创建一个嵌入对象,其中的模型名称由embeddings_model_name提供。

  • 检查向量存储是否存在:
    使用does_vectorstore_exist函数检查在persist_directory中是否已存在向量存储。

    • 如果向量存储存在:输出信息,表示将文档添加到现有的向量存储。

      • 创建一个Chroma对象,用于处理向量存储,这需要向量存储的路径、嵌入函数以及客户端设置。
        在这里插入图片描述
        在这里插入图片描述
        其中的chroma的配置写在constants.py里面
        在这里插入图片描述

      • 获取向量存储中的当前文档集合。
        调用process_documents函数处理那些之前尚未被加入到向量存储中的新文档。
        输出信息,告知用户正在创建嵌入,这可能需要一些时间。
        使用db.add_documents将处理后的文本块添加到向量存储。

    • 如果向量存储不存在:

      • 输出信息,表示正在创建新的向量存储。
        调用process_documents函数处理所有的文档。
      • 输出信息,告知用户正在创建嵌入。
        使用Chroma.from_documents从处理后的文本块创建新的向量存储。
        在这里插入图片描述
        在这里插入图片描述
  • 持久化向量存储:

    调用db.persist方法将向量存储的更改保存到磁盘。
    在这里插入图片描述

2.测试

在这里插入图片描述

四.修改代码,使之适配多知识库需求

目标是可以设置不同的知识库

  • 比如:我的本地知识库集合是一个大文件夹source,里面有小文件a,b,c分别存着不同类型的本地知识文件,然后我想运行ingest.py的时候,选择不同的路径,然后处理对应的本地知识文件,存到对应的VectorStore_of_source里面,里面分别对应a,b,c的向量数据库

1.修改配置文件:constants.py

首先,我们需要一个constants.py文件来存储基本的配置设置。


import os
from dotenv import load_dotenv
from chromadb.config import Settingsload_dotenv()# 分别对应我上面说的VectorStore_of_source和source
BASE_VECTORSTORE_DIRECTORY = os.environ.get('VECTORSTORE_BASE')
BASE_SOURCE_DIRECTORY = os.environ.get('SOURCE_BASE')# 分别对应我刚刚说的两个路径下的a,b,c
PERSIST_SUBDIRECTORIES = os.environ.get('PERSIST_DIRECTORIES').split(',')
SOURCE_SUBDIRECTORIES = os.environ.get('SOURCE_DIRECTORIES').split(',')# 路径合并
PERSIST_DIRECTORIES = [os.path.join(BASE_VECTORSTORE_DIRECTORY, sub_dir) for sub_dir in PERSIST_SUBDIRECTORIES]
SOURCE_DIRECTORIES = [os.path.join(BASE_SOURCE_DIRECTORY, sub_dir) for sub_dir in SOURCE_SUBDIRECTORIES]# 每个路径都有自己的Chroma设置
CHROMA_SETTINGS_LIST = [Settings(chroma_db_impl='duckdb+parquet',persist_directory=dir_path,anonymized_telemetry=False)for dir_path in PERSIST_DIRECTORIES
]

2.设置.env文件

创建一个名为.env的文件,并定义以下变量:

还是对应我刚刚说的那几个,知识源的Base(大目录),具体的小目录a,b,c(SOURCE_DIRECTORIES)
向量数据库的Base和下面的a,b,c(PERSIST_DIRECTORIES)
在这里插入图片描述

3.知识库选择函数

首先,我们创建一个函数来供用户选择知识库:python

def choose_directory():directories = ["a", "b", "c", "d"]print("Choose a persist directory:")for idx, d in enumerate(directories, 1):print(f"{idx}. {d}")choice = int(input("Enter the number: ")) - 1chosen_directory = directories[choice]persist_directory = os.path.join(PERSIST_DIRECTORY_BASE, chosen_directory)source_directory = os.path.join('source_base_directory', chosen_directory)  # Replace 'source_base_directory' with your actual pathreturn persist_directory, source_directory, CHROMA_SETTINGS

可以调用上面的choose_directory函数来获取chosen_persist_directory和chosen_source_directory。这些值随后在main函数中使用。

4.修改main函数

现在,可以在main函数中调用choose_directory来选择存储和源目录,并基于选择的目录对文档进行处理。

def main():chosen_persist_directory, chosen_source_directory, chosen_chroma_settings = choose_directory()

然后把原先的该替换的都用chosen后的变量替换掉

def main():chosen_persist_directory, chosen_source_directory, chosen_chroma_settings = choose_directory()# Create embeddingsembeddings = HuggingFaceEmbeddings(model_name=embeddings_model_name)if does_vectorstore_exist(chosen_persist_directory):# Update and store locally vectorstoreprint(f"Appending to existing vectorstore at {chosen_persist_directory}")db = Chroma(persist_directory=chosen_persist_directory, embedding_function=embeddings, client_settings=chosen_chroma_settings)collection = db.get()texts = process_documents(chosen_source_directory, [metadata['source'] for metadata in collection['metadatas']])print(f"Creating embeddings. May take some minutes...")db.add_documents(texts)else:# Create and store locally vectorstoreprint("Creating new vectorstore")texts = process_documents(chosen_source_directory)print(f"Creating embeddings. May take some minutes...")db = Chroma.from_documents(texts, embeddings, persist_directory=chosen_persist_directory, client_settings=chosen_chroma_settings)db.persist()db = Noneprint(f"Ingestion complete!")

5.效果演示

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/96248.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Elasticsearch:ES|QL 查询语言简介

警告:此功能处于技术预览阶段,可能会在未来版本中更改或删除。 Elastic 将尽最大努力解决任何问题,但技术预览版中的功能不受官方 GA 功能的支持 SLA 的约束。在目前的 Elastic Stack 8.10 中此功能还没有提供。 Elasticsearch 查询语言 (ES|…

IntelliJ IDEA 常用快捷键

目录 一、IDEA 常用快捷键 1 通用型 2 提高编写速度 3 类结构、查找和查看源码 4 查找、替换与关闭 5 调整格式 二、Debug快捷键 三、查看快捷键 1、已知快捷键操作名,未知快捷键 2、已知快捷键,不知道对应的操作名 3、自定义快捷键 4、使用…

MyBatisPlus(十一)包含查询:in

说明 包含查询&#xff0c;对应SQL语句中的 in 语句&#xff0c;查询参数包含在入参列表之内的数据。 in Testvoid inNonEmptyList() {// 非空列表&#xff0c;作为参数List<Integer> ages Stream.of(18, 20, 22).collect(Collectors.toList());in(ages);}Testvoid in…

[强网杯 2022]factor有感

可直接私信&#xff0b;Q 3431550587 此题记录主要是他运用了几个新看见的攻击思路和拜读了一篇论文&#xff0c;所以写写。题目源码&#xff1a; #encoding:utf-8 from Crypto.Util.number import * from gmpy2 import * from random import randint from flag import flagd…

AGI之MFM:《多模态基础模型:从专家到通用助手》翻译与解读之视觉理解、视觉生成

​AGI之MFM&#xff1a;《Multimodal Foundation Models: From Specialists to General-Purpose Assistants多模态基础模型&#xff1a;从专家到通用助手》翻译与解读之视觉理解、视觉生成 目录 相关文章 AGI之MFM&#xff1a;《Multimodal Foundation Models: From Speciali…

【Docker内容大集合】Docker从认识到实践再到底层原理大汇总

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量博客汇总https://blog.csdn.net/yu_cblog/categ…

硬盘损坏不能用怎么办?

硬盘是电脑的核心&#xff0c;如果硬盘出现了问题&#xff0c;那么整台电脑都会受到影响&#xff0c;电脑中的数据也会丢失。那么面对硬盘损坏时我们该如何解决呢&#xff1f;本文今天用5种简单的方法帮您解决&#xff01; 1、硬盘连接是否松动 当电脑的硬盘突然表现出无法识别…

stm32之手动创建keil工程--HAL库

用CubeMx创建了好多stm32的工程&#xff0c;这里记录下手动创建keil工程的过程。 一、准备工作 1.1、下载对应的HAL库&#xff0c; 这里使用的是stm32f103c8t6, 下载地址stm32HAL库 在页面中输入对应型号点击进行二级页面进行下载 1.2、准备工程 各文件夹下具体操作如下&am…

破译滑块验证间距 破译sf顺丰滑块验证

废话不多说直接开干&#xff01; from selenium import webdriver # 导入配置 from selenium.webdriver.chrome.options import Options import time from PIL import Image # 导入动作链 from selenium.webdriver.common.action_chains import ActionChains import random, st…

雷达电子箔条干扰和雷达诱饵简介

一、JAMMING 利用箔条、角反射器和诱饵进行机械干扰。 1、箔条(Chaff) 箔条是一种雷达干扰,在这种干扰中,飞机或其他目标散布一团薄薄的铝、金属化玻璃纤维或塑料,它们要么作为一组主要目标出现在雷达屏幕上,要么以多次回击淹没屏幕。 图1 箔条 2、箔条的雷达散射截面…

linux系统中三个重要的结构体

第一​&#xff1a;struct inode结构体 struct inode { struct hlist_node i_hash; struct list_head i_list; /* backing dev IO list */ struct list_head i_sb_list;​ //主次设备号 dev_t i_rdev;​ struct list_head i_devices; //用联合体是因为该…

uniapp 实现地图头像上的水波纹效果

最近实现了uniapp 地图头像水波纹的效果&#xff0c;话不多说&#xff0c;先来看看视频效果吧&#xff1a;链接 在这里具体的代码就不放出来了&#xff0c;还是利用了uniapp的 uni.createAnimation 方法&#xff0c;因为cover-view 不支持一些css 的动画效果&#xff0c;所以这…

如何使用百度“云一朵”来分析PDF文件

PDF 文件是一种常见的文件格式&#xff0c;用于存储文档、图像和其他内容。在许多情况下&#xff0c;我们需要对 PDF 文件进行分析&#xff0c;以提取其中的信息。百度“云一朵”提供了一个 PDF 分析 API&#xff0c;可以帮助我们轻松地对 PDF 文件进行分析。 在本博客文章中&…

基于Java的企业人事管理系统设计与实现(源码+lw+ppt+部署文档+视频讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

进程互斥的软件实现方法,硬件实现方法以及互斥锁

1.进程互斥的软件实现方法 1.单标志法 1.算法思想: 两个进程在访问完临界区后会把使用临界区的权限转交给另一个进程。 也就是说每个进程进入临界区的权限只能被另一个进程赋予。 2.例子 因此&#xff0c;该算法可以实现“同一时刻最多只允许一个进程访问临界区”。 3.主要…

Polygon Mide状态模型:解决状态膨胀,而不牺牲隐私和去中心化

1. 引言 前序博客有&#xff1a; Polygon Miden&#xff1a;扩展以太坊功能集的ZK-optimized rollupPolygon Miden zkRollup中的UTXO账户混合状态模型Polygon Miden交易模型&#xff1a;Actor模式 ZKP &#xff1e; 并行 隐私 在Polygon Miden交易模型&#xff1a;Actor模…

定时器+按键控制LED流水灯模式+定时器时钟——“51单片机”

各位CSDN的uu们好呀&#xff0c;今天&#xff0c;小雅兰的内容是51单片机中的定时器以及按键控制LED流水灯模式&定时器时钟&#xff0c;下面&#xff0c;让我们进入51单片机的世界吧&#xff01;&#xff01;&#xff01; 定时器 按键控制LED流水灯模式 定时器时钟 源代…

微服务技术栈-Docker应用部署

文章目录 前言一、数据卷二、Docker 应用部署1、MySQL部署2、Tomcat部署3、Nginx部署4、Redis部署5、Kafka部署 总结 前言 之前文章讲到过&#xff0c;docker运行程序的过程就是去仓库把镜像拉到本地&#xff0c;然后用一条命令把镜像运行起来变成容器&#xff0c;接下来我们将…

数据结构与算法-(7)---栈的应用-(4)后缀表达式求值

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

vue 使用 创建二维数组响应数据 渲染 echarts图标

目前我遇到的情况就是用动态的二维数组数据渲染echarts图标&#xff0c;我们从后端收到的接口一般是个一维数组&#xff0c;需要手动构建并且保证响应式。接下来我做了个案例 一、案例总逻辑 1. 先创建一个vue项目 2. 添加 echarts依赖 3. 模拟数据请求&#xff0c;构建二维数组…