-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig.py
More file actions
144 lines (124 loc) · 6.09 KB
/
Copy pathconfig.py
File metadata and controls
144 lines (124 loc) · 6.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
"""
Centralized configuration for the PDF Processing Toolkit.
All paths, constants, and settings used by the modules are defined here.
To customize without editing this file, create a ``config_local.json`` in
the project root — any matching keys will override the defaults below.
Example ``config_local.json``::
{
"TESSERACT_PATH": "D:\\Tools\\tesseract\\tesseract.exe",
"MAX_WORKERS": 8,
"OCR_DPI": 200
}
"""
import json
import os
import sys
# ============================================================
# BASE DIRECTORY (works both from source and when frozen)
# ============================================================
# When PyInstaller builds a --onedir exe, sys.executable is the real,
# stable exe path on disk (unlike sys._MEIPASS in --onefile, which is a
# temp folder that gets deleted on exit). Everything bundled — vendor
# tools, config_local.json — lives next to that exe.
if getattr(sys, "frozen", False):
BASE_DIR = os.path.dirname(os.path.abspath(sys.executable))
else:
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
VENDOR_DIR = os.path.join(BASE_DIR, "vendor")
# ============================================================
# EXTERNAL TOOL PATHS
# ============================================================
# Prefer the bundled copy in vendor/. Fall back to a normal machine
# install if vendor/ isn't present (e.g. running from source on a dev
# machine that already has these tools installed system-wide).
_VENDOR_TESSERACT = os.path.join(VENDOR_DIR, "tesseract", "tesseract.exe")
_VENDOR_POPPLER = os.path.join(VENDOR_DIR, "poppler", "bin")
_VENDOR_GS = os.path.join(VENDOR_DIR, "ghostscript", "bin", "gswin64c.exe")
TESSERACT_PATH = _VENDOR_TESSERACT if os.path.isfile(_VENDOR_TESSERACT) \
else r"C:\Program Files\Tesseract-OCR\tesseract.exe"
POPPLER_PATH = _VENDOR_POPPLER if os.path.isdir(_VENDOR_POPPLER) \
else r"C:\poppler-26.02.0\Library\bin"
GHOSTSCRIPT_PATH = _VENDOR_GS if os.path.isfile(_VENDOR_GS) \
else r"C:\Program Files\gs\gs10.07.1\bin\gswin64c.exe"
# Tesseract needs to find its tessdata folder (language files). If we're
# using the bundled copy, point it there explicitly rather than relying
# on tesseract's own relative-path guessing.
_VENDOR_TESSDATA = os.path.join(VENDOR_DIR, "tesseract", "tessdata")
if os.path.isdir(_VENDOR_TESSDATA):
os.environ["TESSDATA_PREFIX"] = _VENDOR_TESSDATA
# ============================================================
# PDF PROCESSING DEFAULTS
# ============================================================
MAX_WORKERS = 4 # Parallel workers for extraction/matching
MAX_PAGES = 5 # Max pages to scan per PDF
TEXT_THRESHOLD = 50 # Min chars before trying next extraction method
OCR_DPI = 150 # DPI for OCR rendering (faster)
OCR_DPI_HIGH = 300 # Higher DPI for accuracy-critical OCR (brand reader)
# ============================================================
# DOCUMENT SCANNER — MATCH RULES
# ============================================================
MATCH_KEYWORDS = [
"Certificate of Product Registration",
"Certificate of Listing of Identical Drug Product",
]
MATCH_PATTERNS = [
r'Brand\s*Name\s*[:\-]',
r'Registration\s*Number\s*[:\-]\s*[A-Z0-9\-]+',
r'FDA\s+Registration\s+No\.?\s*[:\-]\s*[A-Z0-9\-]+',
r'valid\s+until\s+\d{1,2}\s+\w+\s+\d{4}',
r'Manufacturer\s*[:\-\d]',
r'Importer\s*(?:/\s*Distributor)?\s*[:\-\d]',
]
CHECKPOINT_FILE = "scan_checkpoint.json"
# ============================================================
# DOCUMENT SCANNER SETTINGS
# ============================================================
SEARCH_ROOT = "" # Drive/folder to scan. Leave empty to be prompted.
DEST_FOLDER = "" # Where matched PDFs go. Leave empty to be prompted.
SCAN_LOG_FILE = "scan_results.txt"
FILE_TIMEOUT = 30 # Seconds before giving up on a single PDF
MIN_FILE_SIZE = 1_024 # Skip PDFs smaller than this in bytes
MAX_FILE_SIZE = 0 # Skip PDFs larger than this in bytes. 0 = no limit.
MOVE_FILES = False # True = move, False = copy
SKIP_HIDDEN = True # Skip hidden/system folders
SKIP_DUPLICATES = True # Skip files whose content was already copied
MATCH_THRESHOLD = 2 # Minimum regex pattern hits required
# ============================================================
# BRAND READER — FIELD EXTRACTION PATTERNS
# ============================================================
FIELD_PATTERNS = {
"brand": r'Brand\s*Name\s*[:\-\d]\s*([^\n\r:]+)',
"reg_number": r'Registration\s*Number\s*[:\-]\s*([A-Z0-9\-]+)',
"reg_number_fda": r'FDA\s+Registration\s+No\.?\s*[:\-]\s*([A-Z0-9\-]+)',
"validity": r'valid\s+until\s+(\d{1,2}\s+\w+\s+\d{4})',
"manufacturer": r'Manufacturer\s*(?:Name\s*and\s*Address\s*)?[:\-]?\s*([^\n\r]{1,200}?)(?=\s{2,}|[\n\r]|$)',
"trader": r'Trader\s*[:\-\d]\s*([^\n\r:]+)',
"importer": r'Importer\s*(?:/\s*Distributor)?\s*[:\-\d]\s*([^\n\r:]+)',
"distributor": r'Distributor\s*[:\-\d]\s*([^\n\r:]+)',
}
BRAND_CACHE_FILE = ".brand_cache.json"
# ============================================================
# BRAND READER SETTINGS
# ============================================================
BRAND_LOG_FILE = "brand_results.xlsx"
# ============================================================
# BATCH PRINTER SETTINGS
# ============================================================
PRINTER_NAME = "DocuPrint M455 df"
MAX_ACTIVE_JOBS = 2
PRINT_FIRST_PAGE = 1
PRINT_LAST_PAGE = 1
# ============================================================
# OPTIONAL LOCAL OVERRIDES
# ============================================================
_LOCAL_CONFIG = os.path.join(BASE_DIR, "config_local.json")
if os.path.isfile(_LOCAL_CONFIG):
try:
with open(_LOCAL_CONFIG, encoding="utf-8") as _f:
_overrides = json.load(_f)
for _key, _val in _overrides.items():
_upper = _key.upper()
if _upper in globals():
globals()[_upper] = _val
except (json.JSONDecodeError, OSError) as exc:
print(f"Warning: Could not load config_local.json — {exc}")