文章目录
- 一、关于 检索
- 二、文档加载器
- 入门指南
- 三、CSV
- 1、使用每个文档一行的 CSV 数据加载 CSVLoader
- 2、自定义 csv 解析和加载 (csv_args
- 3、指定用于 标识文档来源的 列(source_column
- 四、文件目录 file_directory
- 1、加载文件目录数据(DirectoryLoader
- 2、显示进度条 (tqdm,show_progress
- 3、使用多线程 (use_multithreading
- 4、更改加载器类(loader_cls
- 5、使用 TextLoader 自动检测文件编码
- A. 默认行为
- B. 静默失败 (silent_errors
- C. 自动检测编码 (loader_kwargs, autodetect_encoding
- 五、HTML
- 1、加载 html (UnstructuredHTMLLoader
- 2、使用 BeautifulSoup4 加载 HTML (BSHTMLLoader
- 六、JSON
- 1、使用 json 加载数据
- 2、使用 JSONLoader
- 3、提取元数据 (Extracting metadata)
- 4、`metadata_func`
- 5、jq schema 中常见的 JSON 结构
- 七、Markdown ( UnstructuredMarkdownLoader
- 保留元素(Retain Elements)
- 八、PDF
- 1、使用 PyPDF
- 2、使用 MathPix
- 3、Using Unstructured
- 4、保留元素 (Retain Elements)
- 5、使用 Unstructured 获取远程 PDF
- 6、使用 PyPDFium2
- 7、使用 PDFMiner
- 使用 PDFMiner 生成 HTML 文本
- 8、使用 PyMuPDF
- 9、PyPDF 目录
- 10、使用 pdfplumber
一、关于 检索
许多LLM应用程序需要用户特定数据,这些数据不是模型的训练集的一部分。
完成这一任务的主要方法是通过检索增强生成(RAG)。
在此过程中,检索外部数据,然后在生成步骤中将其传递给LLM。
LangChain为RAG应用程序提供了所有的构建模块 - 从简单到复杂。
本文档部分涵盖了与检索步骤相关的所有内容,例如数据的获取。
虽然听起来很简单,但可能有微妙的复杂性. 这涵盖了几个关键模块。
1、文档加载器
从许多不同来源加载文档. LangChain提供了100多种不同的文档加载器,并与空间中的其他主要提供商(如AirByte和Unstructured)集成。
我们提供了加载各种类型文档(HTML、PDF、代码)的集成,从各种位置(私人S3存储桶、公共网站)加载。
2、文档转换器
检索的一个关键部分是仅获取文档的相关部分,为了最好地准备文档以进行检索,这涉及几个转换步骤,其中一个主要步骤是 将大型文档分割(或分块)为较小的块。
LangChain提供了几种不同的算法来完成此操作,以及针对特定文档类型(代码、markdown等)进行优化的逻辑.
3、文本嵌入模型
检索的另一个关键部分是 为文档创建嵌入。
嵌入捕捉文本的语义含义,使您能够 快速高效地查找其他相似的文本。
LangChain与25多个不同的嵌入提供商和方法进行集成, 从开源到专有API, 使您能够选择最适合您需求的一种。
LangChain提供了标准接口,使您可以轻松切换模型。
4、向量存储
随着嵌入的兴起,出现了对支持这些嵌入的数据库的需求。
LangChain与50多个不同的向量存储进行集成,从开源本地存储到云托管专有存储, 使您能够选择最适合您需求的一种。
LangChain公开了标准接口,使您可以轻松切换向量存储。
5、检索器
一旦数据在数据库中,您仍然需要检索它。
LangChain支持许多不同的检索算法,并且是我们增加最多价值的地方之一。
我们支持 易于入门的基本方法 - 即简单的语义搜索。
但是,我们还添加了一系列算法以提高性能,这些算法包括:
- 父文档检索器: 允许您为每个父文档 创建 多个嵌入,允许您查找较小的块 但返回较大的上下文。
- 自查询检索器: 用户的问题通常包含 对不仅仅是语义的东西的引用,而是表达一些 最好用元数据过滤器 表示的逻辑。
自查询允许您从查询中解析出语义 部分和查询中存在的其他元数据过滤器。 - 集合检索器: 有时您可能希望 从 多个不同的来源 或 使用多个不同的算法 检索文档。
集合检索器使您可以轻松实现此目的。
二、文档加载器
前往Integrations 以获取与第三方工具 集成的内置文档 加载器 的文档。
使用文档加载器从源加载数据作为Document
。
Document
是一段文本和相关元数据。
例如,有用于加载简单的.txt
文件的文档加载器,用于加载任何网页的文本内容,甚至用于加载YouTube视频的转录稿。
文档加载器提供了一个“load”方法,用于从配置的源加载数据作为文档。
它们还可以选择实现“延迟加载”,以便将数据惰性加载到内存中。
入门指南
最简单的加载器将文件作为文本读入,并将其全部放入一个文档中。
from langchain.document_loaders import TextLoader
loader = TextLoader("./index.md")
loader.load()
[
Document(
page_content='---\nsidebar_position: 0\n---\n# Document loaders\n\nUse document loaders to load data from a source as `Document`\'s. ... They optionally implement:\n\n3. "Lazy load": load documents into memory lazily\n',
metadata={'source': '../docs/docs_skeleton/docs/modules/data_connection/document_loaders/index.md'})
]
三、CSV
逗号分隔值(CSV) 文件是一种使用逗号分隔值的定界文本文件。
文件的每一行是一个数据记录;每个记录由一个或多个字段组成,字段之间用逗号分隔。
1、使用每个文档一行的 CSV 数据加载 CSVLoader
from langchain.document_loaders.csv_loader import CSVLoader
loader = CSVLoader(file_path='./example_data/mlb_teams_2012.csv')
data = loader.load()
data
[Document(page_content='Team: Nationals\n"Payroll (millions)": 81.34\n"Wins": 98', lookup_str='', metadata={'source': './example_data/mlb_teams_2012.csv', 'row': 0}, lookup_index=0),
...
Document(page_content='Team: Astros\n"Payroll (millions)": 60.65\n"Wins": 55', lookup_str='', metadata={'source': './example_data/mlb_teams_2012.csv', 'row': 29}, lookup_index=0)]
2、自定义 csv 解析和加载 (csv_args
参见 csv 模块 文档,了解支持的 csv 参数的更多信息。
loader = CSVLoader(file_path='./mlb_teams_2012.csv',
csv_args={
'delimiter': ',',
'quotechar': '"',
'fieldnames': ['MLB Team', 'Payroll in millions', 'Wins']
})
data = loader.load()
data
[Document(
page_content='MLB Team: Team\nPayroll in millions: "Payroll (millions)"\nWins: "Wins"',
lookup_str='',
metadata={'source': './example_data/mlb_teams_2012.csv', 'row': 0},
lookup_index=0),
...
Document(
page_content='MLB Team: Astros\nPayroll in millions: 60.65\nWins: 55',
lookup_str='',
metadata={'source': './example_data/mlb_teams_2012.csv', 'row': 30},
lookup_index=0)]
3、指定用于 标识文档来源的 列(source_column
使用 source_column
参数指定从每一行创建的文档的来源。
否则,file_path
将作为从 CSV 文件创建的所有文档的来源。
在使用基于来源回答问题的链时,这非常有用。
loader = CSVLoader(file_path='./example_data/mlb_teams_2012.csv',
source_column="Team")
data = loader.load()
data :
[Document(page_content='Team: Nationals\n"Payroll (millions)": 81.34\n"Wins": 98', lookup_str='', metadata={'source': 'Nationals', 'row': 0}, lookup_index=0),
...
Document(page_content='Team: Astros\n"Payroll (millions)": 60.65\n"Wins": 55', lookup_str='', metadata={'source': 'Astros', 'row': 29}, lookup_index=0)]
四、文件目录 file_directory
这里介绍了如何加载目录中的所有文档。
在底层,默认情况下使用 UnstructuredLoader
我们可以使用 glob
参数来控制要加载的文件。
请注意,这里不加载 .rst
文件或 .html
文件。
1、加载文件目录数据(DirectoryLoader
from langchain.document_loaders import DirectoryLoader
loader = DirectoryLoader('../', glob="**/*.md")
docs = loader.load()
len(docs) # -> 1
2、显示进度条 (tqdm,show_progress
默认情况下,不会显示进度条。
要显示进度条,请安装 tqdm
库(如 pip install tqdm
),并将 show_progress
参数设置为 True
。
loader = DirectoryLoader('../',
glob="**/*.md",
show_progress=True)
docs = loader.load()
Requirement already satisfied: tqdm in /Users/jon/.pyenv/versions/3.9.16/envs/microbiome-app/lib/python3.9/site-packages (4.65.0)
0it [00:00, ?it/s]
3、使用多线程 (use_multithreading
默认情况下,加载操作在 一个线程 中进行。
为了利用多个线程,将 use_multithreading
标志设置为 True。
loader = DirectoryLoader('../',
glob="**/*.md",
use_multithreading=True)
docs = loader.load()
4、更改加载器类(loader_cls
默认情况下使用 UnstructuredLoader
类。但是,您可以相当容易地 更改加载器的类型。
from langchain.document_loaders import TextLoader
loader = DirectoryLoader('../',
glob="**/*.md",
loader_cls=TextLoader)
docs = loader.load()
len(docs)
# -> 1
如果需要加载 Python 源代码文件,请使用 PythonLoader
。
from langchain.document_loaders import PythonLoader
loader = DirectoryLoader('../../../../../',
glob="**/*.py",
loader_cls=PythonLoader)
docs = loader.load()
len(docs)
# -> 691
5、使用 TextLoader 自动检测文件编码
在这个示例中,我们将看到一些在使用 TextLoader
类从目录加载一系列任意文件时可能有用的策略。
首先为了说明问题,让我们尝试加载多个具有任意编码的文本。
path = '../../../../../tests/integration_tests/examples'
loader = DirectoryLoader(path, glob="**/*.txt", loader_cls=TextLoader)
A. 默认行为
loader.load()
<pre style="white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace"><span style="color: #800000; text-decoration-color: #800000">╭─────────────────────────────── </span><span style="color: #800000; text-decoration-color: #800000; font-weight: bold">Traceback </span><span style="color: #bf7f7f; text-decoration-color: #bf7f7f; font-weight: bold">(most recent call last)</span><span style="color: #800000; text-decoration-color: #800000"> ────────────────────────────────╮</span>
<span style="color: #800000; text-decoration-color: #800000">│</span>
...
<span style="color: #800000; text-decoration-color: #800000">╰──────────────────────────────────────────────────────────────────────────────────────────────────╯</span>
<span style="color: #ff0000; text-decoration-color: #ff0000; font-weight: bold">RuntimeError: </span>Error loading ..<span style="color: #800080; text-decoration-color: #800080">/../../../../tests/integration_tests/examples/</span><span style="color: #ff00ff; text-decoration-color: #ff00ff">example-non-utf8.txt</span>
</pre>
文件 example-non-utf8.txt
使用了不同的编码,load()
函数会失败,并显示一条有用的消息指示哪个文件解码失败。
使用 TextLoader
的默认行为,任何一个文档加载失败,整个加载过程都将失败,并且不会加载任何文档。
B. 静默失败 (silent_errors
我们可以将参数 silent_errors
传递给 DirectoryLoader
,以跳过 无法加载的文件 并继续加载过程。
loader = DirectoryLoader(path,
glob="**/*.txt",
loader_cls=TextLoader,
silent_errors=True)
docs = loader.load()
Error loading ../../../../../tests/integration_tests/examples/example-non-utf8.txt
doc_sources = [doc.metadata['source'] for doc in docs]
doc_sources
['../../../../../tests/integration_tests/examples/whatsapp_chat.txt',
'../../../../../tests/integration_tests/examples/example-utf8.txt']
C. 自动检测编码 (loader_kwargs, autodetect_encoding
我们也可以 在失败前,使用 TextLoader
来自动检测文件编码。
传递 autodetect_encoding
来加载这个类。
text_loader_kwargs={'autodetect_encoding': True}
loader = DirectoryLoader(path,
glob="**/*.txt",
loader_cls=TextLoader,
loader_kwargs=text_loader_kwargs)
docs = loader.load()
doc_sources = [doc.metadata['source'] for doc in docs]
doc_sources :
['../../../../../tests/integration_tests/examples/example-non-utf8.txt',
'../../../../../tests/integration_tests/examples/whatsapp_chat.txt',
'../../../../../tests/integration_tests/examples/example-utf8.txt']
五、HTML
超文本标记语言或 HTML 是用于在 Web 浏览器中显示的文档的标准标记语言。
1、加载 html (UnstructuredHTMLLoader
这部分介绍如何将 HTML
文档加载到 我们可以在下游使用的文档格式中。
from langchain.document_loaders import UnstructuredHTMLLoader
loader = UnstructuredHTMLLoader("example_data/fake-content.html")
data = loader.load()
data :
[Document(page_content='My First Heading\n\nMy first paragraph.', lookup_str='', metadata={'source': 'example_data/fake-content.html'}, lookup_index=0)]
2、使用 BeautifulSoup4 加载 HTML (BSHTMLLoader
我们还可以使用 BeautifulSoup4
使用 BSHTMLLoader
加载 HTML 文档。
这将提取 HTML 中的文本到 page_content
,并将页面标题作为 metadata
的 title
。
from langchain.document_loaders import BSHTMLLoader
loader = BSHTMLLoader("example_data/fake-content.html")
data = loader.load()
data :
[Document(page_content='\n\nTest Title\n\n\nMy First Heading\nMy first paragraph.\n\n\n', metadata={'source': 'example_data/fake-content.html', 'title': 'Test Title'})]
六、JSON
JSON (JavaScript Object Notation) 是一种开放标准的文件格式和数据交换格式,存储和传输方便,且可读。
JSON 对象由属性 key - 值 value 对和数组(或其他可序列化值)组成的数据对象。
1、使用 json 加载数据
import json
from pathlib import Path
from pprint import pprint
from langchain.document_loaders import JSONLoader
file_path='./facebook_chat.json'
data = json.loads(Path(file_path).read_text())
data :
{'image':
{'creation_timestamp': 1675549016, 'uri': 'image_of_the_chat.jpg'},
'is_still_participant': True,
'joinable_mode': {'link': '', 'mode': 1},
'magic_words': [],
'messages': [{'content': 'Bye!',
'sender_name': 'User 2',
'timestamp_ms': 1675597571851},
...
{'content': 'Hi! Im interested in your bag. Im offering $50. Let me know if you are interested. Thanks!',
'sender_name': 'User 1',
'timestamp_ms': 1675549022673}],
'participants': [{'name': 'User 1'}, {'name': 'User 2'}],
'thread_path': 'inbox/User 1 and User 2 chat',
'title': 'User 1 and User 2 chat'}
2、使用 JSONLoader
JSONLoader
使用指定的 jq schema 来解析 JSON 文件。
它使用 jq
python 包。 查看这个 手册 来详细了解 jq
语法。
pip install jq
假设我们有兴趣提取 JSON 数据中 messages
键下的 content
字段的值。
通过以下示例可以轻松完成这项工作。
loader = JSONLoader(
file_path='./facebook_chat.json',
jq_schema='.messages[].content')
data = loader.load()
data :
[Document(page_content='Bye!',
metadata={'source': '/Users/xx/facebook_chat.json',
'seq_num': 1}),
...
Document(page_content='Hi! Thanks!',
metadata={'source': '/Users/xx/facebook_chat.json', 'seq_num': 11})]
3、提取元数据 (Extracting metadata)
通常,我们希望将 JSON 文件中的元数据包含到从内容创建的文档中。
下面演示了如何使用 JSONLoader
提取元数据。
需要注意一些关键的更改。在前一个示例中,我们没有收集元数据,在模式中直接指定了 page_content
的值的提取位置。
.messages[].content
在当前示例中,我们必须告诉加载器迭代 messages
字段中的记录。
因此,jq_schema 必须是以下形式:
.messages[]
这样我们就可以将记录(字典)传递给必须实现的 metadata_func
。
metadata_func
负责确定哪些记录中的信息应该 包含在最终 Document
对象中的元数据中。
此外,现在我们必须通过加载器 显式指定 content_key
参数,用于从记录中提取 page_content
的值的键。
def metadata_func(record: dict, metadata: dict) -> dict:
metadata["sender_name"] = record.get("sender_name")
metadata["timestamp_ms"] = record.get("timestamp_ms")
return metadata
loader = JSONLoader(
file_path='./example_data/facebook_chat.json',
jq_schema='.messages[]',
content_key="content",
metadata_func=metadata_func
)
data = loader.load()
data :
[Document(page_content='Bye!', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 1, 'sender_name': 'User 2', 'timestamp_ms': 1675597571851}),
...
Document(page_content='Hi! Im interested in your bag. Im offering $50. Let me know if you are interested. Thanks!', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 11, 'sender_name': 'User 1', 'timestamp_ms': 1675549022673})]
现在,您将看到文档包含与我们提取的内容相关联的元数据。
4、metadata_func
如上所示,metadata_func
接受 JSONLoader
生成的默认元数据。这允许用户完全控制元数据的格式。
例如,默认元数据包含 source
和 seq_num
键。
然而,JSON 数据中可能也包含这些键。
用户可以利用 metadata_func
重命名默认键 并使用 JSON 数据中的键。
下面的示例展示了如何修改 source
,只包含与 langchain
目录相关的文件来源信息。
Define the metadata extraction function.
def metadata_func(record: dict, metadata: dict) -> dict:
metadata["sender_name"] = record.get("sender_name")
metadata["timestamp_ms"] = record.get("timestamp_ms")
if "source" in metadata:
source = metadata["source"].split("/")
source = source[source.index("langchain"):]
metadata["source"] = "/".join(source)
return metadata
loader = JSONLoader(
file_path='./example_data/facebook_chat.json',
jq_schema='.messages[]',
content_key="content",
metadata_func=metadata_func
)
data = loader.load()
data :
[Document(page_content='Bye!', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 1, 'sender_name': 'User 2', 'timestamp_ms': 1675597571851}),
...
Document(page_content='Hi! Im interested in your bag. Im offering $50. Let me know if you are interested. Thanks!', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 11, 'sender_name': 'User 1', 'timestamp_ms': 1675549022673})]
5、jq schema 中常见的 JSON 结构
下面的列表提供了 用户可以根据结构 从 JSON 数据中 提取内容时 使用的可能的 jq_schema
的参考。
JSON -> [{"text": ...}, {"text": ...}, {"text": ...}]
jq_schema -> ".[].text"
JSON -> {"key": [{"text": ...}, {"text": ...}, {"text": ...}]}
jq_schema -> ".key[].text"
JSON -> ["...", "...", "..."]
jq_schema -> ".[]"
七、Markdown ( UnstructuredMarkdownLoader
Markdown 是一种轻量级标记语言,用于使用纯文本编辑器创建格式化文本。
这部分内容介绍了如何将 Markdown
文档 加载到我们可以在应用程序中 要使用的文档格式中。
! pip install unstructured > /dev/null
from langchain.document_loaders import UnstructuredMarkdownLoader
markdown_path = "../../../../../README.md"
loader = UnstructuredMarkdownLoader(markdown_path)
data = loader.load()
data :
[Document(page_content="ð\x9f¦\x9cï¸\x8fð\x9f”\x97 LangChain\n\nâ\x9a¡ Building applications with LLMs through composability â\x9a¡\n\nLooking for the JS/TS version? Check out LangChain.js.\n\nProduction Support: As you move your LangChains into production, we'd love to offer more comprehensive support.
...
Evaluation:\n\n[BETA] Generative models are notoriously hard to evaluate with traditional metrics. ... For detailed information on how to contribute, see here.", metadata={'source': '../../../../../README.md'})]
保留元素(Retain Elements)
在底层,Unstructured 为不同的文本块创建不同的“元素”。
默认情况下,我们将它们组合在一起,但通过指定 mode="elements"
可以轻松保留该分离。
loader = UnstructuredMarkdownLoader(markdown_path,
mode="elements")
data = loader.load()
data[0]
Document(page_content='ð\x9f¦\x9cï¸\x8fð\x9f”\x97 LangChain', metadata={'source': '../../../../../README.md', 'page_number': 1, 'category': 'Title'})
八、PDF
便携式文档格式(PDF),标准化为 ISO 32000,是 Adobe 于 1992 年开发的一种文件格式,用于以与应用软件、硬件和操作系统无关的方式呈现文档,包括文本格式和图像。
这涵盖了如何将 PDF
文档加载到 我们在下游使用的 Document 格式中。
1、使用 PyPDF
使用 pypdf
将 PDF 加载到文档数组中,其中每个文档包含页面内容和元数据,以及 page
号码。
pip install pypdf
from langchain.document_loaders import PyPDFLoader
loader = PyPDFLoader("example_data/layout-parser-paper.pdf")
pages = loader.load_and_split()
pages[0]
Document(page_content='LayoutParser : A Uni\x0ced Toolkit for Deep\nLearning Based Document Image Analysis
...
Introduction\nDeep Learning(DL)-based approaches are the state-of-the-art for a wide range of\ndocument image analysis (DIA) tasks including document image classi\x0ccation [ 11,arXiv:2103.15348v2 [cs.CV] 21 Jun 2021', metadata={'source': 'example_data/layout-parser-paper.pdf', 'page': 0})
这种方法的优点是可以通过页面号码检索文档。
我们想使用 OpenAIEmbeddings
,所以我们需要获取 OpenAI API 密钥。
import os
import getpass
os.environ['OPENAI_API_KEY'] = getpass.getpass('OpenAI API Key:')
from langchain.vectorstores import FAISS
from langchain.embeddings.openai import OpenAIEmbeddings
faiss_index = FAISS.from_documents(pages, OpenAIEmbeddings())
docs = faiss_index.similarity_search("How will the community be engaged?", k=2)
for doc in docs:
print(str(doc.metadata["page"]) + ":", doc.page_content[:300])
9: 10 Z. Shen et al.
Fig. 4: Illustration of (a) the original historical Japanese document with layout
detection results and (b) a recreated version of the document image that achieves
much better character recognition recall. The reorganization algorithm rearranges
the tokens based on the their detect
3: 4 Z. Shen et al.
Efficient Data AnnotationC u s t o m i z e d M o d e l T r a i n i n gModel Cust omizationDI A Model HubDI A Pipeline SharingCommunity PlatformLa y out Detection ModelsDocument Images
T h e C o r e L a y o u t P a r s e r L i b r a r yOCR ModuleSt or age & VisualizationLa y ou
2、使用 MathPix
受 Daniel Gross 的 https://gist.github.com/danielgross/3ab4104e14faccc12b49200843adab21 的启发
from langchain.document_loaders import MathpixPDFLoader
loader = MathpixPDFLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
3、Using Unstructured
from langchain.document_loaders import UnstructuredPDFLoader
loader = UnstructuredPDFLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
4、保留元素 (Retain Elements)
在内部,Unstructured 为不同的文本块创建不同的 “元素”。默认情况下,我们将它们组合在一起,但您可以通过指定 mode="elements"
轻松保持分离。
loader = UnstructuredPDFLoader("example_data/layout-parser-paper.pdf", mode="elements")
data = loader.load()
data[0]
Document(page_content='LayoutParser: A Unified Toolkit for Deep\nLearning Based Document Image Analysis
...
Introduction\nDeep Learning(DL)-based approaches are the state-of-the-art for a wide range of\ndocument image analysis (DIA) tasks including document image classification [11,\narXiv:2103.15348v2 [cs.CV] 21 Jun 2021\n', lookup_str='', metadata={'file_path': 'example_data/layout-parser-paper.pdf', 'page_number': 1, 'total_pages': 16, 'format': 'PDF 1.5', 'title': '', 'author': '', 'subject': '', 'keywords': '', 'creator': 'LaTeX with hyperref', 'producer': 'pdfTeX-1.40.21', 'creationDate': 'D:20210622012710Z', 'modDate': 'D:20210622012710Z', 'trapped': '', 'encryption': None}, lookup_index=0)
5、使用 Unstructured 获取远程 PDF
这涵盖了 如何将在线 PDF 加载到 我们可以在 下游使用的文档格式中。
这可用于各种在线 PDF 网站,如 https://open.umn.edu/opentextbooks/textbooks/ 和https://arxiv.org/archive/
注意:所有其他 PDF 加载器也可用于获取远程 PDF,但 OnlinePDFLoader
是一个旧版本函数,专门与 UnstructuredPDFLoader
配合使用。
from langchain.document_loaders import OnlinePDFLoader
loader = OnlinePDFLoader("https://arxiv.org/pdf/2302.03803.pdf")
data = loader.load()
data
[Document(page_content='A WEAK ( k, k ) -LEFSCHETZ THEOREM FOR PROJECTIVE TORIC ORBIFOLDS\n\nWilliam D. Montoya\n\nInstituto de Matem´atica, Estat´ıstica e Computa¸c˜ao Cient´ıfica,
...
Cohomology of complete intersections in toric varieties. Pub-', lookup_str='', metadata={'source': '/var/folders/ph/hhm7_zyx4l13k3v8z02dwp1w0000gn/T/tmpgq0ckaja/online_file.pdf'}, lookup_index=0)]
6、使用 PyPDFium2
from langchain.document_loaders import PyPDFium2Loader
loader = PyPDFium2Loader("example_data/layout-parser-paper.pdf")
data = loader.load()
7、使用 PDFMiner
from langchain.document_loaders import PDFMinerLoader
loader = PDFMinerLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
使用 PDFMiner 生成 HTML 文本
这对于将文本语义分块到部分中非常有用,因为输出的 HTML 内容可以通过 BeautifulSoup
解析,以获取有关字体大小、页码、PDF 标题/页脚等更结构化和丰富的信息。
from langchain.document_loaders import PDFMinerPDFasHTMLLoader
loader = PDFMinerPDFasHTMLLoader("example_data/layout-parser-paper.pdf")
data = loader.load()[0] # entire pdf is loaded as a single Document
from bs4 import BeautifulSoup
soup = BeautifulSoup(data.page_content,'html.parser')
content = soup.find_all('div')
import re
cur_fs = None
cur_text = ''
snippets = [] # first collect all snippets that have the same font size
for c in content:
sp = c.find('span')
if not sp:
continue
st = sp.get('style')
if not st:
continue
fs = re.findall('font-size:(\d+)px',st)
if not fs:
continue
fs = int(fs[0])
if not cur_fs:
cur_fs = fs
if fs == cur_fs:
cur_text += c.text
else:
snippets.append((cur_text,cur_fs))
cur_fs = fs
cur_text = c.text
snippets.append((cur_text,cur_fs))
# Note: The above logic is very straightforward. One can also add more strategies such as removing duplicate snippets (as
# headers/footers in a PDF appear on multiple pages so if we find duplicatess safe to assume that it is redundant info)
from langchain.docstore.document import Document
cur_idx = -1
semantic_snippets = []
# Assumption: headings have higher font size than their respective content
for s in snippets:
# if current snippet's font size > previous section's heading => it is a new heading
if not semantic_snippets or s[1] > semantic_snippets[cur_idx].metadata['heading_font']:
metadata={'heading':s[0], 'content_font': 0, 'heading_font': s[1]}
metadata.update(data.metadata)
semantic_snippets.append(Document(page_content='',metadata=metadata))
cur_idx += 1
continue
# if current snippet's font size <= previous section's content => content belongs to the same section (one can also create
# a tree like structure for sub sections if needed but that may require some more thinking and may be data specific)
if not semantic_snippets[cur_idx].metadata['content_font'] or s[1] <= semantic_snippets[cur_idx].metadata['content_font']:
semantic_snippets[cur_idx].page_content += s[0]
semantic_snippets[cur_idx].metadata['content_font'] = max(s[1], semantic_snippets[cur_idx].metadata['content_font'])
continue
# if current snippet's font size > previous section's content but less tha previous section's heading than also make a new
# section (e.g. title of a pdf will have the highest font size but we don't want it to subsume all sections)
metadata={'heading':s[0], 'content_font': 0, 'heading_font': s[1]}
metadata.update(data.metadata)
semantic_snippets.append(Document(page_content='',metadata=metadata))
cur_idx += 1
semantic_snippets[4]
Document(page_content='Recently, various DL models and datasets have been developed for layout analysis\ntasks.
...
A spectrum of models\ntrained on these datasets are currently available in the LayoutParser model zoo\nto support different use cases.\n',
metadata={'heading': '2 Related Work\n', 'content_font': 9, 'heading_font': 11, 'source': 'example_data/layout-parser-paper.pdf'})
8、使用 PyMuPDF
这是 PDF 解析选项中最快的,并且包含有关 PDF 及其页面的详细元数据,以及每个页面返回一个文档。
from langchain.document_loaders import PyMuPDFLoader
loader = PyMuPDFLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
data[0]
Document(page_content='LayoutParser: A Unified Toolkit for Deep\nLearning Based Document Image Analysis...
Open Source library · Toolkit.\n1\nIntroduction\nDeep Learning(DL)-based approaches are the state-of-the-art for a wide range of\ndocument image analysis (DIA) tasks including document image classification [11,\narXiv:2103.15348v2 [cs.CV] 21 Jun 2021\n', lookup_str='', metadata={'file_path': 'example_data/layout-parser-paper.pdf', 'page_number': 1, 'total_pages': 16, 'format': 'PDF 1.5', 'title': '', 'author': '', 'subject': '', 'keywords': '', 'creator': 'LaTeX with hyperref', 'producer': 'pdfTeX-1.40.21', 'creationDate': 'D:20210622012710Z', 'modDate': 'D:20210622012710Z', 'trapped': '', 'encryption': None}, lookup_index=0)
此外,您可以将 PyMuPDF 文档 中的任何选项作为关键字参数传递给 load
调用,并将其传递给 get_text()
调用。
9、PyPDF 目录
从目录加载 PDF
from langchain.document_loaders import PyPDFDirectoryLoader
loader = PyPDFDirectoryLoader("example_data/")
docs = loader.load()
10、使用 pdfplumber
与 PyMuPDF 类似,输出的文档包含有关 PDF 及其页面的详细元数据,并且每个页面返回一个文档。
from langchain.document_loaders import PDFPlumberLoader
loader = PDFPlumberLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
data[0]
Document(page_content='LayoutParser: A Unified Toolkit for Deep\nLearning Based Document Image Analysis\nZejiang Shen1 ((cid:0)), Ruochen Zhang2, Melissa Dell3, Benjamin Charles Germain\nLee4, Jacob Carlson3, and Weining Li5\n1 Allen Institute for AI
...
of\ndocumentimageanalysis(DIA)tasksincludingdocumentimageclassification[11,', metadata={'source': 'example_data/layout-parser-paper.pdf', 'file_path': 'example_data/layout-parser-paper.pdf', 'page': 1, 'total_pages': 16, 'Author': '', 'CreationDate': 'D:20210622012710Z', 'Creator': 'LaTeX with hyperref', 'Keywords': '', 'ModDate': 'D:20210622012710Z', 'PTEX.Fullbanner': 'This is pdfTeX, Version 3.14159265-2.6-1.40.21 (TeX Live 2020) kpathsea version 6.3.2', 'Producer': 'pdfTeX-1.40.21', 'Subject': '', 'Title': '', 'Trapped': 'False'})
2024-04-08(一)