GChilukala commited on
Commit
326af3a
·
verified ·
1 Parent(s): a09777d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +205 -404
app.py CHANGED
@@ -1,5 +1,5 @@
1
  """
2
- 📱 Instagram Caption Generator - Simplified Version (FIXED DROPDOWNS)
3
  ==================================================
4
 
5
  AI-Powered Instagram Content Creation Suite with SambaNova Integration
@@ -8,7 +8,7 @@ Multi-Modal AI Analysis (Vision + Text) + Multi-Language Support
8
  🚀 Key Features:
9
  - SambaNova Llama-4-Maverick Integration
10
  - Multi-Language Support (German, Chinese, French, Arabic via Hugging Face)
11
- - Advanced Gradio Interface with WORKING DROPDOWNS
12
  - Advanced Error Handling & Security
13
 
14
  Author: MCP Hackathon 2025 Participant
@@ -133,14 +133,14 @@ class AdvancedInstagramGenerator:
133
  print("✅ AI models setup completed!")
134
 
135
  def setup_huggingface_client(self):
136
- """Initialize Hugging Face client for translations - FIXED"""
137
  try:
138
- # Initialize Hugging Face client - FIXED INITIALIZATION
139
  hf_token = os.environ.get("HF_TOKEN")
140
  if hf_token:
141
- # FIXED: Use correct initialization method
142
  self.hf_client = InferenceClient(
143
- token=hf_token, # Changed from provider and api_key
 
144
  )
145
  print("✅ Hugging Face client initialized successfully!")
146
  self.hf_client_working = True
@@ -418,41 +418,6 @@ class AdvancedInstagramGenerator:
418
 
419
  return f"🇸🇦 ARABIC VERSION (Fallback):\n{translated}"
420
 
421
- def get_fallback_hindi_translation(self, text: str) -> str:
422
- """Fallback Hindi translation when HF API fails"""
423
- # Simple keyword-based translation for common Instagram terms
424
- hindi_translations = {
425
- "amazing": "अद्भुत",
426
- "beautiful": "सुंदर",
427
- "love": "प्रेम",
428
- "perfect": "परफेक्ट",
429
- "awesome": "शानदार",
430
- "incredible": "अविश्वसनीय",
431
- "follow": "फॉलो",
432
- "like": "लाइक",
433
- "share": "शेयर",
434
- "comment": "कमेंट",
435
- "today": "आज",
436
- "moment": "पल",
437
- "life": "जीवन",
438
- "inspiration": "प्रेरणा",
439
- "community": "समुदाय",
440
- "content": "कंटेंट",
441
- "check out": "देखें",
442
- "what do you think": "आप क्या सोचते हैं"
443
- }
444
-
445
- # Basic word replacement (not perfect but functional fallback)
446
- translated = text.lower()
447
- for english, hindi in hindi_translations.items():
448
- translated = translated.replace(english, hindi)
449
-
450
- # Add Hindi hashtags
451
- if "#" in translated:
452
- translated += " #हिंदी #भारत #सोशलमीडिया #कंटेंट"
453
-
454
- return f"🇮🇳 HINDI VERSION (Fallback):\n{translated}"
455
-
456
  def setup_trend_analysis(self):
457
  """Initialize basic trend analysis"""
458
  self.trending_cache = {}
@@ -1026,18 +991,16 @@ Format:
1026
  [Hashtags]"""
1027
 
1028
 
1029
- # Global generator instance with caching - FIXED
1030
  @functools.lru_cache(maxsize=1)
1031
  def get_generator():
1032
  """Get cached generator instance"""
1033
  return AdvancedInstagramGenerator()
1034
 
1035
- # FIXED: Initialize generator with proper error handling
1036
  try:
1037
  generator = get_generator()
1038
  setup_success = True
1039
  setup_error = ""
1040
- print("✅ Generator initialized successfully!")
1041
  except Exception as e:
1042
  generator = None
1043
  setup_success = False
@@ -1045,35 +1008,25 @@ except Exception as e:
1045
  print(f"❌ Setup failed: {e}")
1046
 
1047
 
1048
- # FIXED: Gradio Interface Functions with proper parameter handling
1049
- def generate_advanced_caption_interface(uploaded_files, style, audience, custom_prompt):
1050
- """Advanced interface function for caption generation - FIXED"""
 
1051
  if not setup_success:
1052
  return f"❌ Setup Error: {setup_error}", ""
1053
 
1054
- # FIXED: Debug dropdown values
1055
- print(f"🔍 DEBUG - Style received: {style}")
1056
- print(f"🔍 DEBUG - Audience received: {audience}")
1057
- print(f"🔍 DEBUG - Custom prompt: {custom_prompt}")
1058
-
1059
  images = []
1060
  if uploaded_files:
1061
  for file in uploaded_files[:3]:
1062
  try:
1063
  image = Image.open(file.name)
1064
  images.append(image)
1065
- print(f"✅ Loaded image: {file.name}")
1066
  except Exception as e:
1067
  return f"❌ Error processing file: {e}", ""
1068
 
1069
- # FIXED: Use asyncio.run for async function
1070
- try:
1071
- import asyncio
1072
- result = asyncio.run(generator.generate_advanced_caption(
1073
- images, style, audience, custom_prompt
1074
- ))
1075
- except Exception as e:
1076
- return f"❌ Generation error: {str(e)}", ""
1077
 
1078
  # Extract clean caption for multi-language processing
1079
  caption_only = ""
@@ -1099,14 +1052,12 @@ def generate_advanced_caption_interface(uploaded_files, style, audience, custom_
1099
  return result, caption_only
1100
 
1101
 
1102
- def generate_multiple_captions_interface(uploaded_files, style, audience, custom_prompt):
1103
- """Generate multiple caption variations - FIXED"""
 
1104
  if not setup_success:
1105
  return f"❌ Setup Error: {setup_error}"
1106
 
1107
- # FIXED: Debug dropdown values
1108
- print(f"🔍 DEBUG VARIATIONS - Style: {style}, Audience: {audience}")
1109
-
1110
  images = []
1111
  if uploaded_files:
1112
  for file in uploaded_files[:3]:
@@ -1119,141 +1070,126 @@ def generate_multiple_captions_interface(uploaded_files, style, audience, custom
1119
  if not images:
1120
  return "❌ Please upload at least one image to generate caption variations."
1121
 
1122
- # FIXED: Use asyncio.run for async functions
1123
- try:
1124
- import asyncio
1125
-
1126
- # First generate the main caption using Llama-4-Maverick
1127
- main_result = asyncio.run(generator.generate_advanced_caption(
1128
- images, style, audience, custom_prompt
1129
- ))
1130
-
1131
- # Extract just the caption text (without the header and footer)
1132
- base_caption = ""
1133
- if "✨ AI-GENERATED INSTAGRAM CONTENT:" in main_result:
1134
- lines = main_result.split('\n')
1135
- caption_lines = []
1136
- start_capturing = False
1137
-
1138
- for line in lines:
1139
- if "✨ AI-GENERATED INSTAGRAM CONTENT:" in line:
1140
- start_capturing = True
1141
- continue
1142
- elif "🤖 Powered by SambaNova" in line:
1143
- break
1144
- elif start_capturing and line.strip():
1145
- caption_lines.append(line)
1146
-
1147
- base_caption = '\n'.join(caption_lines).strip()
1148
-
1149
- if not base_caption:
1150
- return "❌ Failed to generate base caption for variations"
1151
 
1152
- # Generate 3 variations using Meta-Llama-3.2-3B-Instruct
1153
- variations = asyncio.run(generator.generate_mistral_variations(base_caption, count=3))
 
 
 
 
 
 
1154
 
1155
- # Format the results
1156
- formatted_result = "✨ ALTERNATIVE CAPTIONS:\n\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
1157
  formatted_result += "=" * 60 + "\n\n"
1158
-
1159
- for i, variation in enumerate(variations, 1):
1160
- formatted_result += f"📝 ALTERNATIVE {i}:\n"
1161
- formatted_result += f"{variation}\n"
1162
- formatted_result += "=" * 60 + "\n\n"
1163
-
1164
- return formatted_result
1165
- except Exception as e:
1166
- return f"❌ Variation generation error: {str(e)}"
1167
 
1168
 
1169
- def translate_caption_interface(base_caption, selected_languages):
1170
- """Generate multi-language versions of captions - FIXED"""
1171
  if not base_caption.strip():
1172
  return "❌ Please provide a caption to translate"
1173
 
1174
  if not selected_languages:
1175
  return "❌ Please select at least one language"
1176
 
1177
- # FIXED: Debug language selection
1178
- print(f"🔍 DEBUG TRANSLATION - Languages: {selected_languages}")
1179
-
1180
  result = "🌍 MULTI-LANGUAGE CAPTION VERSIONS:\n\n"
1181
  result += "=" * 60 + "\n\n"
1182
 
1183
- # FIXED: Use asyncio.run for async translation functions
1184
- import asyncio
1185
-
1186
  for language in selected_languages:
1187
- try:
1188
- if language == "🇩🇪 German":
1189
- # Use Hugging Face for German translation
1190
- if generator and generator.hf_client_working:
1191
- try:
1192
- german_translation = asyncio.run(generator.translate_to_german(base_caption))
1193
- result += "🇩🇪 GERMAN VERSION (Hugging Face T5):\n"
1194
- result += f"{german_translation}\n\n"
1195
- result += "=" * 60 + "\n\n"
1196
- except Exception as e:
1197
- fallback_german = generator.get_fallback_german_translation(base_caption)
1198
- result += f"{fallback_german}\n\n"
1199
- result += "=" * 60 + "\n\n"
1200
- else:
1201
  fallback_german = generator.get_fallback_german_translation(base_caption)
1202
  result += f"{fallback_german}\n\n"
1203
  result += "=" * 60 + "\n\n"
1204
-
1205
- elif language == "🇨🇳 Chinese":
1206
- # Use Hugging Face for Chinese translation
1207
- if generator and generator.hf_client_working:
1208
- try:
1209
- chinese_translation = asyncio.run(generator.translate_to_chinese(base_caption))
1210
- result += "🇨🇳 CHINESE VERSION (Hugging Face MT5):\n"
1211
- result += f"{chinese_translation}\n\n"
1212
- result += "=" * 60 + "\n\n"
1213
- except Exception as e:
1214
- fallback_chinese = generator.get_fallback_chinese_translation(base_caption)
1215
- result += f"{fallback_chinese}\n\n"
1216
- result += "=" * 60 + "\n\n"
1217
- else:
1218
  fallback_chinese = generator.get_fallback_chinese_translation(base_caption)
1219
  result += f"{fallback_chinese}\n\n"
1220
  result += "=" * 60 + "\n\n"
1221
-
1222
- elif language == "🇮🇳 Hindi":
1223
- # Use Hugging Face for Hindi translation
1224
- if generator and generator.hf_client_working:
1225
- try:
1226
- hindi_translation = asyncio.run(generator.translate_to_hindi(base_caption))
1227
- result += "🇮🇳 HINDI VERSION (Hugging Face Helsinki-NLP):\n"
1228
- result += f"{hindi_translation}\n\n"
1229
- result += "=" * 60 + "\n\n"
1230
- except Exception as e:
1231
- fallback_hindi = generator.get_fallback_hindi_translation(base_caption)
1232
- result += f"{fallback_hindi}\n\n"
1233
- result += "=" * 60 + "\n\n"
1234
- else:
1235
  fallback_hindi = generator.get_fallback_hindi_translation(base_caption)
1236
  result += f"{fallback_hindi}\n\n"
1237
  result += "=" * 60 + "\n\n"
1238
-
1239
- elif language == "🇸🇦 Arabic":
1240
- # Use Hugging Face for Arabic translation
1241
- if generator and generator.hf_client_working:
1242
- try:
1243
- arabic_translation = asyncio.run(generator.translate_to_arabic(base_caption))
1244
- result += "🇸🇦 ARABIC VERSION (Hugging Face Marefa):\n"
1245
- result += f"{arabic_translation}\n\n"
1246
- result += "=" * 60 + "\n\n"
1247
- except Exception as e:
1248
- fallback_arabic = generator.get_fallback_arabic_translation(base_caption)
1249
- result += f"{fallback_arabic}\n\n"
1250
- result += "=" * 60 + "\n\n"
1251
- else:
1252
  fallback_arabic = generator.get_fallback_arabic_translation(base_caption)
1253
  result += f"{fallback_arabic}\n\n"
1254
  result += "=" * 60 + "\n\n"
1255
- except Exception as e:
1256
- result += f"❌ Error translating to {language}: {str(e)}\n\n"
 
 
1257
 
1258
  if any(lang in selected_languages for lang in ["🇩🇪 German", "🇨🇳 Chinese", "🇮🇳 Hindi", "🇸🇦 Arabic"]):
1259
  hf_langs = []
@@ -1274,9 +1210,13 @@ def translate_caption_interface(base_caption, selected_languages):
1274
 
1275
 
1276
  def create_gradio_app():
1277
- """Create the Gradio app with SambaNova and Hugging Face integration - FIXED DROPDOWNS"""
 
 
 
 
1278
 
1279
- # Championship-level CSS
1280
  css = """
1281
  @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap');
1282
 
@@ -1284,258 +1224,146 @@ def create_gradio_app():
1284
  background: linear-gradient(135deg, #667eea 0%, #764ba2 25%, #f093fb 50%, #f5576c 75%, #4facfe 100%);
1285
  font-family: 'Space Grotesk', 'Inter', system-ui, sans-serif;
1286
  min-height: 100vh;
1287
- position: relative;
1288
- overflow-x: hidden;
1289
- }
1290
-
1291
- .gradio-container::before {
1292
- content: '';
1293
- position: absolute;
1294
- top: 0;
1295
- left: 0;
1296
- right: 0;
1297
- bottom: 0;
1298
- background: radial-gradient(circle at 20% 80%, rgba(120, 119, 198, 0.3) 0%, transparent 50%),
1299
- radial-gradient(circle at 80% 20%, rgba(255, 119, 198, 0.3) 0%, transparent 50%);
1300
- pointer-events: none;
1301
- z-index: 1;
1302
  }
1303
 
1304
  .main-header {
1305
  text-align: center;
1306
  color: white;
1307
- margin-bottom: 40px;
1308
- padding: 40px;
1309
- background: rgba(255,255,255,0.1);
1310
- border-radius: 30px;
1311
- backdrop-filter: blur(30px);
1312
- border: 2px solid rgba(255,255,255,0.2);
1313
- box-shadow: 0 25px 50px rgba(0,0,0,0.1);
1314
- position: relative;
1315
- z-index: 2;
1316
- animation: float 6s ease-in-out infinite;
1317
- }
1318
-
1319
- @keyframes float {
1320
- 0%, 100% { transform: translateY(0px); }
1321
- 50% { transform: translateY(-10px); }
1322
- }
1323
-
1324
- .feature-card {
1325
- background: rgba(255,255,255,0.15);
1326
- border-radius: 25px;
1327
  padding: 30px;
 
 
1328
  backdrop-filter: blur(20px);
1329
- border: 1px solid rgba(255,255,255,0.3);
1330
  box-shadow: 0 20px 40px rgba(0,0,0,0.1);
1331
- transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
1332
- position: relative;
1333
- z-index: 2;
1334
  }
1335
 
1336
- .feature-card:hover {
1337
- transform: translateY(-8px) scale(1.02);
1338
- box-shadow: 0 30px 60px rgba(0,0,0,0.2);
1339
- background: rgba(255,255,255,0.2);
 
 
 
 
1340
  }
1341
 
1342
  .gradio-button-primary {
1343
  background: linear-gradient(45deg, #ff6b6b, #ee5a24, #ff9ff3, #54a0ff) !important;
1344
- background-size: 300% 300% !important;
1345
- animation: gradient-shift 4s ease infinite !important;
1346
  border: none !important;
1347
- border-radius: 20px !important;
1348
- padding: 18px 35px !important;
1349
- font-weight: 700 !important;
1350
- text-transform: uppercase !important;
1351
- letter-spacing: 2px !important;
1352
- box-shadow: 0 15px 35px rgba(255, 107, 107, 0.4) !important;
1353
  transition: all 0.3s ease !important;
1354
- position: relative !important;
1355
- overflow: hidden !important;
1356
- }
1357
-
1358
- @keyframes gradient-shift {
1359
- 0% { background-position: 0% 50%; }
1360
- 50% { background-position: 100% 50%; }
1361
- 100% { background-position: 0% 50%; }
1362
  }
1363
 
1364
  .gradio-button-primary:hover {
1365
- transform: translateY(-3px) scale(1.05) !important;
1366
- box-shadow: 0 20px 40px rgba(255, 107, 107, 0.6) !important;
1367
  }
1368
 
1369
  .gradio-button-secondary {
1370
  background: linear-gradient(45deg, #feca57, #ff9ff3, #54a0ff, #5f27cd) !important;
1371
- background-size: 300% 300% !important;
1372
- animation: gradient-shift 4s ease infinite !important;
1373
  border: none !important;
1374
- border-radius: 18px !important;
1375
- padding: 15px 30px !important;
1376
  font-weight: 600 !important;
1377
- text-transform: uppercase !important;
1378
- letter-spacing: 1.5px !important;
1379
- box-shadow: 0 12px 25px rgba(254, 202, 87, 0.4) !important;
1380
- transition: all 0.3s ease !important;
1381
  color: white !important;
 
1382
  }
1383
 
1384
- .gradio-button-secondary:hover {
1385
- transform: translateY(-2px) scale(1.03) !important;
1386
- box-shadow: 0 15px 30px rgba(254, 202, 87, 0.6) !important;
1387
- }
1388
-
1389
- .advanced-controls {
1390
- background: rgba(255,255,255,0.1);
1391
- border-radius: 20px;
1392
- padding: 25px;
1393
- backdrop-filter: blur(15px);
1394
- border: 1px solid rgba(255,255,255,0.2);
1395
- margin: 20px 0;
1396
- }
1397
-
1398
- .sambanova-status {
1399
  background: linear-gradient(90deg, #2ecc71, #27ae60);
1400
  color: white;
1401
- padding: 15px 25px;
1402
- border-radius: 15px;
1403
  text-align: center;
1404
  font-weight: 600;
1405
- box-shadow: 0 10px 20px rgba(46, 204, 113, 0.3);
1406
- animation: pulse 2s infinite;
1407
- }
1408
-
1409
- @keyframes pulse {
1410
- 0% { box-shadow: 0 10px 20px rgba(46, 204, 113, 0.3); }
1411
- 50% { box-shadow: 0 15px 30px rgba(46, 204, 113, 0.5); }
1412
- 100% { box-shadow: 0 10px 20px rgba(46, 204, 113, 0.3); }
1413
- }
1414
-
1415
- .trending-indicator {
1416
- display: inline-block;
1417
- width: 8px;
1418
- height: 8px;
1419
- background: #ff6b6b;
1420
- border-radius: 50%;
1421
- animation: blink 1s infinite;
1422
- margin-right: 8px;
1423
- }
1424
-
1425
- @keyframes blink {
1426
- 0%, 50% { opacity: 1; }
1427
- 51%, 100% { opacity: 0.3; }
1428
  }
1429
  """
1430
 
1431
- # FIXED: Use specific theme and create proper block structure
1432
- with gr.Blocks(
1433
- css=css,
1434
- title="📱 Instagram Generator - MCP Hackathon 2025",
1435
- theme=gr.themes.Soft() # Changed from Glass to Soft for better dropdown compatibility
1436
- ) as app:
1437
 
1438
  # Main Header
1439
- gr.HTML("""
1440
  <div class="main-header">
1441
- <h1 style="font-size: 3rem; margin-bottom: 15px; font-weight: 800; background: linear-gradient(45deg, #ff6b6b, #feca57, #ff9ff3, #54a0ff); -webkit-background-clip: text; -webkit-text-fill-color: transparent;">
1442
  📱 INSTAGRAM CAPTION GENERATOR
1443
  </h1>
1444
- <h2 style="font-size: 1.4rem; margin-bottom: 20px; opacity: 0.9; font-weight: 500;">
1445
- 🚀 MCP Hackathon 2025 Submission • SambaNova + Hugging Face Edition
1446
  </h2>
1447
- <div style="display: flex; justify-content: center; gap: 20px; margin-top: 25px;">
1448
- <span style="background: rgba(255,255,255,0.2); padding: 8px 16px; border-radius: 20px; font-size: 0.9rem;">🤖 SambaNova AI</span>
1449
- <span style="background: rgba(255,255,255,0.2); padding: 8px 16px; border-radius: 20px; font-size: 0.9rem;">🌍 Multi-Language</span>
1450
- <span style="background: rgba(255,255,255,0.2); padding: 8px 16px; border-radius: 20px; font-size: 0.9rem;">🔗 MCP Server</span>
1451
  </div>
1452
  </div>
1453
  """)
1454
 
1455
- # Status Indicators
1456
- hf_status = "✅ Connected" if generator and generator.hf_client_working else "⚠️ Fallback Mode"
1457
- sambanova_status = "✅ Connected" if generator and generator.sambanova_client_working else "⚠️ Fallback Mode"
1458
-
1459
- gr.HTML(f"""
1460
- <div class="sambanova-status">
1461
- <span class="trending-indicator"></span>
1462
- 🚀 SambaNova: {sambanova_status} • 🤗 Hugging Face: {hf_status} • 🦙 Llama-3.2 • MCP Server Ready
1463
- </div>
1464
- """)
1465
-
1466
  # Main Interface
1467
- with gr.Tab("🎯 Advanced Caption Generator"):
1468
  with gr.Row():
1469
- # Left Column - Enhanced Controls
1470
  with gr.Column(scale=2, elem_classes=["feature-card"]):
1471
- gr.Markdown("### 🖼️ Multi-Image Upload & Analysis")
1472
  gr.Markdown("*SambaNova AI vision analysis with quality scoring*")
1473
 
1474
  images = gr.File(
1475
  label="📸 Upload Images (Max 3)",
1476
  file_count="multiple",
1477
  file_types=["image"],
1478
- height=280
1479
  )
1480
 
1481
- with gr.Group(elem_classes=["advanced-controls"]):
1482
- gr.Markdown("### ⚙️ AI Configuration")
1483
-
1484
- with gr.Row():
1485
- # FIXED: Improved dropdown definition with explicit parameters
1486
- caption_style = gr.Dropdown(
1487
- label="🎨 Caption Style",
1488
- choices=[
1489
- "🎯 Viral Engagement",
1490
- "💼 Professional Brand",
1491
- "😄 Casual Fun",
1492
- "😂 Humor & Memes",
1493
- "💪 Motivational",
1494
- "📖 Storytelling",
1495
- "🌟 Luxury Lifestyle",
1496
- "🔥 Trending Culture"
1497
- ],
1498
- value="🎯 Viral Engagement",
1499
- interactive=True, # FIXED: Explicitly set interactive
1500
- allow_custom_value=False, # FIXED: Prevent custom values
1501
- multiselect=False # FIXED: Single selection only
1502
- )
1503
-
1504
- target_audience = gr.Dropdown(
1505
- label="👥 Target Audience",
1506
- choices=[
1507
- "🌟 General Audience",
1508
- "💼 Business Professionals",
1509
- "✈️ Travel Enthusiasts",
1510
- "🍕 Food Lovers",
1511
- "💪 Fitness Community",
1512
- "👗 Fashion Forward",
1513
- "💻 Tech Innovators",
1514
- "🎨 Creative Artists",
1515
- "🌱 Sustainability Advocates",
1516
- "🎵 Music Fans"
1517
- ],
1518
- value="🌟 General Audience",
1519
- interactive=True, # FIXED: Explicitly set interactive
1520
- allow_custom_value=False, # FIXED: Prevent custom values
1521
- multiselect=False # FIXED: Single selection only
1522
- )
1523
 
1524
- custom_prompt = gr.Textbox(
1525
- label="💬 Advanced Instructions",
1526
- placeholder="e.g., 'Focus on sustainability messaging', 'Include product launch details', 'Emphasize community building'...",
1527
- lines=3,
1528
- interactive=True # FIXED: Explicitly set interactive
 
 
 
 
 
 
 
 
1529
  )
1530
 
 
 
 
 
 
 
1531
  generate_btn = gr.Button(
1532
  "🚀 Generate Caption",
1533
  variant="primary",
1534
- size="lg",
1535
- scale=2
1536
  )
1537
 
1538
-
1539
  # Right Column - Results
1540
  with gr.Column(scale=3, elem_classes=["feature-card"]):
1541
  gr.Markdown("### 📊 Generated Content")
@@ -1545,8 +1373,7 @@ def create_gradio_app():
1545
  lines=15,
1546
  max_lines=20,
1547
  show_copy_button=True,
1548
- placeholder="Upload images and generate your Instagram content...",
1549
- interactive=False # FIXED: Output should not be interactive
1550
  )
1551
 
1552
  with gr.Row():
@@ -1560,8 +1387,7 @@ def create_gradio_app():
1560
  label="✨ Alternative Captions",
1561
  lines=15,
1562
  show_copy_button=True,
1563
- placeholder="Generate 3 different caption alternatives using Meta-Llama-3.2-3B-Instruct...",
1564
- interactive=False # FIXED: Output should not be interactive
1565
  )
1566
 
1567
  # Multi-Language Tab
@@ -1574,21 +1400,18 @@ def create_gradio_app():
1574
  base_caption_input = gr.Textbox(
1575
  label="📝 Base Caption",
1576
  placeholder="Paste your generated caption here...",
1577
- lines=5,
1578
- interactive=True # FIXED: Input should be interactive
1579
  )
1580
 
1581
- # FIXED: Improved checkbox group definition
1582
  language_selector = gr.CheckboxGroup(
1583
- label="🌐 Select Languages",
1584
  choices=[
1585
  "🇩🇪 German",
1586
  "🇨🇳 Chinese",
1587
  "🇮🇳 Hindi",
1588
  "🇸🇦 Arabic"
1589
  ],
1590
- value=["🇩🇪 German", "🇮🇳 Hindi"],
1591
- interactive=True # FIXED: Explicitly set interactive
1592
  )
1593
 
1594
  translate_btn = gr.Button(
@@ -1601,8 +1424,7 @@ def create_gradio_app():
1601
  label="🗺️ Multi-Language Captions",
1602
  lines=20,
1603
  show_copy_button=True,
1604
- placeholder="Culturally adapted captions for global audiences...",
1605
- interactive=False # FIXED: Output should not be interactive
1606
  )
1607
 
1608
  # SambaNova Features Tab
@@ -1722,7 +1544,8 @@ variations = client.chat.completions.create(
1722
  from huggingface_hub import InferenceClient
1723
 
1724
  client = InferenceClient(
1725
- token=os.environ["HF_TOKEN"], # FIXED: Use token parameter
 
1726
  )
1727
 
1728
  # German translation
@@ -1759,34 +1582,26 @@ arabic_result = client.translation(
1759
  label="🔧 Hugging Face Translation Code"
1760
  )
1761
 
1762
- # FIXED: Event Handlers with proper error handling
1763
- print("🔗 Setting up event handlers...")
1764
-
1765
- # Main caption generation
1766
  generate_btn.click(
1767
  fn=generate_advanced_caption_interface,
1768
  inputs=[images, caption_style, target_audience, custom_prompt],
1769
- outputs=[output, base_caption_input],
1770
- show_progress=True # FIXED: Show progress indicator
1771
  )
1772
 
1773
  # Generate multiple alternatives
1774
  alternatives_btn.click(
1775
  fn=generate_multiple_captions_interface,
1776
  inputs=[images, caption_style, target_audience, custom_prompt],
1777
- outputs=alternatives_output,
1778
- show_progress=True # FIXED: Show progress indicator
1779
  )
1780
 
1781
  # Multi-language translation
1782
  translate_btn.click(
1783
  fn=translate_caption_interface,
1784
  inputs=[base_caption_input, language_selector],
1785
- outputs=multilingual_output,
1786
- show_progress=True # FIXED: Show progress indicator
1787
  )
1788
-
1789
- print("✅ Event handlers configured successfully!")
1790
 
1791
  return app
1792
 
@@ -1800,7 +1615,6 @@ def main():
1800
  if not setup_success:
1801
  print(f"❌ Setup failed: {setup_error}")
1802
  print("💡 Please check your API configuration")
1803
- return
1804
 
1805
  # Status messages
1806
  sambanova_msg = "✅ SambaNova ready!" if generator and generator.sambanova_client_working else "⚠️ SambaNova fallback mode"
@@ -1813,20 +1627,7 @@ def main():
1813
 
1814
  # Create and launch the app
1815
  app = create_gradio_app()
1816
-
1817
- # FIXED: Launch configuration for better compatibility
1818
- app.launch(
1819
- server_name="0.0.0.0",
1820
- server_port=7860,
1821
- share=False,
1822
- show_error=True,
1823
- debug=True, # FIXED: Enable debug mode for troubleshooting
1824
- show_api=True, # FIXED: Show API for debugging
1825
- inbrowser=False,
1826
- favicon_path=None,
1827
- ssl_verify=False,
1828
- quiet=False
1829
- )
1830
 
1831
 
1832
  if __name__ == "__main__":
 
1
  """
2
+ 📱 Instagram Caption Generator - Simplified Version
3
  ==================================================
4
 
5
  AI-Powered Instagram Content Creation Suite with SambaNova Integration
 
8
  🚀 Key Features:
9
  - SambaNova Llama-4-Maverick Integration
10
  - Multi-Language Support (German, Chinese, French, Arabic via Hugging Face)
11
+ - Advanced Gradio Interface
12
  - Advanced Error Handling & Security
13
 
14
  Author: MCP Hackathon 2025 Participant
 
133
  print("✅ AI models setup completed!")
134
 
135
  def setup_huggingface_client(self):
136
+ """Initialize Hugging Face client for translations"""
137
  try:
138
+ # Initialize Hugging Face client
139
  hf_token = os.environ.get("HF_TOKEN")
140
  if hf_token:
 
141
  self.hf_client = InferenceClient(
142
+ provider="hf-inference",
143
+ api_key=hf_token,
144
  )
145
  print("✅ Hugging Face client initialized successfully!")
146
  self.hf_client_working = True
 
418
 
419
  return f"🇸🇦 ARABIC VERSION (Fallback):\n{translated}"
420
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
421
  def setup_trend_analysis(self):
422
  """Initialize basic trend analysis"""
423
  self.trending_cache = {}
 
991
  [Hashtags]"""
992
 
993
 
994
+ # Global generator instance with caching
995
  @functools.lru_cache(maxsize=1)
996
  def get_generator():
997
  """Get cached generator instance"""
998
  return AdvancedInstagramGenerator()
999
 
 
1000
  try:
1001
  generator = get_generator()
1002
  setup_success = True
1003
  setup_error = ""
 
1004
  except Exception as e:
1005
  generator = None
1006
  setup_success = False
 
1008
  print(f"❌ Setup failed: {e}")
1009
 
1010
 
1011
+ # Gradio Interface Functions
1012
+ async def generate_advanced_caption_interface(uploaded_files, style, audience,
1013
+ custom_prompt):
1014
+ """Advanced interface function for caption generation"""
1015
  if not setup_success:
1016
  return f"❌ Setup Error: {setup_error}", ""
1017
 
 
 
 
 
 
1018
  images = []
1019
  if uploaded_files:
1020
  for file in uploaded_files[:3]:
1021
  try:
1022
  image = Image.open(file.name)
1023
  images.append(image)
 
1024
  except Exception as e:
1025
  return f"❌ Error processing file: {e}", ""
1026
 
1027
+ result = await generator.generate_advanced_caption(
1028
+ images, style, audience, custom_prompt
1029
+ )
 
 
 
 
 
1030
 
1031
  # Extract clean caption for multi-language processing
1032
  caption_only = ""
 
1052
  return result, caption_only
1053
 
1054
 
1055
+ async def generate_multiple_captions_interface(uploaded_files, style, audience,
1056
+ custom_prompt):
1057
+ """Generate multiple caption variations using Meta-Llama-3.2-3B-Instruct"""
1058
  if not setup_success:
1059
  return f"❌ Setup Error: {setup_error}"
1060
 
 
 
 
1061
  images = []
1062
  if uploaded_files:
1063
  for file in uploaded_files[:3]:
 
1070
  if not images:
1071
  return "❌ Please upload at least one image to generate caption variations."
1072
 
1073
+ # First generate the main caption using Llama-4-Maverick
1074
+ main_result = await generator.generate_advanced_caption(
1075
+ images, style, audience, custom_prompt
1076
+ )
1077
+
1078
+ # Extract just the caption text (without the header and footer)
1079
+ base_caption = ""
1080
+ if "✨ AI-GENERATED INSTAGRAM CONTENT:" in main_result:
1081
+ lines = main_result.split('\n')
1082
+ caption_lines = []
1083
+ start_capturing = False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1084
 
1085
+ for line in lines:
1086
+ if "✨ AI-GENERATED INSTAGRAM CONTENT:" in line:
1087
+ start_capturing = True
1088
+ continue
1089
+ elif "🤖 Powered by SambaNova" in line:
1090
+ break
1091
+ elif start_capturing and line.strip():
1092
+ caption_lines.append(line)
1093
 
1094
+ base_caption = '\n'.join(caption_lines).strip()
1095
+
1096
+ if not base_caption:
1097
+ return "❌ Failed to generate base caption for variations"
1098
+
1099
+ # Generate 3 variations using Meta-Llama-3.2-3B-Instruct
1100
+ variations = await generator.generate_mistral_variations(base_caption, count=3)
1101
+
1102
+ # Format the results
1103
+ formatted_result = "✨ ALTERNATIVE CAPTIONS:\n\n"
1104
+ formatted_result += "=" * 60 + "\n\n"
1105
+
1106
+ for i, variation in enumerate(variations, 1):
1107
+ formatted_result += f"📝 ALTERNATIVE {i}:\n"
1108
+ formatted_result += f"{variation}\n"
1109
  formatted_result += "=" * 60 + "\n\n"
1110
+
1111
+ return formatted_result
 
 
 
 
 
 
 
1112
 
1113
 
1114
+ async def translate_caption_interface(base_caption, selected_languages):
1115
+ """Generate multi-language versions of captions"""
1116
  if not base_caption.strip():
1117
  return "❌ Please provide a caption to translate"
1118
 
1119
  if not selected_languages:
1120
  return "❌ Please select at least one language"
1121
 
 
 
 
1122
  result = "🌍 MULTI-LANGUAGE CAPTION VERSIONS:\n\n"
1123
  result += "=" * 60 + "\n\n"
1124
 
 
 
 
1125
  for language in selected_languages:
1126
+ if language == "🇩🇪 German":
1127
+ # Use Hugging Face for German translation
1128
+ if generator and generator.hf_client_working:
1129
+ try:
1130
+ german_translation = await generator.translate_to_german(base_caption)
1131
+ result += "🇩🇪 GERMAN VERSION (Hugging Face T5):\n"
1132
+ result += f"{german_translation}\n\n"
1133
+ result += "=" * 60 + "\n\n"
1134
+ except Exception as e:
 
 
 
 
 
1135
  fallback_german = generator.get_fallback_german_translation(base_caption)
1136
  result += f"{fallback_german}\n\n"
1137
  result += "=" * 60 + "\n\n"
1138
+ else:
1139
+ fallback_german = generator.get_fallback_german_translation(base_caption)
1140
+ result += f"{fallback_german}\n\n"
1141
+ result += "=" * 60 + "\n\n"
1142
+
1143
+ elif language == "🇨🇳 Chinese":
1144
+ # Use Hugging Face for Chinese translation
1145
+ if generator and generator.hf_client_working:
1146
+ try:
1147
+ chinese_translation = await generator.translate_to_chinese(base_caption)
1148
+ result += "🇨🇳 CHINESE VERSION (Hugging Face MT5):\n"
1149
+ result += f"{chinese_translation}\n\n"
1150
+ result += "=" * 60 + "\n\n"
1151
+ except Exception as e:
1152
  fallback_chinese = generator.get_fallback_chinese_translation(base_caption)
1153
  result += f"{fallback_chinese}\n\n"
1154
  result += "=" * 60 + "\n\n"
1155
+ else:
1156
+ fallback_chinese = generator.get_fallback_chinese_translation(base_caption)
1157
+ result += f"{fallback_chinese}\n\n"
1158
+ result += "=" * 60 + "\n\n"
1159
+
1160
+ elif language == "🇮🇳 Hindi":
1161
+ # Use Hugging Face for Hindi translation
1162
+ if generator and generator.hf_client_working:
1163
+ try:
1164
+ hindi_translation = await generator.translate_to_hindi(base_caption)
1165
+ result += "🇮🇳 HINDI VERSION (Hugging Face Helsinki-NLP):\n"
1166
+ result += f"{hindi_translation}\n\n"
1167
+ result += "=" * 60 + "\n\n"
1168
+ except Exception as e:
1169
  fallback_hindi = generator.get_fallback_hindi_translation(base_caption)
1170
  result += f"{fallback_hindi}\n\n"
1171
  result += "=" * 60 + "\n\n"
1172
+ else:
1173
+ fallback_hindi = generator.get_fallback_hindi_translation(base_caption)
1174
+ result += f"{fallback_hindi}\n\n"
1175
+ result += "=" * 60 + "\n\n"
1176
+
1177
+ elif language == "🇸🇦 Arabic":
1178
+ # Use Hugging Face for Arabic translation
1179
+ if generator and generator.hf_client_working:
1180
+ try:
1181
+ arabic_translation = await generator.translate_to_arabic(base_caption)
1182
+ result += "🇸🇦 ARABIC VERSION (Hugging Face Marefa):\n"
1183
+ result += f"{arabic_translation}\n\n"
1184
+ result += "=" * 60 + "\n\n"
1185
+ except Exception as e:
1186
  fallback_arabic = generator.get_fallback_arabic_translation(base_caption)
1187
  result += f"{fallback_arabic}\n\n"
1188
  result += "=" * 60 + "\n\n"
1189
+ else:
1190
+ fallback_arabic = generator.get_fallback_arabic_translation(base_caption)
1191
+ result += f"{fallback_arabic}\n\n"
1192
+ result += "=" * 60 + "\n\n"
1193
 
1194
  if any(lang in selected_languages for lang in ["🇩🇪 German", "🇨🇳 Chinese", "🇮🇳 Hindi", "🇸🇦 Arabic"]):
1195
  hf_langs = []
 
1210
 
1211
 
1212
  def create_gradio_app():
1213
+ """Create the Gradio app with good UI styling"""
1214
+
1215
+ # Status indicators
1216
+ hf_status = "✅ Connected" if generator and generator.hf_client_working else "⚠️ Fallback Mode"
1217
+ sambanova_status = "✅ Connected" if generator and generator.sambanova_client_working else "⚠️ Fallback Mode"
1218
 
1219
+ # Enhanced CSS for better UI
1220
  css = """
1221
  @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap');
1222
 
 
1224
  background: linear-gradient(135deg, #667eea 0%, #764ba2 25%, #f093fb 50%, #f5576c 75%, #4facfe 100%);
1225
  font-family: 'Space Grotesk', 'Inter', system-ui, sans-serif;
1226
  min-height: 100vh;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1227
  }
1228
 
1229
  .main-header {
1230
  text-align: center;
1231
  color: white;
1232
+ margin-bottom: 30px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1233
  padding: 30px;
1234
+ background: rgba(255,255,255,0.1);
1235
+ border-radius: 20px;
1236
  backdrop-filter: blur(20px);
1237
+ border: 1px solid rgba(255,255,255,0.2);
1238
  box-shadow: 0 20px 40px rgba(0,0,0,0.1);
 
 
 
1239
  }
1240
 
1241
+ .feature-card {
1242
+ background: rgba(255,255,255,0.1);
1243
+ border-radius: 15px;
1244
+ padding: 20px;
1245
+ backdrop-filter: blur(15px);
1246
+ border: 1px solid rgba(255,255,255,0.2);
1247
+ box-shadow: 0 15px 30px rgba(0,0,0,0.1);
1248
+ margin: 10px 0;
1249
  }
1250
 
1251
  .gradio-button-primary {
1252
  background: linear-gradient(45deg, #ff6b6b, #ee5a24, #ff9ff3, #54a0ff) !important;
 
 
1253
  border: none !important;
1254
+ border-radius: 15px !important;
1255
+ padding: 15px 25px !important;
1256
+ font-weight: 600 !important;
1257
+ color: white !important;
1258
+ box-shadow: 0 10px 20px rgba(255, 107, 107, 0.3) !important;
 
1259
  transition: all 0.3s ease !important;
 
 
 
 
 
 
 
 
1260
  }
1261
 
1262
  .gradio-button-primary:hover {
1263
+ transform: translateY(-2px) !important;
1264
+ box-shadow: 0 15px 30px rgba(255, 107, 107, 0.5) !important;
1265
  }
1266
 
1267
  .gradio-button-secondary {
1268
  background: linear-gradient(45deg, #feca57, #ff9ff3, #54a0ff, #5f27cd) !important;
 
 
1269
  border: none !important;
1270
+ border-radius: 12px !important;
1271
+ padding: 12px 20px !important;
1272
  font-weight: 600 !important;
 
 
 
 
1273
  color: white !important;
1274
+ box-shadow: 0 8px 16px rgba(254, 202, 87, 0.3) !important;
1275
  }
1276
 
1277
+ .status-badge {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1278
  background: linear-gradient(90deg, #2ecc71, #27ae60);
1279
  color: white;
1280
+ padding: 10px 20px;
1281
+ border-radius: 10px;
1282
  text-align: center;
1283
  font-weight: 600;
1284
+ box-shadow: 0 8px 16px rgba(46, 204, 113, 0.3);
1285
+ margin: 10px 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1286
  }
1287
  """
1288
 
1289
+ with gr.Blocks(css=css, title="📱 Instagram Generator", theme=gr.themes.Glass()) as app:
 
 
 
 
 
1290
 
1291
  # Main Header
1292
+ gr.HTML(f"""
1293
  <div class="main-header">
1294
+ <h1 style="font-size: 2.5rem; margin-bottom: 15px; font-weight: 800; background: linear-gradient(45deg, #ff6b6b, #feca57, #ff9ff3, #54a0ff); -webkit-background-clip: text; -webkit-text-fill-color: transparent;">
1295
  📱 INSTAGRAM CAPTION GENERATOR
1296
  </h1>
1297
+ <h2 style="font-size: 1.2rem; margin-bottom: 20px; opacity: 0.9;">
1298
+ 🚀 AI-Powered Content Creation • SambaNova + Hugging Face
1299
  </h2>
1300
+ <div style="display: flex; justify-content: center; gap: 20px; margin-top: 15px;">
1301
+ <span style="background: rgba(255,255,255,0.2); padding: 8px 16px; border-radius: 15px;">🤖 SambaNova: {sambanova_status}</span>
1302
+ <span style="background: rgba(255,255,255,0.2); padding: 8px 16px; border-radius: 15px;">🤗 Hugging Face: {hf_status}</span>
 
1303
  </div>
1304
  </div>
1305
  """)
1306
 
 
 
 
 
 
 
 
 
 
 
 
1307
  # Main Interface
1308
+ with gr.Tab("🎯 Caption Generator"):
1309
  with gr.Row():
1310
+ # Left Column - Controls
1311
  with gr.Column(scale=2, elem_classes=["feature-card"]):
1312
+ gr.Markdown("### 🖼️ Upload Images")
1313
  gr.Markdown("*SambaNova AI vision analysis with quality scoring*")
1314
 
1315
  images = gr.File(
1316
  label="📸 Upload Images (Max 3)",
1317
  file_count="multiple",
1318
  file_types=["image"],
1319
+ height=200
1320
  )
1321
 
1322
+ gr.Markdown("### ⚙️ Configuration")
1323
+
1324
+ with gr.Row():
1325
+ caption_style = gr.Dropdown(
1326
+ choices=[
1327
+ "🎯 Viral Engagement",
1328
+ "💼 Professional Brand",
1329
+ "😄 Casual Fun",
1330
+ "😂 Humor & Memes",
1331
+ "💪 Motivational",
1332
+ "📖 Storytelling",
1333
+ "🌟 Luxury Lifestyle",
1334
+ "🔥 Trending Culture"
1335
+ ],
1336
+ value="🎯 Viral Engagement",
1337
+ label="🎨 Caption Style"
1338
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1339
 
1340
+ target_audience = gr.Dropdown(
1341
+ choices=[
1342
+ "🌟 General Audience",
1343
+ "💼 Business Professionals",
1344
+ "✈️ Travel Enthusiasts",
1345
+ "🍕 Food Lovers",
1346
+ "💪 Fitness Community",
1347
+ "👗 Fashion Forward",
1348
+ "💻 Tech Innovators",
1349
+ "🎨 Creative Artists"
1350
+ ],
1351
+ value="🌟 General Audience",
1352
+ label="👥 Target Audience"
1353
  )
1354
 
1355
+ custom_prompt = gr.Textbox(
1356
+ label="💬 Additional Instructions",
1357
+ placeholder="e.g., 'Focus on sustainability', 'Include product details'...",
1358
+ lines=2
1359
+ )
1360
+
1361
  generate_btn = gr.Button(
1362
  "🚀 Generate Caption",
1363
  variant="primary",
1364
+ size="lg"
 
1365
  )
1366
 
 
1367
  # Right Column - Results
1368
  with gr.Column(scale=3, elem_classes=["feature-card"]):
1369
  gr.Markdown("### 📊 Generated Content")
 
1373
  lines=15,
1374
  max_lines=20,
1375
  show_copy_button=True,
1376
+ placeholder="Upload images and generate your Instagram content..."
 
1377
  )
1378
 
1379
  with gr.Row():
 
1387
  label="✨ Alternative Captions",
1388
  lines=15,
1389
  show_copy_button=True,
1390
+ placeholder="Generate 3 different caption alternatives using Meta-Llama-3.2-3B-Instruct..."
 
1391
  )
1392
 
1393
  # Multi-Language Tab
 
1400
  base_caption_input = gr.Textbox(
1401
  label="📝 Base Caption",
1402
  placeholder="Paste your generated caption here...",
1403
+ lines=5
 
1404
  )
1405
 
 
1406
  language_selector = gr.CheckboxGroup(
 
1407
  choices=[
1408
  "🇩🇪 German",
1409
  "🇨🇳 Chinese",
1410
  "🇮🇳 Hindi",
1411
  "🇸🇦 Arabic"
1412
  ],
1413
+ label="🌐 Select Languages",
1414
+ value=["🇩🇪 German", "🇮🇳 Hindi"]
1415
  )
1416
 
1417
  translate_btn = gr.Button(
 
1424
  label="🗺️ Multi-Language Captions",
1425
  lines=20,
1426
  show_copy_button=True,
1427
+ placeholder="Culturally adapted captions for global audiences..."
 
1428
  )
1429
 
1430
  # SambaNova Features Tab
 
1544
  from huggingface_hub import InferenceClient
1545
 
1546
  client = InferenceClient(
1547
+ provider="hf-inference",
1548
+ api_key=os.environ["HF_TOKEN"],
1549
  )
1550
 
1551
  # German translation
 
1582
  label="🔧 Hugging Face Translation Code"
1583
  )
1584
 
1585
+ # Event Handlers
 
 
 
1586
  generate_btn.click(
1587
  fn=generate_advanced_caption_interface,
1588
  inputs=[images, caption_style, target_audience, custom_prompt],
1589
+ outputs=[output, base_caption_input]
 
1590
  )
1591
 
1592
  # Generate multiple alternatives
1593
  alternatives_btn.click(
1594
  fn=generate_multiple_captions_interface,
1595
  inputs=[images, caption_style, target_audience, custom_prompt],
1596
+ outputs=alternatives_output
 
1597
  )
1598
 
1599
  # Multi-language translation
1600
  translate_btn.click(
1601
  fn=translate_caption_interface,
1602
  inputs=[base_caption_input, language_selector],
1603
+ outputs=multilingual_output
 
1604
  )
 
 
1605
 
1606
  return app
1607
 
 
1615
  if not setup_success:
1616
  print(f"❌ Setup failed: {setup_error}")
1617
  print("💡 Please check your API configuration")
 
1618
 
1619
  # Status messages
1620
  sambanova_msg = "✅ SambaNova ready!" if generator and generator.sambanova_client_working else "⚠️ SambaNova fallback mode"
 
1627
 
1628
  # Create and launch the app
1629
  app = create_gradio_app()
1630
+ app.launch(mcp_server=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
1631
 
1632
 
1633
  if __name__ == "__main__":