capita 1.25.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- capita-1.25.1/PKG-INFO +28 -0
- capita-1.25.1/README +1 -0
- capita-1.25.1/capita/__init__.py +79 -0
- capita-1.25.1/capita/__main__.py +13 -0
- capita-1.25.1/capita/__patch__.py +70 -0
- capita-1.25.1/capita/biblio/__init__.py +8 -0
- capita-1.25.1/capita/biblio/utils.py +76 -0
- capita-1.25.1/capita/chapter/__init__.py +8 -0
- capita-1.25.1/capita/chapter/outlines.py +129 -0
- capita-1.25.1/capita/chapter/run.py +123 -0
- capita-1.25.1/capita/chapter/starter.py +174 -0
- capita-1.25.1/capita/chapter/utils.py +45 -0
- capita-1.25.1/capita/cli.py +204 -0
- capita-1.25.1/capita/creator.py +95 -0
- capita-1.25.1/capita/feature/__init__.py +153 -0
- capita-1.25.1/capita/feature/abbreviation.py +195 -0
- capita-1.25.1/capita/feature/abstract.py +88 -0
- capita-1.25.1/capita/feature/acknowledge.py +44 -0
- capita-1.25.1/capita/feature/appendix.py +79 -0
- capita-1.25.1/capita/feature/chapter.py +72 -0
- capita-1.25.1/capita/feature/docinfo.py +57 -0
- capita-1.25.1/capita/feature/figuretable.py +79 -0
- capita-1.25.1/capita/feature/glossary.py +157 -0
- capita-1.25.1/capita/feature/index.py +71 -0
- capita-1.25.1/capita/feature/legal.py +149 -0
- capita-1.25.1/capita/feature/paper.py +57 -0
- capita-1.25.1/capita/feature/section.py +47 -0
- capita-1.25.1/capita/feature/symboltable.py +46 -0
- capita-1.25.1/capita/feature/tabletable.py +77 -0
- capita-1.25.1/capita/feature/title.py +159 -0
- capita-1.25.1/capita/feature/toc.py +101 -0
- capita-1.25.1/capita/feature/whitepage.py +168 -0
- capita-1.25.1/capita/paper/__init__.py +8 -0
- capita-1.25.1/capita/paper/fonts.py +32 -0
- capita-1.25.1/capita/paper/main.py +157 -0
- capita-1.25.1/capita/path.py +160 -0
- capita-1.25.1/capita/section/__init__.py +8 -0
- capita-1.25.1/capita/section/after.py +124 -0
- capita-1.25.1/capita/section/ctor.py +38 -0
- capita-1.25.1/capita/section/improve.py +151 -0
- capita-1.25.1/capita/section/load.py +120 -0
- capita-1.25.1/capita/section/run.py +141 -0
- capita-1.25.1/capita/strategy.py +177 -0
- capita-1.25.1/capita/table.py +28 -0
- capita-1.25.1/capita/utils/__init__.py +17 -0
- capita-1.25.1/capita/utils/headline.py +158 -0
- capita-1.25.1/capita/utils/spa.py +77 -0
- capita-1.25.1/capita/utils/text.py +112 -0
- capita-1.25.1/capita.egg-info/PKG-INFO +28 -0
- capita-1.25.1/capita.egg-info/SOURCES.txt +72 -0
- capita-1.25.1/capita.egg-info/dependency_links.txt +1 -0
- capita-1.25.1/capita.egg-info/entry_points.txt +2 -0
- capita-1.25.1/capita.egg-info/requires.txt +15 -0
- capita-1.25.1/capita.egg-info/top_level.txt +1 -0
- capita-1.25.1/pyproject.toml +110 -0
- capita-1.25.1/setup.cfg +4 -0
- capita-1.25.1/tests/test_abbreviation.py +109 -0
- capita-1.25.1/tests/test_abstract.py +68 -0
- capita-1.25.1/tests/test_appendix.py +50 -0
- capita-1.25.1/tests/test_chapter.py +179 -0
- capita-1.25.1/tests/test_cli.py +45 -0
- capita-1.25.1/tests/test_docinfo.py +26 -0
- capita-1.25.1/tests/test_glossary.py +55 -0
- capita-1.25.1/tests/test_headlines.py +34 -0
- capita-1.25.1/tests/test_index.py +74 -0
- capita-1.25.1/tests/test_legal.py +47 -0
- capita-1.25.1/tests/test_old.py +111 -0
- capita-1.25.1/tests/test_table.py +30 -0
- capita-1.25.1/tests/test_textonpage.py +52 -0
- capita-1.25.1/tests/test_textprocessor.py +46 -0
- capita-1.25.1/tests/test_title.py +103 -0
- capita-1.25.1/tests/test_toc.py +127 -0
- capita-1.25.1/tests/test_validate.py +80 -0
- capita-1.25.1/tests/test_whitepage.py +115 -0
capita-1.25.1/PKG-INFO
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: capita
|
|
3
|
+
Version: 1.25.1
|
|
4
|
+
Author-email: Helmut Konrad Schewe <helmutus@outlook.com>
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/anaticulae/capita
|
|
7
|
+
Project-URL: Repository, https://github.com/anaticulae/capita
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
11
|
+
Requires-Python: >=3.12
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: configos<2.0.0,>=1.0.4
|
|
14
|
+
Requires-Dist: elementae<2.0.0,>=1.0.1
|
|
15
|
+
Requires-Dist: geostrat<2.0.0,>=1.5.1
|
|
16
|
+
Requires-Dist: germania<2.0.0,>=1.32.0
|
|
17
|
+
Requires-Dist: iamraw<5.0.0,>=4.91.6
|
|
18
|
+
Requires-Dist: layouta<2.0.0,>=1.0.0
|
|
19
|
+
Requires-Dist: utilo<3.0.0,>=2.109.0
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: gennex==1.0.3; extra == "dev"
|
|
22
|
+
Requires-Dist: groupmes<2.0.0,>=1.1.0; extra == "dev"
|
|
23
|
+
Requires-Dist: hoverpower==1.4.3; extra == "dev"
|
|
24
|
+
Requires-Dist: pagenumber==1.0.0; extra == "dev"
|
|
25
|
+
Requires-Dist: rawmaker==2.40.3; extra == "dev"
|
|
26
|
+
Requires-Dist: utilotest<2.0.0,>=1.0.4; extra == "dev"
|
|
27
|
+
|
|
28
|
+
# sections
|
capita-1.25.1/README
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# sections
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#==============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
#------------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2019-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
#==============================================================================
|
|
9
|
+
"""Sections
|
|
10
|
+
========
|
|
11
|
+
|
|
12
|
+
The `sections` tool is a very lightwight tool to determine the
|
|
13
|
+
likelihood of a feature on a page very quickly. Sections is runned to
|
|
14
|
+
determine which feature extraction should runned on which pages.
|
|
15
|
+
|
|
16
|
+
Plan
|
|
17
|
+
----
|
|
18
|
+
|
|
19
|
+
The result of the section tool is a plan for the feature extractor.
|
|
20
|
+
Further plans for judgements and informations for the user are not
|
|
21
|
+
provided by sections tool. The section tool extracts only features but
|
|
22
|
+
do not judges the result.
|
|
23
|
+
|
|
24
|
+
Sources
|
|
25
|
+
-------
|
|
26
|
+
|
|
27
|
+
Data Provider:
|
|
28
|
+
|
|
29
|
+
* Rawmaker
|
|
30
|
+
* Linero
|
|
31
|
+
* Imagero (planned)
|
|
32
|
+
* Figero (planned)
|
|
33
|
+
* Tabelero (planned)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
Feature Provider:
|
|
37
|
+
|
|
38
|
+
* Groupme
|
|
39
|
+
* Detector
|
|
40
|
+
|
|
41
|
+
Planned Features
|
|
42
|
+
----------------
|
|
43
|
+
|
|
44
|
+
The following sections are planned to be supported:
|
|
45
|
+
|
|
46
|
+
.. code-block:: none
|
|
47
|
+
|
|
48
|
+
* Introduction
|
|
49
|
+
* Titlepage
|
|
50
|
+
* Thank you
|
|
51
|
+
* Copyright etc.
|
|
52
|
+
* Erklaerung
|
|
53
|
+
* Table-Area
|
|
54
|
+
* Table of content
|
|
55
|
+
* Short cuts
|
|
56
|
+
* Figure table
|
|
57
|
+
* Content
|
|
58
|
+
* Chapter
|
|
59
|
+
* Figure
|
|
60
|
+
* Text
|
|
61
|
+
* Headlines
|
|
62
|
+
* Table-Area-B
|
|
63
|
+
* Appendix
|
|
64
|
+
* Resources
|
|
65
|
+
* Link
|
|
66
|
+
* Bibliography
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
import importlib.metadata
|
|
70
|
+
import os
|
|
71
|
+
|
|
72
|
+
import capita.__patch__
|
|
73
|
+
import capita.path
|
|
74
|
+
|
|
75
|
+
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
|
76
|
+
|
|
77
|
+
PACKAGE = 'capita'
|
|
78
|
+
PROCESS = 'sections'
|
|
79
|
+
__version__ = importlib.metadata.version(PACKAGE)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#==============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
#------------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
#==============================================================================
|
|
9
|
+
|
|
10
|
+
from capita.cli import main
|
|
11
|
+
|
|
12
|
+
if __name__ == "__main__":
|
|
13
|
+
main()
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
import re
|
|
11
|
+
|
|
12
|
+
import germania
|
|
13
|
+
import utilo
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def authors(raw: str, verbose: bool = False) -> list:
|
|
17
|
+
"""\
|
|
18
|
+
>>> authors('PEREIRA, M.G., VOLCHAN, E., SOUZA, G. G. DE, OLIVEIRA, L.,'
|
|
19
|
+
... 'CAMPAGNOLI, R. R., PINHEIRO, W. M., & PESSOA, L. ')
|
|
20
|
+
['PEREIRA, M.G.', 'VOLCHAN, E.', 'SOUZA, G. G. DE', 'OLIVEIRA, L.', 'CAMPAGNOLI, R. R.', 'PINHEIRO, W. M.', 'PESSOA, L.']
|
|
21
|
+
"""
|
|
22
|
+
pattern = r"""
|
|
23
|
+
[a-zA-Z]{4,}\,
|
|
24
|
+
[ ]{0,2}
|
|
25
|
+
([a-zA-Z]\.[ ]{0,2}){1,3}
|
|
26
|
+
[ ]{0,2}
|
|
27
|
+
(DE)?
|
|
28
|
+
"""
|
|
29
|
+
result = []
|
|
30
|
+
for item in re.finditer(pattern, raw, re.VERBOSE):
|
|
31
|
+
item = utilo.extract_match(item).strip()
|
|
32
|
+
if verbose:
|
|
33
|
+
item = (item, item)
|
|
34
|
+
result.append(item)
|
|
35
|
+
return result
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
germania.authors = authors
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def a_minus_b(a: set | list, b: set | list) -> set | list:
|
|
42
|
+
result = []
|
|
43
|
+
for item in a:
|
|
44
|
+
if item in b:
|
|
45
|
+
continue
|
|
46
|
+
result.append(item)
|
|
47
|
+
if isinstance(a, set):
|
|
48
|
+
result: set = set(result)
|
|
49
|
+
return result
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
utilo.a_minus_b = a_minus_b
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def union(*items: set | list):
|
|
56
|
+
"""\
|
|
57
|
+
>>> union([1, 2, 3])
|
|
58
|
+
[1, 2, 3]
|
|
59
|
+
>>> union([1, 2, 3], [2, 2, 2])
|
|
60
|
+
[1, 2, 3]
|
|
61
|
+
"""
|
|
62
|
+
result = []
|
|
63
|
+
for item in items:
|
|
64
|
+
for it in item:
|
|
65
|
+
result.append(it)
|
|
66
|
+
result = utilo.make_unique(result)
|
|
67
|
+
return result
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
utilo.union = union
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2020-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
import configos
|
|
11
|
+
import iamraw
|
|
12
|
+
import utilo
|
|
13
|
+
|
|
14
|
+
DIFF_MAX = configos.HolyTable(
|
|
15
|
+
items=(
|
|
16
|
+
(1, 0),
|
|
17
|
+
(5, 0),
|
|
18
|
+
(6, 1),
|
|
19
|
+
(10, 2),
|
|
20
|
+
(12, 2),
|
|
21
|
+
),
|
|
22
|
+
right_outranges_none=False,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def cluster_bibpages(
|
|
27
|
+
items,
|
|
28
|
+
likelihood_name='bibliography_table',
|
|
29
|
+
):
|
|
30
|
+
"""Select hugest(max sum likelihood value) group."""
|
|
31
|
+
if not items:
|
|
32
|
+
return []
|
|
33
|
+
maxdiff = DIFF_MAX(len(items)) + 1
|
|
34
|
+
grouped = utilo.groupby_diff(
|
|
35
|
+
items,
|
|
36
|
+
maxdiff=maxdiff,
|
|
37
|
+
selector=lambda x: x.page,
|
|
38
|
+
)
|
|
39
|
+
if not grouped:
|
|
40
|
+
return []
|
|
41
|
+
hugest = sorted(
|
|
42
|
+
grouped,
|
|
43
|
+
key=lambda x: sum(item.content.value for item in x),
|
|
44
|
+
)
|
|
45
|
+
hugest = hugest[-1]
|
|
46
|
+
avg = sum((item.content.value for item in hugest)) / len(hugest)
|
|
47
|
+
avg = utilo.roundme(avg)
|
|
48
|
+
for item in hugest:
|
|
49
|
+
# every item of the group should have the same likelihood
|
|
50
|
+
item.content.value = avg
|
|
51
|
+
result = fill_empty(
|
|
52
|
+
hugest,
|
|
53
|
+
likelihood_name=likelihood_name,
|
|
54
|
+
)
|
|
55
|
+
return result
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def fill_empty(items: list, likelihood_name: str) -> list:
|
|
59
|
+
"""Fill holes inside connected bib."""
|
|
60
|
+
result = list(items)
|
|
61
|
+
start, end = result[0].page, result[-1].page
|
|
62
|
+
done = {item.page for item in result}
|
|
63
|
+
avg = result[0].content.value
|
|
64
|
+
for page in utilo.rlist(start, end):
|
|
65
|
+
if page in done:
|
|
66
|
+
continue
|
|
67
|
+
result.append(
|
|
68
|
+
iamraw.PageContentLikelihood(
|
|
69
|
+
page=page,
|
|
70
|
+
content=iamraw.Likelihood(
|
|
71
|
+
value=avg,
|
|
72
|
+
name=likelihood_name,
|
|
73
|
+
),
|
|
74
|
+
))
|
|
75
|
+
result.sort(key=lambda x: x.page)
|
|
76
|
+
return result
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2022-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2022-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
"""Chapter: Outlines
|
|
10
|
+
=================
|
|
11
|
+
|
|
12
|
+
Try to find text on the page which matches with lines from the outlines.
|
|
13
|
+
|
|
14
|
+
In most cases, if outlines are given, there represent the headlines
|
|
15
|
+
inside the document.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import re
|
|
19
|
+
|
|
20
|
+
import configos
|
|
21
|
+
import elementae.headline.lookup
|
|
22
|
+
import utilo
|
|
23
|
+
|
|
24
|
+
import capita.chapter.utils
|
|
25
|
+
|
|
26
|
+
TOCS_COUNT_MIN = configos.HV_INT_PLUS(default=3)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def rate_from_outlines(tocs, pagestart: list) -> float:
|
|
30
|
+
"""Try to find potential headline inside toc from outlines.
|
|
31
|
+
|
|
32
|
+
If no toc is given, use elementae.headlines-list as backup strategy.
|
|
33
|
+
"""
|
|
34
|
+
chapter_rate = 0.0
|
|
35
|
+
if len(tocs) >= TOCS_COUNT_MIN:
|
|
36
|
+
chapter_rate = contains_outline(pagestart, tocs)
|
|
37
|
+
return chapter_rate
|
|
38
|
+
# disable feature if no toc is given
|
|
39
|
+
utilo.info('chapter: no toc provided')
|
|
40
|
+
# try backup
|
|
41
|
+
matched = any(
|
|
42
|
+
utilo.similar(
|
|
43
|
+
expected=HEADLINES_BACKUP,
|
|
44
|
+
current=item.text,
|
|
45
|
+
maxdiff=0.9,
|
|
46
|
+
) for item in pagestart)
|
|
47
|
+
if matched:
|
|
48
|
+
return 1.0
|
|
49
|
+
return 0.0
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
HEADLINES_BACKUP = elementae.headline.lookup.CHAPTER
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def contains_outline(content, toc) -> float:
|
|
56
|
+
"""Check that content starts with a parsed headline entree.
|
|
57
|
+
|
|
58
|
+
Supported Pattern; line starts with:
|
|
59
|
+
* 3. Headline text
|
|
60
|
+
* Headline text
|
|
61
|
+
"""
|
|
62
|
+
flat_toc = level_remove(toc)
|
|
63
|
+
flat_toc = toc_shrink(flat_toc)
|
|
64
|
+
if not flat_toc:
|
|
65
|
+
# no table of content was extracted
|
|
66
|
+
return 0.0
|
|
67
|
+
flat_toc = [item for item in flat_toc if item.lower() not in NOHEADLINES]
|
|
68
|
+
for line in content:
|
|
69
|
+
line = utilo.normalize_whitespaces(line.text.strip())
|
|
70
|
+
if utilo.issinglechar(line):
|
|
71
|
+
# I N T R O D U C T I O N 1
|
|
72
|
+
line = line.replace(' ', '')
|
|
73
|
+
# remove numbered headline pattern and potential white spaces
|
|
74
|
+
without_number = FIRSTLEVEL_DOT_PATTERN.sub('', line)
|
|
75
|
+
for headline in flat_toc:
|
|
76
|
+
if all((
|
|
77
|
+
not capita.chapter.utils.startswith(line, headline),
|
|
78
|
+
not capita.chapter.utils.startswith(without_number,
|
|
79
|
+
headline),
|
|
80
|
+
)):
|
|
81
|
+
continue
|
|
82
|
+
rate = len(without_number) / len(headline)
|
|
83
|
+
if not 0.2 < rate < 2.0:
|
|
84
|
+
# headline is too long or too short, could not match with
|
|
85
|
+
# detected toc
|
|
86
|
+
continue
|
|
87
|
+
return 1.0
|
|
88
|
+
return -0.5
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
NOHEADLINES = utilo.a_minus_b( #pylint:disable=no-member
|
|
92
|
+
elementae.headline.lookup.HEADLINES,
|
|
93
|
+
elementae.headline.lookup.CHAPTER,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
FIRSTLEVEL_DOT_PATTERN = re.compile(r'^\d{1,2}\.{0,1}\s+')
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def level_remove(toc):
|
|
100
|
+
flat = []
|
|
101
|
+
for item in toc:
|
|
102
|
+
if not item.title.strip():
|
|
103
|
+
# invalid outlines can break further processing
|
|
104
|
+
utilo.debug('empty outline element')
|
|
105
|
+
continue
|
|
106
|
+
flat.append(FIRSTLEVEL_DOT_PATTERN.sub('', item.title))
|
|
107
|
+
# remove roman level
|
|
108
|
+
result = []
|
|
109
|
+
for item in flat:
|
|
110
|
+
splitted = item.split(maxsplit=1)
|
|
111
|
+
if len(splitted) == 1:
|
|
112
|
+
result.append(item)
|
|
113
|
+
continue
|
|
114
|
+
if utilo.isroman(splitted[0]):
|
|
115
|
+
result.append(splitted[1])
|
|
116
|
+
continue
|
|
117
|
+
result.append(item)
|
|
118
|
+
return result
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def toc_shrink(items):
|
|
122
|
+
"""Remove tocs after Anhang."""
|
|
123
|
+
result = []
|
|
124
|
+
for item in items:
|
|
125
|
+
if 'anhang' in item.lower():
|
|
126
|
+
# TODO: DANGEROUS! ANHANG CAN BE PART OF ANY OTHER HEADLINE
|
|
127
|
+
break
|
|
128
|
+
result.append(item)
|
|
129
|
+
return result
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# C O P Y R I G H T
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Copyright (c) 2022-2023 by Helmut Konrad Schewe. All rights reserved.
|
|
5
|
+
# This file is property of Helmut Konrad Schewe. Any unauthorized copy,
|
|
6
|
+
# use or distribution is an offensive act against international law and may
|
|
7
|
+
# be prosecuted under federal law. Its content is company confidential.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
import statistics
|
|
11
|
+
|
|
12
|
+
import configos
|
|
13
|
+
import iamraw
|
|
14
|
+
import texmex
|
|
15
|
+
import utilo
|
|
16
|
+
|
|
17
|
+
import capita.chapter.outlines
|
|
18
|
+
import capita.chapter.starter
|
|
19
|
+
|
|
20
|
+
FIRST_QUARTER = configos.HV_PERCENT_PLUS(default=45.0)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def extract_chapter(
|
|
24
|
+
navigators: texmex.PTNs,
|
|
25
|
+
outlines,
|
|
26
|
+
) -> iamraw.PageContentLikelihoods:
|
|
27
|
+
result = []
|
|
28
|
+
for page in navigators:
|
|
29
|
+
if nochapter(page):
|
|
30
|
+
continue
|
|
31
|
+
# prepare content
|
|
32
|
+
pagestart = page.before(FIRST_QUARTER)
|
|
33
|
+
# run strategies
|
|
34
|
+
rate = capita.chapter.starter.contain_chapter(pagestart)
|
|
35
|
+
rate += capita.chapter.outlines.rate_from_outlines(
|
|
36
|
+
outlines,
|
|
37
|
+
pagestart,
|
|
38
|
+
)
|
|
39
|
+
if rate <= 0.0:
|
|
40
|
+
# TODO: VERY VERBOSE, CHECK LATER
|
|
41
|
+
utilo.verbose(f' no chapter {page.page}: chapterate {rate}')
|
|
42
|
+
continue
|
|
43
|
+
# convert result to percents
|
|
44
|
+
rate_in_percent = chaptervalue_to_percent(rate, outlines)
|
|
45
|
+
result.append(
|
|
46
|
+
iamraw.PageContentLikelihood(
|
|
47
|
+
page=page.page,
|
|
48
|
+
content=iamraw.Likelihood(rate_in_percent, 'chapter'),
|
|
49
|
+
))
|
|
50
|
+
# TODO: There is the possiblity that header and start of chapter
|
|
51
|
+
# are together, support later
|
|
52
|
+
# result.append(0.0)
|
|
53
|
+
return result
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def nochapter(page) -> bool:
|
|
57
|
+
if not page:
|
|
58
|
+
# empty page
|
|
59
|
+
return True
|
|
60
|
+
if page.rotated:
|
|
61
|
+
utilo.verbose(f'no chapter {page.page}: rotated')
|
|
62
|
+
return True
|
|
63
|
+
pagestart = page.before(FIRST_QUARTER)
|
|
64
|
+
if no_textcontent(pagestart):
|
|
65
|
+
utilo.verbose(f'no chapter {page.page}: no textcontent')
|
|
66
|
+
return True
|
|
67
|
+
if contains_listof(pagestart):
|
|
68
|
+
if not capita.chapter.starter.startwith_hugenumber(pagestart):
|
|
69
|
+
utilo.verbose(f'no chapter {page.page}: list of dots')
|
|
70
|
+
# TODO: See todo below XXX???
|
|
71
|
+
# chapter_rate = 0
|
|
72
|
+
return True
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def no_textcontent(content: list) -> bool:
|
|
77
|
+
"""A chapter start requires some text line at the start.
|
|
78
|
+
|
|
79
|
+
This is required to skip false positive chapter starts which are
|
|
80
|
+
just a table or so.
|
|
81
|
+
"""
|
|
82
|
+
if len(content) < 5:
|
|
83
|
+
return False
|
|
84
|
+
avg = statistics.mean((len(item.text) for item in content))
|
|
85
|
+
if avg < 35:
|
|
86
|
+
# TODO: HOLY VALUE
|
|
87
|
+
return True
|
|
88
|
+
return False
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def chaptervalue_to_percent(chaptervalue: float, hastoc: bool) -> float:
|
|
92
|
+
"""Convert `chaptervalue` to percent.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
chaptervalue(float): value of detected features
|
|
96
|
+
hastoc(bool): if no toc is provided, some features can not be
|
|
97
|
+
processed.
|
|
98
|
+
Returns:
|
|
99
|
+
Likelihood of beeing a chapter start.?
|
|
100
|
+
"""
|
|
101
|
+
# TODO: HOLY VALUES
|
|
102
|
+
# TODO: IMPROVE THIS CONCEPT
|
|
103
|
+
if not hastoc and chaptervalue >= 1.0:
|
|
104
|
+
return 1.0
|
|
105
|
+
if chaptervalue >= 2.5:
|
|
106
|
+
return 1.0
|
|
107
|
+
if chaptervalue >= 0.5:
|
|
108
|
+
return 0.5
|
|
109
|
+
return 0.0
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def contains_listof(content: list) -> bool:
|
|
113
|
+
raw = rawcontent(content)
|
|
114
|
+
dots_with_spaces = raw.count('. . . .')
|
|
115
|
+
connected_dots = raw.count('....')
|
|
116
|
+
result = dots_with_spaces > 4 or connected_dots >= 3
|
|
117
|
+
return result
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def rawcontent(content) -> str:
|
|
121
|
+
raw = utilo.NEWLINE.join([item.text for item in content])
|
|
122
|
+
raw = raw.lower()
|
|
123
|
+
return raw
|