1 个不稳定版本

0.0.0 2022年3月29日

#9 in #legal

自定义许可

170KB
2.5K SLoC

Python 1.5K SLoC // 0.3% comments Rust 712 SLoC // 0.1% comments Jupyter Notebooks 33 SLoC // 0.4% comments Forge Config 10 SLoC // 0.4% comments Shell 4 SLoC // 0.5% comments

eyecite

eyecite 是一个开源工具,用于从文本中提取法律引用。它被用于处理数百万份法律文件,包括来自CourtListener 和哈佛大学的Caselaw Access Project 的文件,并且是与这两个项目合作开发的。

eyecite 识别美国法律判决中常见的各种引用,包括

  • 完整案例Bush v. Gore, 531 U.S. 98, 99-100 (2000)
  • 简短案例531 U.S., at 99
  • 法规Mass. Gen. Laws ch. 1, § 2
  • 法律期刊1 Minn. L. Rev. 1
  • 上文Bush, supra, at 100
  • Id.Id., at 101

所有贡献者、纠正和新增内容都受欢迎!

功能

eyecite 提供四个核心功能

  • 提取:识别并从文本中提取引用,使用一个经过超过 5500 万现有引用训练的数据库(查看 eyecite 查找的所有引用模式,请参阅reporters_db)。
  • 聚合:根据它们的逻辑前体对具有共同引用的引用(例如,supraid. 引用)进行聚合。
  • 注释:使用围绕每个引用的定制标记来注释引用丰富的文本,使用快速差异算法。
  • 清理:清理和预处理文本,以便轻松使用 eyecite。

请继续阅读以下内容,了解如何快速开始或使用 eyecite 的简短教程。

贡献和支持

请参阅 GitHub 上的问题列表,了解我们需要的内容,或者在您有疑问或需要支持时开始对话。

如果您正在修复错误或添加功能,在您做出第一次贡献之前,我们将需要签署贡献者许可协议。请参阅仓库根目录中的模板,了解如何处理此事。

API

API 文档位于此处

https://freelawproject.github.io/eyecite/

每次我们发布新版本时都会自动生成。不幸的是,目前我们不支持旧版本的 API 文档,但如果需要,可以在 gh-pages 分支中浏览。

快速入门

安装 eyecite

pip install eyecite

以下是一个使用eyecite主函数 get_citations() 提取引用及其元数据的简单示例

from eyecite import get_citations

text = """
    Mass. Gen. Laws ch. 1, § 2 (West 1999) (barring ...).
    Foo v. Bar, 1 U.S. 2, 3-4 (1999) (overruling ...).
    Id. at 3.
    Foo, supra, at 5.
"""

get_citations(text)

# returns:
[
    FullLawCitation(
        'Mass. Gen. Laws ch. 1, § 2',
        groups={'reporter': 'Mass. Gen. Laws', 'chapter': '1', 'section': '2'},
        metadata=Metadata(parenthetical='barring ...', pin_cite=None, year='1999', publisher='West', ...)
    ),
    FullCaseCitation(
        '1 U.S. 2',
        groups={'volume': '1', 'reporter': 'U.S.', 'page': '2'},
        metadata=Metadata(parenthetical='overruling ...', pin_cite='3-4', year='1999', court='scotus', plaintiff='Foo', defendant='Bar,', ...)
    ),
    IdCitation(
        'Id.',
        metadata=Metadata(pin_cite='at 3')
    ),
    SupraCitation(
        'supra,',
        metadata=Metadata(antecedent_guess='Foo', pin_cite='at 5', ...)
    )
]

教程

要详细了解如何使用eyecite的所有功能,请参阅教程

文档

eyecite的完整API文档在此,但以下是一些关于其四个核心函数、其分词逻辑和其调试工具的详细信息。

提取引用

主执行函数 get_citations() 接收三个参数。

  1. plain_text ==> str: 要解析的文本。首先应该进行清理。
  2. remove_ambiguous ==> bool,默认 False:是否删除可能指向多个报告且无法通过日期缩小范围的引用。
  3. tokenizer ==> Tokenizer,默认 eyecite.tokenizers.default_tokenizer:Tokenizer对象的实例(见下文“分词器”)。

清理输入文本

对于给定的引用文本,例如 "... 1 Baldwin's Rep. 1 ...",eyecite期望在将其传递给 get_citation 之前,文本将是“清洁”的。这意味着

  • 空格将是单个空格字符,而不是多个空格或其他空白字符。
  • 引号和连字符将是标准的引号和连字符字符。
  • 引用中不应包含HTML标签等垃圾。

您可以使用 clean_text 来帮助完成此操作

from eyecite import clean_text, get_citations

source_text = '<p>foo   1  U.S.  1   </p>'
plain_text = clean_text(text, ['html', 'inline_whitespace', my_func])
found_citations = get_citations(plain_text)

有关如何使用从清理文本中提取的引用在原始文本中插入链接的说明,请参阅标注引用部分。

clean_text 目前接受以下作为清理器的值

  1. inline_whitespace:将所有制表符和空格字符的连续序列替换为一个空格字符
  2. all_whitespace:将所有空白字符的连续序列替换为一个空格字符
  3. underscores:删除两个或多个下划线,这是从PDF中提取的文本中常见的错误
  4. html:使用lxml库删除非可见HTML内容
  5. 自定义函数:接受字符串并返回字符串的任何函数。

标注引用

对于简单的纯文本,您可以使用 annotate 函数插入引用链接

from eyecite import get_citations, annotate

plain_text = 'bob lissner v. test 1 U.S. 12, 347-348 (4th Cir. 1982)'
citations = get_citations(plain_text)
linked_text = annotate(plain_text, [[c.span(), "<a>", "</a>"] for c in citations])

returns:
'bob lissner v. test <a>1 U.S. 12</a>, 347-348 (4th Cir. 1982)'

get_citations返回的每个引用都记录了其在源文本中的位置。因此,annotate 必须使用与 get_citations 提取引用相同的 相同 清理文本来调用。如果不这样做,引用的 span 方法的返回偏移量将与文本不匹配,您的标注将位于错误的位置。

如果您想清理文本然后向原始文本中插入标注,您可以将原始文本作为 source_text 传递

from eyecite import get_citations, annotate, clean_text

source_text = '<p>bob lissner v. <i>test   1 U.S.</i> 12,   347-348 (4th Cir. 1982)</p>'
plain_text = clean_text(source_text, ['html', 'inline_whitespace'])
citations = get_citations(plain_text)
linked_text = annotate(plain_text, [[c.span(), "<a>", "</a>"] for c in citations], source_text=source_text)

returns:
'<p>bob lissner v. <i>test   <a>1 U.S.</i> 12</a>,   347-348 (4th Cir. 1982)</p>'

上述示例从 plain_text 中提取引用并将其应用于 source_text,使用差异算法在原始文本的正确位置插入标注。

包装HTML标签

请注意,上述示例中包含不匹配的HTML标签:“<a>1 U.S.</i> 12</a>”。要指定对不平衡标签的处理,请使用 unbalanced_tags 参数

  • unbalanced_tags="skip":会导致标签不平衡的注释将不会被插入。
  • unbalanced_tags="wrap":不平衡的标签将被包裹,导致 <a>1 U.S.</a></i><a> 12</a>

重要提示:使用 unbalanced_tags="wrap" 时,它使用简单的正则表达式,并且仅适用于角度括号正确转义的HTML,例如由 lxml.html.tostring 生成的HTML。它旨在用于格式规范文档,例如法院发布的案例文本。对于故意构建的具有挑战性的输入(例如包含部分HTML注释或 <pre> 标签的引用)可能产生不可预测的结果。

自定义注释

如果插入文本前后不够,请在 annotator 参数下提供一个可调用的函数,该函数接受 (before, span_text, after) 并返回注释过的文本

def annotator(before, span_text, after):
    return before + span_text.lower() + after
linked_text = annotate(plain_text, [[c.span(), "<a>", "</a>"] for c in citations], annotator=annotator)

returns:
'bob lissner v. test <a>1 u.s. 12</a>, 347-348 (4th Cir. 1982)'

解决引用

一旦从文档中提取了引用,您可能希望将其解析为常见的参考文献。要这样做,只需将 get_citations() 的结果传递给 resolve_citations()。此函数将尽力将每个 "全"、"简略形式"、"supra" 和 "id" 引用解析为常见的 Resource 对象,并返回一个将资源映射到相关引用列表的字典

from eyecite import get_citations, resolve_citations

text = 'first citation: 1 U.S. 12. second citation: 2 F.3d 2. third citation: Id.'
found_citations = get_citations(text)
resolved_citations = resolve_citations(found_citations)

returns (pseudo):
{
    <Resource object>: [FullCaseCitation('1 U.S. 12')],
    <Resource object>: [FullCaseCitation('2 F.3d 2'), IdCitation('Id.')]
}

重要的是,eyecite 仅使用其对每个引用文本表示形式的内在知识来进行这些解析。如果您想执行更复杂的解析(例如,通过使用第三方API的信息增强每个引用),只需将自定义的 resolve_id_citation()resolve_supra_citation()resolve_shortcase_citation()resolve_full_citation() 函数作为关键字参数传递给 resolve_citations()。您还可以配置这些函数以返回更复杂资源对象(例如Django模型),只要该对象继承自 eyecite.models.ResourceType 类型(这仅要求可哈希性)。例如,您可能会实现如下自定义全引用解析函数,其中默认解析逻辑作为后备

def my_resolve(full_cite):
    # special handling for resolution of known cases in our database
    resource = MyOpinion.objects.get(full_cite)
    if resource:
        return resource
    # allow normal clustering of other citations
    return resolve_full_citation(full_cite)

resolve_citations(citations, resolve_full_citation=my_resolve)

returns (pseudo):
{
    <MyOpinion object>: [<full_cite>, <short_cite>, <id_cite>],
    <Resource object>: [<full cite>, <short cite>],
}

分词器

eyecite 在内部通过将一系列正则表达式应用于源文本,将其转换为标记列表来实现。

In [1]: from eyecite.tokenizers import default_tokenizer

In [2]: list(default_tokenizer.tokenize("Foo v. Bar, 123 U.S. 456 (2016). Id. at 457."))
Out[2]:
['Foo',
 StopWordToken(data='v.', ...),
 'Bar,',
 CitationToken(data='123 U.S. 456', volume='123', reporter='U.S.', page='456', ...),
 '(2016).',
 IdToken(data='Id.', ...),
 'at',
 '457.']

然后扫描这些标记以确定引用年份或案例名称等值,从而进行引用解析。

可以通过向 get_citations() 提供标记化器实例来替换其他标记化器。

from eyecite.tokenizers import HyperscanTokenizer
hyperscan_tokenizer = HyperscanTokenizer(cache_dir='.hyperscan')
cites = get_citations(text, tokenizer=hyperscan_tokenizer)

test_FindTest.py 包含了一个使用修改后的正则表达式提取包含 OCR 错误的引用的简化示例。

eyecite 随附了两个标记化器。

AhocorasickTokenizer(默认)

默认标记化器使用 pyahocorasick 库来过滤 eyecite 的提取器正则表达式列表。然后使用内置的 re 库进行提取。

HyperscanTokenizer

另一种 HyperscanTokenizer 将所有提取正则表达式编译成一个 hyperscan 数据库,以便在一次遍历中提取。这比默认标记化器快得多(具体快多少取决于目标文本中包含多少引用格式),但需要具有有限平台支持的 hyperscan 依赖项。有关 hyperscan 安装说明和限制,请参阅“安装”部分。

编译 hyperscan 数据库需要几秒钟,因此短运行脚本的脚本可能需要提供一个缓存目录,以便存储数据库。该目录只能由用户写入。

hyperscan_tokenizer = HyperscanTokenizer(cache_dir='.hyperscan')

调试

如果您想查看 eyecite 能够为每个引用提取哪些元数据,可以使用 dump_citations。这对于开发 eyecite 主要有用,但也可能有助于探索您可用的数据。

In [1]: from eyecite import dump_citations, get_citations

In [2]: text="Mass. Gen. Laws ch. 1, § 2. Foo v. Bar, 1 U.S. 2, 3-4 (1999). Id. at 3. Foo, supra, at 5."

In [3]: cites=get_citations(text)

In [4]: print(dump_citations(get_citations(text), text))
FullLawCitation: Mass. Gen. Laws ch. 1, § 2. Foo v. Bar, 1 U.S. 2, 3-4 (1
  * groups
    * reporter='Mass. Gen. Laws'
    * chapter='1'
    * section='2'
FullCaseCitation: Laws ch. 1, § 2. Foo v. Bar, 1 U.S. 2, 3-4 (1999). Id. at 3. Foo, s
  * groups
    * volume='1'
    * reporter='U.S.'
    * page='2'
  * metadata
    * pin_cite='3-4'
    * year='1999'
    * court='scotus'
    * plaintiff='Foo'
    * defendant='Bar,'
  * year=1999
IdCitation: v. Bar, 1 U.S. 2, 3-4 (1999). Id. at 3. Foo, supra, at 5.
  * metadata
    * pin_cite='at 3'
SupraCitation: 2, 3-4 (1999). Id. at 3. Foo, supra, at 5.
  * metadata
    * antecedent_guess='Foo'
    * pin_cite='at 5'

在实际终端中,每个提取引用的 span() 将被突出显示。您可以使用 context_chars=30 参数来控制显示多少文本在前后。

安装

安装 eyecite 很简单。

poetry add eyecite

或通过 pip

pip install eyecite

或从 github 安装最新版本的开发版本

pip install https://github.com/freelawproject/eyecite/archive/main.zip#egg=eyecite

Hyperscan 安装

要使用 HyperscanTokenizer,您还必须安装 python hyperscan 库及其依赖项。python-hyperscan 官方只支持 x86 Linux,尽管其他配置也可能可行。

x86 Ubuntu 20.04 上的 Hyperscan 安装示例

apt install libhyperscan-dev
pip install hyperscan

x86 Debian Buster 上的 Hyperscan 安装示例

echo 'deb http://deb.debian.org/debian buster-backports main' > /etc/apt/sources.list.d/backports.list
apt install -t buster-backports libhyperscan-dev
pip install hyperscan

使用 homebrew 在 x86 MacOS 上的 Hyperscan 安装示例

brew install hyperscan
pip install hyperscan

部署

  1. pyproject.toml 中更新版本信息。

对于自动化部署,使用 vx.y.z 标签提交,并将其推送到 master。将为您完成自动部署和文档更新。

对于手动部署,运行

poetry publish --build

您可能还需要将新的文档文件推送到 gh-pages 分支。

测试

eyecite 随附了一个健壮的测试套件,它配备了不同的引用字符串,可以处理这些字符串。按照以下方式运行这些测试

python3 -m unittest discover -s tests -p 'test_*.py'

如果您想创建模拟引用对象以帮助您编写自己的本地测试,可以导入并使用以下函数进行便利

from eyecite.test_factories import (
    case_citation,
    id_citation,
    supra_citation,
    unknown_citation,
)

许可证

此存储库可在宽松的 BSD 许可证下获得,使其易于且安全地集成到您自己的库中。

欢迎拉取请求和功能请求。在 GitHub 上的在线编辑是可能的(而且很简单)!

依赖关系

~4.5–6.5MB
~115K SLoC