文本分割的方式 第二篇

 一:根据文档的特定属性或内容进行拆分Document Specific Splitting)

让我们开始处理 .txt 中普通散文以外的文档类型。如果有图片怎么办?或PDF?或代码片段?

我们的前两个级别对此不太适用,因此我们需要找到不同的策略。

Markdown

  • \n#{1,6} - 按新行分割,后跟标题(H1 到 H6)
  • ```\n - 代码块
  • \n\\*\\*\\*+\n - 水平线
  • \n---+\n - 水平线
  • \n___+\n - 水平线
  • \n\n 双换行
  • \n - 换行
  • " " - 空格
  • "" - 字符
from langchain.text_splitter import MarkdownTextSplitter


splitter = MarkdownTextSplitter(chunk_size = 40, chunk_overlap=0)


markdown_text = """
# Fun in California

## Driving

Try driving on the 1 down to San Diego

### Food

Make sure to eat a burrito while you're there

## Hiking

Go to Yosemite
"""

splitter.create_documents([markdown_text])
[Document(page_content='# Fun in California\n\n## Driving'),
 Document(page_content='Try driving on the 1 down to San Diego'),
 Document(page_content='### Food'),
 Document(page_content="Make sure to eat a burrito while you're"),
 Document(page_content='there'),
 Document(page_content='## Hiking\n\nGo to Yosemite')]

请注意,分割点倾向于靠近Markdown部分。然而,这仍然不是完美的。注意有一个只包含 "there" 的块。在处理较小的片段时,你可能会遇到这种情况

Python

  • \nclass - Classes first
  • \ndef - Functions next
  • \n\tdef - Indented functions
  • \n\n - Double New lines
  • \n - New Lines
  • " " - Spaces
  • "" - Characters
from langchain.text_splitter import PythonCodeTextSplitter

python_text = """
class Person:
  def __init__(self, name, age):
    self.name = name
    self.age = age

p1 = Person("John", 36)

for i in range(10):
    print (i)
"""


python_splitter = PythonCodeTextSplitter(chunk_size=100, chunk_overlap=0)


python_splitter.create_documents([python_text])
[Document(page_content='class Person:\n  def __init__(self, name, age):\n    self.name = name\n    self.age = age'),
 Document(page_content='p1 = Person("John", 36)\n\nfor i in range(10):\n    print (i)')]

注意类是如何在单个文档中保持在一起的,然后其余的代码在第二个文档中。

JS

与python非常相似

Separators: 分隔符:

  • \nfunction - Indicates the beginning of a function declaration
  • \nconst - Used for declaring constant variables
  • \nlet - Used for declaring block-scoped variables
  • \nvar - Used for declaring a variable
  • \nclass - Indicates the start of a class definition
  • \nif - Indicates the beginning of an if statement
  • \nfor - Used for for-loops
  • \nwhile - Used for while-loops
  • \nswitch - Used for switch statements
  • \ncase - Used within switch statements
  • \ndefault - Also used within switch statements
  • \n\n - Indicates a larger separation in text or code
  • \n - Separates lines of code or text
  • " " - Separates words or tokens in the code
  • "" - Makes every character a separate element
from langchain.text_splitter import RecursiveCharacterTextSplitter, Language

javascript_text = """
// Function is called, the return value will end up in x
let x = myFunction(4, 3);

function myFunction(a, b) {
// Function returns the product of a and b
  return a * b;
}
"""


js_splitter = RecursiveCharacterTextSplitter.from_language(
    language=Language.JS, chunk_size=65, chunk_overlap=0
)

js_splitter.create_documents([javascript_text])
[Document(page_content='// Function is called, the return value will end up in x'),
 Document(page_content='let x = myFunction(4, 3);'),
 Document(page_content='function myFunction(a, b) {'),
 Document(page_content='// Function returns the product of a and b\n  return a * b;\n}')]

PDFs w/ tables

PDF 是语言模型工作中极其常见的数据类型。它们通常会包含包含信息的表格。

这可以是财务数据、研究、学术论文等。

尝试通过基于字符的分隔符拆分表是不可靠的。我们需要尝试一种不同的方法。

实现此目的的一个非常方便的方法是使用 Unstructured,这是一个专门用于使您的数据LLM 准备就绪的库。

import os
from unstructured.partition.pdf import partition_pdf
from unstructured.staging.base import elements_to_json

#让我们加载 PDF,然后对其进行分区。这是来自 Salesforce 收入报告的 PDF 文件 
filename = "static/SalesforceFinancial.pdf"

# Extracts the elements from the PDF
elements = partition_pdf(
    filename=filename,

    # Unstructured Helpers
    strategy="hi_res", 
    infer_table_structure=True, 
    model_name="yolox"
)

elements[-4].metadata.text_as_html
'<table><thead><th>Revenue)</th><th>Guidance $7.69 - $7.70 Billion</th><th>Guidance $31.7 - $31.8 Billion</th></thead><tr><td>Y/Y Growth</td><td>~21%</td><td>~20%</td></tr><tr><td>FX Impact?)</td><td>~($200M) y/y FX</td><td>~($600M) y/y FX®</td></tr><tr><td>GAAP operating margin</td><td></td><td>~3.8%</td></tr><tr><td>Non-GAAP operating margin)</td><td></td><td>~20.4%</td></tr><tr><td>GAAP earnings (loss) per share</td><td>($0.03) - ($0.02)</td><td>$0.38 - $0.40</td></tr><tr><td>Non-GAAP earnings per share</td><td>$1.01 - $1.02</td><td>$4.74 - $4.76</td></tr><tr><td>Operating Cash Flow Growth (Y/Y)</td><td></td><td>~21% - 22%</td></tr><tr><td>Current Remaining Performance Obligation Growth (Y/Y)</td><td>~15%</td><td></td></tr></table>'

该表可能看起来很混乱,但由于它是 HTML 格式,因此 LLM 能够比制表符或逗号分隔更容易地解析它。您可以将该 html 复制并粘贴到在线 html 查看器中以查看其重建情况。

Multi-Modal (text + images)

接下来,我们将深入探讨多模态文本拆分的领域。这是一个非常活跃的领域,最佳实践正在不断发展。我将向您展示一种由LangChain的Lance Martin广泛采用的方法。您可以在这里here.查看他的源代码。如果您找到更好的方法,请与社区分享

#!pip3 install "unstructured[all-docs]"
from typing import Any

from pydantic import BaseModel
from unstructured.partition.pdf import partition_pdf

首先,让我们获取一个PDF文件进行操作。这将来自一篇关于视觉指导调整的论文paper.。

filepath = "static/VisualInstruction.pdf"

# 获取元素
raw_pdf_elements = partition_pdf(
    filename=filepath,
    
    # 使用PDF格式查找嵌入的图像块
    extract_images_in_pdf=True,
    
    # 使用布局模型(YOLOX)获取边界框(用于表格)并查找标题
    # 标题是文档的任何子部分
    infer_table_structure=True,
    
    # 后处理以在获取标题后聚合文本
    chunking_strategy="by_title",
    # 用于聚合文本块的分块参数
    # 尝试创建新块3800个字符
    # 尝试保持块> 2000个字符
    # 块的硬性上限
    max_characters=4000,
    new_after_n_chars=3800,
    combine_text_under_n_chars=2000,
    image_output_dir_path="static/pdfImages/",
)

如果你到 static/pdfImages/ 文件夹并查看解析的图像。

但图像只是放在一个文件夹里什么都做不了,我们需要对它们做点什么!虽然这有点超出了分块的范围,但让我们谈谈如何处理这些图像。

常见的策略要么使用多模型来生成图像的摘要,要么将图像本身用于您的任务。其他人获取图像的嵌入(如CLIP)。

让我们生成摘要,这样你就会受到启发,将其推进到下一步。我们将使用GPT-4V。在这里查看其他模型。
 

from langchain.chat_models import ChatOpenAI
from langchain.schema.messages import HumanMessage
import os
from dotenv import load_dotenv
from PIL import Image
import base64
import io

load_dotenv()

输出true

接下来我们使用gpt-4-vision

llm = ChatOpenAI(model="gpt-4-vision-preview")


# Function to convert image to base64
def image_to_base64(image_path):
    with Image.open(image_path) as image:
        buffered = io.BytesIO()
        image.save(buffered, format=image.format)
        img_str = base64.b64encode(buffered.getvalue())
        return img_str.decode('utf-8')

image_str = image_to_base64("../RetrievalTutorials/static/pdfImages/figure-15-6.jpg")

#我正在创建一个快速的辅助函数,将图像从文件转换为base64,以便我们可以将其传递给GPT-4V。

chat = ChatOpenAI(model="gpt-4-vision-preview",
                  max_tokens=1024)

msg = chat.invoke(
    [
        HumanMessage(
            content=[
                {"type": "text", "text" : "Please give a summary of the image provided. Be descriptive"},
                {
                    "type": "image_url",
                    "image_url": {
                        "url": f"data:image/jpeg;base64,{image_str}"
                    },
                },
            ]
        )
    ]
)

#然后,返回的摘要就是我们将放入向量数据库的内容。当进行检索过程时,我们将使用这些嵌入进行语义搜索。

msg.content
图中显示了一个烤盘,上面摆放着一些食物碎片(可能是饼干或其他烘焙食品),松散地排列成类似地球大陆的形状,就像从太空中看到的地球一样。这个排列并不准确,但是它是一种充满趣味的表现,不规则的形状旨在模仿大陆的轮廓。在盘子上方有一段文字,写着:“有时候我只是看着太空中的地球图片,惊叹于一切的美丽。”这段文字增添了一些幽默色彩,因为观众并不是在从太空中看地球,而是在欣赏一幅富有创意的、地球的想象图景。

嗯,看来是这样啊!有很多方法可以实现这一点。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值