fix mail final
Browse files
app.py
CHANGED
|
@@ -36,63 +36,21 @@ except ImportError as e:
|
|
| 36 |
print(f"β οΈ Detectron2 not available: {e}")
|
| 37 |
DETECTRON2_AVAILABLE = False
|
| 38 |
|
| 39 |
-
|
| 40 |
-
"""Check availability of model files locally and remotely"""
|
| 41 |
-
model_status = {}
|
| 42 |
-
|
| 43 |
-
print("\nπ Checking model files...")
|
| 44 |
-
|
| 45 |
-
# Check damage detection model (Detectron2)
|
| 46 |
-
if os.path.exists(DEFAULT_DAMAGE_MODEL_PATH):
|
| 47 |
-
file_size = os.path.getsize(DEFAULT_DAMAGE_MODEL_PATH) / (1024 * 1024) # Size in MB
|
| 48 |
-
print(f"β
Damage Model: Available ({file_size:.2f} MB) at {DEFAULT_DAMAGE_MODEL_PATH}")
|
| 49 |
-
model_status['damage_model'] = {'available': True, 'size': file_size, 'path': DEFAULT_DAMAGE_MODEL_PATH}
|
| 50 |
-
else:
|
| 51 |
-
print(f"β Damage Model: Not found at {DEFAULT_DAMAGE_MODEL_PATH}")
|
| 52 |
-
model_status['damage_model'] = {'available': False, 'path': DEFAULT_DAMAGE_MODEL_PATH}
|
| 53 |
-
|
| 54 |
-
# Check deepfake detection model (ViT) - Local first
|
| 55 |
-
local_deepfake_path = None
|
| 56 |
-
if os.path.exists(DEFAULT_DEEPFAKE_MODEL_PATH):
|
| 57 |
-
file_size = os.path.getsize(DEFAULT_DEEPFAKE_MODEL_PATH) / (1024 * 1024) # Size in MB
|
| 58 |
-
print(f"β
Deepfake Model: Available locally ({file_size:.2f} MB) at {DEFAULT_DEEPFAKE_MODEL_PATH}")
|
| 59 |
-
local_deepfake_path = DEFAULT_DEEPFAKE_MODEL_PATH
|
| 60 |
-
model_status['deepfake_model'] = {'available': True, 'size': file_size, 'path': local_deepfake_path, 'source': 'local'}
|
| 61 |
-
else:
|
| 62 |
-
print(f"β οΈ Deepfake Model: Not found locally at {DEFAULT_DEEPFAKE_MODEL_PATH}")
|
| 63 |
-
model_status['deepfake_model'] = {'available': False, 'path': DEFAULT_DEEPFAKE_MODEL_PATH, 'source': 'local'}
|
| 64 |
-
|
| 65 |
-
return model_status, local_deepfake_path
|
| 66 |
-
|
| 67 |
-
# Check local models first
|
| 68 |
-
model_status, local_deepfake_model_path = check_model_files()
|
| 69 |
-
|
| 70 |
-
# Try to download deepfake model from Hugging Face if not available locally
|
| 71 |
huggingface_model_path = None
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
model_status['deepfake_model'] = {'available': True, 'size': file_size, 'path': huggingface_model_path, 'source': 'huggingface'}
|
| 86 |
-
except Exception as e:
|
| 87 |
-
print(f"β οΈ Could not download model from Hugging Face: {e}")
|
| 88 |
-
print("π Will use demo mode with simulated results")
|
| 89 |
-
huggingface_model_path = None
|
| 90 |
-
else:
|
| 91 |
-
print("β
Using local deepfake model")
|
| 92 |
-
huggingface_model_path = local_deepfake_model_path
|
| 93 |
-
|
| 94 |
-
# Make model_status global for access in functions
|
| 95 |
-
globals()['model_status'] = model_status
|
| 96 |
|
| 97 |
# Define model paths
|
| 98 |
DEFAULT_DAMAGE_MODEL_PATH = "./output/model_final.pth"
|
|
@@ -766,7 +724,6 @@ def load_vit_deepfake_model(model_path, device):
|
|
| 766 |
|
| 767 |
def process_image(input_image, damage_threshold, deepfake_threshold, skip_damage, device_str, usage_count, recipient_email):
|
| 768 |
"""Main processing function with Mailjet email integration"""
|
| 769 |
-
global model_status # Access global model status
|
| 770 |
|
| 771 |
# Handle usage count
|
| 772 |
if usage_count is None:
|
|
@@ -822,37 +779,20 @@ def process_image(input_image, damage_threshold, deepfake_threshold, skip_damage
|
|
| 822 |
progress_info.append(f"π₯οΈ Using device: {device}")
|
| 823 |
|
| 824 |
# Initialize models
|
| 825 |
-
|
| 826 |
deepfake_model = None
|
| 827 |
demo_mode = False
|
| 828 |
|
| 829 |
-
|
| 830 |
-
|
| 831 |
-
|
| 832 |
-
damage_detector, _ = setup_damage_detector(model_status['damage_model']['path'], float(damage_threshold))
|
| 833 |
-
if damage_detector:
|
| 834 |
-
progress_info.append("β
Damage detection model loaded successfully")
|
| 835 |
-
else:
|
| 836 |
-
progress_info.append("β Failed to load damage detection model")
|
| 837 |
-
elif skip_damage:
|
| 838 |
-
progress_info.append("β οΈ Damage detection skipped (user setting)")
|
| 839 |
-
else:
|
| 840 |
-
if not DETECTRON2_AVAILABLE:
|
| 841 |
-
progress_info.append("β οΈ Detectron2 not available - skipping damage detection")
|
| 842 |
-
else:
|
| 843 |
-
progress_info.append("β Damage detection model not found")
|
| 844 |
-
|
| 845 |
-
# Setup deepfake detector
|
| 846 |
-
if model_status['deepfake_model']['available']:
|
| 847 |
-
progress_info.append(f"π€ Loading deepfake model from {model_status['deepfake_model']['source']}...")
|
| 848 |
-
deepfake_model = load_vit_deepfake_model(model_status['deepfake_model']['path'], device)
|
| 849 |
if deepfake_model:
|
| 850 |
-
progress_info.append("β
|
| 851 |
else:
|
| 852 |
-
progress_info.append("β Failed to load
|
| 853 |
demo_mode = True
|
| 854 |
else:
|
| 855 |
-
progress_info.append("β οΈ
|
| 856 |
demo_mode = True
|
| 857 |
|
| 858 |
# Analyze the image
|
|
@@ -971,9 +911,6 @@ def process_image(input_image, damage_threshold, deepfake_threshold, skip_damage
|
|
| 971 |
|
| 972 |
def create_gradio_interface():
|
| 973 |
"""Create Gradio interface with Mailjet integration"""
|
| 974 |
-
# Make model_status accessible to the interface
|
| 975 |
-
global model_status
|
| 976 |
-
|
| 977 |
theme = gr.themes.Soft(primary_hue="blue", secondary_hue="orange")
|
| 978 |
|
| 979 |
with gr.Blocks(title="Car Damage Fraud Detector - Mailjet Edition", theme=theme) as app:
|
|
@@ -991,26 +928,12 @@ def create_gradio_interface():
|
|
| 991 |
""")
|
| 992 |
|
| 993 |
# Model and Mailjet status
|
| 994 |
-
|
| 995 |
-
deepfake_status = "β
Available" if model_status['deepfake_model']['available'] else "π§ͺ Demo mode"
|
| 996 |
-
detectron2_status = "β
Available" if DETECTRON2_AVAILABLE else "β Not installed"
|
| 997 |
-
|
| 998 |
-
if model_status['deepfake_model']['available']:
|
| 999 |
-
deepfake_source = f"({model_status['deepfake_model']['source']})"
|
| 1000 |
-
deepfake_status += f" {deepfake_source}"
|
| 1001 |
-
|
| 1002 |
-
mailjet_status = "β
Configured" if (MAILJET_CONFIG['API_KEY'] and MAILJET_CONFIG['SECRET_KEY']) else "β οΈ Not configured"
|
| 1003 |
|
| 1004 |
-
|
| 1005 |
-
|
| 1006 |
-
|
| 1007 |
-
|
| 1008 |
-
- **Deepfake Model:** {deepfake_status}
|
| 1009 |
-
- **Mailjet API:** {mailjet_status}
|
| 1010 |
-
""")
|
| 1011 |
-
|
| 1012 |
-
if not model_status['deepfake_model']['available']:
|
| 1013 |
-
gr.Markdown("β οΈ **Demo Mode Active**: Simulated results will be generated for demonstration purposes.")
|
| 1014 |
|
| 1015 |
usage_counter = gr.State(0)
|
| 1016 |
|
|
@@ -1070,81 +993,6 @@ def create_gradio_interface():
|
|
| 1070 |
)
|
| 1071 |
download_info = gr.Markdown("**Complete analysis package will appear here after processing...**")
|
| 1072 |
|
| 1073 |
-
with gr.Tab("π§ System Status"):
|
| 1074 |
-
gr.Markdown("## π Model and System Status")
|
| 1075 |
-
|
| 1076 |
-
def create_model_status():
|
| 1077 |
-
status_info = []
|
| 1078 |
-
|
| 1079 |
-
# Detectron2 status
|
| 1080 |
-
if DETECTRON2_AVAILABLE:
|
| 1081 |
-
status_info.append("β
**Detectron2**: Available for damage detection")
|
| 1082 |
-
else:
|
| 1083 |
-
status_info.append("β **Detectron2**: Not installed (pip install detectron2)")
|
| 1084 |
-
|
| 1085 |
-
# Damage model status
|
| 1086 |
-
if model_status['damage_model']['available']:
|
| 1087 |
-
size_mb = model_status['damage_model']['size']
|
| 1088 |
-
path = model_status['damage_model']['path']
|
| 1089 |
-
status_info.append(f"β
**Damage Model**: Available ({size_mb:.2f} MB)")
|
| 1090 |
-
status_info.append(f" π Path: `{path}`")
|
| 1091 |
-
else:
|
| 1092 |
-
path = model_status['damage_model']['path']
|
| 1093 |
-
status_info.append(f"β **Damage Model**: Not found")
|
| 1094 |
-
status_info.append(f" π Expected path: `{path}`")
|
| 1095 |
-
|
| 1096 |
-
# Deepfake model status
|
| 1097 |
-
if model_status['deepfake_model']['available']:
|
| 1098 |
-
size_mb = model_status['deepfake_model']['size']
|
| 1099 |
-
path = model_status['deepfake_model']['path']
|
| 1100 |
-
source = model_status['deepfake_model']['source']
|
| 1101 |
-
status_info.append(f"β
**Deepfake Model**: Available ({size_mb:.2f} MB) - {source}")
|
| 1102 |
-
status_info.append(f" π Path: `{path}`")
|
| 1103 |
-
else:
|
| 1104 |
-
path = model_status['deepfake_model']['path']
|
| 1105 |
-
status_info.append(f"π§ͺ **Deepfake Model**: Using demo mode")
|
| 1106 |
-
status_info.append(f" π Expected local path: `{path}`")
|
| 1107 |
-
status_info.append(f" π Remote: Hugging Face repository not accessible")
|
| 1108 |
-
|
| 1109 |
-
# Mailjet status
|
| 1110 |
-
if MAILJET_CONFIG['API_KEY'] and MAILJET_CONFIG['SECRET_KEY']:
|
| 1111 |
-
status_info.append(f"β
**Mailjet API**: Configured")
|
| 1112 |
-
status_info.append(f" π§ From: {MAILJET_CONFIG['FROM_NAME']} <{MAILJET_CONFIG['FROM_EMAIL']}>")
|
| 1113 |
-
status_info.append(f" π API Key: {MAILJET_CONFIG['API_KEY'][:8]}...{MAILJET_CONFIG['API_KEY'][-4:]}")
|
| 1114 |
-
else:
|
| 1115 |
-
status_info.append(f"β οΈ **Mailjet API**: Not configured")
|
| 1116 |
-
status_info.append(f" π§ Email delivery unavailable")
|
| 1117 |
-
|
| 1118 |
-
return "\n".join(status_info)
|
| 1119 |
-
|
| 1120 |
-
gr.Markdown(create_model_status())
|
| 1121 |
-
|
| 1122 |
-
gr.Markdown("""
|
| 1123 |
-
## π§ Setup Instructions
|
| 1124 |
-
|
| 1125 |
-
### For Damage Detection (Optional):
|
| 1126 |
-
1. **Install Detectron2**: `pip install detectron2`
|
| 1127 |
-
2. **Place model file** at: `./output/model_final.pth`
|
| 1128 |
-
|
| 1129 |
-
### For AI Deepfake Detection:
|
| 1130 |
-
1. **Option 1 - Local**: Place model at `./output/vit_deepfake_final.pth`
|
| 1131 |
-
2. **Option 2 - Hugging Face**: Configure `HF_TOKEN` environment variable
|
| 1132 |
-
|
| 1133 |
-
### For Email Delivery:
|
| 1134 |
-
1. **Get Mailjet credentials** from https://www.mailjet.com/
|
| 1135 |
-
2. **Set environment variables**:
|
| 1136 |
-
```
|
| 1137 |
-
MAILJET_API_KEY=your_api_key
|
| 1138 |
-
MAILJET_SECRET_KEY=your_secret_key
|
| 1139 |
-
FROM_EMAIL=your-email@domain.com
|
| 1140 |
-
```
|
| 1141 |
-
|
| 1142 |
-
## π¦ File Locations Expected:
|
| 1143 |
-
- **Damage Model**: `./output/model_final.pth`
|
| 1144 |
-
- **Deepfake Model**: `./output/vit_deepfake_final.pth`
|
| 1145 |
-
- **Config**: Environment variables for Mailjet
|
| 1146 |
-
""")
|
| 1147 |
-
|
| 1148 |
with gr.Tab("π§ Mailjet Setup"):
|
| 1149 |
gr.Markdown("""
|
| 1150 |
## π§ Mailjet Configuration
|
|
@@ -1320,35 +1168,13 @@ def create_gradio_interface():
|
|
| 1320 |
|
| 1321 |
if __name__ == "__main__":
|
| 1322 |
print("π Starting Car Damage Fraud Detector - Mailjet Edition...")
|
|
|
|
| 1323 |
|
| 1324 |
-
#
|
| 1325 |
-
print("\nπ SYSTEM STATUS SUMMARY:")
|
| 1326 |
-
print("=" * 50)
|
| 1327 |
-
|
| 1328 |
-
# Detectron2 status
|
| 1329 |
-
detectron2_status = "β
Available" if DETECTRON2_AVAILABLE else "β Not installed"
|
| 1330 |
-
print(f"π§ Detectron2: {detectron2_status}")
|
| 1331 |
-
|
| 1332 |
-
# Models status
|
| 1333 |
-
if model_status['damage_model']['available']:
|
| 1334 |
-
size_mb = model_status['damage_model']['size']
|
| 1335 |
-
print(f"π― Damage Model: β
Available ({size_mb:.2f} MB)")
|
| 1336 |
-
else:
|
| 1337 |
-
print(f"π― Damage Model: β Not found at {DEFAULT_DAMAGE_MODEL_PATH}")
|
| 1338 |
-
|
| 1339 |
-
if model_status['deepfake_model']['available']:
|
| 1340 |
-
size_mb = model_status['deepfake_model']['size']
|
| 1341 |
-
source = model_status['deepfake_model']['source']
|
| 1342 |
-
print(f"π€ Deepfake Model: β
Available ({size_mb:.2f} MB) - {source}")
|
| 1343 |
-
else:
|
| 1344 |
-
print(f"π€ Deepfake Model: π§ͺ Demo mode (model not available)")
|
| 1345 |
-
|
| 1346 |
-
# Mailjet status
|
| 1347 |
if MAILJET_CONFIG['API_KEY'] and MAILJET_CONFIG['SECRET_KEY']:
|
| 1348 |
-
print(
|
| 1349 |
print(f"π§ From: {MAILJET_CONFIG['FROM_NAME']} <{MAILJET_CONFIG['FROM_EMAIL']}>")
|
| 1350 |
-
|
| 1351 |
-
# Test Mailjet connection
|
| 1352 |
if test_mailjet_connection():
|
| 1353 |
print("π§ Mailjet: β
Connection test successful")
|
| 1354 |
else:
|
|
@@ -1356,16 +1182,6 @@ if __name__ == "__main__":
|
|
| 1356 |
else:
|
| 1357 |
print("π§ Mailjet API: β Not configured")
|
| 1358 |
|
| 1359 |
-
print("=" * 50)
|
| 1360 |
-
|
| 1361 |
-
# Display operational mode
|
| 1362 |
-
if model_status['deepfake_model']['available']:
|
| 1363 |
-
print("π― OPERATIONAL MODE: Full AI Analysis")
|
| 1364 |
-
else:
|
| 1365 |
-
print("π§ͺ OPERATIONAL MODE: Demo Mode (simulated results)")
|
| 1366 |
-
|
| 1367 |
-
print("π Starting Gradio interface...")
|
| 1368 |
-
|
| 1369 |
app = create_gradio_interface()
|
| 1370 |
app.launch(
|
| 1371 |
share=False,
|
|
|
|
| 36 |
print(f"β οΈ Detectron2 not available: {e}")
|
| 37 |
DETECTRON2_AVAILABLE = False
|
| 38 |
|
| 39 |
+
# Try to download model from Hugging Face
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
huggingface_model_path = None
|
| 41 |
+
try:
|
| 42 |
+
from huggingface_hub import hf_hub_download
|
| 43 |
+
# Try to download from your repository
|
| 44 |
+
huggingface_model_path = hf_hub_download(
|
| 45 |
+
repo_id="Askhedi/Car_damage_fraud_detector",
|
| 46 |
+
filename="vit_deepfake_final.pth",
|
| 47 |
+
token=os.getenv('HF_TOKEN')
|
| 48 |
+
)
|
| 49 |
+
print(f"β
Model downloaded from Hugging Face: {huggingface_model_path}")
|
| 50 |
+
except Exception as e:
|
| 51 |
+
print(f"β οΈ Could not download model from Hugging Face: {e}")
|
| 52 |
+
print("π Will use demo mode with simulated results")
|
| 53 |
+
huggingface_model_path = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
# Define model paths
|
| 56 |
DEFAULT_DAMAGE_MODEL_PATH = "./output/model_final.pth"
|
|
|
|
| 724 |
|
| 725 |
def process_image(input_image, damage_threshold, deepfake_threshold, skip_damage, device_str, usage_count, recipient_email):
|
| 726 |
"""Main processing function with Mailjet email integration"""
|
|
|
|
| 727 |
|
| 728 |
# Handle usage count
|
| 729 |
if usage_count is None:
|
|
|
|
| 779 |
progress_info.append(f"π₯οΈ Using device: {device}")
|
| 780 |
|
| 781 |
# Initialize models
|
| 782 |
+
deepfake_model_path = huggingface_model_path or DEFAULT_DEEPFAKE_MODEL_PATH
|
| 783 |
deepfake_model = None
|
| 784 |
demo_mode = False
|
| 785 |
|
| 786 |
+
if deepfake_model_path and os.path.exists(deepfake_model_path):
|
| 787 |
+
progress_info.append("π€ Loading AI model...")
|
| 788 |
+
deepfake_model = load_vit_deepfake_model(deepfake_model_path, device)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 789 |
if deepfake_model:
|
| 790 |
+
progress_info.append("β
AI model loaded successfully")
|
| 791 |
else:
|
| 792 |
+
progress_info.append("β Failed to load AI model - using demo mode")
|
| 793 |
demo_mode = True
|
| 794 |
else:
|
| 795 |
+
progress_info.append("β οΈ AI model not found - using demo mode")
|
| 796 |
demo_mode = True
|
| 797 |
|
| 798 |
# Analyze the image
|
|
|
|
| 911 |
|
| 912 |
def create_gradio_interface():
|
| 913 |
"""Create Gradio interface with Mailjet integration"""
|
|
|
|
|
|
|
|
|
|
| 914 |
theme = gr.themes.Soft(primary_hue="blue", secondary_hue="orange")
|
| 915 |
|
| 916 |
with gr.Blocks(title="Car Damage Fraud Detector - Mailjet Edition", theme=theme) as app:
|
|
|
|
| 928 |
""")
|
| 929 |
|
| 930 |
# Model and Mailjet status
|
| 931 |
+
model_status = "β
AI Model Ready" if huggingface_model_path and os.path.exists(huggingface_model_path) else "π§ͺ Demo Mode (simulated results)"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 932 |
|
| 933 |
+
if MAILJET_CONFIG['API_KEY'] and MAILJET_CONFIG['SECRET_KEY']:
|
| 934 |
+
gr.Markdown(f"**β
Mailjet API configured** | **{model_status}**")
|
| 935 |
+
else:
|
| 936 |
+
gr.Markdown(f"**β οΈ Mailjet API not configured** | **{model_status}**")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 937 |
|
| 938 |
usage_counter = gr.State(0)
|
| 939 |
|
|
|
|
| 993 |
)
|
| 994 |
download_info = gr.Markdown("**Complete analysis package will appear here after processing...**")
|
| 995 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 996 |
with gr.Tab("π§ Mailjet Setup"):
|
| 997 |
gr.Markdown("""
|
| 998 |
## π§ Mailjet Configuration
|
|
|
|
| 1168 |
|
| 1169 |
if __name__ == "__main__":
|
| 1170 |
print("π Starting Car Damage Fraud Detector - Mailjet Edition...")
|
| 1171 |
+
print(f"β
HuggingFace model: {'Available' if huggingface_model_path else 'Not available'}")
|
| 1172 |
|
| 1173 |
+
# Test Mailjet configuration
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1174 |
if MAILJET_CONFIG['API_KEY'] and MAILJET_CONFIG['SECRET_KEY']:
|
| 1175 |
+
print("π§ Mailjet API: β
Configured")
|
| 1176 |
print(f"π§ From: {MAILJET_CONFIG['FROM_NAME']} <{MAILJET_CONFIG['FROM_EMAIL']}>")
|
| 1177 |
+
# Test connection at startup
|
|
|
|
| 1178 |
if test_mailjet_connection():
|
| 1179 |
print("π§ Mailjet: β
Connection test successful")
|
| 1180 |
else:
|
|
|
|
| 1182 |
else:
|
| 1183 |
print("π§ Mailjet API: β Not configured")
|
| 1184 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1185 |
app = create_gradio_interface()
|
| 1186 |
app.launch(
|
| 1187 |
share=False,
|