import re import io import pdfplumber def apply_value_replacement(extracted_text, mapping_str): if not extracted_text or not mapping_str or "=" not in mapping_str: return extracted_text text_clean = str(extracted_text).strip() pairs = [p.strip() for p in mapping_str.split(",") if "=" in p] for pair in pairs: parts = pair.split("=") if len(parts) == 2: find_kw = parts[0].strip() replace_kw = parts[1].strip() if text_clean.lower() == find_kw.lower(): return replace_kw elif find_kw.lower() in text_clean.lower(): pattern = re.compile(re.escape(find_kw), re.IGNORECASE) return pattern.sub(replace_kw, text_clean) return text_clean def apply_rule_filter(raw_text, mode, stop_kw, flt, keyword=""): if flt == "Exact Keyword Paste (If Found)": target_check = stop_kw.strip() if stop_kw and str(stop_kw).strip() else keyword.strip() if target_check and target_check.lower() in str(raw_text).lower(): return target_check return target_check if target_check else "" if not raw_text: return "" text = raw_text.strip() if text.startswith(":"): text = text[1:].strip() if keyword and ("consignee" in keyword.lower() or "buyer" in keyword.lower()): return text if mode == "Word Position" or mode.startswith("Word "): w_num = int(stop_kw.strip()) if stop_kw and str(stop_kw).strip().isdigit() else 1 parts = text.split() text = parts[w_num - 1].strip() if len(parts) >= w_num else "" elif mode == "After Word" and stop_kw: if "=" not in stop_kw and stop_kw.lower() in text.lower(): start_idx = text.lower().find(stop_kw.lower()) + len(stop_kw) text = text[start_idx:].strip() if text.startswith(":"): text = text[1:].strip() elif mode == "Between Keywords" and stop_kw: if "=" not in stop_kw and stop_kw.lower() in text.lower(): text = text.lower().split(stop_kw.lower())[0].strip() elif mode == "Exact Word": parts = text.split() text = parts[0].strip() if parts else "" elif mode == "Full Line": text = text.split("\n")[0].strip() if flt in ["Text Inside Parentheses ()", "Inside Parentheses ()"]: bracket_match = re.search(r'\((.*?)\)', text) text = bracket_match.group(1).strip() if bracket_match else text.strip() elif flt == "Container Number (ISO Format)": cntr_match = re.search(r'\b[A-Za-z]{4}\s*\d{7}\b', text) text = cntr_match.group(0).replace(" ", "") if cntr_match else text.strip() elif flt == "Remove All Spaces": text = text.replace(" ", "").strip() elif flt == "Numbers Only": nums = re.findall(r'[\d,.]+', text) text = nums[0].strip() if nums else "" elif flt == "Letters Only": text = re.sub(r'[^A-Za-z\s]', '', text).strip() elif flt == "Clean Date (DD/MM/YYYY)": d_match = re.search(r'\b\d{2}[./-]\d{2}[./-]\d{4}\b', text) text = d_match.group(0).replace(".", "/").replace("-", "/") if d_match else text.strip() if stop_kw and "=" in stop_kw: text = apply_value_replacement(text, stop_kw) if flt and "=" in flt: text = apply_value_replacement(text, flt) return text.strip() def extract_header_value(pdf_lines, pdf_text, keyword, position, mode, stop_kw, filter_type, field_label="", pdf_bytes=None): raw_t = "" if keyword and pdf_bytes and ("Box" in str(position) or "डब्बा" in str(position)): try: with pdfplumber.open(io.BytesIO(pdf_bytes)) as pdf: page = pdf.pages[0] words = page.extract_words() kw_word = None for w in words: if keyword.lower() in w['text'].lower(): kw_word = w break if kw_word: kw_x0 = kw_word['x0'] kw_y0 = kw_word['top'] box_x0 = kw_x0 - 5 box_x1 = kw_x0 + 300 box_y0 = kw_y0 - 2 box_y1 = kw_y0 + 100 block_words = [] for w in words: if box_x0 <= w['x0'] <= box_x1 and box_y0 <= w['top'] <= box_y1: if keyword.lower() not in w['text'].lower(): block_words.append(w) if block_words: sorted_words = sorted(block_words, key=lambda x: (round(x['top']/6)*6, x['x0'])) extracted_phrase = " ".join([w['text'] for w in sorted_words]).strip() if extracted_phrase: extracted_phrase = re.sub(r'^[:\-\s]+', '', extracted_phrase) return apply_rule_filter(extracted_phrase, mode, stop_kw, filter_type, keyword) except Exception: pass if filter_type == "Exact Keyword Paste (If Found)": raw_t = pdf_text elif keyword: for line_i, line in enumerate(pdf_lines): if keyword.lower() in line.lower(): if "Right" in str(position) or position == "Right (आगे)": start_idx = line.lower().find(keyword.lower()) + len(keyword) raw_t = line[start_idx:].strip() if raw_t.startswith(":"): raw_t = raw_t[1:].strip() if raw_t: break elif "Below" in str(position) or position == "Below (नीचे)": if line_i + 1 < len(pdf_lines): raw_t = pdf_lines[line_i + 1].strip() if raw_t: break elif position == "2 Lines Below": if line_i + 2 < len(pdf_lines): raw_t = pdf_lines[line_i + 2].strip() if raw_t: break else: raw_t = pdf_text if position == "📦 Extract Inside Box (डब्बे के अंदर का टेक्स्ट)": return raw_t.strip() return apply_rule_filter(raw_t, mode, stop_kw, filter_type, keyword) def detect_igst_status(pdf_text, lut_keywords="", paid_keywords=""): if not pdf_text: return "UNKNOWN" text_lower = pdf_text.lower() custom_lut_kws = [k.strip().lower() for k in lut_keywords.split(",") if k.strip()] for kw in custom_lut_kws: if kw in text_lower: return "LUT" custom_paid_kws = [k.strip().lower() for k in paid_keywords.split(",") if k.strip()] for kw in custom_paid_kws: if kw in text_lower: return "P" return "UNKNOWN"