Spaces:
Running on Zero
Running on Zero
Update shipper_data.py
Browse files- shipper_data.py +2 -147
shipper_data.py
CHANGED
|
@@ -8,11 +8,9 @@ import re
|
|
| 8 |
|
| 9 |
from pdf_engine import detect_igst_status, extract_header_value
|
| 10 |
from test_suite import render_universal_test_suite
|
| 11 |
-
from ai_engine import ask_local_ai, create_new_parser_file_on_github, WEB_APP_URL
|
| 12 |
-
from ai_parser_agent import render_ai_parser_agent_ui
|
| 13 |
from google_sheet_sync import (
|
| 14 |
fetch_all_from_sheet, push_rules_to_sheet, push_template_file_to_sheet,
|
| 15 |
-
load_template_bytes_from_sheet
|
| 16 |
)
|
| 17 |
import requests
|
| 18 |
|
|
@@ -74,26 +72,6 @@ def load_local_shippers():
|
|
| 74 |
def ensure_default_shipper():
|
| 75 |
load_local_shippers()
|
| 76 |
|
| 77 |
-
@st.dialog("➕ Add New Custom Header Field")
|
| 78 |
-
def add_custom_header_field_dialog(selected_shipper):
|
| 79 |
-
st.write("यहाँ नया हेडर फ़ील्ड जोड़ें:")
|
| 80 |
-
new_field = st.text_input("Field Name (उदा: Invoice No, GST Inv No):")
|
| 81 |
-
doc_source = st.selectbox(
|
| 82 |
-
"यह डेटा किस डॉक्यूमेंट से लिया जाएगा?",
|
| 83 |
-
["Main Invoice", "GST Invoice (PDF/Excel)", "DEEC Declaration (PDF/Excel)"]
|
| 84 |
-
)
|
| 85 |
-
if st.button("Confirm & Add Field", type="primary"):
|
| 86 |
-
if not new_field.strip():
|
| 87 |
-
st.error("फ़ील्ड नाम खाली नहीं हो सकता!")
|
| 88 |
-
else:
|
| 89 |
-
rules = st.session_state["shipper_database"][selected_shipper].setdefault("mapping_rules", {})
|
| 90 |
-
rules[new_field.strip()] = {
|
| 91 |
-
"logic": doc_source, "keyword": "", "cell": "", "ai_prompt": "", "result_example": "", "extracted_logic": ""
|
| 92 |
-
}
|
| 93 |
-
save_local_shippers()
|
| 94 |
-
st.success(f"🎉 फ़ील्ड '{new_field}' गूगल शीट पर सिंक हो गया!")
|
| 95 |
-
st.rerun()
|
| 96 |
-
|
| 97 |
def render_shipper_data():
|
| 98 |
load_local_shippers()
|
| 99 |
|
|
@@ -145,132 +123,9 @@ def render_shipper_data():
|
|
| 145 |
else:
|
| 146 |
st.error("❌ अपलोड फेल हो गया!")
|
| 147 |
|
| 148 |
-
# 🧪 2. PDF Upload & Text Inspector
|
| 149 |
-
st.write("---")
|
| 150 |
-
st.subheader("🧪 2. Sample PDF Upload & Text Viewer")
|
| 151 |
-
test_pdf = st.file_uploader("➡️ टेस्ट करने के लिए सैंपल इनवॉइस PDF अपलोड करें", type=["pdf"], key=f"test_pdf_{selected_shipper}")
|
| 152 |
-
|
| 153 |
-
if test_pdf:
|
| 154 |
-
st.session_state["cached_pdf_bytes"] = test_pdf.getvalue()
|
| 155 |
-
pdf_lines, pdf_text = [], ""
|
| 156 |
-
with pdfplumber.open(test_pdf) as pdf:
|
| 157 |
-
for page in pdf.pages:
|
| 158 |
-
t = page.extract_text()
|
| 159 |
-
if t:
|
| 160 |
-
pdf_text += t + "\n"
|
| 161 |
-
pdf_lines.extend(t.split("\n"))
|
| 162 |
-
st.session_state["cached_pdf_lines"] = pdf_lines
|
| 163 |
-
st.session_state["cached_pdf_text"] = pdf_text
|
| 164 |
-
st.success(f"📄 PDF लोड हो गई है ({len(pdf_lines)} पंक्तियाँ)।")
|
| 165 |
-
|
| 166 |
-
curr_pdf_text = st.session_state.get("cached_pdf_text", "")
|
| 167 |
-
if curr_pdf_text:
|
| 168 |
-
with st.expander("👁️ View PDF Raw Text (यहाँ से वैल्यू देखें)", expanded=False):
|
| 169 |
-
st.text_area("PDF Raw Text:", value=curr_pdf_text[:4000], height=180, key=f"raw_txt_{selected_shipper}")
|
| 170 |
-
|
| 171 |
-
# ⚡ 3. Smart Test & Save Generator Box
|
| 172 |
-
st.write("---")
|
| 173 |
-
st.subheader("⚡ 3. Smart Test & Save Generator (Box & Position)")
|
| 174 |
-
st.caption("कीवर्ड, दिशा (आगे/नीचे/डब्बा) और वर्ड इंडेक्स सेट करके टेस्ट करें:")
|
| 175 |
-
|
| 176 |
-
gen_col1, gen_col2, gen_col3, gen_col4 = st.columns([1.5, 1.5, 1.2, 0.8])
|
| 177 |
-
with gen_col1:
|
| 178 |
-
target_val_input = st.text_input("1. टारगेट वैल्यू:", key=f"t_val_{selected_shipper}")
|
| 179 |
-
with gen_col2:
|
| 180 |
-
keyword_input = st.text_input("2. मुख्य कीवर्ड:", key=f"t_kw_{selected_shipper}")
|
| 181 |
-
with gen_col3:
|
| 182 |
-
pos_direction = st.selectbox("3. दिशा / तरीका:", ["Right (आगे)", "Below (नीचे)", "📦 Extract Inside Box (डब्बा)"], key=f"t_dir_{selected_shipper}")
|
| 183 |
-
with gen_col4:
|
| 184 |
-
word_offset = st.number_input("4. Index:", min_value=1, max_value=20, value=1, key=f"t_off_{selected_shipper}")
|
| 185 |
-
|
| 186 |
-
test_state_key = f"tested_code_{selected_shipper}"
|
| 187 |
-
|
| 188 |
-
if st.button("🧪 Test Extraction First", type="secondary", key=f"btn_test_{selected_shipper}"):
|
| 189 |
-
if not keyword_input.strip():
|
| 190 |
-
st.error("कृपया कीवर्ड दर्ज करें!")
|
| 191 |
-
else:
|
| 192 |
-
escaped_kw = re.escape(keyword_input.strip())
|
| 193 |
-
pdf_bytes_cache = st.session_state.get("cached_pdf_bytes", None)
|
| 194 |
-
|
| 195 |
-
if "Box" in pos_direction and pdf_bytes_cache:
|
| 196 |
-
try:
|
| 197 |
-
extracted_box_val = extract_header_value(
|
| 198 |
-
st.session_state.get("cached_pdf_lines", []),
|
| 199 |
-
curr_pdf_text,
|
| 200 |
-
keyword_input.strip(),
|
| 201 |
-
"📦 Extract Inside Box (डब्बे के अंदर का टेक्स्ट)",
|
| 202 |
-
"Exact Word",
|
| 203 |
-
"",
|
| 204 |
-
"None",
|
| 205 |
-
pdf_bytes=pdf_bytes_cache
|
| 206 |
-
)
|
| 207 |
-
generated_code = (
|
| 208 |
-
f'import pdfplumber, io, re\n'
|
| 209 |
-
f'# Smart Box Extraction Logic for "{keyword_input.strip()}"\n'
|
| 210 |
-
f'value = """{extracted_box_val}""".strip()'
|
| 211 |
-
)
|
| 212 |
-
except Exception:
|
| 213 |
-
generated_code = f'value = None'
|
| 214 |
-
elif "Below" in pos_direction:
|
| 215 |
-
generated_code = (
|
| 216 |
-
f'import re\n'
|
| 217 |
-
f'lines = text.split("\\n")\n'
|
| 218 |
-
f'found_line = ""\n'
|
| 219 |
-
f'for idx, l in enumerate(lines):\n'
|
| 220 |
-
f' if re.search(r"{escaped_kw}", l, re.IGNORECASE):\n'
|
| 221 |
-
f' if idx + 1 < len(lines):\n'
|
| 222 |
-
f' found_line = lines[idx + 1].strip()\n'
|
| 223 |
-
f' break\n'
|
| 224 |
-
f'words = found_line.split()\n'
|
| 225 |
-
f'value = words[{word_offset - 1}] if len(words) >= {word_offset} else (found_line if found_line else None)'
|
| 226 |
-
)
|
| 227 |
-
else:
|
| 228 |
-
generated_code = (
|
| 229 |
-
f'import re\n'
|
| 230 |
-
f'text_clean = re.sub(r"\\s+", " ", text)\n'
|
| 231 |
-
f'pattern = r"{escaped_kw}(?:[^A-Za-z0-9]+[A-Za-z0-9]+){{{word_offset - 1}}}[^A-Za-z0-9]+([0-9A-Z\\-/\\., ]{{2,35}})"\n'
|
| 232 |
-
f'match = re.search(pattern, text_clean)\n'
|
| 233 |
-
f'value = match.group(1).strip() if match else None'
|
| 234 |
-
)
|
| 235 |
-
|
| 236 |
-
st.session_state[test_state_key] = generated_code
|
| 237 |
-
|
| 238 |
-
try:
|
| 239 |
-
local_env = {"text": curr_pdf_text, "re": re}
|
| 240 |
-
exec(generated_code, {}, local_env)
|
| 241 |
-
found_res = local_env.get("value", "Not Found")
|
| 242 |
-
if found_res and found_res != "None":
|
| 243 |
-
st.success(f"✅ **Test Result Found:** 👉 **`{found_res}`** (यदि सही है, तो नीचे फील्ड चुनकर सेव करें)")
|
| 244 |
-
else:
|
| 245 |
-
st.warning("⚠️ इस विधि से वैल्यू नहीं मिली। कृपया तरीका या कीवर्ड बदल कर देखें।")
|
| 246 |
-
except Exception as ex:
|
| 247 |
-
st.error(f"Test Error: {str(ex)}")
|
| 248 |
-
|
| 249 |
-
# 4. फील्ड सेलेक्शन और सेव बटन
|
| 250 |
-
mapping_keys = list(shipper_info.get("mapping_rules", {}).keys())
|
| 251 |
-
target_field_to_update = st.selectbox("5. यह लॉजिक किस हेडर फील्ड (Field Name) पर सेव करना है?", mapping_keys if mapping_keys else ["Inv. No."], key=f"target_f_{selected_shipper}")
|
| 252 |
-
|
| 253 |
-
if st.button("💾 Confirm & Save to Shipper Rule", type="primary", use_container_width=True, key=f"btn_save_tested_{selected_shipper}"):
|
| 254 |
-
if test_state_key in st.session_state and st.session_state[test_state_key]:
|
| 255 |
-
final_code_to_save = st.session_state[test_state_key]
|
| 256 |
-
shipper_info["mapping_rules"][target_field_to_update]["extracted_logic"] = final_code_to_save
|
| 257 |
-
shipper_info["mapping_rules"][target_field_to_update]["result_example"] = target_val_input.strip()
|
| 258 |
-
shipper_info["mapping_rules"][target_field_to_update]["keyword"] = keyword_input.strip()
|
| 259 |
-
shipper_info["mapping_rules"][target_field_to_update]["position"] = pos_direction
|
| 260 |
-
|
| 261 |
-
save_local_shippers()
|
| 262 |
-
st.success(f"🎉 सफलता! '{target_field_to_update}' के लिए रूल गूगल शीट पर परमानेंट सेव हो गया है!")
|
| 263 |
-
else:
|
| 264 |
-
st.warning("⚠️ कृपया पह��े ऊपर 'Test Extraction First' बटन दबाकर रिजल्ट वैलिडेट करें!")
|
| 265 |
-
|
| 266 |
# 🛠️ 4. Header Fields Mapping Rules Table
|
| 267 |
st.write("---")
|
| 268 |
-
|
| 269 |
-
with c_title:
|
| 270 |
-
st.subheader("🛠️ 4. Header Fields Mapping & Regex Rules")
|
| 271 |
-
with c_add_h:
|
| 272 |
-
if st.button("➕ Add Header Field", type="secondary", use_container_width=True):
|
| 273 |
-
add_custom_header_field_dialog(selected_shipper)
|
| 274 |
|
| 275 |
current_rules = shipper_info.get("mapping_rules", {})
|
| 276 |
updated_rules = {}
|
|
|
|
| 8 |
|
| 9 |
from pdf_engine import detect_igst_status, extract_header_value
|
| 10 |
from test_suite import render_universal_test_suite
|
|
|
|
|
|
|
| 11 |
from google_sheet_sync import (
|
| 12 |
fetch_all_from_sheet, push_rules_to_sheet, push_template_file_to_sheet,
|
| 13 |
+
load_template_bytes_from_sheet
|
| 14 |
)
|
| 15 |
import requests
|
| 16 |
|
|
|
|
| 72 |
def ensure_default_shipper():
|
| 73 |
load_local_shippers()
|
| 74 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
def render_shipper_data():
|
| 76 |
load_local_shippers()
|
| 77 |
|
|
|
|
| 123 |
else:
|
| 124 |
st.error("❌ अपलोड फेल हो गया!")
|
| 125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
# 🛠️ 4. Header Fields Mapping Rules Table
|
| 127 |
st.write("---")
|
| 128 |
+
st.subheader("🛠️ 4. Header Fields Mapping & Regex Rules")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
|
| 130 |
current_rules = shipper_info.get("mapping_rules", {})
|
| 131 |
updated_rules = {}
|