DrAbbas commited on
Commit
2baea45
ยท
verified ยท
1 Parent(s): e0800d4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +565 -218
app.py CHANGED
@@ -1,7 +1,15 @@
1
  #!/usr/bin/env python3
2
  """
3
- SONAR-AI v12.5 - Multi-Label Classification
4
- ูŠุฏุนู… ุงูƒุชุดุงู ุฃุตู†ุงู ู…ุชุนุฏุฏุฉ ููŠ ุงู„ุญุงูˆูŠุฉ ุงู„ูˆุงุญุฏุฉ
 
 
 
 
 
 
 
 
5
  """
6
 
7
  import gradio as gr
@@ -9,263 +17,602 @@ import pandas as pd
9
  import numpy as np
10
  from datetime import datetime
11
  import random
 
 
12
 
13
- VERSION = "12.5"
14
 
15
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
16
- # ู‚ุงู…ูˆุณ ุงู„ุจุถุงุฆุน ู…ุน ุฃูƒูˆุงุฏ HS
17
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  CARGO_DATABASE = {
19
- 'shoes': {'ar': 'ุฃุญุฐูŠุฉ', 'hs': '640299', 'duty': 20},
20
- 'makeup_pads': {'ar': 'ููˆุท ู…ูƒูŠุงุฌ', 'hs': '300590', 'duty': 5},
21
- 'cotton_wipes': {'ar': 'ู…ู†ุงุฏูŠู„ ู‚ุทู†ูŠุฉ', 'hs': '330790', 'duty': 5},
22
- 'comb': {'ar': 'ู…ุดุท', 'hs': '96151100', 'duty': 15},
23
- 'hinge': {'ar': 'ู…ูุตู„ุฉ', 'hs': '830210', 'duty': 10},
24
- 'bolt': {'ar': 'ุจูˆู„ุช', 'hs': '830241', 'duty': 10},
25
- 'fabric': {'ar': 'ู‚ู…ุงุด', 'hs': '600192', 'duty': 20},
26
- 'bearing': {'ar': 'ุญุงู…ู„', 'hs': '848210', 'duty': 5},
27
- 'tv_stand': {'ar': 'ุญุงู…ู„ ุชู„ูุฒูŠูˆู†', 'hs': '940390', 'duty': 30},
28
- 'notebook': {'ar': 'ุฏูุงุชุฑ ู…ู„ุงุญุธุงุช', 'hs': '482010', 'duty': 10},
29
- 'daily_necessities': {'ar': 'ู…ุณุชู„ุฒู…ุงุช ูŠูˆู…ูŠุฉ', 'hs': '392410', 'duty': 15},
30
- 'plastic_flower': {'ar': 'ุฒู‡ุฑุฉ ุจู„ุงุณุชูŠูƒูŠุฉ', 'hs': '39264000', 'duty': 15},
31
- 'tent': {'ar': 'ุฎูŠู…ุฉ', 'hs': '630629', 'duty': 20},
32
- 'meat_grinder': {'ar': 'ู…ูุฑู…ุฉ ู„ุญู…', 'hs': '843850', 'duty': 5},
33
- 'vegetable_basin': {'ar': 'ุญูˆุถ ุฎุถุฑูˆุงุช', 'hs': '732393', 'duty': 15},
34
- 'led_light': {'ar': 'ุถูˆุก LED', 'hs': '940540', 'duty': 15},
35
- 'shelf': {'ar': 'ุฑู', 'hs': '940390', 'duty': 30},
36
- 'stationery': {'ar': 'ู‚ุฑุทุงุณูŠุฉ', 'hs': '482010', 'duty': 10},
37
- 'appliances': {'ar': 'ุฃุฌู‡ุฒุฉ ู…ู†ุฒู„ูŠุฉ', 'hs': '851660', 'duty': 20},
38
- 'food_grinder': {'ar': 'ู…ูุฑู…ุฉ ุงู„ุทุนุงู…', 'hs': '850940', 'duty': 10},
39
-
40
- # ุงู„ุฃุตู†ุงู ุงู„ุฃุตู„ูŠุฉ
41
- 'banana': {'ar': 'ู…ูˆุฒ', 'hs': '080390', 'duty': 5},
42
- 'furniture': {'ar': 'ุฃุซุงุซ', 'hs': '940360', 'duty': 30},
43
- 'electronics': {'ar': 'ุฅู„ูƒุชุฑูˆู†ูŠุงุช', 'hs': '854370', 'duty': 10},
44
- 'clothes': {'ar': 'ู…ู„ุงุจุณ', 'hs': '620342', 'duty': 20},
45
- 'rice': {'ar': 'ุฑุฒ', 'hs': '100630', 'duty': 10},
46
- 'tea': {'ar': 'ุดุงูŠ', 'hs': '090230', 'duty': 10},
47
- 'sugar': {'ar': 'ุณูƒุฑ', 'hs': '170199', 'duty': 5},
48
- 'ceramic': {'ar': 'ุณูŠุฑุงู…ูŠูƒ', 'hs': '691090', 'duty': 15},
49
- 'chemicals': {'ar': 'ูƒูŠู…ูŠุงุฆูŠุงุช', 'hs': '382499', 'duty': 5},
50
- 'toys': {'ar': 'ุฃู„ุนุงุจ', 'hs': '950300', 'duty': 20},
51
- 'tools': {'ar': 'ุฃุฏูˆุงุช', 'hs': '820559', 'duty': 10},
52
- 'pipes': {'ar': 'ุฃู†ุงุจูŠุจ', 'hs': '730890', 'duty': 10},
53
- 'glass': {'ar': 'ุฒุฌุงุฌ', 'hs': '701090', 'duty': 15},
54
- 'paper': {'ar': 'ูˆุฑู‚', 'hs': '480519', 'duty': 10},
55
- 'plastic': {'ar': 'ุจู„ุงุณุชูŠูƒ', 'hs': '392690', 'duty': 15},
56
- 'steel': {'ar': 'ุญุฏูŠุฏ', 'hs': '721049', 'duty': 5},
57
- 'wood': {'ar': 'ุฎุดุจ', 'hs': '440799', 'duty': 10},
58
- 'batteries': {'ar': 'ุจุทุงุฑูŠุงุช', 'hs': '850760', 'duty': 15},
59
- 'cosmetics': {'ar': 'ู…ุณุชุญุถุฑุงุช ุชุฌู…ูŠู„', 'hs': '330499', 'duty': 20},
60
- 'medical': {'ar': 'ู…ุณุชู„ุฒู…ุงุช ุทุจูŠุฉ', 'hs': '901890', 'duty': 0},
61
- 'meat': {'ar': 'ู„ุญูˆู…', 'hs': '020230', 'duty': 5},
62
- 'spices': {'ar': 'ุจู‡ุงุฑุงุช', 'hs': '090421', 'duty': 10},
63
- 'nuts': {'ar': 'ู…ูƒุณุฑุงุช', 'hs': '080212', 'duty': 10},
64
- 'snacks': {'ar': 'ูˆุฌุจุงุช ุฎููŠูุฉ', 'hs': '190590', 'duty': 15},
65
- 'beverages': {'ar': 'ู…ุดุฑูˆุจุงุช', 'hs': '220299', 'duty': 20},
66
- 'cooking_oil': {'ar': 'ุฒูŠุช ุทุนุงู…', 'hs': '150910', 'duty': 5},
67
- 'canned_food': {'ar': 'ู…ุนู„ุจุงุช', 'hs': '200799', 'duty': 15},
68
- 'cables': {'ar': 'ูƒุงุจู„ุงุช', 'hs': '854449', 'duty': 10},
69
- 'tires': {'ar': 'ุฅุทุงุฑุงุช', 'hs': '401110', 'duty': 15},
70
- 'auto_parts': {'ar': 'ู‚ุทุน ุบูŠุงุฑ', 'hs': '870899', 'duty': 5},
71
- 'machinery': {'ar': 'ุขู„ุงุช', 'hs': '847989', 'duty': 5},
72
- 'kitchenware': {'ar': 'ุฃุฏูˆุงุช ู…ุทุจุฎ', 'hs': '732393', 'duty': 15},
73
- 'bags': {'ar': 'ุญู‚ุงุฆุจ', 'hs': '420222', 'duty': 20},
74
- 'fruits': {'ar': 'ููˆุงูƒู‡', 'hs': '081090', 'duty': 5},
75
- 'vegetables': {'ar': 'ุฎุถุฑูˆุงุช', 'hs': '070999', 'duty': 5},
76
- 'seeds': {'ar': 'ุจุฐูˆุฑ', 'hs': '120991', 'duty': 5},
77
- 'milk': {'ar': 'ุญู„ูŠุจ', 'hs': '040120', 'duty': 5},
78
- 'cleaning': {'ar': 'ู…ูˆุงุฏ ุชู†ุธูŠู', 'hs': '340220', 'duty': 10},
79
- 'motorcycle': {'ar': 'ุฏุฑุงุฌุงุช ู†ุงุฑูŠุฉ', 'hs': '871190', 'duty': 20},
80
- 'other': {'ar': 'ุฃุฎุฑู‰', 'hs': '999999', 'duty': 15},
81
  }
82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  def get_stats():
84
- return {'total': 6707, 'match': 6034, 'mismatch': 673, 'high_risk': 294}
 
 
 
 
 
 
 
85
 
86
  def get_anomalies():
87
- return pd.DataFrame([{
88
- 'ุงู„ุฑู‚ู…': 6700-i, 'ุงู„ุญุงูˆูŠุฉ': f'TCNU{random.randint(1000000,9999999)}',
89
- 'ุนุฏุฏ_ุงู„ุฃุตู†ุงู': random.randint(3,12), 'ุงู„ุฎุทูˆุฑุฉ': random.randint(1,5),
90
- 'ุงู„ุชุงุฑูŠุฎ': datetime.now().strftime('%Y-%m-%d')
91
- } for i in range(30)])
 
 
 
 
 
 
 
92
 
93
  def get_categories():
94
- return pd.DataFrame([{
95
- 'ุงู„ุฑู‚ู…': i+1, 'EN': en, 'AR': info['ar'], 'HS': info['hs'], 'ุงู„ุฑุณูˆู…': f"{info['duty']}%"
96
- } for i, (en, info) in enumerate(CARGO_DATABASE.items())])
 
 
 
 
 
 
 
 
 
 
 
97
 
98
- def stats_html():
99
- s = get_stats()
100
- return f"""
101
- <div style='display:grid;grid-template-columns:repeat(4,1fr);gap:12px;'>
102
- <div style='background:linear-gradient(135deg,#3F51B5,#5C6BC0);padding:20px;border-radius:12px;text-align:center;color:white;'>
103
- <div style='font-size:32px;font-weight:bold;'>{s['total']:,}</div><div>ุฅุฌู…ุงู„ูŠ ุงู„ุญุงูˆูŠุงุช</div></div>
104
- <div style='background:linear-gradient(135deg,#4CAF50,#66BB6A);padding:20px;border-radius:12px;text-align:center;color:white;'>
105
- <div style='font-size:32px;font-weight:bold;'>{s['match']:,}</div><div>ู…ุทุงุจู‚</div></div>
106
- <div style='background:linear-gradient(135deg,#FF9800,#FFB74D);padding:20px;border-radius:12px;text-align:center;color:white;'>
107
- <div style='font-size:32px;font-weight:bold;'>{s['mismatch']:,}</div><div>ู…ุฎุงู„ู</div></div>
108
- <div style='background:linear-gradient(135deg,#F44336,#EF5350);padding:20px;border-radius:12px;text-align:center;color:white;'>
109
- <div style='font-size:32px;font-weight:bold;'>{s['high_risk']:,}</div><div>ุฎุทุฑ ุนุงู„ูŠ</div></div>
110
- </div>"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
 
112
  def analyze_multi_label(img, declared_text):
113
- """ุชุญู„ูŠู„ ู…ุชุนุฏุฏ ุงู„ุฃุตู†ุงู - Multi-Label Detection"""
114
  if img is None:
115
- return "โณ ุงุฑูุน ุตูˆุฑุฉ ู„ู„ุชุญู„ูŠู„...", pd.DataFrame()
116
-
117
- # ู…ุญุงูƒุงุฉ ุงูƒุชุดุงู ุฃุตู†ุงู ู…ุชุนุฏุฏุฉ (ููŠ ุงู„ูˆุงู‚ุน ุณูŠุณุชุฎุฏู… YOLO)
118
  all_items = list(CARGO_DATABASE.keys())
119
- num_detected = random.randint(4, 10)
120
  detected_items = random.sample(all_items, num_detected)
121
-
122
- # ุญุณุงุจ ุฅุฌู…ุงู„ูŠ ุงู„ุฑุณูˆู…
123
  total_duty = 0
124
  items_data = []
125
-
126
  for i, item in enumerate(detected_items):
127
- info = CARGO_DATABASE[item]
128
- conf = random.uniform(0.75, 0.99)
129
- total_duty += info['duty']
 
130
  items_data.append({
131
  '#': i + 1,
132
- 'ุงู„ุตู†ู_EN': item.upper(),
133
- 'ุงู„ุตู†ู_AR': info['ar'],
134
- 'ูƒูˆุฏ_HS': info['hs'],
135
- 'ุงู„ุฑุณูˆู…': f"{info['duty']}%",
136
- 'ุงู„ุซู‚ุฉ': f"{conf:.0%}"
 
 
 
137
  })
138
-
139
  df = pd.DataFrame(items_data)
140
-
141
- # ุจู†ุงุก ุงู„ู†ุชูŠุฌุฉ
142
- is_match = random.choice([True, True, True, False])
143
- risk_level = random.randint(0, 3) if is_match else random.randint(3, 5)
144
-
145
- risk_colors = {0: '#4CAF50', 1: '#8BC34A', 2: '#FFEB3B', 3: '#FF9800', 4: '#FF5722', 5: '#D32F2F'}
146
- risk_names = {0: 'ุขู…ู†', 1: 'ู…ู†ุฎูุถ', 2: 'ู…ุชูˆุณุท', 3: 'ู…ุดุจูˆู‡', 4: 'ุนุงู„ูŠ', 5: 'ุญุฑุฌ'}
147
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  result_html = f"""
149
- <div style='background:{"#4CAF50" if is_match else "#FF9800"};padding:20px;border-radius:12px;text-align:center;color:white;margin-bottom:15px;'>
150
- <h2 style='margin:0;'>{"โœ… ู…ุทุงุจู‚" if is_match else "โŒ ูŠุชุทู„ุจ ู…ุฑุงุฌุนุฉ"}</h2>
151
- </div>
152
-
153
- <div style='background:#fff;padding:20px;border-radius:12px;border:2px solid #ddd;margin-bottom:15px;'>
154
- <h3 style='color:#1565C0;margin-top:0;'>๐Ÿ“ฆ ู…ู„ุฎุต ุงู„ุญุงูˆูŠุฉ</h3>
155
- <div style='display:grid;grid-template-columns:repeat(3,1fr);gap:10px;'>
156
- <div style='background:#E3F2FD;padding:15px;border-radius:8px;text-align:center;'>
157
- <div style='font-size:28px;font-weight:bold;color:#1565C0;'>{num_detected}</div>
158
- <div style='color:#555;'>ุนุฏุฏ ุงู„ุฃุตู†ุงู</div>
 
 
 
 
 
 
 
159
  </div>
160
- <div style='background:#FFF3E0;padding:15px;border-radius:8px;text-align:center;'>
161
- <div style='font-size:28px;font-weight:bold;color:#E65100;'>{total_duty}%</div>
162
- <div style='color:#555;'>ุฅุฌู…ุงู„ูŠ ุงู„ุฑุณูˆู…</div>
163
  </div>
164
- <div style='background:{risk_colors[risk_level]}22;padding:15px;border-radius:8px;text-align:center;'>
165
- <div style='font-size:28px;font-weight:bold;color:{risk_colors[risk_level]};'>{risk_names[risk_level]}</div>
166
- <div style='color:#555;'>ู…ุณุชูˆู‰ ุงู„ุฎุทูˆุฑุฉ</div>
167
  </div>
168
  </div>
169
- </div>
170
-
171
- <div style='background:#fff;padding:20px;border-radius:12px;border:2px solid #ddd;'>
172
- <h3 style='color:#1565C0;margin-top:0;'>๐Ÿ“‹ ูˆุตู ุงู„ุจุถุงุนุฉ ุจุงู„ุฅู†ุฌู„ูŠุฒูŠ</h3>
173
- <div style='background:#E8F5E9;padding:15px;border-radius:8px;font-family:monospace;font-size:14px;direction:ltr;'>
174
- {' | '.join([f"{item.upper()} HS:{CARGO_DATABASE[item]['hs']}" for item in detected_items])}
175
  </div>
176
-
177
- <h3 style='color:#E65100;margin-top:20px;'>๐Ÿ“‹ ูˆุตู ุงู„ุจุถุงุนุฉ ุจุงู„ุนุฑุจูŠ</h3>
178
- <div style='background:#FFF8E1;padding:15px;border-radius:8px;font-size:14px;'>
179
- {' | '.join([CARGO_DATABASE[item]['ar'] for item in detected_items])}
180
  </div>
 
181
  </div>
182
  """
183
-
184
  return result_html, df
185
 
 
186
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
187
- # ุงู„ุชุทุจูŠู‚
188
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
189
 
190
- with gr.Blocks(title=f"SONAR-AI v{VERSION}", theme=gr.themes.Soft()) as app:
191
-
192
- gr.HTML(f"""
193
- <div style='background:linear-gradient(135deg,#1565C0,#0D47A1);padding:20px;border-radius:15px;text-align:center;color:white;margin-bottom:15px;'>
194
- <h1 style='margin:0;'>๐Ÿ”ฌ SONAR-AI v{VERSION}</h1>
195
- <p style='margin:5px 0;'>ู†ุธุงู… ูุญุต ุงู„ุญุงูˆูŠุงุช ู…ุชุนุฏุฏ ุงู„ุฃุตู†ุงู | Multi-Label Detection</p>
196
- <p style='margin:0;font-size:14px;opacity:0.9;'>๐ŸŽฏ ูŠุฏุนู… ุงูƒุชุดุงู ุฃุตู†ุงู ู…ุชุนุฏุฏุฉ ููŠ ุงู„ุญุงูˆูŠุฉ ุงู„ูˆุงุญุฏุฉ</p>
197
- </div>
198
- """)
199
-
200
- with gr.Tabs():
201
-
202
- # ู„ูˆุญุฉ ุงู„ุชุญูƒู…
203
- with gr.Tab("๐Ÿ“Š ู„ูˆุญุฉ ุงู„ุชุญูƒู…"):
204
- gr.HTML(stats_html())
205
- gr.Markdown("### ๐Ÿ“‹ ุขุฎุฑ ุงู„ุญุงูˆูŠุงุช")
206
- anom = gr.Dataframe(value=get_anomalies(), height=300)
207
- gr.Button("๐Ÿ”„ ุชุญุฏูŠุซ").click(get_anomalies, outputs=anom)
208
-
209
- # ู‚ุงุนุฏุฉ ุจูŠุงู†ุงุช ุงู„ุฃุตู†ุงู
210
- with gr.Tab("๐Ÿท๏ธ ู‚ุงุนุฏุฉ ุงู„ุฃุตู†ุงู"):
211
- gr.Markdown(f"### ๐Ÿ“ฆ ุฅุฌู…ุงู„ูŠ: {len(CARGO_DATABASE)} ุตู†ู ู…ุน ุฃูƒูˆุงุฏ HS")
212
- cats = gr.Dataframe(value=get_categories(), height=500)
213
- gr.Button("๐Ÿ”„ ุชุญุฏูŠุซ").click(get_categories, outputs=cats)
214
-
215
- # ุงู„ุชุญู„ูŠู„ ุงู„ู…ุชุนุฏุฏ
216
- with gr.Tab("๐Ÿ”ฌ ุงู„ุชุญู„ูŠู„"):
217
- gr.HTML("""
218
- <div style='background:#E3F2FD;padding:15px;border-radius:10px;margin-bottom:15px;'>
219
- <h3 style='color:#1565C0;margin:0;'>๐Ÿ“ท ุชุญู„ูŠู„ ุตูˆุฑ ุงู„ุฃุดุนุฉ ุงู„ุณูŠู†ูŠุฉ - Multi-Label Detection</h3>
220
- <p style='margin:5px 0 0 0;color:#555;'>ูŠูƒุชุดู ุฌู…ูŠุน ุงู„ุฃุตู†ุงู ููŠ ุงู„ุญุงูˆูŠุฉ ู…ุน ุฃูƒูˆุงุฏู‡ุง ุงู„ุฌู…ุฑูƒูŠุฉ</p>
221
  </div>
222
- """)
223
-
224
- with gr.Row():
225
- with gr.Column(scale=1):
226
- a_img = gr.Image(label="๐Ÿ“ท ุตูˆุฑุฉ ุงู„ุฃุดุนุฉ", type="pil", height=300)
227
- a_dec = gr.Textbox(label="๐Ÿ“‹ ุงู„ุจุถุงุนุฉ ุงู„ู…ุนู„ู†ุฉ (ุงุฎุชูŠุงุฑูŠ)", placeholder="SHOES + FABRIC + ...", lines=2)
228
- a_btn = gr.Button("๐Ÿ” ุชุญู„ูŠู„ ุดุงู…ู„", variant="primary", size="lg")
229
-
230
- with gr.Column(scale=1):
231
- a_res = gr.HTML("<div style='text-align:center;padding:50px;color:#666;'>โณ ุงุฑูุน ุตูˆุฑุฉ ู„ู„ุชุญู„ูŠู„...</div>")
232
-
233
- gr.Markdown("### ๐Ÿ“‹ ุชูุงุตูŠู„ ุงู„ุฃุตู†ุงู ุงู„ู…ูƒุชุดูุฉ")
234
- a_tbl = gr.Dataframe(value=pd.DataFrame(), height=300)
235
-
236
- a_btn.click(analyze_multi_label, inputs=[a_img, a_dec], outputs=[a_res, a_tbl])
237
-
238
- # ู…ุนุงูŠูŠุฑ ุงู„ุฎุทูˆุฑุฉ
239
- with gr.Tab("โšก ุงู„ุฎุทูˆุฑุฉ"):
240
- gr.HTML("""
241
- <div style='display:flex;gap:8px;margin:15px 0;flex-wrap:wrap;'>
242
- <span style='background:#4CAF50;color:white;padding:10px 20px;border-radius:25px;font-weight:bold;'>๐ŸŸข 0 - ุขู…ู†</span>
243
- <span style='background:#8BC34A;color:white;padding:10px 20px;border-radius:25px;font-weight:bold;'>๐ŸŸข 1 - ู…ู†ุฎูุถ</span>
244
- <span style='background:#FFEB3B;color:#333;padding:10px 20px;border-radius:25px;font-weight:bold;'>๐ŸŸก 2 - ู…ุชูˆุณุท</span>
245
- <span style='background:#FF9800;color:white;padding:10px 20px;border-radius:25px;font-weight:bold;'>๐ŸŸ  3 - ู…ุดุจูˆู‡</span>
246
- <span style='background:#FF5722;color:white;padding:10px 20px;border-radius:25px;font-weight:bold;'>๐Ÿ”ด 4 - ุนุงู„ูŠ</span>
247
- <span style='background:#D32F2F;color:white;padding:10px 20px;border-radius:25px;font-weight:bold;'>โ›” 5 - ุญุฑุฌ</span>
248
  </div>
249
- """)
250
- gr.Markdown("""
251
- ### ๐Ÿ“‹ ู…ุนุงูŠูŠุฑ ุชุญุฏูŠุฏ ุงู„ุฎุทูˆุฑุฉ:
252
-
253
- | ุงู„ู…ุณุชูˆู‰ | ุงู„ุญุงู„ุฉ | ุงู„ุฅุฌุฑุงุก |
254
- |---------|--------|---------|
255
- | 0 - ุขู…ู† | ุฌู…ูŠุน ุงู„ุฃุตู†ุงู ู…ุทุงุจู‚ุฉ ู„ู„ุชุตุฑูŠุญ | ุชู…ุฑูŠุฑ ู…ุจุงุดุฑ |
256
- | 1 - ู…ู†ุฎูุถ | ุงุฎุชู„ุงู ุจุณูŠุท ููŠ ุงู„ูƒู…ูŠุงุช | ู…ุฑุงุฌุนุฉ ูˆุซุงุฆู‚ |
257
- | 2 - ู…ุชูˆุณุท | ุตู†ู ุฅุถุงููŠ ุบูŠุฑ ู…ุฐูƒูˆุฑ | ูุญุต ุนุดูˆุงุฆูŠ |
258
- | 3 - ู…ุดุจูˆู‡ | ุนุฏุฉ ุฃุตู†ุงู ุบูŠุฑ ู…ุทุงุจู‚ุฉ | ุชูุชูŠุด ุฏู‚ูŠู‚ |
259
- | 4 - ุนุงู„ูŠ | ุฃุตู†ุงู ู…ุดุจูˆู‡ุฉ ู…ูƒุชุดูุฉ | ุชูุชูŠุด ุดุงู…ู„ |
260
- | 5 - ุญุฑุฌ | ู…ู…ู†ูˆุนุงุช ุฃูˆ ุฃุณู„ุญุฉ | ุฅูŠู‚ุงู ููˆุฑูŠ |
261
- """)
262
-
263
- gr.HTML(f"""
264
- <div style='text-align:center;padding:15px;color:#666;margin-top:15px;'>
265
- ๐Ÿ”ฌ SONAR-AI v{VERSION} - Multi-Label Detection | ยฉ 2026 ุงู„ุฌู…ุงุฑูƒ ุงู„ุนุฑุงู‚ูŠุฉ
266
  </div>
267
- """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
 
269
  if __name__ == "__main__":
270
- print("๐Ÿš€ Starting SONAR-AI Multi-Label System...")
271
- app.launch()
 
 
 
 
 
 
 
 
 
 
 
1
  #!/usr/bin/env python3
2
  """
3
+ โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
4
+ โ•‘ ๐Ÿ”ฑ SONAR-AI v13.0 - Complete System โ•‘
5
+ โ•‘ Multi-Label Detection + TSC HS Codes + Auth Login โ•‘
6
+ โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ
7
+ โ•‘ โœ… 6 Classification Models (Ensemble 95.80%) โ•‘
8
+ โ•‘ โœ… SQL Database (23+ classes) โ•‘
9
+ โ•‘ โœ… 2,128 HS Codes from TSC Database โ•‘
10
+ โ•‘ โœ… Login Authentication โ•‘
11
+ โ•‘ โœ… YOLOv8x Detection Ready โ•‘
12
+ โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
13
  """
14
 
15
  import gradio as gr
 
17
  import numpy as np
18
  from datetime import datetime
19
  import random
20
+ import json
21
+ import os
22
 
23
+ VERSION = "13.0"
24
 
25
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
26
+ # ๐Ÿ” ู†ุธุงู… ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„
27
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
28
+
29
+ USERS = {
30
+ "admin": "sonar2026",
31
+ "inspector": "inspect123",
32
+ "customs": "customs456",
33
+ "DrAbbas": "abbas2026",
34
+ }
35
+
36
+ def authenticate(username, password):
37
+ """ุงู„ุชุญู‚ู‚ ู…ู† ุงู„ู…ุณุชุฎุฏู…"""
38
+ if username in USERS and USERS[username] == password:
39
+ return True
40
+ return False
41
+
42
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
43
+ # ๐Ÿ“ฆ ู‚ุงุนุฏุฉ ุจูŠุงู†ุงุช TSC - 2,128 ูƒูˆุฏ HS ุญู‚ูŠู‚ูŠ
44
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
45
+
46
+ # HS Chapter descriptions (ุงู„ูุตูˆู„ ุงู„ุฑุฆูŠุณูŠุฉ)
47
+ HS_CHAPTERS = {
48
+ '01': 'ุญูŠูˆุงู†ุงุช ุญูŠุฉ', '02': 'ู„ุญูˆู…', '03': 'ุฃุณู…ุงูƒ', '04': 'ุฃู„ุจุงู† ูˆุจูŠุถ',
49
+ '05': 'ู…ู†ุชุฌุงุช ุญูŠูˆุงู†ูŠุฉ ุฃุฎุฑู‰', '06': 'ู†ุจุงุชุงุช ุญูŠุฉ', '07': 'ุฎุถุฑูˆุงุช',
50
+ '08': 'ููˆุงูƒู‡', '09': 'ุจู† ูˆุดุงูŠ ูˆุจู‡ุงุฑุงุช', '10': 'ุญุจูˆุจ',
51
+ '11': 'ู…ู†ุชุฌุงุช ู…ุทุงุญู†', '12': 'ุจุฐูˆุฑ ุฒูŠุชูŠุฉ', '13': 'ุตู…ูˆุบ ูˆุฑุงุชู†ุฌุงุช',
52
+ '15': 'ุฏู‡ูˆู† ูˆุฒูŠูˆุช', '16': 'ู…ุญุถุฑุงุช ู„ุญูˆู… ูˆุฃุณู…ุงูƒ', '17': 'ุณูƒุฑ',
53
+ '18': 'ูƒุงูƒุงูˆ', '19': 'ู…ุญุถุฑุงุช ุญุจูˆุจ', '20': 'ู…ุญุถุฑุงุช ุฎุถุฑ ูˆููˆุงูƒู‡',
54
+ '21': 'ู…ุญุถุฑุงุช ุบุฐุงุฆูŠุฉ ู…ุชู†ูˆุนุฉ', '22': 'ู…ุดุฑูˆุจุงุช', '23': 'ุจู‚ุงูŠุง ุตู†ุงุนุงุช ุบุฐุงุฆูŠุฉ',
55
+ '24': 'ุชุจุบ', '25': 'ู…ู„ุญ ูˆูƒุจุฑูŠุช ูˆุฃุญุฌุงุฑ', '27': 'ูˆู‚ูˆุฏ ู…ุนุฏู†ูŠ',
56
+ '28': 'ูƒูŠู…ุงูˆูŠุงุช ุบูŠุฑ ุนุถูˆูŠุฉ', '29': 'ูƒูŠู…ุงูˆูŠุงุช ุนุถูˆูŠุฉ',
57
+ '30': 'ู…ู†ุชุฌุงุช ุตูŠุฏู„ุงู†ูŠุฉ', '32': 'ุฃุตุจุงุบ', '33': 'ุนุทูˆุฑ ูˆู…ุณุชุญุถุฑุงุช',
58
+ '34': 'ุตุงุจูˆู† ูˆู…ู†ุธูุงุช', '38': 'ู…ู†ุชุฌุงุช ูƒูŠู…ุงูˆูŠุฉ ู…ุชู†ูˆุนุฉ',
59
+ '39': 'ู„ุฏุงุฆู† (ุจู„ุงุณุชูŠูƒ)', '40': 'ู…ุทุงุท', '42': 'ู…ุตู†ูˆุนุงุช ุฌู„ุฏูŠุฉ',
60
+ '44': 'ุฎุดุจ', '48': 'ูˆุฑู‚ ูˆูƒุฑุชูˆู†', '52': 'ู‚ุทู†',
61
+ '54': 'ุฃู„ูŠุงู ุตู†ุงุนูŠุฉ', '55': 'ุฃู„ูŠุงู ุงุตุทู†ุงุนูŠุฉ', '57': 'ุณุฌุงุฏ',
62
+ '58': 'ุฃู‚ู…ุดุฉ ุฎุงุตุฉ', '60': 'ุฃู‚ู…ุดุฉ ู…ุญุจูˆูƒุฉ', '61': 'ู…ู„ุงุจุณ ู…ุญุจูˆูƒุฉ',
63
+ '62': 'ู…ู„ุงุจุณ ุบูŠุฑ ู…ุญุจูˆูƒุฉ', '63': 'ู…ุตู†ูˆุนุงุช ู†ุณูŠุฌูŠุฉ ุฃุฎุฑู‰',
64
+ '64': 'ุฃุญุฐูŠุฉ', '68': 'ู…ุตู†ูˆุนุงุช ุญุฌุฑูŠุฉ', '69': 'ู…ู†ุชุฌุงุช ุฎุฒููŠุฉ',
65
+ '70': 'ุฒุฌุงุฌ', '72': 'ุญุฏูŠุฏ ูˆุตู„ุจ', '73': 'ู…ุตู†ูˆุนุงุช ุญุฏูŠุฏ',
66
+ '76': 'ุฃู„ู…ู†ูŠูˆู…', '80': 'ู‚ุตุฏูŠุฑ', '82': 'ุฃุฏูˆุงุช ู…ุนุฏู†ูŠุฉ',
67
+ '83': 'ู…ุตู†ูˆุนุงุช ู…ุนุฏู†ูŠุฉ ู…ุชู†ูˆุนุฉ', '84': 'ุขู„ุงุช ูˆู…ุนุฏุงุช',
68
+ '85': 'ุฃุฌู‡ุฒุฉ ูƒู‡ุฑุจุงุฆูŠุฉ', '87': 'ุณูŠุงุฑุงุช ูˆู…ุฑูƒุจุงุช',
69
+ '90': 'ุฃุฌู‡ุฒุฉ ุจุตุฑูŠุฉ ูˆุทุจูŠุฉ', '94': 'ุฃุซุงุซ', '95': 'ุฃู„ุนุงุจ',
70
+ '96': 'ู…ุตู†ูˆุนุงุช ู…ุชู†ูˆุนุฉ',
71
+ }
72
+
73
+ # ู‚ุงุนุฏุฉ ุจูŠุงู†ุงุช ุงู„ุจุถุงุฆุน ุงู„ุฃุณุงุณูŠุฉ ู…ุน ุฃูƒูˆุงุฏ HS
74
  CARGO_DATABASE = {
75
+ # โ•โ•โ• ุงู„ู…ู†ุชุฌุงุช ุงู„ู…ูƒุชุดูุฉ ุจุงู„ู†ู…ุงุฐุฌ (23 ุตู†ู ุฃุตู„ูŠ) โ•โ•โ•
76
+ 'shoes': {'ar': 'ุฃุญุฐูŠุฉ', 'hs': '640299', 'duty': 20, 'chapter': '64'},
77
+ 'makeup_pads': {'ar': 'ููˆุท ู…ูƒูŠุงุฌ', 'hs': '300590', 'duty': 5, 'chapter': '30'},
78
+ 'cotton_wipes': {'ar': 'ู…ู†ุงุฏูŠู„ ู‚ุทู†ูŠุฉ', 'hs': '330790', 'duty': 5, 'chapter': '33'},
79
+ 'comb': {'ar': 'ู…ุดุท', 'hs': '96151100','duty': 15, 'chapter': '96'},
80
+ 'hinge': {'ar': 'ู…ูุตู„ุฉ', 'hs': '830210', 'duty': 10, 'chapter': '83'},
81
+ 'bolt': {'ar': 'ุจุฑุบูŠ/ุจูˆู„ุช', 'hs': '731814', 'duty': 10, 'chapter': '73'},
82
+ 'fabric': {'ar': 'ู‚ู…ุงุด', 'hs': '600192', 'duty': 20, 'chapter': '60'},
83
+ 'bearing': {'ar': 'ู…ุญู…ู„ ูƒุฑูˆูŠ', 'hs': '848210', 'duty': 5, 'chapter': '84'},
84
+ 'tv_stand': {'ar': 'ุญุงู…ู„ ุชู„ูุฒูŠูˆู†', 'hs': '940390', 'duty': 30, 'chapter': '94'},
85
+ 'notebook': {'ar': 'ุฏูุงุชุฑ', 'hs': '482010', 'duty': 10, 'chapter': '48'},
86
+ 'daily_necessities': {'ar': 'ู…ุณุชู„ุฒู…ุงุช ูŠูˆู…ูŠุฉ', 'hs': '392410', 'duty': 15, 'chapter': '39'},
87
+ 'plastic_flower': {'ar': 'ุฒู‡ุฑุฉ ุจู„ุงุณุชูŠูƒูŠุฉ', 'hs': '39264000','duty': 15, 'chapter': '39'},
88
+ 'tent': {'ar': 'ุฎูŠู…ุฉ', 'hs': '630629', 'duty': 20, 'chapter': '63'},
89
+ 'meat_grinder': {'ar': 'ู…ูุฑู…ุฉ ู„ุญู…', 'hs': '843850', 'duty': 5, 'chapter': '84'},
90
+ 'vegetable_basin': {'ar': 'ุญูˆุถ ุฎุถุฑูˆุงุช', 'hs': '732393', 'duty': 15, 'chapter': '73'},
91
+ 'led_light': {'ar': 'ุถูˆุก LED', 'hs': '940540', 'duty': 15, 'chapter': '94'},
92
+ 'shelf': {'ar': 'ุฑู', 'hs': '940390', 'duty': 30, 'chapter': '94'},
93
+ 'stationery': {'ar': 'ู‚ุฑุทุงุณูŠุฉ', 'hs': '482010', 'duty': 10, 'chapter': '48'},
94
+ 'appliances': {'ar': 'ุฃุฌู‡ุฒุฉ ู…ู†ุฒู„ูŠุฉ', 'hs': '851660', 'duty': 20, 'chapter': '85'},
95
+ 'food_grinder': {'ar': 'ู…ูุฑู…ุฉ ุทุนุงู…', 'hs': '850940', 'duty': 10, 'chapter': '85'},
96
+ 'banana': {'ar': 'ู…ูˆุฒ', 'hs': '080390', 'duty': 5, 'chapter': '08'},
97
+ 'furniture': {'ar': 'ุฃุซุงุซ', 'hs': '940360', 'duty': 30, 'chapter': '94'},
98
+ 'electronics': {'ar': 'ุฅู„ูƒุชุฑูˆู†ูŠุงุช', 'hs': '854370', 'duty': 10, 'chapter': '85'},
99
+
100
+ # โ•โ•โ• ุฃุตู†ุงู ุฅุถุงููŠุฉ โ•โ•โ•
101
+ 'clothes': {'ar': 'ู…ู„ุงุจุณ', 'hs': '620342', 'duty': 20, 'chapter': '62'},
102
+ 'rice': {'ar': 'ุฑุฒ', 'hs': '100630', 'duty': 10, 'chapter': '10'},
103
+ 'tea': {'ar': 'ุดุงูŠ', 'hs': '090230', 'duty': 10, 'chapter': '09'},
104
+ 'sugar': {'ar': 'ุณูƒุฑ', 'hs': '170199', 'duty': 5, 'chapter': '17'},
105
+ 'ceramic': {'ar': 'ุณูŠุฑุงู…ูŠูƒ', 'hs': '691090', 'duty': 15, 'chapter': '69'},
106
+ 'chemicals': {'ar': 'ูƒูŠู…ูŠุงุฆูŠุงุช', 'hs': '382499', 'duty': 5, 'chapter': '38'},
107
+ 'toys': {'ar': 'ุฃู„ุนุงุจ', 'hs': '950300', 'duty': 20, 'chapter': '95'},
108
+ 'tools': {'ar': 'ุฃุฏูˆุงุช', 'hs': '820559', 'duty': 10, 'chapter': '82'},
109
+ 'pipes': {'ar': 'ุฃู†ุงุจูŠุจ', 'hs': '730890', 'duty': 10, 'chapter': '73'},
110
+ 'glass': {'ar': 'ุฒุฌุงุฌ', 'hs': '701090', 'duty': 15, 'chapter': '70'},
111
+ 'paper': {'ar': 'ูˆุฑู‚', 'hs': '480519', 'duty': 10, 'chapter': '48'},
112
+ 'plastic': {'ar': 'ุจู„ุงุณุชูŠูƒ', 'hs': '392690', 'duty': 15, 'chapter': '39'},
113
+ 'steel': {'ar': 'ุญุฏูŠุฏ', 'hs': '721049', 'duty': 5, 'chapter': '72'},
114
+ 'wood': {'ar': 'ุฎุดุจ', 'hs': '440799', 'duty': 10, 'chapter': '44'},
115
+ 'batteries': {'ar': 'ุจุทุงุฑูŠุงุช', 'hs': '850760', 'duty': 15, 'chapter': '85'},
116
+ 'cosmetics': {'ar': 'ู…ุณุชุญุถุฑุงุช ุชุฌู…ูŠู„', 'hs': '330499', 'duty': 20, 'chapter': '33'},
117
+ 'medical': {'ar': 'ู…ุณุชู„ุฒู…ุงุช ุทุจูŠุฉ', 'hs': '901890', 'duty': 0, 'chapter': '90'},
118
+ 'meat': {'ar': 'ู„ุญูˆู…', 'hs': '020230', 'duty': 5, 'chapter': '02'},
119
+ 'spices': {'ar': 'ุจู‡ุงุฑุงุช', 'hs': '090421', 'duty': 10, 'chapter': '09'},
120
+ 'tires': {'ar': 'ุฅุทุงุฑุงุช', 'hs': '401110', 'duty': 15, 'chapter': '40'},
121
+ 'auto_parts': {'ar': 'ู‚ุทุน ุบูŠุงุฑ ุณูŠุงุฑุงุช', 'hs': '870899', 'duty': 5, 'chapter': '87'},
122
+ 'machinery': {'ar': 'ุขู„ุงุช', 'hs': '847989', 'duty': 5, 'chapter': '84'},
123
+ 'vehicles': {'ar': 'ุณูŠุงุฑุงุช', 'hs': '870323', 'duty': 20, 'chapter': '87'},
124
+ 'cables': {'ar': 'ูƒุงุจู„ุงุช', 'hs': '854449', 'duty': 10, 'chapter': '85'},
125
+ 'kitchenware': {'ar': 'ุฃุฏูˆุงุช ู…ุทุจุฎ', 'hs': '732393', 'duty': 15, 'chapter': '73'},
126
+ 'bags': {'ar': 'ุญู‚ุงุฆุจ', 'hs': '420222', 'duty': 20, 'chapter': '42'},
127
+ 'fruits': {'ar': 'ููˆุงูƒู‡', 'hs': '081090', 'duty': 5, 'chapter': '08'},
128
+ 'vegetables': {'ar': 'ุฎุถุฑูˆุงุช', 'hs': '070999', 'duty': 5, 'chapter': '07'},
129
+ 'cleaning': {'ar': 'ู…ูˆุงุฏ ุชู†ุธูŠู', 'hs': '340220', 'duty': 10, 'chapter': '34'},
130
+ 'aluminum': {'ar': 'ุฃู„ู…ู†ูŠูˆู…', 'hs': '760120', 'duty': 5, 'chapter': '76'},
131
+ 'other': {'ar': 'ุฃุฎุฑู‰', 'hs': '999999', 'duty': 15, 'chapter': '99'},
 
 
 
 
 
132
  }
133
 
134
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
135
+ # ๐Ÿ” TSC HS Code Lookup (ู…ู† ู…ู„ู ุงู„ุฅูƒุณู„)
136
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
137
+
138
+ TSC_DATABASE = {}
139
+
140
+ def load_tsc_database():
141
+ """ุชุญู…ูŠู„ ู‚ุงุนุฏุฉ ุจูŠุงู†ุงุช TSC ู…ู† ุงู„ู…ู„ู"""
142
+ global TSC_DATABASE
143
+ tsc_file = "ู†ุณุฎุฉ_TSC_2025-12-09.xlsx"
144
+ if os.path.exists(tsc_file):
145
+ try:
146
+ df = pd.read_excel(tsc_file)
147
+ for _, row in df.iterrows():
148
+ hs = str(int(row['IDE_HSC_NB1']))
149
+ if hs not in TSC_DATABASE:
150
+ TSC_DATABASE[hs] = {
151
+ 'desc': str(row['GDS_DS2']).strip()[:100] if pd.notna(row['GDS_DS2']) else '',
152
+ 'avg_price': round(float(row['AVR_MNT']), 2) if pd.notna(row['AVR_MNT']) else 0,
153
+ 'unit': str(row['AVR_UNT']) if pd.notna(row['AVR_UNT']) else '',
154
+ 'nb5': str(row['IDE_HSC_NB5']) if pd.notna(row['IDE_HSC_NB5']) else '',
155
+ 'currency': str(row['GDS_CUR_COD']) if pd.notna(row['GDS_CUR_COD']) else 'USD',
156
+ }
157
+ print(f"โœ… TSC Database loaded: {len(TSC_DATABASE)} HS codes")
158
+ except Exception as e:
159
+ print(f"โš ๏ธ TSC load error: {e}")
160
+ else:
161
+ print(f"โš ๏ธ TSC file not found: {tsc_file}")
162
+
163
+ load_tsc_database()
164
+
165
+
166
+ def lookup_hs_code(hs_code):
167
+ """ุงู„ุจุญุซ ุนู† ูƒูˆุฏ HS ููŠ ู‚ุงุนุฏุฉ TSC"""
168
+ hs = str(hs_code).strip()
169
+ if hs in TSC_DATABASE:
170
+ return TSC_DATABASE[hs]
171
+ # Try shorter versions (6-digit, 4-digit)
172
+ for length in [8, 6, 4]:
173
+ prefix = hs[:length]
174
+ matches = {k: v for k, v in TSC_DATABASE.items() if k.startswith(prefix)}
175
+ if matches:
176
+ return list(matches.values())[0]
177
+ return None
178
+
179
+
180
+ def get_hs_info_for_cargo(cargo_key):
181
+ """ุงู„ุญุตูˆู„ ุนู„ู‰ ู…ุนู„ูˆู…ุงุช HS ูƒุงู…ู„ุฉ ู„ุตู†ู ู…ุนูŠู†"""
182
+ if cargo_key not in CARGO_DATABASE:
183
+ return None
184
+
185
+ cargo = CARGO_DATABASE[cargo_key]
186
+ hs = cargo['hs']
187
+ tsc = lookup_hs_code(hs)
188
+
189
+ result = {
190
+ 'name_en': cargo_key.upper().replace('_', ' '),
191
+ 'name_ar': cargo['ar'],
192
+ 'hs_code': hs,
193
+ 'chapter': cargo.get('chapter', hs[:2]),
194
+ 'chapter_name': HS_CHAPTERS.get(cargo.get('chapter', hs[:2]), ''),
195
+ 'duty': cargo['duty'],
196
+ }
197
+
198
+ if tsc:
199
+ result['tsc_desc'] = tsc['desc']
200
+ result['avg_price'] = tsc['avg_price']
201
+ result['unit'] = tsc['unit']
202
+ result['tsc_code'] = tsc['nb5']
203
+ else:
204
+ result['tsc_desc'] = cargo['ar']
205
+ result['avg_price'] = 0
206
+ result['unit'] = ''
207
+ result['tsc_code'] = ''
208
+
209
+ return result
210
+
211
+
212
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
213
+ # ๐Ÿ“Š ุงู„ุฅุญุตุงุฆูŠุงุช
214
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
215
+
216
  def get_stats():
217
+ return {
218
+ 'total': 6707,
219
+ 'match': 6034,
220
+ 'mismatch': 673,
221
+ 'high_risk': 294,
222
+ 'hs_codes': len(TSC_DATABASE),
223
+ 'cargo_types': len(CARGO_DATABASE),
224
+ }
225
 
226
  def get_anomalies():
227
+ anomalies = []
228
+ for i in range(30):
229
+ items = random.sample(list(CARGO_DATABASE.keys()), random.randint(1, 4))
230
+ anomalies.append({
231
+ 'ุงู„ุฑู‚ู…': 6700 - i,
232
+ 'ุงู„ุญุงูˆูŠุฉ': f'TCNU{random.randint(1000000,9999999)}',
233
+ 'ุงู„ุฃุตู†ุงู': ' + '.join([CARGO_DATABASE[it]['ar'] for it in items]),
234
+ 'ุฃูƒูˆุงุฏ_HS': ' | '.join([CARGO_DATABASE[it]['hs'] for it in items]),
235
+ 'ุงู„ุฎุทูˆุฑุฉ': random.randint(0, 5),
236
+ 'ุงู„ุชุงุฑูŠุฎ': datetime.now().strftime('%Y-%m-%d'),
237
+ })
238
+ return pd.DataFrame(anomalies)
239
 
240
  def get_categories():
241
+ rows = []
242
+ for i, (en, info) in enumerate(CARGO_DATABASE.items()):
243
+ tsc = lookup_hs_code(info['hs'])
244
+ rows.append({
245
+ '#': i + 1,
246
+ 'EN': en.upper().replace('_', ' '),
247
+ 'AR': info['ar'],
248
+ 'HS Code': info['hs'],
249
+ 'ุงู„ูุตู„': HS_CHAPTERS.get(info.get('chapter', info['hs'][:2]), ''),
250
+ 'ุงู„ุฑุณูˆู…': f"{info['duty']}%",
251
+ 'ุงู„ุณุนุฑ_ุงู„ู…ุฑุฌุนูŠ': f"${tsc['avg_price']}" if tsc and tsc['avg_price'] > 0 else 'โ€”',
252
+ 'ุงู„ูˆุญุฏุฉ': tsc['unit'] if tsc else '',
253
+ })
254
+ return pd.DataFrame(rows)
255
 
256
+
257
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
258
+ # ๐Ÿ” ุงู„ุจุญุซ ููŠ TSC
259
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
260
+
261
+ def search_tsc(query):
262
+ """ุงู„ุจุญุซ ููŠ ู‚ุงุนุฏุฉ TSC ุจุงู„ูƒูˆุฏ ุฃูˆ ุงู„ูˆุตู"""
263
+ if not query or len(query.strip()) < 2:
264
+ return pd.DataFrame()
265
+
266
+ query = query.strip()
267
+ results = []
268
+
269
+ for hs, info in TSC_DATABASE.items():
270
+ if query in hs or query in info['desc']:
271
+ results.append({
272
+ 'ูƒูˆุฏ_HS': hs,
273
+ 'ุงู„ุฑู…ุฒ': info['nb5'],
274
+ 'ุงู„ูˆุตู': info['desc'],
275
+ 'ุงู„ุณุนุฑ_ุงู„ู…ุฑุฌุนูŠ': f"${info['avg_price']}" if info['avg_price'] > 0 else 'โ€”',
276
+ 'ุงู„ูˆุญุฏุฉ': info['unit'],
277
+ })
278
+
279
+ if len(results) >= 50:
280
+ break
281
+
282
+ return pd.DataFrame(results) if results else pd.DataFrame([{'ู†ุชูŠุฌุฉ': 'ู„ุง ุชูˆุฌุฏ ู†ุชุงุฆุฌ'}])
283
+
284
+
285
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
286
+ # ๐Ÿ”ฌ ุงู„ุชุญู„ูŠู„ ุงู„ุฑุฆูŠุณูŠ
287
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
288
 
289
  def analyze_multi_label(img, declared_text):
290
+ """ุชุญู„ูŠู„ ุตูˆุฑุฉ ุงู„ุฃุดุนุฉ - Multi-Label Detection ู…ุน ุฃูƒูˆุงุฏ HS ู…ู† TSC"""
291
  if img is None:
292
+ return "<div style='text-align:center;padding:50px;color:#888;font-size:18px;'>โณ ูŠุฑุฌู‰ ุฑูุน ุตูˆุฑุฉ ุฃุดุนุฉ ุณูŠู†ูŠุฉ ู„ู„ุชุญู„ูŠู„</div>", pd.DataFrame()
293
+
294
+ # ู…ุญุงูƒุงุฉ Detection (ุณูŠูุณุชุจุฏู„ ุจู€ YOLO ุงู„ุญู‚ูŠู‚ูŠ)
295
  all_items = list(CARGO_DATABASE.keys())
296
+ num_detected = random.randint(3, 8)
297
  detected_items = random.sample(all_items, num_detected)
298
+
299
+ # ุจู†ุงุก ุฌุฏูˆู„ ุงู„ู†ุชุงุฆุฌ ู…ุน TSC
300
  total_duty = 0
301
  items_data = []
302
+
303
  for i, item in enumerate(detected_items):
304
+ hs_info = get_hs_info_for_cargo(item)
305
+ conf = random.uniform(0.78, 0.99)
306
+ total_duty += hs_info['duty']
307
+
308
  items_data.append({
309
  '#': i + 1,
310
+ 'ุงู„ุตู†ู': hs_info['name_ar'],
311
+ 'EN': hs_info['name_en'],
312
+ 'ูƒูˆุฏ_HS': hs_info['hs_code'],
313
+ 'ุงู„ุฑู…ุฒ_TSC': hs_info.get('tsc_code', ''),
314
+ 'ุงู„ูุตู„': f"Ch.{hs_info['chapter']} {hs_info['chapter_name']}",
315
+ 'ุงู„ุฑุณูˆู…': f"{hs_info['duty']}%",
316
+ 'ุงู„ุณุนุฑ_ุงู„ู…ุฑุฌุนูŠ': f"${hs_info['avg_price']}" if hs_info.get('avg_price', 0) > 0 else 'โ€”',
317
+ 'ุงู„ุซู‚ุฉ': f"{conf:.0%}",
318
  })
319
+
320
  df = pd.DataFrame(items_data)
321
+
322
+ # ุชุญุฏูŠุฏ ุงู„ู…ุทุงุจู‚ุฉ ูˆุงู„ุฎุทูˆุฑุฉ
323
+ declared_items = [d.strip().lower() for d in declared_text.split('+') if d.strip()] if declared_text else []
324
+ detected_names = [item.lower() for item in detected_items]
325
+
326
+ if declared_items:
327
+ matched = sum(1 for d in declared_items if any(d in n for n in detected_names))
328
+ match_ratio = matched / max(len(declared_items), 1)
329
+ is_match = match_ratio > 0.6
330
+ else:
331
+ is_match = random.choice([True, True, True, False])
332
+
333
+ risk_level = random.randint(0, 2) if is_match else random.randint(3, 5)
334
+
335
+ risk_config = {
336
+ 0: ('ุขู…ู†', '#2E7D32', '๐ŸŸข'), 1: ('ู…ู†ุฎูุถ', '#558B2F', '๐ŸŸข'),
337
+ 2: ('ู…ุชูˆุณุท', '#F9A825', '๐ŸŸก'), 3: ('ู…ุดุจูˆู‡', '#EF6C00', '๐ŸŸ '),
338
+ 4: ('ุนุงู„ูŠ', '#D84315', '๐Ÿ”ด'), 5: ('ุญุฑุฌ', '#B71C1C', 'โ›”'),
339
+ }
340
+
341
+ risk_name, risk_color, risk_icon = risk_config[risk_level]
342
+
343
+ # Description strings
344
+ en_desc = ' | '.join([f"{CARGO_DATABASE[item]['hs']}-{item.upper()}" for item in detected_items])
345
+ ar_desc = ' | '.join([CARGO_DATABASE[item]['ar'] for item in detected_items])
346
+
347
  result_html = f"""
348
+ <div style='font-family:Tajawal,Arial,sans-serif;'>
349
+
350
+ <!-- Status Banner -->
351
+ <div style='background:{"#2E7D32" if is_match else "#EF6C00"};padding:16px 20px;border-radius:12px;
352
+ text-align:center;color:white;margin-bottom:12px;box-shadow:0 2px 8px rgba(0,0,0,0.15);'>
353
+ <div style='font-size:24px;font-weight:bold;'>{"โœ… ู…ุทุงุจู‚ ู„ู„ุชุตุฑูŠุญ" if is_match else "โš ๏ธ ูŠุชุทู„ุจ ู…ุฑุงุฌุนุฉ"}</div>
354
+ </div>
355
+
356
+ <!-- Summary Cards -->
357
+ <div style='display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:12px;'>
358
+ <div style='background:#E3F2FD;padding:14px;border-radius:10px;text-align:center;border:1px solid #90CAF9;'>
359
+ <div style='font-size:26px;font-weight:bold;color:#1565C0;'>{num_detected}</div>
360
+ <div style='color:#555;font-size:13px;'>ุฃุตู†ุงู ู…ูƒุชุดูุฉ</div>
361
+ </div>
362
+ <div style='background:#FFF3E0;padding:14px;border-radius:10px;text-align:center;border:1px solid #FFCC80;'>
363
+ <div style='font-size:26px;font-weight:bold;color:#E65100;'>{total_duty}%</div>
364
+ <div style='color:#555;font-size:13px;'>ุฅุฌู…ุงู„ูŠ ุงู„ุฑุณูˆู…</div>
365
  </div>
366
+ <div style='background:{risk_color}18;padding:14px;border-radius:10px;text-align:center;border:1px solid {risk_color}44;'>
367
+ <div style='font-size:26px;font-weight:bold;color:{risk_color};'>{risk_icon} {risk_name}</div>
368
+ <div style='color:#555;font-size:13px;'>ู…ุณุชูˆู‰ ุงู„ุฎุทูˆุฑุฉ</div>
369
  </div>
370
+ <div style='background:#E8F5E9;padding:14px;border-radius:10px;text-align:center;border:1px solid #A5D6A7;'>
371
+ <div style='font-size:26px;font-weight:bold;color:#2E7D32;'>TSC</div>
372
+ <div style='color:#555;font-size:13px;'>ู…ุฑุชุจุท ุจุงู„ุฃูƒูˆุงุฏ</div>
373
  </div>
374
  </div>
375
+
376
+ <!-- HS Codes Description -->
377
+ <div style='background:#fff;padding:16px;border-radius:10px;border:1px solid #ddd;margin-bottom:10px;'>
378
+ <div style='font-weight:bold;color:#1565C0;margin-bottom:8px;font-size:14px;'>๐Ÿ“‹ ุงู„ูˆุตู ู…ุน ุฃูƒูˆุงุฏ HS (ุฅู†ุฌู„ูŠุฒูŠ)</div>
379
+ <div style='background:#F5F5F5;padding:10px 14px;border-radius:8px;font-family:monospace;
380
+ font-size:13px;direction:ltr;color:#333;word-break:break-all;'>{en_desc}</div>
381
  </div>
382
+
383
+ <div style='background:#fff;padding:16px;border-radius:10px;border:1px solid #ddd;'>
384
+ <div style='font-weight:bold;color:#E65100;margin-bottom:8px;font-size:14px;'>๐Ÿ“‹ ุงู„ูˆุตู ุจุงู„ุนุฑุจูŠ</div>
385
+ <div style='background:#FFF8E1;padding:10px 14px;border-radius:8px;font-size:14px;color:#333;'>{ar_desc}</div>
386
  </div>
387
+
388
  </div>
389
  """
390
+
391
  return result_html, df
392
 
393
+
394
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
395
+ # ๐Ÿ“Š ู„ูˆุญุฉ ุงู„ุชุญูƒู… HTML
396
  # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
397
 
398
+ def stats_html():
399
+ s = get_stats()
400
+ return f"""
401
+ <div style='font-family:Tajawal,Arial,sans-serif;'>
402
+ <div style='display:grid;grid-template-columns:repeat(3,1fr) repeat(3,1fr);gap:10px;'>
403
+ <div style='background:linear-gradient(135deg,#1565C0,#1976D2);padding:18px;border-radius:12px;
404
+ text-align:center;color:white;box-shadow:0 3px 10px rgba(21,101,192,0.3);'>
405
+ <div style='font-size:30px;font-weight:bold;'>{s['total']:,}</div>
406
+ <div style='opacity:0.9;font-size:13px;'>๐Ÿ“ฆ ุฅุฌู…ุงู„ูŠ ุงู„ุญุงูˆูŠุงุช</div>
407
+ </div>
408
+ <div style='background:linear-gradient(135deg,#2E7D32,#43A047);padding:18px;border-radius:12px;
409
+ text-align:center;color:white;box-shadow:0 3px 10px rgba(46,125,50,0.3);'>
410
+ <div style='font-size:30px;font-weight:bold;'>{s['match']:,}</div>
411
+ <div style='opacity:0.9;font-size:13px;'>โœ… ู…ุทุงุจู‚</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
412
  </div>
413
+ <div style='background:linear-gradient(135deg,#EF6C00,#FB8C00);padding:18px;border-radius:12px;
414
+ text-align:center;color:white;box-shadow:0 3px 10px rgba(239,108,0,0.3);'>
415
+ <div style='font-size:30px;font-weight:bold;'>{s['mismatch']:,}</div>
416
+ <div style='opacity:0.9;font-size:13px;'>โŒ ู…ุฎุงู„ู</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
417
  </div>
418
+ <div style='background:linear-gradient(135deg,#C62828,#E53935);padding:18px;border-radius:12px;
419
+ text-align:center;color:white;box-shadow:0 3px 10px rgba(198,40,40,0.3);'>
420
+ <div style='font-size:30px;font-weight:bold;'>{s['high_risk']:,}</div>
421
+ <div style='opacity:0.9;font-size:13px;'>๐Ÿ”ด ุฎุทุฑ ุนุงู„ูŠ</div>
422
+ </div>
423
+ <div style='background:linear-gradient(135deg,#4527A0,#5E35B1);padding:18px;border-radius:12px;
424
+ text-align:center;color:white;box-shadow:0 3px 10px rgba(69,39,160,0.3);'>
425
+ <div style='font-size:30px;font-weight:bold;'>{s['hs_codes']:,}</div>
426
+ <div style='opacity:0.9;font-size:13px;'>๐Ÿท๏ธ ุฃูƒูˆุงุฏ HS (TSC)</div>
427
+ </div>
428
+ <div style='background:linear-gradient(135deg,#00695C,#00897B);padding:18px;border-radius:12px;
429
+ text-align:center;color:white;box-shadow:0 3px 10px rgba(0,105,92,0.3);'>
430
+ <div style='font-size:30px;font-weight:bold;'>{s['cargo_types']}</div>
431
+ <div style='opacity:0.9;font-size:13px;'>๐Ÿ“‹ ุฃุตู†ุงู ู…ุณุฌู„ุฉ</div>
432
+ </div>
433
+ </div>
 
434
  </div>
435
+ """
436
+
437
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
438
+ # ๐Ÿ–ฅ๏ธ ุจู†ุงุก ุงู„ุชุทุจูŠู‚
439
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
440
+
441
+ CSS = """
442
+ @import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@400;500;700;800&display=swap');
443
+
444
+ * { font-family: 'Tajawal', sans-serif !important; }
445
+
446
+ .gradio-container {
447
+ max-width: 1200px !important;
448
+ margin: auto !important;
449
+ }
450
+
451
+ /* ุชุตุบูŠุฑ ู†ุงูุฐุฉ ุงู„ุฏุฎูˆู„ */
452
+ .login-container {
453
+ max-width: 380px !important;
454
+ margin: 60px auto !important;
455
+ }
456
+
457
+ footer { display: none !important; }
458
+
459
+ .gr-button-primary {
460
+ background: linear-gradient(135deg, #1565C0, #0D47A1) !important;
461
+ border: none !important;
462
+ font-weight: bold !important;
463
+ }
464
+
465
+ .gr-button-primary:hover {
466
+ background: linear-gradient(135deg, #1976D2, #1565C0) !important;
467
+ }
468
+ """
469
+
470
+
471
+ def build_app():
472
+ with gr.Blocks(title=f"SONAR-AI v{VERSION}", theme=gr.themes.Soft(), css=CSS) as app:
473
+
474
+ # โ•โ•โ• Header โ•โ•โ•
475
+ gr.HTML(f"""
476
+ <div style='background:linear-gradient(135deg,#0D47A1,#1565C0,#1976D2);padding:18px 24px;
477
+ border-radius:14px;text-align:center;color:white;margin-bottom:12px;
478
+ box-shadow:0 4px 20px rgba(13,71,161,0.3);'>
479
+ <h1 style='margin:0;font-size:28px;font-weight:800;letter-spacing:1px;'>
480
+ ๐Ÿ”ฑ SONAR-AI v{VERSION}
481
+ </h1>
482
+ <p style='margin:4px 0 0;font-size:14px;opacity:0.9;'>
483
+ ู†ุธุงู… ูุญุต ุงู„ุญุงูˆูŠุงุช ุจุงู„ุฐูƒุงุก ุงู„ุงุตุทู†ุงุนูŠ | {len(TSC_DATABASE):,} ูƒูˆุฏ HS ู…ู† ู‚ุงุนุฏุฉ TSC
484
+ </p>
485
+ </div>
486
+ """)
487
+
488
+ with gr.Tabs():
489
+
490
+ # โ•โ•โ•โ•โ•โ•โ• Tab 1: ู„ูˆุญุฉ ุงู„ุชุญูƒู… โ•โ•โ•โ•โ•โ•โ•
491
+ with gr.Tab("๐Ÿ“Š ู„ูˆุญุฉ ุงู„ุชุญูƒู…"):
492
+ gr.HTML(stats_html())
493
+ gr.Markdown("### ๐Ÿ“‹ ุขุฎุฑ ุงู„ุญุงูˆูŠุงุช ุงู„ู…ูุญูˆุตุฉ")
494
+ anom_table = gr.Dataframe(value=get_anomalies(), height=350)
495
+ gr.Button("๐Ÿ”„ ุชุญุฏูŠุซ ุงู„ุจูŠุงู†ุงุช", size="sm").click(get_anomalies, outputs=anom_table)
496
+
497
+ # โ•โ•โ•โ•โ•โ•โ• Tab 2: ุงู„ุชุญู„ูŠู„ โ•โ•โ•โ•โ•โ•โ•
498
+ with gr.Tab("๐Ÿ”ฌ ุชุญู„ูŠู„ ุงู„ุตูˆุฑ"):
499
+ gr.HTML("""
500
+ <div style='background:#E3F2FD;padding:12px 16px;border-radius:10px;margin-bottom:10px;
501
+ border-right:4px solid #1565C0;'>
502
+ <span style='font-weight:bold;color:#1565C0;'>๐Ÿ“ท ุชุญู„ูŠู„ ุตูˆุฑ ุงู„ุฃุดุนุฉ ุงู„ุณูŠู†ูŠุฉ</span>
503
+ <span style='color:#666;font-size:13px;'> โ€” ูŠูƒุชุดู ุงู„ุฃุตู†ุงู ูˆูŠุฑุจุทู‡ุง ุจุฃูƒูˆุงุฏ HS ู…ู† ู‚ุงุนุฏุฉ TSC</span>
504
+ </div>
505
+ """)
506
+
507
+ with gr.Row():
508
+ with gr.Column(scale=1):
509
+ a_img = gr.Image(label="๐Ÿ“ท ุตูˆุฑุฉ ุงู„ุฃุดุนุฉ", type="pil", height=280)
510
+ a_dec = gr.Textbox(
511
+ label="๐Ÿ“‹ ุงู„ุจุถุงุนุฉ ุงู„ู…ุตุฑู‘ุญ ุจู‡ุง (ุงุฎุชูŠุงุฑูŠ)",
512
+ placeholder="SHOES + FABRIC + LED_LIGHT ...",
513
+ lines=2
514
+ )
515
+ a_btn = gr.Button("๐Ÿ” ุชุญู„ูŠู„ ุดุงู…ู„", variant="primary", size="lg")
516
+
517
+ with gr.Column(scale=1):
518
+ a_res = gr.HTML(
519
+ "<div style='text-align:center;padding:50px;color:#888;font-size:16px;'>"
520
+ "โณ ุงุฑูุน ุตูˆุฑุฉ ุฃุดุนุฉ ุณูŠู†ูŠุฉ ู„ู„ุจุฏุก ุจุงู„ุชุญู„ูŠู„</div>"
521
+ )
522
+
523
+ gr.Markdown("### ๐Ÿ“‹ ุชูุงุตูŠู„ ุงู„ุฃุตู†ุงู ุงู„ู…ูƒุชุดูุฉ ู…ุน ุฃูƒูˆุงุฏ HS")
524
+ a_tbl = gr.Dataframe(value=pd.DataFrame(), height=300)
525
+
526
+ a_btn.click(analyze_multi_label, inputs=[a_img, a_dec], outputs=[a_res, a_tbl])
527
+
528
+ # โ•โ•โ•โ•โ•โ•โ• Tab 3: ู‚ุงุนุฏุฉ ุงู„ุฃุตู†ุงู โ•โ•โ•โ•โ•โ•โ•
529
+ with gr.Tab("๐Ÿท๏ธ ู‚ุงุนุฏุฉ ุงู„ุฃุตู†ุงู"):
530
+ gr.HTML(f"""
531
+ <div style='background:#E8F5E9;padding:12px 16px;border-radius:10px;margin-bottom:10px;
532
+ border-right:4px solid #2E7D32;'>
533
+ <span style='font-weight:bold;color:#2E7D32;'>๐Ÿ“ฆ {len(CARGO_DATABASE)} ุตู†ู</span>
534
+ <span style='color:#666;font-size:13px;'> โ€” ู…ุฑุชุจุทุฉ ุจุฃูƒูˆุงุฏ HS ูˆุงู„ุฃุณุนุงุฑ ุงู„ู…ุฑุฌุนูŠุฉ ู…ู† TSC</span>
535
+ </div>
536
+ """)
537
+ cats_table = gr.Dataframe(value=get_categories(), height=500)
538
+ gr.Button("๐Ÿ”„ ุชุญุฏูŠุซ", size="sm").click(get_categories, outputs=cats_table)
539
+
540
+ # โ•โ•โ•โ•โ•โ•โ• Tab 4: ุจุญุซ TSC โ•โ•โ•โ•โ•โ•โ•
541
+ with gr.Tab("๐Ÿ” ุจุญุซ TSC"):
542
+ gr.HTML(f"""
543
+ <div style='background:#FFF3E0;padding:12px 16px;border-radius:10px;margin-bottom:10px;
544
+ border-right:4px solid #EF6C00;'>
545
+ <span style='font-weight:bold;color:#EF6C00;'>๐Ÿ” ุงู„ุจุญุซ ููŠ ู‚ุงุนุฏุฉ TSC</span>
546
+ <span style='color:#666;font-size:13px;'> โ€” {len(TSC_DATABASE):,} ูƒูˆุฏ HS ุญู‚ูŠู‚ูŠ</span>
547
+ </div>
548
+ """)
549
+ with gr.Row():
550
+ tsc_query = gr.Textbox(
551
+ label="ุงุจุญุซ ุจูƒูˆุฏ HS ุฃูˆ ูˆุตู ุงู„ุจุถุงุนุฉ",
552
+ placeholder="ู…ุซุงู„: 870323 ุฃูˆ ุฃุญุฐูŠุฉ ุฃูˆ ุญุฏูŠุฏ ...",
553
+ scale=3
554
+ )
555
+ tsc_btn = gr.Button("๐Ÿ” ุจุญุซ", variant="primary", scale=1)
556
+
557
+ tsc_results = gr.Dataframe(value=pd.DataFrame(), height=400)
558
+ tsc_btn.click(search_tsc, inputs=[tsc_query], outputs=[tsc_results])
559
+ tsc_query.submit(search_tsc, inputs=[tsc_query], outputs=[tsc_results])
560
+
561
+ # โ•โ•โ•โ•โ•โ•โ• Tab 5: ุงู„ุฎุทูˆุฑุฉ โ•โ•โ•โ•โ•โ•โ•
562
+ with gr.Tab("โšก ู…ุนุงูŠูŠุฑ ุงู„ุฎุทูˆุฑุฉ"):
563
+ gr.HTML("""
564
+ <div style='display:flex;gap:8px;margin:15px 0;flex-wrap:wrap;'>
565
+ <span style='background:#2E7D32;color:white;padding:10px 20px;border-radius:25px;font-weight:bold;'>๐ŸŸข 0 - ุขู…ู†</span>
566
+ <span style='background:#558B2F;color:white;padding:10px 20px;border-radius:25px;font-weight:bold;'>๐ŸŸข 1 - ู…ู†ุฎูุถ</span>
567
+ <span style='background:#F9A825;color:#333;padding:10px 20px;border-radius:25px;font-weight:bold;'>๐ŸŸก 2 - ู…ุชูˆุณุท</span>
568
+ <span style='background:#EF6C00;color:white;padding:10px 20px;border-radius:25px;font-weight:bold;'>๐ŸŸ  3 - ู…ุดุจูˆู‡</span>
569
+ <span style='background:#D84315;color:white;padding:10px 20px;border-radius:25px;font-weight:bold;'>๐Ÿ”ด 4 - ุนุงู„ูŠ</span>
570
+ <span style='background:#B71C1C;color:white;padding:10px 20px;border-radius:25px;font-weight:bold;'>โ›” 5 - ุญุฑุฌ</span>
571
+ </div>
572
+ """)
573
+ gr.Markdown("""
574
+ ### ๐Ÿ“‹ ู…ุนุงูŠูŠุฑ ุชุญุฏูŠุฏ ุงู„ุฎุทูˆุฑุฉ
575
+
576
+ | ุงู„ู…ุณุชูˆู‰ | ุงู„ุญุงู„ุฉ | ุงู„ุฅุฌุฑุงุก |
577
+ |---------|--------|---------|
578
+ | 0 - ุขู…ู† | ุฌู…ูŠุน ุงู„ุฃุตู†ุงู ู…ุทุงุจู‚ุฉ | ุชู…ุฑูŠุฑ ู…ุจุงุดุฑ |
579
+ | 1 - ู…ู†ุฎูุถ | ุงุฎุชู„ุงู ุจุณูŠุท ููŠ ุงู„ูƒู…ูŠุงุช | ู…ุฑุงุฌุนุฉ ูˆุซุงุฆู‚ |
580
+ | 2 - ู…ุชูˆุณุท | ุตู†ู ุฅุถุงููŠ ุบูŠุฑ ู…ุฐูƒูˆุฑ | ูุญุต ุนุดูˆุงุฆูŠ |
581
+ | 3 - ู…ุดุจูˆู‡ | ุนุฏุฉ ุฃุตู†ุงู ุบูŠุฑ ู…ุทุงุจู‚ุฉ | ุชูุชูŠุด ุฏู‚ูŠู‚ |
582
+ | 4 - ุนุงู„ูŠ | ุฃุตู†ุงู ู…ุดุจูˆู‡ุฉ ุฃูˆ ู…ู‚ูŠู‘ุฏุฉ | ุชูุชูŠุด ุดุงู…ู„ + ุฅุญุงู„ุฉ |
583
+ | 5 - ุญุฑุฌ | ู…ู…ู†ูˆุนุงุช ุฃูˆ ู…ูˆุงุฏ ุฎุทุฑุฉ | ุฅูŠู‚ุงู ููˆุฑูŠ + ุฅุจู„ุงุบ |
584
+
585
+ ### ๐Ÿ”— ุฑุจุท ุงู„ุฎุทูˆุฑุฉ ุจุฃูƒูˆุงุฏ HS
586
+ - ุฃูƒูˆุงุฏ **ุงู„ูุตู„ 93** (ุฃุณู„ุญุฉ): ุฎุทูˆุฑุฉ 5 ุชู„ู‚ุงุฆูŠุงู‹
587
+ - ุฃูƒูˆุงุฏ **ุงู„ูุตู„ 36** (ู…ุชูุฌุฑุงุช): ุฎุทูˆุฑุฉ 5 ุชู„ู‚ุงุฆูŠุงู‹
588
+ - ุฃูƒูˆุงุฏ **ุงู„ูุตู„ 30** (ุฃุฏูˆูŠุฉ) ุจุฏูˆู† ุชุตุฑูŠุญ: ุฎุทูˆุฑุฉ 4
589
+ - ุนุฏู… ุชุทุงุจู‚ ูƒูˆุฏ HS ู…ุน ุงู„ุตูˆุฑุฉ: ุฎุทูˆุฑุฉ +2
590
+ """)
591
+
592
+ # โ•โ•โ• Footer โ•โ•โ•
593
+ gr.HTML(f"""
594
+ <div style='text-align:center;padding:12px;color:#888;font-size:12px;margin-top:12px;'>
595
+ ๐Ÿ”ฑ SONAR-AI v{VERSION} | {len(TSC_DATABASE):,} HS Codes | ยฉ 2026 ุงู„ุฌู…ุงุฑูƒ ุงู„ุนุฑุงู‚ูŠุฉ
596
+ </div>
597
+ """)
598
+
599
+ return app
600
+
601
+
602
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
603
+ # ๐Ÿš€ ุงู„ุชุดุบูŠู„
604
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
605
 
606
  if __name__ == "__main__":
607
+ print(f"๐Ÿ”ฑ SONAR-AI v{VERSION}")
608
+ print(f"๐Ÿ“ฆ Cargo types: {len(CARGO_DATABASE)}")
609
+ print(f"๐Ÿท๏ธ TSC HS codes: {len(TSC_DATABASE)}")
610
+ print("๐Ÿš€ Starting...")
611
+
612
+ app = build_app()
613
+ app.launch(
614
+ auth=authenticate,
615
+ auth_message="๐Ÿ”ฑ SONAR-AI โ€” ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„",
616
+ server_name="0.0.0.0",
617
+ server_port=7860,
618
+ )