当前位置: 首页 > article >正文

私有知识库 Coco AI 实战(七):摄入本地 PDF 文件

是否有些本地文件要检索?没问题。我们先对 PDF 类的文件进行处理,其他的文件往后稍。

Coco Server Token

创建一个 token 备用。

PDF_Reader

直接写个 python 程序解析 PDF 内容,上传到 Coco Server 就行了。还记得以前都是直接写入 Coco 后台的 Easysearch 的,这次我们走 Coco Server 的 API 写入数据。

程序逻辑

  1. 检查是否存在 id 为 local_pdf 的 connector 和 datasource,不存在就创建。
  2. 遍历一个目录中的所有 pdf 文件
  3. 把 pdf 文件的内容发送给 Coco Server 的 API

使用程序

  1. 修改 220 行替换成自己的 Coco server token
  2. 修改 221 行换成自己 Coco Server 的地址
  3. 修改 229 行换成自己 PDF 文件的目录
  4. 运行程序
from PyPDF2 import PdfReader
import os
import requests
from pathlib import Pathclass PDFPage:def __init__(self, title: str, content: str, page_number: int):self.title = titleself.content = contentself.type = "pdf"self.page = page_numberdef read_pdf(file_path: str) -> list[PDFPage]:"""读取PDF文件并为每一页创建一个PDFPage对象Args:file_path (str): PDF文件的路径Returns:list[PDFPage]: 包含所有页面对象的列表"""# 检查文件是否存在if not os.path.exists(file_path):raise FileNotFoundError(f"找不到文件: {file_path}")# 检查文件是否为PDFif not file_path.lower().endswith('.pdf'):raise ValueError("文件必须是PDF格式")# 获取文件名(不包含路径)file_name = os.path.basename(file_path)# 创建PDF阅读器对象pdf_reader = PdfReader(file_path)pages = []# 遍历每一页for page_num in range(len(pdf_reader.pages)):# 获取当前页面page = pdf_reader.pages[page_num]# 提取文本内容content = page.extract_text()# 创建页面对象pdf_page = PDFPage(title=file_name,content=content,page_number=page_num + 1  # 页码从1开始)pages.append(pdf_page)return pagesdef send_to_coco_server(page: PDFPage,datasource_id: str,api_token: str,file_path: str,server_url: str = "http://localhost:9000") -> dict:"""将PDF页面内容发送到Coco ServerArgs:page (PDFPage): PDF页面对象datasource_id (str): Coco Server的数据源IDapi_token (str): API Tokenfile_path (str): PDF文件的完整路径server_url (str): Coco Server的URLReturns:dict: 服务器响应"""headers = {'X-API-TOKEN': api_token, 'Content-Type': 'application/json'}# 将Windows路径转换为标准路径格式(使用正斜杠)file_url = file_path.replace('\\', '/')data = {'title': f"{page.title} - 第{page.page}页",'summary': f"PDF文档 {page.title} 的第{page.page}页内容",'content': page.content,'category': 'local_pdf','url': file_url}url = f"{server_url}/datasource/{datasource_id}/_doc"response = requests.post(url, headers=headers, json=data)return response.json()def process_directory(directory_path: str, api_token: str, datasource_id: str,server_url: str) -> None:"""处理指定目录下的所有PDF文件Args:directory_path (str): 目录路径api_token (str): API Tokendatasource_id (str): 数据源IDserver_url (str): 服务器URL"""# 确保目录存在if not os.path.exists(directory_path):raise FileNotFoundError(f"目录不存在: {directory_path}")# 获取所有PDF文件pdf_files = list(Path(directory_path).rglob("*.pdf"))total_files = len(pdf_files)print(f"找到 {total_files} 个PDF文件")# 处理每个PDF文件for file_index, pdf_file in enumerate(pdf_files, 1):print(f"\n处理文件 {file_index}/{total_files}: {pdf_file}")try:# 获取文件的绝对路径absolute_path = str(pdf_file.absolute())# 读取PDF文件pdf_pages = read_pdf(absolute_path)# 处理每一页for page in pdf_pages:print(f"  正在处理: {page.title} - 第{page.page}页")try:result = send_to_coco_server(page, datasource_id,api_token, absolute_path,server_url)print(f"  上传成功! 文档ID: {result.get('_id')}")except Exception as e:print(f"  上传失败: {str(e)}")except Exception as e:print(f"处理文件 {pdf_file} 时出错: {str(e)}")continuedef create_connector_and_datasource(server_url: str, api_token: str) -> str:"""创建connector和datasourceArgs:server_url (str): 服务器URLapi_token (str): API TokenReturns:str: 创建的datasource ID"""headers = {'X-API-TOKEN': api_token, 'Content-Type': 'application/json'}# 检查connector是否存在connector_id = 'local_pdf'connector_url = f"{server_url}/connector/{connector_id}"try:response = requests.get(connector_url, headers=headers)if response.status_code == 404:# 创建connectorconnector = {'name': 'Local PDF Connector','category': 'local_files','icon': 'font_filetype-PDF'}print("创建 local_pdf connector...")response = requests.put(f"{server_url}/connector/local_pdf?replace=true",headers=headers,json=connector)# print(response.json())# print(response.status_code)if response.status_code == 200 and response.json().get('result') == 'updated':print("Connector创建成功")else:raise Exception(f"创建Connector失败: {response.text}")# 检查datasource是否存在datasource_url = f"{server_url}/datasource/local_pdf"response = requests.get(datasource_url, headers=headers)if response.status_code == 404:# 创建datasourcedatasource = {'name': 'Local PDF Datasource','id': 'local_pdf','type': 'connector','connector': {'id': 'local_pdf',},'sync_enabled': False,'enabled': True}print("创建 local_pdf datasource...")response = requests.put(f"{server_url}/datasource/local_pdf?replace=true",headers=headers,json=datasource)if response.status_code == 200 and response.json().get('result') == 'updated':print("Datasource创建成功")else:raise Exception(f"创建Datasource失败: {response.text}")return 'local_pdf'except Exception as e:print(f"创建过程中发生错误: {str(e)}")raisedef main():"""主函数,处理指定目录下的所有PDF文件并发送到Coco Server"""try:# Coco Server配置api_token = "d02rutog1maf0invql60130c0y8g4se4i5brurqa2k72r6ozysvxvzgda90cnbwg26bw4g7tv09zjfuw0c33"server_url = "http://192.168.10.3:9000"# 创建或获取datasourceprint("检查并创建必要的connector和datasource...")datasource_id = create_connector_and_datasource(server_url, api_token)print(f"使用datasource ID: {datasource_id}")# 指定要处理的目录directory_path = "D:/LangChain/infini-rag/easysearch"  # 替换为你的目录路径# 处理目录process_directory(directory_path, api_token, datasource_id, server_url)print("\n所有文件处理完成!")except Exception as e:print(f"发生错误: {str(e)}")if __name__ == "__main__":main()

测试搜索

我的测试目录里有三个 PDF 文件。

通过程序采集内容后,就能对这些内容进行搜索了。

选择对应的条目回车就能直接打开 PDF 文件。

测试小助手

有了之前创建小助手的经验,我们很快也能打造一个本地 PDF 资源的小助手。

回答内容基本来自本地 PDF 文件内容,用这个来管理本地 PDF 知识,真是太方便了。

相关文章:

私有知识库 Coco AI 实战(七):摄入本地 PDF 文件

是否有些本地文件要检索?没问题。我们先对 PDF 类的文件进行处理,其他的文件往后稍。 Coco Server Token 创建一个 token 备用。 PDF_Reader 直接写个 python 程序解析 PDF 内容,上传到 Coco Server 就行了。还记得以前都是直接写入 Coco …...

GitLab 18.0 正式发布,15.0 将不再受技术支持,须升级【二】

GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料: 极狐GitLab 官网极狐…...

NtfsLookupAttributeByName函数分析之和Scb->AttributeName的关系

第一部分: VOID FindFirstIndexEntry ( IN PIRP_CONTEXT IrpContext, IN PSCB Scb, IN PVOID Value, IN OUT PINDEX_CONTEXT IndexContext ) { 。。。。。。 // // Lookup the attribute record from the Scb. // if (!NtfsLookupAt…...

STM32H7系列USART驱动区别解析 stm32h7xx_hal_usart.c与stm32h7xx_ll_usart.c的区别?

在STM32H7系列中,stm32h7xx_hal_usart.c和stm32h7xx_ll_usart.c是ST提供的两种不同层次的USART驱动程序,主要区别在于设计理念、抽象层次和使用场景: 1. HAL库(Hardware Abstraction Layer) 文件:stm32h7x…...

网络原理 | TCP与UDP协议的区别以及回显服务器的实现

目录 TCP与UDP协议的区别 基于 UDP 协议实现回显服务器 UDP Socket 编程常用 Api UDP 服务器 UDP 客户端 基于 TCP 协议实现回显服务器 TCP Socket 编程常用 Api TCP 服务器 TCP 客户端 TCP 服务端常见的 bug 客户端发送数据后,没有响应 服务器仅支持…...

IP动态伪装开关

IP动态伪装开关 在OpenWrt系统中,IP动态伪装(IP Masquerading)是一种网络地址转换(NAT)技术,用于在私有网络和公共网络之间转换IP地址。它通常用于允许多个设备共享单个公共IP地址访问互联网。以下是关于O…...

【Unity3D】将自动生成的脚本包含到C#工程文件中

我们知道,在用C#开发中,通过vs编辑器新建的脚本,会自动包含到vs工程中,而通过外部创建,比如复制别的工程或代码创建的C#脚本不会包含到vs工程。 在我们的日常开发中,通常会自动创建C#脚本,特别…...

解决leetcode第3509题.最大化交错和为K的子序列乘积

3509.最大化交错和为K的子序列乘积 难度:困难 问题描述: 给你一个整数数组nums和两个整数k与limit,你的任务是找到一个非空的子序列,满足以下条件: 它的交错和等于k。 在乘积不超过limit的前提下,最大…...

【Python 深度学习】1D~3D iou计算

一维iou 二维 import numpy as npdef iou_1d(set_a, set_b):# 获得集合A和B的边界 x1, x2 set_ay1, y2 set_b# 计算交集的上下界low max(x1,y1)high - min(x2, y2)# 计算交集if high - low < 0:inter 0else:inter high - low# 计算并集union (x2 -x1) (y2 - y1) - in…...

java23

1.美化界面 添加背景图片 所以我们添加背景图片要放在后面添加 添加图片边框 绝对路径&#xff1a; 相对(模块)路径&#xff1a; 第一个是绝对路径&#xff0c;第二个是相对路径&#xff0c;但是斜杠的方向不对 总结&#xff1a; 2.图片移动 先实现KeyListener接口&#xf…...

嵌入式工程师常用软件

1、 Git Git 是公司常用的版本管理工具&#xff0c;人人都要会。在线的 git 教程可以参考菜鸟教程&#xff1a; https://www.runoob.com/git/git-tutorial.html 电子书教程请在搜索栏搜索&#xff1a; git Git 教程很多&#xff0c;常用的命令如下&#xff0c;这些命令可…...

LitCTF2025 WEB

星愿信箱 使用的是python&#xff0c;那么大概率是ssti注入 测试{{5*5}} 发现需要包含文字&#xff0c;那么添加文字 可以看到被waf过滤了&#xff0c;直接抓包查看参数上fenjing 可以看到这里是json格式&#xff0c;其实fenjing也是支持json格式的 https://github.com/Marv…...

Redisson WatchDog会一直续期吗?

取决于加锁的方式。 Lock 方法有2种形式&#xff0c;如果指定了leaseTime &#xff08;且不为-1&#xff09;&#xff0c; 不会启用watchDog机制. 如果没有指定leaseTime&#xff0c; 则会启动watchDog机制&#xff0c;且会一直续期&#xff0c;除非线程宕调或者续期失败。 p…...

Linux 下VS Code 的使用

这里以创建helloworld 为例。 Step 0:准备工作&#xff1a; Install Visual Studio Code. Install the C extension for VS Code. You can install the C/C extension by searching for c in the Extensions view (CtrlShiftX). Step 1: 创建工作目录 helloworld&#xff0…...

Android开发namespace奇葩bug

Android开发namespace奇葩bug namespace "com.yibanxxx.yiban"buildFeatures {buildConfig true}namespace 对应你的module的清单下的package...

watchEffect

在处理复杂异步逻辑时&#xff0c;Vue 3 的 watchEffect 相比传统的 watch 具有以下优势&#xff1a; 1. 自动追踪依赖 watchEffect 会自动收集其回调中使用的所有响应式依赖&#xff0c;无需手动指定监听源&#xff1a; import { ref, watchEffect } from vue;const count …...

Qt 布局管理器的层级关系

1、HomeWidget.h头文件&#xff1a; #ifndef HOMEWIDGET_H #define HOMEWIDGET_H#include <QWidget> #include <QPushButton> #include <QVBoxLayout> #include <QHBoxLayout>class HomeWidget : public QWidget {Q_OBJECTpublic:HomeWidget(QWidget …...

Android 之 kotlin 语言学习笔记一

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/learn?hlzh-cn 1、变量声明 Kotlin 使用两个不同的关键字&#xff08;即 val 和 var&#xff09;来声明变量。 val 用于值从不更改的变量。使用 val 声明的变量无法重新赋值。var 用于值可以更改的变量…...

maven模块化开发

使用方法 将项目安装到本地仓库 mvn install 的作用 运行 mvn install 时&#xff0c;Maven 会执行项目的整个构建生命周期&#xff08;包括 compile、test、package 等阶段&#xff09;&#xff0c;最终将构建的 artifact 安装到本地仓库&#xff08;默认路径为 ~/.m2/repos…...

为什么要使用stream流

总的来说就是 它支持链式调用&#xff0c;方便 不会修改原始数据源&#xff0c;而是生成一个新的流或结果 中间操作不会立即执行&#xff0c;只有在终端操作触发时才会真正执行 注意事项 无状态操作&#xff1a;Stream 操作应该是无状态的&#xff0c;不要依赖外部变量的状…...

语义分割的image

假设图像的尺寸为 3x3&#xff0c;并且是 RGB 图像&#xff08;有 3 个通道&#xff09;。每个通道的像素值范围为 [0, 1]&#xff0c;我们将构造一个 batch_size 2 的图像批次。 Image: tensor([[[[0.1347, 0.4583, 0.7102], # 第一张图像的红色通道[0.1774, 0.0328, 0.308…...

云原生安全之网络IP协议:从基础到实践指南

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 IP协议&#xff08;Internet Protocol&#xff09;是互联网通信的核心协议族之一&#xff0c;负责在设备间传递数据包。其核心特性包括&…...

C++——QT 文件操作类

QFile 概述 QFile是Qt框架中用于文件操作的类&#xff08;位于QtCore模块&#xff09;&#xff0c;继承自 QIODevice&#xff0c;提供文件的读写、状态查询和路径管理功能。它与 QTextStream、QDataStream 配合使用&#xff0c;可简化文本和二进制数据的处理&#xff0c;并具备…...

【排错】kylinLinx环境python读json文件报错UTF-8 BOM

kylin Linux环境python读json文件报错UTF-8 BOM 报错描述&#xff1a; windows环境下,python代码读取json文件正常&#xff0c;但是sftp到linux环境下 报错信息&#xff1a; json.decoder.JSONDecodeError: Unexpected UTF-8 BOM (decode using utf-8-sig): line 1 column …...

[spring] spring 框架、IOC和AOP思想

目录 传统Javaweb开发的困惑 loC、DI和AOP思想提出 Spring框架的诞生 传统Javaweb开发的困惑 问题一&#xff1a;层与层之间紧密耦合在了一起&#xff0c;接口与具体实现紧密耦合在了一起 解决思路&#xff1a;程序代码中不要手动new对象&#xff0c;第三方根据要求为程序提…...

LInux—shell编程

一、Shell 编程核心特性 解释型语言 无需编译&#xff0c;直接由 bash、sh 等解释器逐行执行。 类似 PHP 的解释执行&#xff0c;不同于 C 的编译型。 系统命令集成 可直接调用 Linux 命令&#xff08;如 ls、grep、awk&#xff09;&#xff0c;实现系统管理自动化。 与 C/…...

尚硅谷redis7 37-39 redis持久化之AOF简介

37 redis持久化之AOF简介 AOF 以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工…...

GitLab 备份所有仓库(自动克隆)

一、准备工作 1. 环境要求 已安装 Git&#xff08;版本 2.10&#xff09;本地磁盘空间充足&#xff08;根据仓库总大小预估&#xff09;已配置 SSH 密钥到 GitLab&#xff08;推荐方式&#xff09; 2. 获取 GitLab API 访问权限 登录 GitLab&#xff0c;点击右上角头像 → …...

[浏览器]缓存策略机制详解

在做页面性能优化的时候&#xff0c;有一个点容易被忽略&#xff0c;那就是资源缓存优化。 浏览器里缓存策略分为强缓存&#xff0c;协商缓存以及不缓存&#xff0c;每个缓存策略都有其适用的优化场景。 下面为大家详解何为强缓存&#xff0c;协商缓存 先说结论强缓>协商&g…...

Vue修饰符全解析

目录 一、事件修饰符 二、按键修饰符 三、系统修饰键 四、表单修饰符 五、鼠标修饰符 六、特殊修饰符 七、自定义修饰符 使用建议 一、事件修饰符 <!-- 阻止冒泡 --> <button click.stop"handleClick">点击测试</button><!-- 阻止默认行…...