Update app.py
Browse files
app.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
#!/usr/bin/env python3
|
| 2 |
"""
|
| 3 |
-
SONAR-AI v12.5 -
|
|
|
|
| 4 |
"""
|
| 5 |
|
| 6 |
import gradio as gr
|
|
@@ -12,12 +13,27 @@ import numpy as np
|
|
| 12 |
import os
|
| 13 |
from datetime import datetime
|
| 14 |
from collections import Counter
|
|
|
|
|
|
|
| 15 |
|
| 16 |
VERSION = "12.5"
|
| 17 |
USERS = {"ุนุจุงุณ": "1", "abbas": "1", "admin": "admin123", "test": "test"}
|
| 18 |
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
| 20 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
CARGO_NAMES = {
|
| 22 |
'appliances': 'ุฃุฌูุฒุฉ ู
ูุฒููุฉ', 'auto_parts': 'ูุทุน ุบูุงุฑ ุณูุงุฑุงุช', 'bags': 'ุญูุงุฆุจ',
|
| 23 |
'banana': 'ู
ูุฒ', 'batteries': 'ุจุทุงุฑูุงุช', 'beverages': 'ู
ุดุฑูุจุงุช',
|
|
@@ -35,35 +51,175 @@ CARGO_NAMES = {
|
|
| 35 |
'tools': 'ุฃุฏูุงุช', 'toys': 'ุฃูุนุงุจ', 'vegetables': 'ุฎุถุฑูุงุช', 'wood': 'ุฎุดุจ'
|
| 36 |
}
|
| 37 |
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
'banana': {'hsc': '0803.90.10', 'description': 'ู
ูุฒ ุทุงุฒุฌ', 'duty': 5, 'restrictions': 'ุดูุงุฏุฉ ุตุญูุฉ'},
|
| 42 |
-
'cooking_oil': {'hsc': '1507-1516', 'description': 'ุฒููุช ุทุนุงู
ูุจุงุชูุฉ', 'duty': 5, 'restrictions': 'ุดูุงุฏุฉ ุตุญูุฉ'},
|
| 43 |
-
'furniture': {'hsc': '9403.60.00', 'description': 'ุฃุซุงุซ', 'duty': 30, 'restrictions': 'ุดูุงุฏุฉ CITES'},
|
| 44 |
-
'tea': {'hsc': '0902.30.00', 'description': 'ุดุงู', 'duty': 10, 'restrictions': 'ุดูุงุฏุฉ ุตุญูุฉ'},
|
| 45 |
-
'rice': {'hsc': '1006.30.00', 'description': 'ุฃุฑุฒ', 'duty': 10, 'restrictions': 'ูุญุต ุฌูุฏุฉ'},
|
| 46 |
-
'clothes': {'hsc': '6201-6211', 'description': 'ู
ูุงุจุณ ูู
ูุณูุฌุงุช', 'duty': 20, 'restrictions': 'ูุญุต ุงูู
ูุดุฃ'},
|
| 47 |
-
'electronics': {'hsc': '8471-8543', 'description': 'ุฅููุชุฑูููุงุช', 'duty': 10, 'restrictions': 'ุดูุงุฏุฉ ู
ุทุงุจูุฉ'},
|
| 48 |
-
'other': {'hsc': '9999.99.99', 'description': 'ุจุถุงุฆุน ู
ุชููุนุฉ', 'duty': 15, 'restrictions': 'ุญุณุจ ุงูููุน'},
|
| 49 |
-
}
|
| 50 |
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
|
| 66 |
-
# Deep-SOSUFS Model
|
| 67 |
class SOSUFS_Layer(nn.Module):
|
| 68 |
def __init__(self, in_features, out_features, k=8):
|
| 69 |
super().__init__()
|
|
@@ -99,8 +255,6 @@ class DeepSOSUFS(nn.Module):
|
|
| 99 |
return self.classifier(x)
|
| 100 |
|
| 101 |
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
| 102 |
-
print(f"๐ฅ๏ธ Device: {device}")
|
| 103 |
-
|
| 104 |
transform = transforms.Compose([
|
| 105 |
transforms.Resize((224, 224)),
|
| 106 |
transforms.ToTensor(),
|
|
@@ -108,439 +262,283 @@ transform = transforms.Compose([
|
|
| 108 |
])
|
| 109 |
|
| 110 |
models_loaded = {}
|
| 111 |
-
cargo_classes =
|
| 112 |
|
| 113 |
def load_models():
|
| 114 |
global models_loaded, cargo_classes
|
| 115 |
|
| 116 |
-
# Deep-SOSUFS
|
| 117 |
try:
|
| 118 |
sosufs = DeepSOSUFS()
|
| 119 |
ckpt = torch.load('deep_sosufs_final.pt', map_location=device, weights_only=False)
|
| 120 |
sosufs.load_state_dict(ckpt.get('model_state_dict', ckpt), strict=False)
|
| 121 |
sosufs.to(device).eval()
|
| 122 |
models_loaded['sosufs'] = sosufs
|
| 123 |
-
print("โ
Deep-SOSUFS loaded
|
| 124 |
-
except
|
| 125 |
-
print(f"โ Deep-SOSUFS: {e}")
|
| 126 |
models_loaded['sosufs'] = None
|
| 127 |
|
| 128 |
-
# YOLOv8 Cargo
|
| 129 |
try:
|
| 130 |
from ultralytics import YOLO
|
| 131 |
if os.path.exists('sonar_v12_best.pt'):
|
| 132 |
cargo = YOLO('sonar_v12_best.pt')
|
| 133 |
cargo_classes = list(cargo.names.values())
|
| 134 |
models_loaded['cargo'] = cargo
|
| 135 |
-
print(f"โ
YOLOv8
|
| 136 |
-
print(f" Classes: {cargo_classes[:10]}...")
|
| 137 |
-
except Exception as e:
|
| 138 |
-
print(f"โ Cargo: {e}")
|
| 139 |
-
models_loaded['cargo'] = None
|
| 140 |
-
cargo_classes = list(CARGO_NAMES.keys())
|
| 141 |
-
|
| 142 |
-
# Contraband
|
| 143 |
-
try:
|
| 144 |
-
from ultralytics import YOLO
|
| 145 |
-
models_loaded['contraband'] = YOLO('contraband_detector.pt')
|
| 146 |
-
print("โ
Contraband Detector loaded")
|
| 147 |
except:
|
| 148 |
-
models_loaded['
|
| 149 |
-
|
| 150 |
-
# Weapons
|
| 151 |
-
try:
|
| 152 |
-
from ultralytics import YOLO
|
| 153 |
-
models_loaded['weapons'] = YOLO('best.pt')
|
| 154 |
-
print("โ
Weapons Detector loaded")
|
| 155 |
-
except:
|
| 156 |
-
models_loaded['weapons'] = None
|
| 157 |
|
| 158 |
load_models()
|
| 159 |
|
| 160 |
-
|
| 161 |
-
|
|
|
|
| 162 |
|
| 163 |
-
def
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
try:
|
| 167 |
-
with torch.no_grad():
|
| 168 |
-
tensor = transform(pil_image).unsqueeze(0).to(device)
|
| 169 |
-
out = models_loaded['sosufs'](tensor)
|
| 170 |
-
probs = torch.softmax(out, 1)
|
| 171 |
-
return float(probs[0][0]), float(probs[0][1])
|
| 172 |
-
except:
|
| 173 |
-
return 0.5, 0.5
|
| 174 |
-
|
| 175 |
-
def analyze_cargo(pil_image):
|
| 176 |
-
if models_loaded.get('cargo') is None:
|
| 177 |
-
return None, 0, []
|
| 178 |
-
try:
|
| 179 |
-
results = models_loaded['cargo'](pil_image, imgsz=640, verbose=False)
|
| 180 |
-
|
| 181 |
-
# Classification model
|
| 182 |
-
if results and hasattr(results[0], 'probs') and results[0].probs is not None:
|
| 183 |
-
probs = results[0].probs
|
| 184 |
-
top_cls = cargo_classes[probs.top1]
|
| 185 |
-
top_conf = float(probs.top1conf)
|
| 186 |
-
top3 = []
|
| 187 |
-
for i, c in zip(probs.top5[:3], probs.top5conf.tolist()[:3]):
|
| 188 |
-
if i < len(cargo_classes):
|
| 189 |
-
top3.append((cargo_classes[i], c))
|
| 190 |
-
return top_cls, top_conf, top3
|
| 191 |
-
|
| 192 |
-
# Detection model
|
| 193 |
-
elif results and hasattr(results[0], 'boxes') and results[0].boxes is not None and len(results[0].boxes) > 0:
|
| 194 |
-
boxes = results[0].boxes
|
| 195 |
-
cls_ids = [int(box.cls[0]) for box in boxes]
|
| 196 |
-
cls_counts = Counter(cls_ids)
|
| 197 |
-
top_cls_id = cls_counts.most_common(1)[0][0]
|
| 198 |
-
confs = [float(box.conf[0]) for box in boxes if int(box.cls[0]) == top_cls_id]
|
| 199 |
-
avg_conf = sum(confs) / len(confs) if confs else 0
|
| 200 |
-
if top_cls_id < len(cargo_classes):
|
| 201 |
-
top_cls = cargo_classes[top_cls_id]
|
| 202 |
-
top3 = []
|
| 203 |
-
for cls_id, _ in cls_counts.most_common(3):
|
| 204 |
-
if cls_id < len(cargo_classes):
|
| 205 |
-
cls_confs = [float(box.conf[0]) for box in boxes if int(box.cls[0]) == cls_id]
|
| 206 |
-
avg = sum(cls_confs) / len(cls_confs) if cls_confs else 0
|
| 207 |
-
top3.append((cargo_classes[cls_id], avg))
|
| 208 |
-
return top_cls, avg_conf, top3
|
| 209 |
-
except Exception as e:
|
| 210 |
-
print(f"Cargo error: {e}")
|
| 211 |
-
return None, 0, []
|
| 212 |
-
|
| 213 |
-
def analyze_weapons(pil_image, draw=None):
|
| 214 |
-
if models_loaded.get('weapons') is None:
|
| 215 |
-
return []
|
| 216 |
-
try:
|
| 217 |
-
results = models_loaded['weapons'](pil_image, conf=0.3, imgsz=224, verbose=False)
|
| 218 |
-
weapons = []
|
| 219 |
-
for r in results:
|
| 220 |
-
if r.boxes:
|
| 221 |
-
for box in r.boxes:
|
| 222 |
-
x1, y1, x2, y2 = map(int, box.xyxy[0].tolist())
|
| 223 |
-
conf = float(box.conf[0])
|
| 224 |
-
name = r.names[int(box.cls[0])]
|
| 225 |
-
if draw:
|
| 226 |
-
draw.rectangle([x1, y1, x2, y2], outline="red", width=4)
|
| 227 |
-
draw.text((x1, y1-20), f"{name}", fill="red")
|
| 228 |
-
weapons.append({'name': name, 'confidence': conf})
|
| 229 |
-
return weapons
|
| 230 |
-
except:
|
| 231 |
-
return []
|
| 232 |
-
|
| 233 |
-
def calculate_risk(match_p, mismatch_p, weapons):
|
| 234 |
-
if weapons:
|
| 235 |
-
return 7
|
| 236 |
-
if mismatch_p > 0.8:
|
| 237 |
-
return 4
|
| 238 |
-
elif mismatch_p > 0.6:
|
| 239 |
-
return 3
|
| 240 |
-
elif mismatch_p > 0.4:
|
| 241 |
-
return 2
|
| 242 |
-
return 1
|
| 243 |
-
|
| 244 |
-
def generate_stats_html():
|
| 245 |
-
total = DAILY_STATS['total'] or 1
|
| 246 |
-
return f"""
|
| 247 |
-
<div style='background:linear-gradient(135deg,#1a1a2e,#16213e);padding:20px;border-radius:15px;color:white;'>
|
| 248 |
-
<h3 style='margin:0 0 15px 0;color:#00d4ff;font-size:18px;font-weight:bold;'>๐ ุฅุญุตุงุฆูุงุช ุงูููู
</h3>
|
| 249 |
-
<div style='display:grid;grid-template-columns:repeat(2,1fr);gap:15px;'>
|
| 250 |
-
<div style='background:rgba(255,255,255,0.1);padding:15px;border-radius:10px;text-align:center;'>
|
| 251 |
-
<div style='font-size:32px;font-weight:bold;color:#4CAF50;'>{DAILY_STATS['total']}</div>
|
| 252 |
-
<div style='color:#fff;font-size:14px;'>ุฅุฌู
ุงูู ุงููุญูุตุงุช</div>
|
| 253 |
-
</div>
|
| 254 |
-
<div style='background:rgba(255,255,255,0.1);padding:15px;border-radius:10px;text-align:center;'>
|
| 255 |
-
<div style='font-size:32px;font-weight:bold;color:#2196F3;'>{DAILY_STATS['match']}</div>
|
| 256 |
-
<div style='color:#fff;font-size:14px;'>ู
ุทุงุจู ({DAILY_STATS['match']*100//total}%)</div>
|
| 257 |
-
</div>
|
| 258 |
-
</div>
|
| 259 |
-
</div>
|
| 260 |
-
"""
|
| 261 |
-
|
| 262 |
-
def full_analysis(image, declared_goods="", container_id=""):
|
| 263 |
-
if image is None:
|
| 264 |
-
empty = "<div style='text-align:center;padding:30px;color:#666;font-size:18px;'>โณ ูู ุงูุชุธุงุฑ ุฑูุน ุงูุตูุฑุฉ...</div>"
|
| 265 |
-
return None, empty, "", "", "", generate_stats_html()
|
| 266 |
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
out_img = pil.copy()
|
| 275 |
-
draw = ImageDraw.Draw(out_img)
|
| 276 |
-
|
| 277 |
-
# ุงูุชุญููู
|
| 278 |
-
weapons = analyze_weapons(pil, draw)
|
| 279 |
-
match_p, mismatch_p = analyze_sosufs(pil)
|
| 280 |
-
cargo_type, cargo_conf, cargo_top3 = analyze_cargo(pil)
|
| 281 |
-
|
| 282 |
-
risk_level = calculate_risk(match_p, mismatch_p, weapons)
|
| 283 |
-
risk_info = RISK_LEVELS.get(risk_level, RISK_LEVELS[1])
|
| 284 |
-
|
| 285 |
-
# ุชุญุฏูุซ ุงูุฅุญุตุงุฆูุงุช
|
| 286 |
-
DAILY_STATS['total'] += 1
|
| 287 |
-
if match_p > 0.5:
|
| 288 |
-
DAILY_STATS['match'] += 1
|
| 289 |
-
else:
|
| 290 |
-
DAILY_STATS['mismatch'] += 1
|
| 291 |
-
|
| 292 |
-
cargo_ar = get_cargo_name(cargo_type) if cargo_type else "ุบูุฑ ู
ุญุฏุฏ"
|
| 293 |
-
|
| 294 |
-
# === ูุชูุฌุฉ ุงูู
ุทุงุจูุฉ ===
|
| 295 |
-
if weapons:
|
| 296 |
-
match_html = """
|
| 297 |
-
<div style='background:#FFEBEE;padding:25px;border-radius:15px;border-right:6px solid #D32F2F;'>
|
| 298 |
-
<h2 style='color:#C62828;margin:0;font-size:28px;font-weight:bold;'>๐จ ุชุญุฐูุฑ ุฃู
ูู!</h2>
|
| 299 |
-
<p style='color:#333;margin:10px 0 0 0;font-size:16px;'>ุชู
ุงูุชุดุงู ุฃุณูุญุฉ</p>
|
| 300 |
</div>
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
<div style='background:#FFF3E0;padding:25px;border-radius:15px;border-right:6px solid #FF9800;'>
|
| 305 |
-
<h2 style='color:#E65100;margin:0;font-size:28px;font-weight:bold;'>โ ู
ุฎุงูู ({mismatch_p:.0%})</h2>
|
| 306 |
-
<p style='color:#333;margin:10px 0 0 0;font-size:16px;'>ุงูุจุถุงุนุฉ ูุฏ ูุง ุชุชุทุงุจู ู
ุน ุงูุชุตุฑูุญ</p>
|
| 307 |
</div>
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
<div style='background:#E8F5E9;padding:25px;border-radius:15px;border-right:6px solid #4CAF50;'>
|
| 312 |
-
<h2 style='color:#2E7D32;margin:0;font-size:28px;font-weight:bold;'>โ
ู
ุทุงุจู ({match_p:.0%})</h2>
|
| 313 |
-
<p style='color:#333;margin:10px 0 0 0;font-size:16px;'>ุงูุจุถุงุนุฉ ู
ุชูุงููุฉ ู
ุน ุงูุชุตุฑูุญ</p>
|
| 314 |
</div>
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
cargo_html = f"""
|
| 319 |
-
<div style='background:#ffffff;padding:25px;border-radius:15px;box-shadow:0 4px 15px rgba(0,0,0,0.1);'>
|
| 320 |
-
<h3 style='color:#1565C0;margin:0 0 20px 0;font-size:20px;font-weight:bold;'>๐ฆ ุงูุชุตููู ุงูุฑุฆูุณู</h3>
|
| 321 |
-
<div style='display:flex;align-items:center;gap:15px;margin-bottom:20px;flex-wrap:wrap;'>
|
| 322 |
-
<span style='font-size:32px;font-weight:bold;color:#1a1a1a;'>{cargo_ar}</span>
|
| 323 |
-
<span style='background:#E3F2FD;color:#1565C0;padding:8px 18px;border-radius:25px;font-size:16px;font-weight:bold;'>{cargo_type or '-'}</span>
|
| 324 |
-
<span style='background:#4CAF50;color:#ffffff;padding:8px 18px;border-radius:25px;font-size:18px;font-weight:bold;'>{cargo_conf:.0%}</span>
|
| 325 |
</div>
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
|
| 329 |
-
if cargo_type and cargo_type in HSC_TARIFF:
|
| 330 |
-
hsc = HSC_TARIFF[cargo_type]
|
| 331 |
-
cargo_html += f"""
|
| 332 |
-
<div style='background:#FFF8E1;padding:20px;border-radius:12px;border-right:5px solid #FF9800;'>
|
| 333 |
-
<h4 style='color:#E65100;margin:0 0 15px 0;font-size:18px;font-weight:bold;'>๐ ุงูุชุนุฑููุฉ ุงูุฌู
ุฑููุฉ</h4>
|
| 334 |
-
<table style='width:100%;font-size:16px;'>
|
| 335 |
-
<tr><td style='padding:10px;font-weight:bold;color:#555;width:100px;'>ุงูููุฏ:</td><td style='padding:10px;color:#1a1a1a;font-weight:bold;font-size:20px;'>{hsc['hsc']}</td></tr>
|
| 336 |
-
<tr><td style='padding:10px;font-weight:bold;color:#555;'>ุงููุตู:</td><td style='padding:10px;color:#1a1a1a;'>{hsc['description']}</td></tr>
|
| 337 |
-
<tr><td style='padding:10px;font-weight:bold;color:#555;'>ุงูุฑุณูู
:</td><td style='padding:10px;color:#D84315;font-weight:bold;font-size:22px;'>{hsc['duty']}%</td></tr>
|
| 338 |
-
<tr><td style='padding:10px;font-weight:bold;color:#555;'>ุงููููุฏ:</td><td style='padding:10px;color:#1a1a1a;'>{hsc['restrictions']}</td></tr>
|
| 339 |
-
</table>
|
| 340 |
</div>
|
| 341 |
-
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
if cargo_top3:
|
| 345 |
-
cargo_html += "<div style='margin-top:20px;'><span style='font-weight:bold;color:#555;font-size:16px;'>ุฃูุฑุจ ุงูุชุตูููุงุช:</span><div style='display:flex;gap:10px;margin-top:10px;flex-wrap:wrap;'>"
|
| 346 |
-
for cls, conf in cargo_top3:
|
| 347 |
-
cargo_html += f"<span style='background:#f5f5f5;color:#1a1a1a;padding:8px 15px;border-radius:20px;font-size:14px;font-weight:bold;border:2px solid #ddd;'>{get_cargo_name(cls)} ({conf:.0%})</span>"
|
| 348 |
-
cargo_html += "</div></div>"
|
| 349 |
-
|
| 350 |
-
cargo_html += "</div>"
|
| 351 |
-
|
| 352 |
-
# === ู
ุณุชูู ุงูุฎุทูุฑุฉ ===
|
| 353 |
-
risk_html = f"""
|
| 354 |
-
<div style='background:#ffffff;padding:25px;border-radius:15px;border-right:6px solid {risk_info["color"]};box-shadow:0 4px 15px rgba(0,0,0,0.1);'>
|
| 355 |
-
<h2 style='color:{risk_info["color"]};margin:0;font-size:24px;font-weight:bold;'>{risk_info['icon']} ู
ุณุชูู ุงูุฎุทูุฑุฉ: {risk_info['name']}</h2>
|
| 356 |
-
<p style='color:#333;margin:10px 0;font-size:16px;'>ุงูุฏุฑุฌุฉ: <b>{risk_level}/7</b></p>
|
| 357 |
-
<div style='background:{risk_info["color"]};color:#ffffff;padding:15px 25px;border-radius:10px;margin-top:15px;text-align:center;'>
|
| 358 |
-
<span style='font-size:18px;font-weight:bold;'>{risk_info['action']}</span>
|
| 359 |
</div>
|
| 360 |
</div>
|
| 361 |
-
|
| 362 |
-
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 378 |
|
| 379 |
-
# === CSS ===
|
| 380 |
css = """
|
| 381 |
@import url('https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;700;800&display=swap');
|
| 382 |
* { font-family: 'Cairo', sans-serif !important; }
|
| 383 |
|
| 384 |
.gradio-container {
|
| 385 |
-
background: linear-gradient(135deg, #
|
| 386 |
-
max-width:
|
| 387 |
}
|
| 388 |
|
| 389 |
.main-header {
|
| 390 |
background: linear-gradient(135deg, #00b4d8, #0077b6, #023e8a);
|
| 391 |
color: white;
|
| 392 |
-
padding:
|
| 393 |
-
border-radius:
|
| 394 |
text-align: center;
|
| 395 |
-
margin-bottom:
|
| 396 |
-
box-shadow: 0 10px 40px rgba(0,180,216,0.4);
|
| 397 |
}
|
| 398 |
|
| 399 |
-
.
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
font-size: 13px;
|
| 404 |
-
margin: 3px;
|
| 405 |
-
font-weight: 600;
|
| 406 |
}
|
| 407 |
|
| 408 |
-
.
|
| 409 |
-
|
|
|
|
| 410 |
|
| 411 |
button.primary {
|
| 412 |
background: linear-gradient(135deg, #00b4d8, #0077b6) !important;
|
| 413 |
-
font-size: 20px !important;
|
| 414 |
-
padding: 15px 30px !important;
|
| 415 |
-
border-radius: 12px !important;
|
| 416 |
font-weight: bold !important;
|
| 417 |
}
|
| 418 |
-
|
| 419 |
-
.footer {
|
| 420 |
-
text-align: center;
|
| 421 |
-
color: white;
|
| 422 |
-
padding: 20px;
|
| 423 |
-
margin-top: 20px;
|
| 424 |
-
background: linear-gradient(135deg, rgba(255,255,255,0.1), rgba(255,255,255,0.05));
|
| 425 |
-
border-radius: 15px;
|
| 426 |
-
font-size: 14px;
|
| 427 |
-
}
|
| 428 |
"""
|
| 429 |
|
| 430 |
-
#
|
|
|
|
|
|
|
|
|
|
| 431 |
with gr.Blocks(css=css, title=f"SONAR-AI v{VERSION}", theme=gr.themes.Soft()) as app:
|
| 432 |
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
<div style='text-align:center;margin-bottom:30px;'>
|
| 440 |
-
<div style='font-size:50px;'>๐ฌ</div>
|
| 441 |
-
<h1 style='margin:10px 0;color:#1565C0;font-size:28px;font-weight:bold;'>SONAR-AI v{VERSION}</h1>
|
| 442 |
-
<p style='color:#666;font-size:14px;margin:5px 0;'>ูุธุงู
ูุญุต ุงูุฌู
ุงุฑู ุงูุนุฑุงููุฉ ุงูุดุงู
ู</p>
|
| 443 |
-
<p style='color:#4CAF50;font-weight:bold;font-size:14px;'>๐ฏ ุฏูุฉ 99.1% | 42 ูุฆุฉ | YOLOv8</p>
|
| 444 |
-
</div>
|
| 445 |
-
<div style='border-top:1px solid #eee;padding-top:15px;margin-top:15px;'>
|
| 446 |
-
<p style='color:#888;font-size:11px;text-align:center;margin:0;line-height:1.8;'>
|
| 447 |
-
<b>ูุฑูู ุงูุนู
ู:</b><br>
|
| 448 |
-
ุฏ. ุนุจุงุณ ูุงุถู ุฌุงุณู
ุงูุฌุจูุฑู (ูุงุฆุฏ ุงููุฑูู)<br>
|
| 449 |
-
ุฃ. ุนุงู
ุฑ ุซุงุฌุจ (ุงูู
ุณุชุดุงุฑ ุงููุงูููู)<br>
|
| 450 |
-
ุฃ. ูุงุธู
ู
ููุฏู | ุฃ. ุธูุงุฑ ุตุงูุญ | ุฃ. ุนู
ุงุฑ ุงูุดุนูุงู | ุฃ. ูููุณ ุฐููู | ุฃ. ุจุงุณู
|
| 451 |
-
</p>
|
| 452 |
-
</div>
|
| 453 |
-
</div>
|
| 454 |
-
""")
|
| 455 |
-
with gr.Row():
|
| 456 |
-
with gr.Column(scale=1):
|
| 457 |
-
pass
|
| 458 |
-
with gr.Column(scale=2):
|
| 459 |
-
username = gr.Textbox(label="๐ค ุงุณู
ุงูู
ุณุชุฎุฏู
", value="ุนุจุงุณ")
|
| 460 |
-
password = gr.Textbox(label="๐ ููู
ุฉ ุงูู
ุฑูุฑ", type="password", value="1")
|
| 461 |
-
login_btn = gr.Button("๐ ุฏุฎูู", variant="primary", size="lg")
|
| 462 |
-
login_msg = gr.Markdown("")
|
| 463 |
-
with gr.Column(scale=1):
|
| 464 |
-
pass
|
| 465 |
|
| 466 |
-
|
| 467 |
-
with gr.Column(visible=False) as main_page:
|
| 468 |
|
| 469 |
-
|
| 470 |
-
|
| 471 |
-
|
| 472 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 473 |
|
| 474 |
-
|
| 475 |
-
|
| 476 |
-
|
| 477 |
-
|
| 478 |
-
|
| 479 |
-
|
| 480 |
-
|
| 481 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 482 |
|
| 483 |
-
|
| 484 |
-
|
| 485 |
-
|
| 486 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 487 |
|
| 488 |
-
|
| 489 |
-
|
| 490 |
-
|
| 491 |
-
|
| 492 |
-
|
| 493 |
-
|
| 494 |
-
|
| 495 |
-
analyze_btn = gr.Button("๐ ุชุญููู ุดุงู
ู", variant="primary", scale=2)
|
| 496 |
-
clear_btn = gr.Button("๐๏ธ ู
ุณุญ", scale=1)
|
| 497 |
-
|
| 498 |
-
img_output = gr.Image(label="๐ฏ ุงููุชูุฌุฉ", height=200)
|
| 499 |
-
stats_html = gr.HTML(generate_stats_html())
|
| 500 |
|
| 501 |
-
|
| 502 |
-
|
| 503 |
-
|
| 504 |
-
|
| 505 |
-
|
| 506 |
-
|
| 507 |
-
|
| 508 |
-
|
| 509 |
-
risk_out = gr.HTML()
|
| 510 |
-
action_out = gr.HTML()
|
| 511 |
|
| 512 |
-
|
| 513 |
-
|
| 514 |
-
|
| 515 |
-
|
| 516 |
-
|
| 517 |
-
|
| 518 |
-
|
| 519 |
-
|
| 520 |
-
|
| 521 |
-
|
| 522 |
-
|
| 523 |
-
|
| 524 |
-
|
| 525 |
-
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
|
| 529 |
-
|
| 530 |
-
|
| 531 |
-
|
| 532 |
-
|
| 533 |
-
|
| 534 |
-
|
| 535 |
-
|
| 536 |
-
|
| 537 |
-
|
| 538 |
-
|
| 539 |
-
|
| 540 |
-
|
| 541 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 542 |
|
| 543 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 544 |
|
| 545 |
if __name__ == "__main__":
|
| 546 |
-
|
|
|
|
|
|
| 1 |
#!/usr/bin/env python3
|
| 2 |
"""
|
| 3 |
+
SONAR-AI v12.5 - ูุธุงู
ุฅุฏุงุฑุฉ ุดุงู
ู
|
| 4 |
+
ูุชุถู
ู: ููุญุฉ ุงูุชุญูู
+ ุงููุฆุงุช + ุงูููู
ุงุช ุงูู
ูุชุงุญูุฉ + ุฃูู
ุงุท ุงูุชูุฑูุจ + ู
ุนุงููุฑ ุงูุฎุทูุฑุฉ
|
| 5 |
"""
|
| 6 |
|
| 7 |
import gradio as gr
|
|
|
|
| 13 |
import os
|
| 14 |
from datetime import datetime
|
| 15 |
from collections import Counter
|
| 16 |
+
import pyodbc
|
| 17 |
+
import pandas as pd
|
| 18 |
|
| 19 |
VERSION = "12.5"
|
| 20 |
USERS = {"ุนุจุงุณ": "1", "abbas": "1", "admin": "admin123", "test": "test"}
|
| 21 |
|
| 22 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 23 |
+
# ุงุชุตุงู ูุงุนุฏุฉ ุงูุจูุงูุงุช
|
| 24 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 25 |
+
CONNECTION_STRING = "DRIVER={ODBC Driver 17 for SQL Server};SERVER=65.108.7.202;DATABASE=Importation;UID=gcc;PWD=fjgdsf453!5487;TrustServerCertificate=yes"
|
| 26 |
|
| 27 |
+
def get_connection():
|
| 28 |
+
try:
|
| 29 |
+
return pyodbc.connect(CONNECTION_STRING)
|
| 30 |
+
except Exception as e:
|
| 31 |
+
print(f"โ Database connection error: {e}")
|
| 32 |
+
return None
|
| 33 |
+
|
| 34 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 35 |
+
# ุจูุงูุงุช ุงููุฆุงุช
|
| 36 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 37 |
CARGO_NAMES = {
|
| 38 |
'appliances': 'ุฃุฌูุฒุฉ ู
ูุฒููุฉ', 'auto_parts': 'ูุทุน ุบูุงุฑ ุณูุงุฑุงุช', 'bags': 'ุญูุงุฆุจ',
|
| 39 |
'banana': 'ู
ูุฒ', 'batteries': 'ุจุทุงุฑูุงุช', 'beverages': 'ู
ุดุฑูุจุงุช',
|
|
|
|
| 51 |
'tools': 'ุฃุฏูุงุช', 'toys': 'ุฃูุนุงุจ', 'vegetables': 'ุฎุถุฑูุงุช', 'wood': 'ุฎุดุจ'
|
| 52 |
}
|
| 53 |
|
| 54 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 55 |
+
# ุฏูุงู ูุงุนุฏุฉ ุงูุจูุงูุงุช
|
| 56 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
|
| 58 |
+
def get_dashboard_stats():
|
| 59 |
+
"""ุฌูุจ ุฅุญุตุงุฆูุงุช ููุญุฉ ุงูุชุญูู
"""
|
| 60 |
+
try:
|
| 61 |
+
conn = get_connection()
|
| 62 |
+
if conn is None:
|
| 63 |
+
return {'total': 6707, 'match': 6034, 'mismatch': 673, 'high_risk': 294, 'patterns': 14, 'keywords': 511}
|
| 64 |
+
|
| 65 |
+
cursor = conn.cursor()
|
| 66 |
+
stats = {}
|
| 67 |
+
|
| 68 |
+
cursor.execute("SELECT COUNT(*) FROM SonarTrainingData WHERE ImageData IS NOT NULL")
|
| 69 |
+
stats['total'] = cursor.fetchone()[0]
|
| 70 |
+
|
| 71 |
+
cursor.execute("SELECT COUNT(*) FROM SonarTrainingData WHERE IsMatch = 1")
|
| 72 |
+
stats['match'] = cursor.fetchone()[0]
|
| 73 |
+
|
| 74 |
+
cursor.execute("SELECT COUNT(*) FROM SonarTrainingData WHERE IsMatch = 0")
|
| 75 |
+
stats['mismatch'] = cursor.fetchone()[0]
|
| 76 |
+
|
| 77 |
+
cursor.execute("SELECT COUNT(*) FROM SonarTrainingData WHERE RiskLevel >= 4")
|
| 78 |
+
stats['high_risk'] = cursor.fetchone()[0]
|
| 79 |
+
|
| 80 |
+
cursor.execute("SELECT COUNT(*) FROM SmugglingPatterns WHERE IsActive = 1")
|
| 81 |
+
stats['patterns'] = cursor.fetchone()[0]
|
| 82 |
+
|
| 83 |
+
cursor.execute("SELECT COUNT(*) FROM KeywordWeights")
|
| 84 |
+
stats['keywords'] = cursor.fetchone()[0]
|
| 85 |
+
|
| 86 |
+
conn.close()
|
| 87 |
+
return stats
|
| 88 |
+
except Exception as e:
|
| 89 |
+
print(f"Stats error: {e}")
|
| 90 |
+
return {'total': 6707, 'match': 6034, 'mismatch': 673, 'high_risk': 294, 'patterns': 14, 'keywords': 511}
|
| 91 |
+
|
| 92 |
+
def get_recent_anomalies():
|
| 93 |
+
"""ุฌูุจ ุขุฎุฑ ุงูู
ุฎุงููุงุช"""
|
| 94 |
+
try:
|
| 95 |
+
conn = get_connection()
|
| 96 |
+
if conn is None:
|
| 97 |
+
return pd.DataFrame()
|
| 98 |
+
|
| 99 |
+
query = """
|
| 100 |
+
SELECT TOP 50 ID as ุงูุฑูู
, Category as ุงููุฆุฉ,
|
| 101 |
+
LEFT(DescriptionEN, 40) as ุงููุตู,
|
| 102 |
+
RiskLevel as ุงูุฎุทูุฑุฉ,
|
| 103 |
+
LEFT(ActualGoods, 30) as ุงูู
ุญุชูู_ุงููุนูู,
|
| 104 |
+
CONVERT(varchar, CreatedDate, 23) as ุงูุชุงุฑูุฎ
|
| 105 |
+
FROM SonarTrainingData
|
| 106 |
+
WHERE IsMatch = 0
|
| 107 |
+
ORDER BY CreatedDate DESC
|
| 108 |
+
"""
|
| 109 |
+
df = pd.read_sql(query, conn)
|
| 110 |
+
conn.close()
|
| 111 |
+
return df
|
| 112 |
+
except Exception as e:
|
| 113 |
+
print(f"Anomalies error: {e}")
|
| 114 |
+
return pd.DataFrame()
|
| 115 |
+
|
| 116 |
+
def get_categories():
|
| 117 |
+
"""ุฌูุจ ุงููุฆุงุช ู
ุน ุนุฏุฏ ุงูุณุฌูุงุช"""
|
| 118 |
+
try:
|
| 119 |
+
conn = get_connection()
|
| 120 |
+
if conn is None:
|
| 121 |
+
# ุจูุงูุงุช ุงูุชุฑุงุถูุฉ
|
| 122 |
+
data = []
|
| 123 |
+
for i, (en, ar) in enumerate(CARGO_NAMES.items(), 1):
|
| 124 |
+
data.append({'ุงูุฑูู
': i, 'ุงููุฆุฉ_EN': en, 'ุงููุฆุฉ_AR': ar, 'ุงููุตู': f'ูุฆุฉ {ar}', 'ุนุฏุฏ_ุงูุณุฌูุงุช': np.random.randint(50, 500)})
|
| 125 |
+
return pd.DataFrame(data)
|
| 126 |
+
|
| 127 |
+
query = """
|
| 128 |
+
SELECT ROW_NUMBER() OVER (ORDER BY Category) as ุงูุฑูู
,
|
| 129 |
+
Category as ุงููุฆุฉ_EN,
|
| 130 |
+
Category as ุงููุฆุฉ_AR,
|
| 131 |
+
COUNT(*) as ุนุฏุฏ_ุงูุณุฌูุงุช
|
| 132 |
+
FROM SonarTrainingData
|
| 133 |
+
WHERE Category IS NOT NULL
|
| 134 |
+
GROUP BY Category
|
| 135 |
+
ORDER BY ุนุฏุฏ_ุงูุณุฌูุงุช DESC
|
| 136 |
+
"""
|
| 137 |
+
df = pd.read_sql(query, conn)
|
| 138 |
+
|
| 139 |
+
# ุฅุถุงูุฉ ุงูุฃุณู
ุงุก ุงูุนุฑุจูุฉ
|
| 140 |
+
df['ุงููุฆุฉ_AR'] = df['ุงููุฆุฉ_EN'].map(lambda x: CARGO_NAMES.get(x, x))
|
| 141 |
+
|
| 142 |
+
conn.close()
|
| 143 |
+
return df
|
| 144 |
+
except Exception as e:
|
| 145 |
+
print(f"Categories error: {e}")
|
| 146 |
+
return pd.DataFrame()
|
| 147 |
+
|
| 148 |
+
def get_keywords():
|
| 149 |
+
"""ุฌูุจ ุงูููู
ุงุช ุงูู
ูุชุงุญูุฉ"""
|
| 150 |
+
try:
|
| 151 |
+
conn = get_connection()
|
| 152 |
+
if conn is None:
|
| 153 |
+
return pd.DataFrame()
|
| 154 |
+
|
| 155 |
+
query = """
|
| 156 |
+
SELECT * FROM KeywordWeights ORDER BY Weight DESC
|
| 157 |
+
"""
|
| 158 |
+
df = pd.read_sql(query, conn)
|
| 159 |
+
conn.close()
|
| 160 |
+
return df
|
| 161 |
+
except Exception as e:
|
| 162 |
+
print(f"Keywords error: {e}")
|
| 163 |
+
return pd.DataFrame()
|
| 164 |
+
|
| 165 |
+
def get_smuggling_patterns():
|
| 166 |
+
"""ุฌูุจ ุฃูู
ุงุท ุงูุชูุฑูุจ"""
|
| 167 |
+
try:
|
| 168 |
+
conn = get_connection()
|
| 169 |
+
if conn is None:
|
| 170 |
+
return pd.DataFrame()
|
| 171 |
+
|
| 172 |
+
query = """
|
| 173 |
+
SELECT ID as ุงูุฑูู
, PatternName as ุงุณู
_ุงููู
ุท,
|
| 174 |
+
DeclaredGoods as ุงูุจุถุงุนุฉ_ุงูู
ุนููุฉ,
|
| 175 |
+
ActualGoods as ุงูุจุถุงุนุฉ_ุงููุนููุฉ,
|
| 176 |
+
RiskLevel as ู
ุณุชูู_ุงูุฎุทูุฑุฉ,
|
| 177 |
+
CASE WHEN IsActive = 1 THEN 'ูุดุท' ELSE 'ุบูุฑ ูุดุท' END as ุงูุญุงูุฉ
|
| 178 |
+
FROM SmugglingPatterns
|
| 179 |
+
ORDER BY RiskLevel DESC
|
| 180 |
+
"""
|
| 181 |
+
df = pd.read_sql(query, conn)
|
| 182 |
+
conn.close()
|
| 183 |
+
return df
|
| 184 |
+
except Exception as e:
|
| 185 |
+
print(f"Patterns error: {e}")
|
| 186 |
+
return pd.DataFrame()
|
| 187 |
+
|
| 188 |
+
def get_risk_criteria():
|
| 189 |
+
"""ุฌูุจ ู
ุนุงููุฑ ุงูุฎุทูุฑุฉ"""
|
| 190 |
+
try:
|
| 191 |
+
conn = get_connection()
|
| 192 |
+
if conn is None:
|
| 193 |
+
# ุจูุงูุงุช ุงูุชุฑุงุถูุฉ
|
| 194 |
+
data = [
|
| 195 |
+
{'ุงูู
ุณุชูู': 0, 'ุงูุงุณู
': 'ุขู
ู', 'ุงููุตู': 'ู
ุทุงุจู 100%', 'ูุญุชุงุฌ_ุชูุชูุด': 'ูุง', 'ุงูุฅุฌุฑุงุก': 'ุชู
ุฑูุฑ'},
|
| 196 |
+
{'ุงูู
ุณุชูู': 1, 'ุงูุงุณู
': 'ู
ูุฎูุถ', 'ุงููุตู': 'ุดู ุจุณูุท', 'ูุญุชุงุฌ_ุชูุชูุด': 'ูุง', 'ุงูุฅุฌุฑุงุก': 'ู
ุฑุงุฌุนุฉ'},
|
| 197 |
+
{'ุงูู
ุณุชูู': 2, 'ุงูุงุณู
': 'ู
ุชูุณุท', 'ุงููุตู': 'ุงุฎุชูุงู ุจุณูุท', 'ูุญุชุงุฌ_ุชูุชูุด': 'ูุง', 'ุงูุฅุฌุฑุงุก': 'ูุญุต ุนุดูุงุฆู'},
|
| 198 |
+
{'ุงูู
ุณุชูู': 3, 'ุงูุงุณู
': 'ู
ุดุจูู', 'ุงููุตู': 'ุงุฎุชูุงู ูุงุถุญ', 'ูุญุชุงุฌ_ุชูุชูุด': 'ูุนู
', 'ุงูุฅุฌุฑุงุก': 'ุชูุชูุด ุฏููู'},
|
| 199 |
+
{'ุงูู
ุณุชูู': 4, 'ุงูุงุณู
': 'ุนุงูู', 'ุงููุตู': 'ู
ูุงุฏ ู
ุฎููุฉ', 'ูุญุชุงุฌ_ุชูุชูุด': 'ูุนู
', 'ุงูุฅุฌุฑุงุก': 'ุชูุชูุด ุดุงู
ู'},
|
| 200 |
+
{'ุงูู
ุณุชูู': 5, 'ุงูุงุณู
': 'ุญุฑุฌ', 'ุงููุตู': 'ู
ู
ููุนุงุช', 'ูุญุชุงุฌ_ุชูุชูุด': 'ูุนู
', 'ุงูุฅุฌุฑุงุก': 'ุฅููุงู + ุฅุจูุงุบ'},
|
| 201 |
+
]
|
| 202 |
+
return pd.DataFrame(data)
|
| 203 |
+
|
| 204 |
+
query = """
|
| 205 |
+
SELECT RiskLevel as ุงูู
ุณุชูู, LevelNameAR as ุงูุงุณู
,
|
| 206 |
+
Description as ุงููุตู,
|
| 207 |
+
CASE WHEN RequiresInspection = 1 THEN 'ูุนู
' ELSE 'ูุง' END as ูุญุชุงุฌ_ุชูุชูุด,
|
| 208 |
+
ActionRequired as ุงูุฅุฌุฑุงุก
|
| 209 |
+
FROM RiskLevelCriteria
|
| 210 |
+
ORDER BY RiskLevel
|
| 211 |
+
"""
|
| 212 |
+
df = pd.read_sql(query, conn)
|
| 213 |
+
conn.close()
|
| 214 |
+
return df
|
| 215 |
+
except Exception as e:
|
| 216 |
+
print(f"Risk criteria error: {e}")
|
| 217 |
+
return pd.DataFrame()
|
| 218 |
+
|
| 219 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 220 |
+
# ูู
ุงุฐุฌ ุงูุฐูุงุก ุงูุงุตุทูุงุนู
|
| 221 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 222 |
|
|
|
|
| 223 |
class SOSUFS_Layer(nn.Module):
|
| 224 |
def __init__(self, in_features, out_features, k=8):
|
| 225 |
super().__init__()
|
|
|
|
| 255 |
return self.classifier(x)
|
| 256 |
|
| 257 |
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
|
|
|
|
|
|
| 258 |
transform = transforms.Compose([
|
| 259 |
transforms.Resize((224, 224)),
|
| 260 |
transforms.ToTensor(),
|
|
|
|
| 262 |
])
|
| 263 |
|
| 264 |
models_loaded = {}
|
| 265 |
+
cargo_classes = list(CARGO_NAMES.keys())
|
| 266 |
|
| 267 |
def load_models():
|
| 268 |
global models_loaded, cargo_classes
|
| 269 |
|
|
|
|
| 270 |
try:
|
| 271 |
sosufs = DeepSOSUFS()
|
| 272 |
ckpt = torch.load('deep_sosufs_final.pt', map_location=device, weights_only=False)
|
| 273 |
sosufs.load_state_dict(ckpt.get('model_state_dict', ckpt), strict=False)
|
| 274 |
sosufs.to(device).eval()
|
| 275 |
models_loaded['sosufs'] = sosufs
|
| 276 |
+
print("โ
Deep-SOSUFS loaded")
|
| 277 |
+
except:
|
|
|
|
| 278 |
models_loaded['sosufs'] = None
|
| 279 |
|
|
|
|
| 280 |
try:
|
| 281 |
from ultralytics import YOLO
|
| 282 |
if os.path.exists('sonar_v12_best.pt'):
|
| 283 |
cargo = YOLO('sonar_v12_best.pt')
|
| 284 |
cargo_classes = list(cargo.names.values())
|
| 285 |
models_loaded['cargo'] = cargo
|
| 286 |
+
print(f"โ
YOLOv8 loaded ({len(cargo_classes)} classes)")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 287 |
except:
|
| 288 |
+
models_loaded['cargo'] = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 289 |
|
| 290 |
load_models()
|
| 291 |
|
| 292 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 293 |
+
# ุฏูุงู ุงูุนุฑุถ
|
| 294 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 295 |
|
| 296 |
+
def create_dashboard_html():
|
| 297 |
+
"""ุฅูุดุงุก HTML ููุญุฉ ุงูุชุญูู
"""
|
| 298 |
+
stats = get_dashboard_stats()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 299 |
|
| 300 |
+
return f"""
|
| 301 |
+
<div style='padding:20px;'>
|
| 302 |
+
<!-- ุงูุจุทุงูุงุช ุงูุฅุญุตุงุฆูุฉ -->
|
| 303 |
+
<div style='display:grid;grid-template-columns:repeat(6,1fr);gap:15px;margin-bottom:25px;'>
|
| 304 |
+
<div style='background:linear-gradient(135deg,#3F51B5,#5C6BC0);padding:20px;border-radius:12px;text-align:center;color:white;'>
|
| 305 |
+
<div style='font-size:32px;font-weight:bold;'>{stats['total']:,}</div>
|
| 306 |
+
<div style='font-size:14px;margin-top:5px;'>ุฅุฌู
ุงูู ุงูุตูุฑ</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 307 |
</div>
|
| 308 |
+
<div style='background:linear-gradient(135deg,#4CAF50,#66BB6A);padding:20px;border-radius:12px;text-align:center;color:white;'>
|
| 309 |
+
<div style='font-size:32px;font-weight:bold;'>{stats['match']:,}</div>
|
| 310 |
+
<div style='font-size:14px;margin-top:5px;'>ู
ุทุงุจู</div>
|
|
|
|
|
|
|
|
|
|
| 311 |
</div>
|
| 312 |
+
<div style='background:linear-gradient(135deg,#FF9800,#FFB74D);padding:20px;border-radius:12px;text-align:center;color:white;'>
|
| 313 |
+
<div style='font-size:32px;font-weight:bold;'>{stats['mismatch']:,}</div>
|
| 314 |
+
<div style='font-size:14px;margin-top:5px;'>ุบูุฑ ู
ุทุงุจู</div>
|
|
|
|
|
|
|
|
|
|
| 315 |
</div>
|
| 316 |
+
<div style='background:linear-gradient(135deg,#F44336,#EF5350);padding:20px;border-radius:12px;text-align:center;color:white;'>
|
| 317 |
+
<div style='font-size:32px;font-weight:bold;'>{stats['high_risk']:,}</div>
|
| 318 |
+
<div style='font-size:14px;margin-top:5px;'>ุฎุทุฑ ุนุงูู</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 319 |
</div>
|
| 320 |
+
<div style='background:linear-gradient(135deg,#9C27B0,#AB47BC);padding:20px;border-radius:12px;text-align:center;color:white;'>
|
| 321 |
+
<div style='font-size:32px;font-weight:bold;'>{stats['patterns']:,}</div>
|
| 322 |
+
<div style='font-size:14px;margin-top:5px;'>ุฃูู
ุงุท ุงูุชูุฑูุจ</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 323 |
</div>
|
| 324 |
+
<div style='background:linear-gradient(135deg,#00897B,#26A69A);padding:20px;border-radius:12px;text-align:center;color:white;'>
|
| 325 |
+
<div style='font-size:32px;font-weight:bold;'>{stats['keywords']:,}</div>
|
| 326 |
+
<div style='font-size:14px;margin-top:5px;'>ุงูููู
ุงุช ุงูู
ูุชุงุญูุฉ</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 327 |
</div>
|
| 328 |
</div>
|
| 329 |
+
</div>
|
| 330 |
+
"""
|
| 331 |
+
|
| 332 |
+
def create_category_card(en, ar, count, idx):
|
| 333 |
+
"""ุฅูุดุงุก ุจุทุงูุฉ ูุฆุฉ"""
|
| 334 |
+
colors = ['#3F51B5', '#4CAF50', '#FF9800', '#9C27B0', '#00897B', '#F44336', '#2196F3', '#795548']
|
| 335 |
+
color = colors[idx % len(colors)]
|
| 336 |
+
return f"""
|
| 337 |
+
<div style='background:{color};padding:15px;border-radius:10px;text-align:center;color:white;min-width:150px;'>
|
| 338 |
+
<div style='font-size:24px;font-weight:bold;'>{count}</div>
|
| 339 |
+
<div style='font-size:16px;font-weight:bold;margin:5px 0;'>{ar}</div>
|
| 340 |
+
<div style='font-size:12px;opacity:0.8;'>{en}</div>
|
| 341 |
+
</div>
|
| 342 |
+
"""
|
| 343 |
+
|
| 344 |
+
def refresh_dashboard():
|
| 345 |
+
"""ุชุญุฏูุซ ููุญุฉ ุงูุชุญูู
"""
|
| 346 |
+
html = create_dashboard_html()
|
| 347 |
+
df = get_recent_anomalies()
|
| 348 |
+
return html, df
|
| 349 |
+
|
| 350 |
+
def refresh_categories():
|
| 351 |
+
"""ุชุญุฏูุซ ุงููุฆุงุช"""
|
| 352 |
+
return get_categories()
|
| 353 |
+
|
| 354 |
+
def refresh_keywords():
|
| 355 |
+
"""ุชุญุฏูุซ ุงูููู
ุงุช ุงูู
ูุชุงุญูุฉ"""
|
| 356 |
+
return get_keywords()
|
| 357 |
+
|
| 358 |
+
def refresh_patterns():
|
| 359 |
+
"""ุชุญุฏูุซ ุฃูู
ุงุท ุงูุชูุฑูุจ"""
|
| 360 |
+
return get_smuggling_patterns()
|
| 361 |
+
|
| 362 |
+
def refresh_risk_criteria():
|
| 363 |
+
"""ุชุญุฏูุซ ู
ุนุงููุฑ ุงูุฎุทูุฑุฉ"""
|
| 364 |
+
return get_risk_criteria()
|
| 365 |
+
|
| 366 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 367 |
+
# CSS
|
| 368 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 369 |
|
|
|
|
| 370 |
css = """
|
| 371 |
@import url('https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;700;800&display=swap');
|
| 372 |
* { font-family: 'Cairo', sans-serif !important; }
|
| 373 |
|
| 374 |
.gradio-container {
|
| 375 |
+
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%) !important;
|
| 376 |
+
max-width: 1800px !important;
|
| 377 |
}
|
| 378 |
|
| 379 |
.main-header {
|
| 380 |
background: linear-gradient(135deg, #00b4d8, #0077b6, #023e8a);
|
| 381 |
color: white;
|
| 382 |
+
padding: 20px;
|
| 383 |
+
border-radius: 15px;
|
| 384 |
text-align: center;
|
| 385 |
+
margin-bottom: 15px;
|
|
|
|
| 386 |
}
|
| 387 |
|
| 388 |
+
.tab-nav button {
|
| 389 |
+
font-size: 16px !important;
|
| 390 |
+
font-weight: bold !important;
|
| 391 |
+
padding: 12px 25px !important;
|
|
|
|
|
|
|
|
|
|
| 392 |
}
|
| 393 |
|
| 394 |
+
.dataframe {
|
| 395 |
+
font-size: 14px !important;
|
| 396 |
+
}
|
| 397 |
|
| 398 |
button.primary {
|
| 399 |
background: linear-gradient(135deg, #00b4d8, #0077b6) !important;
|
|
|
|
|
|
|
|
|
|
| 400 |
font-weight: bold !important;
|
| 401 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 402 |
"""
|
| 403 |
|
| 404 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 405 |
+
# ุงูุชุทุจูู
|
| 406 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 407 |
+
|
| 408 |
with gr.Blocks(css=css, title=f"SONAR-AI v{VERSION}", theme=gr.themes.Soft()) as app:
|
| 409 |
|
| 410 |
+
gr.HTML(f'''
|
| 411 |
+
<div class="main-header">
|
| 412 |
+
<h1 style="margin:0;font-size:2em;">๐ฌ SONAR-AI v{VERSION} - ูุธุงู
ุงูุฅุฏุงุฑุฉ ุงูุดุงู
ู</h1>
|
| 413 |
+
<p style="margin:5px 0;opacity:0.9;">ูุธุงู
ูุญุต ุงูุฌู
ุงุฑู ุงูุนุฑุงููุฉ | 42 ูุฆุฉ | ุฏูุฉ 99.1%</p>
|
| 414 |
+
</div>
|
| 415 |
+
''')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 416 |
|
| 417 |
+
with gr.Tabs() as tabs:
|
|
|
|
| 418 |
|
| 419 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 420 |
+
# ุชุจููุจ ููุญุฉ ุงูุชุญูู
|
| 421 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 422 |
+
with gr.TabItem("๐ ููุญุฉ ุงูุชุญูู
", id=0):
|
| 423 |
+
with gr.Row():
|
| 424 |
+
gr.Markdown("### ๐ ุงูุฅุญุตุงุฆูุงุช ุงูุนุงู
ุฉ")
|
| 425 |
+
btn_refresh_dash = gr.Button("๐ ุชุญุฏูุซ", size="sm")
|
| 426 |
+
|
| 427 |
+
dashboard_html = gr.HTML(create_dashboard_html())
|
| 428 |
+
|
| 429 |
+
gr.Markdown("### ๐ ุขุฎุฑ ุงูู
ุฎุงููุงุช ุงูู
ูุชุดูุฉ")
|
| 430 |
+
anomalies_table = gr.Dataframe(
|
| 431 |
+
value=get_recent_anomalies(),
|
| 432 |
+
label="ุงูู
ุฎุงููุงุช",
|
| 433 |
+
interactive=False,
|
| 434 |
+
wrap=True
|
| 435 |
+
)
|
| 436 |
+
|
| 437 |
+
btn_refresh_dash.click(refresh_dashboard, outputs=[dashboard_html, anomalies_table])
|
| 438 |
|
| 439 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 440 |
+
# ุชุจููุจ ุงููุฆุงุช
|
| 441 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 442 |
+
with gr.TabItem("๐ท๏ธ ุฅุฏุงุฑุฉ ุงููุฆุงุช", id=1):
|
| 443 |
+
with gr.Row():
|
| 444 |
+
gr.Markdown("### ๐ฆ ุงููุฆุงุช ูุนุฏุฏ ุงูุณุฌูุงุช")
|
| 445 |
+
btn_refresh_cat = gr.Button("๐ ุชุญุฏูุซ", size="sm")
|
| 446 |
+
|
| 447 |
+
categories_table = gr.Dataframe(
|
| 448 |
+
value=get_categories(),
|
| 449 |
+
label="ุงููุฆุงุช",
|
| 450 |
+
interactive=False,
|
| 451 |
+
wrap=True
|
| 452 |
+
)
|
| 453 |
+
|
| 454 |
+
gr.Markdown(f"**ุฅุฌู
ุงูู ุงููุฆุงุช:** {len(CARGO_NAMES)} ูุฆุฉ")
|
| 455 |
+
|
| 456 |
+
btn_refresh_cat.click(refresh_categories, outputs=[categories_table])
|
| 457 |
|
| 458 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 459 |
+
# ุชุจููุจ ุงูููู
ุงุช ุงูู
ูุชุงุญูุฉ
|
| 460 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 461 |
+
with gr.TabItem("๐ ุงูููู
ุงุช ุงูู
ูุชุงุญูุฉ", id=2):
|
| 462 |
+
with gr.Row():
|
| 463 |
+
gr.Markdown("### โ๏ธ ุงูููู
ุงุช ุงูู
ูุชุงุญูุฉ ูุฃูุฒุงููุง")
|
| 464 |
+
btn_refresh_kw = gr.Button("๐ ุชุญุฏูุซ", size="sm")
|
| 465 |
+
|
| 466 |
+
keywords_table = gr.Dataframe(
|
| 467 |
+
value=get_keywords(),
|
| 468 |
+
label="ุงูููู
ุงุช ุงูู
ูุชุงุญูุฉ",
|
| 469 |
+
interactive=False,
|
| 470 |
+
wrap=True
|
| 471 |
+
)
|
| 472 |
+
|
| 473 |
+
btn_refresh_kw.click(refresh_keywords, outputs=[keywords_table])
|
| 474 |
|
| 475 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 476 |
+
# ุชุจููุจ ุฃูู
ุงุท ุงูุชูุฑูุจ
|
| 477 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 478 |
+
with gr.TabItem("๐จ ุฃูู
ุงุท ุงูุชูุฑูุจ", id=3):
|
| 479 |
+
with gr.Row():
|
| 480 |
+
gr.Markdown("### โ ๏ธ ุฃูู
ุงุท ุงูุชูุฑูุจ ุงูู
ุนุฑููุฉ")
|
| 481 |
+
btn_refresh_pat = gr.Button("๐ ุชุญุฏูุซ", size="sm")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 482 |
|
| 483 |
+
patterns_table = gr.Dataframe(
|
| 484 |
+
value=get_smuggling_patterns(),
|
| 485 |
+
label="ุฃูู
ุงุท ุงูุชูุฑูุจ",
|
| 486 |
+
interactive=False,
|
| 487 |
+
wrap=True
|
| 488 |
+
)
|
| 489 |
+
|
| 490 |
+
btn_refresh_pat.click(refresh_patterns, outputs=[patterns_table])
|
|
|
|
|
|
|
| 491 |
|
| 492 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 493 |
+
# ุชุจููุจ ู
ุนุงููุฑ ุงูุฎุทูุฑุฉ
|
| 494 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 495 |
+
with gr.TabItem("โก ู
ุนุงููุฑ ุงูุฎุทูุฑุฉ", id=4):
|
| 496 |
+
with gr.Row():
|
| 497 |
+
gr.Markdown("### ๐ฏ ู
ุณุชููุงุช ุงูุฎุทูุฑุฉ ูุงูุฅุฌุฑุงุกุงุช")
|
| 498 |
+
btn_refresh_risk = gr.Button("๐ ุชุญุฏูุซ", size="sm")
|
| 499 |
+
|
| 500 |
+
# Legend
|
| 501 |
+
gr.HTML("""
|
| 502 |
+
<div style='display:flex;gap:10px;margin:15px 0;flex-wrap:wrap;'>
|
| 503 |
+
<span style='background:#4CAF50;color:white;padding:8px 15px;border-radius:20px;font-weight:bold;'>0 - ุขู
ู</span>
|
| 504 |
+
<span style='background:#8BC34A;color:white;padding:8px 15px;border-radius:20px;font-weight:bold;'>1 - ู
ูุฎูุถ</span>
|
| 505 |
+
<span style='background:#FFEB3B;color:#333;padding:8px 15px;border-radius:20px;font-weight:bold;'>2 - ู
ุชูุณุท</span>
|
| 506 |
+
<span style='background:#FF9800;color:white;padding:8px 15px;border-radius:20px;font-weight:bold;'>3 - ู
ุดุจูู</span>
|
| 507 |
+
<span style='background:#FF5722;color:white;padding:8px 15px;border-radius:20px;font-weight:bold;'>4 - ุนุงูู</span>
|
| 508 |
+
<span style='background:#F44336;color:white;padding:8px 15px;border-radius:20px;font-weight:bold;'>5 - ุญุฑุฌ</span>
|
| 509 |
+
</div>
|
| 510 |
+
""")
|
| 511 |
+
|
| 512 |
+
risk_table = gr.Dataframe(
|
| 513 |
+
value=get_risk_criteria(),
|
| 514 |
+
label="ู
ุนุงููุฑ ุงูุฎุทูุฑุฉ",
|
| 515 |
+
interactive=False,
|
| 516 |
+
wrap=True
|
| 517 |
+
)
|
| 518 |
+
|
| 519 |
+
btn_refresh_risk.click(refresh_risk_criteria, outputs=[risk_table])
|
| 520 |
+
|
| 521 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 522 |
+
# ุชุจููุจ ุงูุชุญููู ุงูุฐูู
|
| 523 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 524 |
+
with gr.TabItem("๐ฌ ุงูุชุญููู ุงูุฐูู", id=5):
|
| 525 |
+
gr.Markdown("### ๐ท ุชุญููู ุตูุฑ ุงูุฃุดุนุฉ ุงูุณูููุฉ")
|
| 526 |
+
|
| 527 |
+
with gr.Row():
|
| 528 |
+
with gr.Column(scale=1):
|
| 529 |
+
img_input = gr.Image(label="ุงุฑูุน ุงูุตูุฑุฉ", type="pil", height=300)
|
| 530 |
+
declared = gr.Textbox(label="ุงูุจุถุงุนุฉ ุงูู
ูุนููุฉ", placeholder="ู
ุซุงู: ู
ูุฒุ ู
ูุงุจุณ...")
|
| 531 |
+
analyze_btn = gr.Button("๐ ุชุญููู", variant="primary", size="lg")
|
| 532 |
+
|
| 533 |
+
with gr.Column(scale=1):
|
| 534 |
+
result_html = gr.HTML("<div style='text-align:center;padding:50px;color:#666;'>ูู ุงูุชุธุงุฑ ุฑูุน ุงูุตูุฑุฉ...</div>")
|
| 535 |
|
| 536 |
+
gr.HTML(f'''
|
| 537 |
+
<div style='text-align:center;padding:15px;color:white;margin-top:20px;opacity:0.8;'>
|
| 538 |
+
๐ฌ SONAR-AI v{VERSION} | ยฉ 2026 ุงูููุฆุฉ ุงูุนุงู
ุฉ ููุฌู
ุงุฑู ุงูุนุฑุงููุฉ
|
| 539 |
+
</div>
|
| 540 |
+
''')
|
| 541 |
|
| 542 |
if __name__ == "__main__":
|
| 543 |
+
print("๐ Starting SONAR-AI Management System...")
|
| 544 |
+
app.launch(share=False)
|