๐ฑ SONAR-AI v18.2 | 2026-04-11 08:29:38
Browse files
app.py
CHANGED
|
@@ -240,14 +240,31 @@ def load_tsc_database():
|
|
| 240 |
try:
|
| 241 |
df = pd.read_excel(path, engine='openpyxl')
|
| 242 |
for _, row in df.iterrows():
|
| 243 |
-
|
|
|
|
|
|
|
|
|
|
| 244 |
if hs not in TSC_DATABASE:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 245 |
TSC_DATABASE[hs] = {
|
| 246 |
-
'desc':
|
| 247 |
-
'avg_price':
|
| 248 |
-
'
|
| 249 |
-
'
|
| 250 |
-
'
|
|
|
|
|
|
|
|
|
|
| 251 |
}
|
| 252 |
print(f"โ
TSC loaded: {len(TSC_DATABASE)} HS codes from {path}")
|
| 253 |
return
|
|
@@ -1211,16 +1228,20 @@ def lookup_hs(hs_code):
|
|
| 1211 |
def get_hs_info(cargo_key):
|
| 1212 |
if cargo_key not in CARGO_DATABASE:
|
| 1213 |
return {'en': cargo_key.upper(), 'ar': cargo_key, 'hs': '999999', 'ch': '99',
|
| 1214 |
-
'ch_name': '', 'duty': 15, 'tsc_desc': '', 'avg_price': 0,
|
|
|
|
| 1215 |
c = CARGO_DATABASE[cargo_key]
|
| 1216 |
tsc = lookup_hs(c['hs'])
|
| 1217 |
return {
|
| 1218 |
'en': cargo_key.upper().replace('_', ' '), 'ar': c['ar'], 'hs': c['hs'], 'ch': c['ch'],
|
| 1219 |
-
'ch_name': HS_CHAPTERS.get(c['ch'], ''), 'duty': c['duty'],
|
| 1220 |
'tsc_desc': tsc['desc'] if tsc else c['ar'],
|
| 1221 |
'avg_price': tsc['avg_price'] if tsc else 0,
|
| 1222 |
-
'
|
| 1223 |
-
'
|
|
|
|
|
|
|
|
|
|
| 1224 |
}
|
| 1225 |
|
| 1226 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
@@ -3480,10 +3501,10 @@ def analyze_full(img, declared_text):
|
|
| 3480 |
|
| 3481 |
# โโ ุฏู
ุฌ ุฐูู ูููุฆุงุช ุงูู
ุชุดุงุจูุฉ โโ
|
| 3482 |
_SMART_GROUPS = {
|
| 3483 |
-
'rice': (['seeds','rice','food','canned_food','sugar'],
|
| 3484 |
-
'banana': (['banana','fruit','food'],
|
| 3485 |
-
'pharmaceutical': (['pharmaceutical','medicine','medical','pharmacy'],
|
| 3486 |
-
'tobacco': (['tobacco','cigarette','snacks','smoking'],
|
| 3487 |
}
|
| 3488 |
|
| 3489 |
def smart_category(top5):
|
|
@@ -3580,11 +3601,24 @@ def analyze_full(img, declared_text):
|
|
| 3580 |
ar4 = info4.get('ar', best_cat14) or best_cat14
|
| 3581 |
hs4 = info4.get('hs', 'โ') or 'โ'
|
| 3582 |
duty4 = info4.get('duty', 0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3583 |
is_d4 = any(d in best_cat14.lower() for d in DANGER_48)
|
| 3584 |
bg4 = '#FFEBEE' if is_d4 else '#E8F5E9'
|
| 3585 |
clr4 = '#B71C1C' if is_d4 else '#1B5E20'
|
| 3586 |
icon4 = '๐จ' if is_d4 else 'โ
'
|
| 3587 |
smart_badge14 = f"<span style='background:#1565C0;color:white;font-size:11px;padding:2px 7px;border-radius:8px;margin-top:4px;display:inline-block;'>{smart_note14}</span>" if smart_note14 else ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3588 |
rows4 = ''.join([
|
| 3589 |
f"<div style='display:flex;justify-content:space-between;padding:4px 8px;"
|
| 3590 |
f"border-bottom:1px solid #F0F0F0;font-size:13px;'>"
|
|
@@ -3603,6 +3637,7 @@ def analyze_full(img, declared_text):
|
|
| 3603 |
<div style='font-size:12px;color:{clr4};margin-top:2px;'>HS: {hs4} | ุงูุฑุณูู
: {duty4}% | ุซูุฉ: {best_conf14:.1%}</div>
|
| 3604 |
{smart_badge14}
|
| 3605 |
</div>
|
|
|
|
| 3606 |
<div style='padding:4px 0;'>{rows4}</div>
|
| 3607 |
</div>"""
|
| 3608 |
except Exception as e:
|
|
@@ -3702,11 +3737,24 @@ def analyze_full(img, declared_text):
|
|
| 3702 |
ar17 = info17.get('ar', best_cat17) or best_cat17
|
| 3703 |
hs17 = info17.get('hs', 'โ') or 'โ'
|
| 3704 |
duty17 = info17.get('duty', 0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3705 |
is_d17 = any(d in best_cat17.lower() for d in DANGER_48)
|
| 3706 |
bg17 = '#FFEBEE' if is_d17 else '#E8F5E9'
|
| 3707 |
clr17 = '#B71C1C' if is_d17 else '#1B5E20'
|
| 3708 |
icon17 = '๐จ' if is_d17 else 'โ
'
|
| 3709 |
smart_badge17 = f"<span style='background:#1565C0;color:white;font-size:11px;padding:2px 7px;border-radius:8px;margin-top:4px;display:inline-block;'>{smart_note17}</span>" if smart_note17 else ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3710 |
rows17 = ''.join([
|
| 3711 |
f"<div style='display:flex;justify-content:space-between;padding:4px 8px;"
|
| 3712 |
f"border-bottom:1px solid #F0F0F0;font-size:13px;'>"
|
|
@@ -3747,6 +3795,7 @@ def analyze_full(img, declared_text):
|
|
| 3747 |
<div style='font-size:12px;color:{clr17};margin-top:2px;'>HS: {hs17} | ุงูุฑุณูู
: {duty17}% | ุซูุฉ: {best_conf17:.1%}</div>
|
| 3748 |
<div style='margin-top:5px;'>{smart_badge17}{agree_badge}</div>
|
| 3749 |
</div>
|
|
|
|
| 3750 |
<div style='padding:4px 0;'>{rows17}</div>
|
| 3751 |
<div style='background:{fusion_color};color:white;padding:8px 12px;text-align:center;font-weight:bold;font-size:14px;'>
|
| 3752 |
{fusion_icon} ุงูุญูู
ุงูููุงุฆู: {fusion_text}
|
|
|
|
| 240 |
try:
|
| 241 |
df = pd.read_excel(path, engine='openpyxl')
|
| 242 |
for _, row in df.iterrows():
|
| 243 |
+
try:
|
| 244 |
+
hs = str(int(float(str(row['IDE_HSC_NB1']).replace(',','')))).strip()
|
| 245 |
+
except:
|
| 246 |
+
continue
|
| 247 |
if hs not in TSC_DATABASE:
|
| 248 |
+
try: avg_p = round(float(str(row['AVR_MNT']).replace(',','')), 3)
|
| 249 |
+
except: avg_p = 0
|
| 250 |
+
try: min_p = round(float(str(row['CAL_MIN_VAL']).replace(',','')), 3)
|
| 251 |
+
except: min_p = 0
|
| 252 |
+
try: max_p = round(float(str(row['CAL_MAX_VAL']).replace(',','')), 3)
|
| 253 |
+
except: max_p = 0
|
| 254 |
+
try: duty = round(float(str(row['GDS_MRG']).replace(',','')), 1)
|
| 255 |
+
except: duty = 0
|
| 256 |
+
unit_name = ''
|
| 257 |
+
if pd.notna(row.get('AVR_UNT_NAM',None)): unit_name = str(row['AVR_UNT_NAM'])
|
| 258 |
+
elif pd.notna(row.get('AVR_UNT',None)): unit_name = str(row['AVR_UNT'])
|
| 259 |
TSC_DATABASE[hs] = {
|
| 260 |
+
'desc': str(row['GDS_DS2']).strip()[:120] if pd.notna(row['GDS_DS2']) else '',
|
| 261 |
+
'avg_price': avg_p,
|
| 262 |
+
'min_price': min_p,
|
| 263 |
+
'max_price': max_p,
|
| 264 |
+
'unit': unit_name,
|
| 265 |
+
'duty': duty,
|
| 266 |
+
'nb5': str(row['IDE_HSC_NB5']) if pd.notna(row['IDE_HSC_NB5']) else '',
|
| 267 |
+
'currency': str(row['GDS_CUR_COD']) if pd.notna(row.get('GDS_CUR_COD',None)) else 'USD',
|
| 268 |
}
|
| 269 |
print(f"โ
TSC loaded: {len(TSC_DATABASE)} HS codes from {path}")
|
| 270 |
return
|
|
|
|
| 1228 |
def get_hs_info(cargo_key):
|
| 1229 |
if cargo_key not in CARGO_DATABASE:
|
| 1230 |
return {'en': cargo_key.upper(), 'ar': cargo_key, 'hs': '999999', 'ch': '99',
|
| 1231 |
+
'ch_name': '', 'duty': 15, 'tsc_desc': '', 'avg_price': 0,
|
| 1232 |
+
'min_price': 0, 'max_price': 0, 'unit': '', 'tsc_code': '', 'currency': 'USD'}
|
| 1233 |
c = CARGO_DATABASE[cargo_key]
|
| 1234 |
tsc = lookup_hs(c['hs'])
|
| 1235 |
return {
|
| 1236 |
'en': cargo_key.upper().replace('_', ' '), 'ar': c['ar'], 'hs': c['hs'], 'ch': c['ch'],
|
| 1237 |
+
'ch_name': HS_CHAPTERS.get(c['ch'], ''), 'duty': tsc['duty'] if tsc else c['duty'],
|
| 1238 |
'tsc_desc': tsc['desc'] if tsc else c['ar'],
|
| 1239 |
'avg_price': tsc['avg_price'] if tsc else 0,
|
| 1240 |
+
'min_price': tsc['min_price'] if tsc else 0,
|
| 1241 |
+
'max_price': tsc['max_price'] if tsc else 0,
|
| 1242 |
+
'unit': tsc['unit'] if tsc else '',
|
| 1243 |
+
'currency': tsc['currency'] if tsc else 'USD',
|
| 1244 |
+
'tsc_code': tsc['nb5'] if tsc else '',
|
| 1245 |
}
|
| 1246 |
|
| 1247 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
|
|
| 3501 |
|
| 3502 |
# โโ ุฏู
ุฌ ุฐูู ูููุฆุงุช ุงูู
ุชุดุงุจูุฉ โโ
|
| 3503 |
_SMART_GROUPS = {
|
| 3504 |
+
'rice': (['seeds','rice','food','canned_food','sugar'], 'ุฑุฒ', '๐พ'),
|
| 3505 |
+
'banana': (['banana','fruit','food'], 'ู
ูุฒ', '๐'),
|
| 3506 |
+
'pharmaceutical': (['pharmaceutical','medicine','medical','pharmacy','drug'], 'ุฃุฏููุฉ ุจุดุฑูุฉ', '๐'),
|
| 3507 |
+
'tobacco': (['tobacco','cigarette','snacks','smoking'], 'ุณุฌุงุฆุฑ', '๐ฌ'),
|
| 3508 |
}
|
| 3509 |
|
| 3510 |
def smart_category(top5):
|
|
|
|
| 3601 |
ar4 = info4.get('ar', best_cat14) or best_cat14
|
| 3602 |
hs4 = info4.get('hs', 'โ') or 'โ'
|
| 3603 |
duty4 = info4.get('duty', 0)
|
| 3604 |
+
avg_p4 = info4.get('avg_price', 0)
|
| 3605 |
+
min_p4 = info4.get('min_price', 0)
|
| 3606 |
+
max_p4 = info4.get('max_price', 0)
|
| 3607 |
+
unit4 = info4.get('unit', '')
|
| 3608 |
+
cur4 = info4.get('currency', 'USD')
|
| 3609 |
is_d4 = any(d in best_cat14.lower() for d in DANGER_48)
|
| 3610 |
bg4 = '#FFEBEE' if is_d4 else '#E8F5E9'
|
| 3611 |
clr4 = '#B71C1C' if is_d4 else '#1B5E20'
|
| 3612 |
icon4 = '๐จ' if is_d4 else 'โ
'
|
| 3613 |
smart_badge14 = f"<span style='background:#1565C0;color:white;font-size:11px;padding:2px 7px;border-radius:8px;margin-top:4px;display:inline-block;'>{smart_note14}</span>" if smart_note14 else ""
|
| 3614 |
+
# ุณุนุฑ TSC
|
| 3615 |
+
if avg_p4 > 0:
|
| 3616 |
+
price_str = f"{avg_p4:.2f} {cur4}/{unit4}"
|
| 3617 |
+
if min_p4 > 0 and max_p4 > 0:
|
| 3618 |
+
price_str += f" (ูุทุงู: {min_p4:.2f}โ{max_p4:.2f})"
|
| 3619 |
+
price_row4 = f"<div style='background:#E3F2FD;padding:5px 10px;font-size:12px;color:#0D47A1;border-top:1px solid #E0E0E0;'>๐ฐ ู
ุชูุณุท ุงูุณุนุฑ: <b>{price_str}</b></div>"
|
| 3620 |
+
else:
|
| 3621 |
+
price_row4 = ""
|
| 3622 |
rows4 = ''.join([
|
| 3623 |
f"<div style='display:flex;justify-content:space-between;padding:4px 8px;"
|
| 3624 |
f"border-bottom:1px solid #F0F0F0;font-size:13px;'>"
|
|
|
|
| 3637 |
<div style='font-size:12px;color:{clr4};margin-top:2px;'>HS: {hs4} | ุงูุฑุณูู
: {duty4}% | ุซูุฉ: {best_conf14:.1%}</div>
|
| 3638 |
{smart_badge14}
|
| 3639 |
</div>
|
| 3640 |
+
{price_row4}
|
| 3641 |
<div style='padding:4px 0;'>{rows4}</div>
|
| 3642 |
</div>"""
|
| 3643 |
except Exception as e:
|
|
|
|
| 3737 |
ar17 = info17.get('ar', best_cat17) or best_cat17
|
| 3738 |
hs17 = info17.get('hs', 'โ') or 'โ'
|
| 3739 |
duty17 = info17.get('duty', 0)
|
| 3740 |
+
avg_p17= info17.get('avg_price', 0)
|
| 3741 |
+
min_p17= info17.get('min_price', 0)
|
| 3742 |
+
max_p17= info17.get('max_price', 0)
|
| 3743 |
+
unit17 = info17.get('unit', '')
|
| 3744 |
+
cur17 = info17.get('currency', 'USD')
|
| 3745 |
is_d17 = any(d in best_cat17.lower() for d in DANGER_48)
|
| 3746 |
bg17 = '#FFEBEE' if is_d17 else '#E8F5E9'
|
| 3747 |
clr17 = '#B71C1C' if is_d17 else '#1B5E20'
|
| 3748 |
icon17 = '๐จ' if is_d17 else 'โ
'
|
| 3749 |
smart_badge17 = f"<span style='background:#1565C0;color:white;font-size:11px;padding:2px 7px;border-radius:8px;margin-top:4px;display:inline-block;'>{smart_note17}</span>" if smart_note17 else ""
|
| 3750 |
+
# ุณุนุฑ TSC
|
| 3751 |
+
if avg_p17 > 0:
|
| 3752 |
+
price_str17 = f"{avg_p17:.2f} {cur17}/{unit17}"
|
| 3753 |
+
if min_p17 > 0 and max_p17 > 0:
|
| 3754 |
+
price_str17 += f" (ูุทุงู: {min_p17:.2f}โ{max_p17:.2f})"
|
| 3755 |
+
price_row17 = f"<div style='background:#E3F2FD;padding:5px 10px;font-size:12px;color:#0D47A1;border-top:1px solid #E0E0E0;'>๐ฐ ู
ุชูุณุท ุงูุณุนุฑ: <b>{price_str17}</b></div>"
|
| 3756 |
+
else:
|
| 3757 |
+
price_row17 = ""
|
| 3758 |
rows17 = ''.join([
|
| 3759 |
f"<div style='display:flex;justify-content:space-between;padding:4px 8px;"
|
| 3760 |
f"border-bottom:1px solid #F0F0F0;font-size:13px;'>"
|
|
|
|
| 3795 |
<div style='font-size:12px;color:{clr17};margin-top:2px;'>HS: {hs17} | ุงูุฑุณูู
: {duty17}% | ุซูุฉ: {best_conf17:.1%}</div>
|
| 3796 |
<div style='margin-top:5px;'>{smart_badge17}{agree_badge}</div>
|
| 3797 |
</div>
|
| 3798 |
+
{price_row17}
|
| 3799 |
<div style='padding:4px 0;'>{rows17}</div>
|
| 3800 |
<div style='background:{fusion_color};color:white;padding:8px 12px;text-align:center;font-weight:bold;font-size:14px;'>
|
| 3801 |
{fusion_icon} ุงูุญูู
ุงูููุงุฆู: {fusion_text}
|