Spaces:
Running on Zero
Running on Zero
File size: 13,111 Bytes
31f24ea 0d43588 373fe70 0d43588 31f24ea a8a7cff 31f24ea 373fe70 31f24ea 373fe70 31f24ea 373fe70 31f24ea 373fe70 31f24ea 0d43588 373fe70 0d43588 373fe70 28b18b7 373fe70 48bea4f 373fe70 48bea4f 373fe70 73446ee 373fe70 73446ee 373fe70 48bea4f 373fe70 73446ee 373fe70 0d43588 373fe70 48bea4f 373fe70 48bea4f 373fe70 0d43588 373fe70 48bea4f 373fe70 48bea4f 373fe70 48bea4f 0d43588 373fe70 48bea4f 373fe70 48bea4f 373fe70 48bea4f 0d43588 373fe70 48bea4f 373fe70 48bea4f 373fe70 48bea4f 373fe70 0d43588 373fe70 0d43588 373fe70 0d43588 373fe70 73446ee 373fe70 0d43588 373fe70 0d43588 373fe70 0d43588 373fe70 0d43588 373fe70 0d43588 373fe70 0d43588 | 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 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | import os
import json
import pdfplumber
import io
from io import BytesIO
import re
import gradio as gr
from pdf_engine import detect_igst_status, extract_header_value
from google_sheet_sync import (
fetch_all_from_sheet, push_rules_to_sheet, push_template_file_to_sheet,
load_template_bytes_from_sheet
)
import requests
LOCAL_DATA_DIR = "local_shipper_data"
TEMPLATES_DIR = os.path.join(LOCAL_DATA_DIR, "templates")
def ensure_local_directories():
if not os.path.exists(LOCAL_DATA_DIR):
os.makedirs(LOCAL_DATA_DIR)
if not os.path.exists(TEMPLATES_DIR):
os.makedirs(TEMPLATES_DIR)
def fetch_data_from_google_sheet():
try:
data = fetch_all_from_sheet()
if isinstance(data, dict) and data:
return data
except Exception as e:
pass
return {}
def load_shipper_database():
ensure_local_directories()
sheet_data = fetch_data_from_google_sheet()
shippers_dict = sheet_data.get("shippers", {}) if isinstance(sheet_data, dict) else {}
if shippers_dict:
return shippers_dict
else:
json_path = os.path.join(LOCAL_DATA_DIR, "shippers_rules.json")
if os.path.exists(json_path):
try:
with open(json_path, "r", encoding="utf-8") as f:
saved_data = json.load(f)
if isinstance(saved_data, dict) and saved_data:
return saved_data
except Exception:
pass
return {}
def save_shipper_database_to_sheet(shipper_database):
ensure_local_directories()
json_path = os.path.join(LOCAL_DATA_DIR, "shippers_rules.json")
try:
with open(json_path, "w", encoding="utf-8") as f:
json.dump(shipper_database, f, indent=4)
shippers_payload = {}
for s_name, s_data in shipper_database.items():
shippers_payload[s_name] = {
"mapping_rules": s_data.get("mapping_rules", {}),
"item_table_rules": s_data.get("item_table_rules", {}),
"item_table_rule_name": s_data.get("item_table_rule_name", "parser_welspun"),
"igst_config": s_data.get("igst_config", {})
}
push_rules_to_sheet(shippers_payload)
return True, "🎉 Rules successfully saved and synced to Google Sheet!"
except Exception as e:
return False, f"Save Error: {str(e)}"
def render_shipper_data():
db = load_shipper_database()
shippers_list = sorted(list(db.keys()))
gr.Markdown("### 🏢 Add Shipper Name & No-Code Visual Mapping Builder")
gr.Markdown("कीवर्ड, बॉक्स एक्सट्रैक्शन और पोजीशन के जरिए स्मार्ट टेस्ट और सेव टूल।")
# 1. Shipper Selection Dropdown (Jab tak select na ho, niche ka kuch nahi dikhega)
selected_shipper_dropdown = gr.Dropdown(
choices=shippers_list,
label="1. कॉन्फ़िगर करने के लिए शिपर चुनें:",
value=None,
interactive=True
)
# Config Section Wrapper (Initially Hidden)
with gr.Column(visible=False) as config_container:
shipper_title_md = gr.Markdown("### ⚙️ शिपर प्रोफाइल:")
# 📁 1. Template File Section
gr.Markdown("---")
gr.Markdown("### 📁 1. टेम्पलेट फ़ाइल अपलोड (Full Job Excel Template)")
with gr.Row() as tpl_upload_row:
tpl_file_input = gr.File(label="Blank Full Job Excel Format File (Template) चुनें", file_types=[".xlsx", ".xls"])
save_tpl_btn = gr.Button("🚀 Save Template to Google Sheet", variant="primary")
with gr.Row(visible=False) as tpl_status_row:
tpl_status_txt = gr.Textbox(label="Template Status", interactive=False, scale=3)
replace_tpl_file = gr.File(label="🔄 Replace Template", file_types=[".xlsx", ".xls"], scale=2)
confirm_replace_btn = gr.Button("🚀 Confirm & Replace", variant="secondary")
delete_tpl_btn = gr.Button("🗑️ Delete Template", variant="stop")
tpl_action_msg = gr.Textbox(label="Status Message", interactive=False)
# 🧪 2. Sample PDF Upload & Text Inspector
gr.Markdown("---")
gr.Markdown("### 🧪 2. Sample PDF Upload & Text Viewer")
with gr.Row():
test_pdf_input = gr.File(label="टेस्ट करने के लिए सैंपल इनवॉइस PDF अपलोड करें", file_types=[".pdf"], scale=1)
pdf_preview_box = gr.Textbox(label="Extracted PDF Text Preview", lines=4, scale=2, interactive=False)
# ⚡ 3. Smart Test & Save Generator
gr.Markdown("---")
gr.Markdown("### ⚡ 3. Smart Test & Save Generator (Box & Position)")
with gr.Row():
target_val_box = gr.Textbox(label="1. टारगेट वैल्यू:")
keyword_box = gr.Textbox(label="2. मुख्य कीवर्ड:")
direction_radio = gr.Radio(["Right (आगे)", "Below (नीचे)", "📦 Extract Inside Box (डब्बा)"], label="3. दिशा / तरीका:", value="Right (आगे)")
offset_num = gr.Number(value=1, label="4. Index:")
test_run_btn = gr.Button("🧪 Test Extraction First", variant="secondary")
test_output_box = gr.Textbox(label="Test Result", interactive=False)
target_field_dropdown = gr.Dropdown(choices=[], label="5. यह लॉजिक किस हेडर फील्ड पर सेव करना है?", interactive=True)
save_tested_rule_btn = gr.Button("💾 Confirm & Save to Shipper Rule", variant="primary")
# 🛠️ 4. Header Fields Mapping Rules Table
gr.Markdown("---")
gr.Markdown("### 🛠️ 4. Header Fields Mapping & Regex Rules")
header_rules_dataframe = gr.Dataframe(
headers=["Field Name", "Source Doc", "Keyword", "Cell", "Prompt", "Result Ex", "Local Python/Regex Logic"],
datatype=["str", "str", "str", "str", "str", "str", "str"],
row_count=5,
col_count=7,
interactive=True,
label="Header Mapping Rules"
)
# 📋 5. Dynamic Item Table Rules & Mapping
gr.Markdown("---")
gr.Markdown("### 📋 5. Dynamic Item Table Rules & Mapping")
parser_dropdown = gr.Dropdown(["parser_welspun", "parser_polycab", "parser_bkt", "parser_vapi_welspun"], label="इस शिपर के लिए आइटम पार्सर चुनें:")
item_rules_dataframe = gr.Dataframe(
headers=["Item Field Name", "Excel Col", "Source Type", "Extraction Rule / Keyword", "Result Example"],
datatype=["str", "str", "str", "str", "str"],
row_count=5,
col_count=5,
interactive=True,
label="Item Table Rules"
)
# ⚙️ 6. IGST & Lut Configuration
gr.Markdown("---")
gr.Markdown("### ⚙️ 6. IGST & Lut Configuration")
with gr.Row():
lut_kws_box = gr.Textbox(label="LUT Keywords (कॉमा से अलग करें):")
paid_kws_box = gr.Textbox(label="Paid Keywords (कॉमा से अलग करें):")
save_all_btn = gr.Button("💾 Save All Rules & Sync to Google Sheet", variant="primary", size="lg")
sync_status_box = gr.Textbox(label="Sync Status", interactive=False)
# --- Event Handlers & Dynamic Binding ---
def on_shipper_select(shipper_name):
if not shipper_name:
return (
gr.update(visible=False), "", gr.update(visible=True), gr.update(visible=False),
"", [], [], "parser_welspun", "", "", gr.update(choices=[])
)
current_db = load_shipper_database()
s_info = current_db.get(shipper_name, {})
# Template Check
t_bytes = load_template_bytes_from_sheet(shipper_name)
has_tpl = t_bytes is not None and len(t_bytes) > 0
tpl_msg = f"✅ 'Full Job Excel Format File (Template)' गूगल शीट पर अपलोडेड एवं सुरक्षित है।" if has_tpl else "ℹ️ इस शिपर के लिए अभी कोई टेम्पलेट अपलोड नहीं की गई है।"
# Header Rules Rows
mapping_rules = s_info.get("mapping_rules", {})
h_rows = [[f, v.get("logic", "Main Invoice"), v.get("keyword", ""), v.get("cell", ""), v.get("ai_prompt", ""), v.get("result_example", ""), v.get("extracted_logic", "")] for f, v in mapping_rules.items()]
if not h_rows: h_rows = [["", "Main Invoice", "", "", "", "", ""]]
# Item Rules Rows
item_rules = s_info.get("item_table_rules", {})
i_rows = [[i, v.get("col", "K"), v.get("type", "PDF Row Item"), v.get("rule", ""), v.get("result_example", "")] for i, v in item_rules.items()]
if not i_rows: i_rows = [["", "K", "PDF Row Item", "", ""]]
parser_name = s_info.get("item_table_rule_name", "parser_welspun")
igst_cfg = s_info.get("igst_config", {})
lut_val = igst_cfg.get("lut_keywords", "LUT, UNDER LUT, UNDER BOND")
paid_val = igst_cfg.get("paid_keywords", "SUPPLY MEANT FOR EXPORT ON PAYMENT OF IGST.")
field_choices = list(mapping_rules.keys())
return (
gr.update(visible=True),
f"### ⚙️ शिपर प्रोफाइल: **{shipper_name}**",
gr.update(visible=not has_tpl),
gr.update(visible=has_tpl),
tpl_msg,
h_rows,
i_rows,
parser_name,
lut_val,
paid_val,
gr.update(choices=field_choices, value=field_choices[0] if field_choices else None)
)
selected_shipper_dropdown.change(
fn=on_shipper_select,
inputs=selected_shipper_dropdown,
outputs=[
config_container, shipper_title_md, tpl_upload_row, tpl_status_row,
tpl_status_txt, header_rules_dataframe, item_rules_dataframe,
parser_dropdown, lut_kws_box, paid_kws_box, target_field_dropdown
]
)
# Template Save & Replace Handlers
def save_tpl_action(shipper_name, file_obj):
if not shipper_name or not file_obj:
return "❌ कृपया शिपर चुनें और फाइल अपलोड करें!"
with open(file_obj.name, "rb") as f:
success = push_template_file_to_sheet(shipper_name, f.read())
return "🎉 टेम्पलेट सफलतापूर्वक गूगल शीट पर सेव हो गई!" if success else "❌ अपलोड फेल हो गया!"
save_tpl_btn.click(fn=save_tpl_action, inputs=[selected_shipper_dropdown, tpl_file_input], outputs=tpl_action_msg)
confirm_replace_btn.click(fn=save_tpl_action, inputs=[selected_shipper_dropdown, replace_tpl_file], outputs=tpl_action_msg)
def delete_tpl_action(shipper_name):
if not shipper_name: return "❌ शिपर नहीं चुना गया।"
push_template_file_to_sheet(shipper_name, b"")
return "🗑️ टेम्पलेट डिलीट हो गई!"
delete_tpl_btn.click(fn=delete_tpl_action, inputs=[selected_shipper_dropdown], outputs=tpl_action_msg)
# Save All Rules Handler
def save_all_rules(shipper_name, h_data, i_data, parser_val, lut_val, paid_val):
if not shipper_name: return "❌ शिपर नहीं चुना गया।"
db = load_shipper_database()
s_info = db.setdefault(shipper_name, {})
# Map Header Rules
new_mapping = {}
for row in h_data:
if row and row[0]:
new_mapping[row[0]] = {
"logic": row[1], "keyword": row[2], "cell": row[3],
"ai_prompt": row[4], "result_example": row[5], "extracted_logic": row[6]
}
s_info["mapping_rules"] = new_mapping
# Map Item Rules
new_items = {}
for row in i_data:
if row and row[0]:
new_items[row[0]] = {
"col": row[1], "type": row[2], "rule": row[3], "result_example": row[4]
}
s_info["item_table_rules"] = new_items
s_info["item_table_rule_name"] = parser_val
s_info["igst_config"] = {"lut_keywords": lut_val, "paid_keywords": paid_val}
_, msg = save_shipper_database_to_sheet(db)
return msg
save_all_btn.click(
fn=save_all_rules,
inputs=[selected_shipper_dropdown, header_rules_dataframe, item_rules_dataframe, parser_dropdown, lut_kws_box, paid_kws_box],
outputs=sync_status_box
) |