nixaut-codelabs commited on
Commit
ad3ac5b
·
verified ·
1 Parent(s): c070b5f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -493
app.py CHANGED
@@ -240,499 +240,6 @@ def metrics():
240
 
241
  return jsonify(get_performance_metrics())
242
 
243
- # Create the HTML template with Tailwind CSS
244
- with open("templates/index.html", "w") as f:
245
- f.write("""
246
- <!DOCTYPE html>
247
- <html lang="en">
248
- <head>
249
- <meta charset="UTF-8">
250
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
251
- <title>AI Content Moderator</title>
252
- <script src="https://cdn.tailwindcss.com"></script>
253
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
254
- <style>
255
- @keyframes float {
256
- 0% { transform: translateY(0px); }
257
- 50% { transform: translateY(-10px); }
258
- 100% { transform: translateY(0px); }
259
- }
260
- @keyframes pulse-border {
261
- 0% { box-shadow: 0 0 0 0 rgba(99, 102, 241, 0.7); }
262
- 70% { box-shadow: 0 0 0 10px rgba(99, 102, 241, 0); }
263
- 100% { box-shadow: 0 0 0 0 rgba(99, 102, 241, 0); }
264
- }
265
- .float-animation {
266
- animation: float 3s ease-in-out infinite;
267
- }
268
- .pulse-border {
269
- animation: pulse-border 2s infinite;
270
- }
271
- .gradient-bg {
272
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
273
- }
274
- .glass-effect {
275
- background: rgba(255, 255, 255, 0.1);
276
- backdrop-filter: blur(10px);
277
- border-radius: 10px;
278
- border: 1px solid rgba(255, 255, 255, 0.2);
279
- }
280
- .safe-gradient {
281
- background: linear-gradient(135deg, #84fab0 0%, #8fd3f4 100%);
282
- }
283
- .unsafe-gradient {
284
- background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
285
- }
286
- </style>
287
- </head>
288
- <body class="min-h-screen gradient-bg text-white">
289
- <div class="container mx-auto px-4 py-8">
290
- <header class="text-center mb-12">
291
- <div class="inline-block p-4 rounded-full glass-effect float-animation mb-6">
292
- <i class="fas fa-shield-alt text-5xl text-white"></i>
293
- </div>
294
- <h1 class="text-4xl md:text-5xl font-bold mb-4">Smart Moderator</h1>
295
- <p class="text-xl text-gray-200 max-w-2xl mx-auto">
296
- Advanced, multilingual and multimodal content moderation API
297
- </p>
298
- </header>
299
-
300
- <main class="max-w-6xl mx-auto">
301
- <div class="grid grid-cols-1 lg:grid-cols-3 gap-8 mb-12">
302
- <!-- API Key Section -->
303
- <div class="lg:col-span-1">
304
- <div class="glass-effect p-6 rounded-xl h-full">
305
- <h2 class="text-2xl font-bold mb-4 flex items-center">
306
- <i class="fas fa-key mr-2"></i> API Configuration
307
- </h2>
308
- <div class="mb-4">
309
- <label class="block text-sm font-medium mb-2">API Key</label>
310
- <div class="relative">
311
- <input type="password" id="apiKey" placeholder="Enter your API key"
312
- class="w-full px-4 py-3 rounded-lg bg-white/10 border border-white/20 focus:outline-none focus:ring-2 focus:ring-indigo-400 text-white">
313
- <button id="toggleApiKey" class="absolute right-3 top-3 text-gray-300 hover:text-white">
314
- <i class="fas fa-eye"></i>
315
- </button>
316
- </div>
317
- </div>
318
- <div class="mb-4">
319
- <label class="block text-sm font-medium mb-2">Model</label>
320
- <select id="modelSelect" class="w-full px-4 py-3 rounded-lg bg-white/10 border border-white/20 focus:outline-none focus:ring-2 focus:ring-indigo-400 text-white">
321
- <option value="text-moderation-detoxify-multilingual" selected>Detoxify Multilingual</option>
322
- </select>
323
- </div>
324
- <div class="mt-6">
325
- <h3 class="text-lg font-semibold mb-2">API Usage</h3>
326
- <div class="bg-black/20 p-4 rounded-lg text-sm font-mono">
327
- <div class="mb-2">POST /v1/moderations</div>
328
- <div class="mb-2">Site: https://nixaut-codelabs-smart-moderator.hf.space</div>
329
- <div class="text-xs text-gray-300">curl -X POST -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" -d '{"input":"text to moderate"}' /v1/moderations</div>
330
- </div>
331
- </div>
332
- </div>
333
- </div>
334
-
335
- <!-- Main Content Section -->
336
- <div class="lg:col-span-2">
337
- <div class="glass-effect p-6 rounded-xl">
338
- <h2 class="text-2xl font-bold mb-4 flex items-center">
339
- <i class="fas fa-check-circle mr-2"></i> Content Analysis
340
- </h2>
341
-
342
- <!-- Tabs -->
343
- <div class="flex border-b border-white/20 mb-6">
344
- <button id="singleTab" class="px-4 py-2 font-medium border-b-2 border-indigo-400 text-indigo-300 tab-active">
345
- Single Text
346
- </button>
347
- <button id="batchTab" class="px-4 py-2 font-medium border-b-2 border-transparent text-gray-300 hover:text-white">
348
- Batch Processing
349
- </button>
350
- </div>
351
-
352
- <!-- Single Text Tab -->
353
- <div id="singleContent" class="tab-content">
354
- <div class="mb-6">
355
- <label class="block text-sm font-medium mb-2">Text to Analyze</label>
356
- <textarea id="textInput" rows="6" placeholder="Enter any text in any language for content moderation analysis..."
357
- class="w-full px-4 py-3 rounded-lg bg-white/10 border border-white/20 focus:outline-none focus:ring-2 focus:ring-indigo-400 text-white resize-none"></textarea>
358
- </div>
359
-
360
-
361
- <div class="flex space-x-4">
362
- <button id="analyzeBtn" class="flex-1 bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-3 px-6 rounded-lg transition duration-300 transform hover:scale-105 pulse-border">
363
- <i class="fas fa-search mr-2"></i> Analyze Content
364
- </button>
365
- <button id="clearBtn" class="bg-gray-600 hover:bg-gray-700 text-white font-bold py-3 px-6 rounded-lg transition duration-300">
366
- <i class="fas fa-trash mr-2"></i> Clear
367
- </button>
368
- </div>
369
- </div>
370
-
371
- <!-- Batch Processing Tab -->
372
- <div id="batchContent" class="tab-content hidden">
373
- <div class="mb-6">
374
- <label class="block text-sm font-medium mb-2">Texts to Analyze (one per line)</label>
375
- <textarea id="batchTextInput" rows="8" placeholder="Enter multiple texts, one per line..."
376
- class="w-full px-4 py-3 rounded-lg bg-white/10 border border-white/20 focus:outline-none focus:ring-2 focus:ring-indigo-400 text-white resize-none"></textarea>
377
- </div>
378
-
379
- <div class="flex space-x-4">
380
- <button id="batchAnalyzeBtn" class="flex-1 bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-3 px-6 rounded-lg transition duration-300 transform hover:scale-105 pulse-border">
381
- <i class="fas fa-layer-group mr-2"></i> Analyze Batch
382
- </button>
383
- <button id="batchClearBtn" class="bg-gray-600 hover:bg-gray-700 text-white font-bold py-3 px-6 rounded-lg transition duration-300">
384
- <i class="fas fa-trash mr-2"></i> Clear
385
- </button>
386
- </div>
387
- </div>
388
-
389
- <!-- Results Section -->
390
- <div id="resultsSection" class="mt-8 hidden">
391
- <h3 class="text-xl font-bold mb-4 flex items-center">
392
- <i class="fas fa-chart-bar mr-2"></i> Analysis Results
393
- </h3>
394
- <div id="resultsContainer" class="space-y-4">
395
- <!-- Results will be dynamically inserted here -->
396
- </div>
397
- </div>
398
- </div>
399
- </div>
400
- </div>
401
-
402
- <!-- Examples Section -->
403
- <div class="glass-effect p-6 rounded-xl mb-12">
404
- <h2 class="text-2xl font-bold mb-4 flex items-center">
405
- <i class="fas fa-lightbulb mr-2"></i> Example Prompts
406
- </h2>
407
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
408
- <div class="example-card bg-white/10 p-4 rounded-lg cursor-pointer hover:bg-white/20 transition duration-300">
409
- <p class="text-sm">"Hello, how are you today? I hope you're having a wonderful time!"</p>
410
- </div>
411
- <div class="example-card bg-white/10 p-4 rounded-lg cursor-pointer hover:bg-white/20 transition duration-300">
412
- <p class="text-sm">"I hate you and I will find you and hurt you badly."</p>
413
- </div>
414
- <div class="example-card bg-white/10 p-4 rounded-lg cursor-pointer hover:bg-white/20 transition duration-300">
415
- <p class="text-sm">"C'est une belle journée pour apprendre la programmation et l'intelligence artificielle."</p>
416
- </div>
417
- <div class="example-card bg-white/10 p-4 rounded-lg cursor-pointer hover:bg-white/20 transition duration-300">
418
- <p class="text-sm">"I can't take this anymore. I want to end everything and disappear forever."</p>
419
- </div>
420
- <div class="example-card bg-white/10 p-4 rounded-lg cursor-pointer hover:bg-white/20 transition duration-300">
421
- <p class="text-sm">"¡Hola! Me encanta aprender nuevos idiomas y conocer diferentes culturas."</p>
422
- </div>
423
- <div class="example-card bg-white/10 p-4 rounded-lg cursor-pointer hover:bg-white/20 transition duration-300">
424
- <p class="text-sm">"You're absolutely worthless and nobody will ever love someone like you."</p>
425
- </div>
426
- </div>
427
- </div>
428
-
429
- <!-- Information Section -->
430
- <div class="glass-effect p-6 rounded-xl">
431
- <h2 class="text-2xl font-bold mb-4 flex items-center">
432
- <i class="fas fa-info-circle mr-2"></i> About This Tool
433
- </h2>
434
- <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
435
- <div class="text-center">
436
- <div class="inline-block p-3 rounded-full bg-indigo-500/20 mb-3">
437
- <i class="fas fa-globe text-2xl text-indigo-300"></i>
438
- </div>
439
- <h3 class="text-lg font-semibold mb-2">Multilingual</h3>
440
- <p class="text-gray-300">Supports content analysis in multiple languages with high accuracy.</p>
441
- </div>
442
- <div class="text-center">
443
- <div class="inline-block p-3 rounded-full bg-indigo-500/20 mb-3">
444
- <i class="fas fa-bolt text-2xl text-indigo-300"></i>
445
- </div>
446
- <h3 class="text-lg font-semibold mb-2">Fast Processing</h3>
447
- <p class="text-gray-300">Optimized model for quick content analysis with real-time results.</p>
448
- </div>
449
- <div class="text-center">
450
- <div class="inline-block p-3 rounded-full bg-indigo-500/20 mb-3">
451
- <i class="fas fa-shield-alt text-2xl text-indigo-300"></i>
452
- </div>
453
- <h3 class="text-lg font-semibold mb-2">Secure</h3>
454
- <p class="text-gray-300">API key authentication ensures your requests remain secure and private.</p>
455
- </div>
456
- </div>
457
- </div>
458
- </main>
459
-
460
- <footer class="mt-12 text-center text-gray-300">
461
- <p>© 2025 Smart Moderator. All rights reserved.</p>
462
- </footer>
463
- </div>
464
-
465
- <!-- Loading Modal -->
466
- <div id="loadingModal" class="fixed inset-0 bg-black/70 flex items-center justify-center z-50 hidden">
467
- <div class="glass-effect p-8 rounded-xl max-w-md w-full mx-4 text-center">
468
- <div class="mb-4">
469
- <div class="inline-block animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-indigo-500"></div>
470
- </div>
471
- <h3 class="text-xl font-bold mb-2">Analyzing Content</h3>
472
- <p class="text-gray-300">Please wait while we process your request...</p>
473
- </div>
474
- </div>
475
-
476
- <script>
477
- // DOM Elements
478
- const singleTab = document.getElementById('singleTab');
479
- const batchTab = document.getElementById('batchTab');
480
- const singleContent = document.getElementById('singleContent');
481
- const batchContent = document.getElementById('batchContent');
482
- const apiKeyInput = document.getElementById('apiKey');
483
- const toggleApiKeyBtn = document.getElementById('toggleApiKey');
484
- const textInput = document.getElementById('textInput');
485
- const batchTextInput = document.getElementById('batchTextInput');
486
- const analyzeBtn = document.getElementById('analyzeBtn');
487
- const batchAnalyzeBtn = document.getElementById('batchAnalyzeBtn');
488
- const clearBtn = document.getElementById('clearBtn');
489
- const batchClearBtn = document.getElementById('batchClearBtn');
490
- const resultsSection = document.getElementById('resultsSection');
491
- const resultsContainer = document.getElementById('resultsContainer');
492
- const loadingModal = document.getElementById('loadingModal');
493
- const exampleCards = document.querySelectorAll('.example-card');
494
-
495
- // Tab switching
496
- singleTab.addEventListener('click', () => {
497
- singleTab.classList.add('border-indigo-400', 'text-indigo-300');
498
- singleTab.classList.remove('border-transparent', 'text-gray-300');
499
- batchTab.classList.add('border-transparent', 'text-gray-300');
500
- batchTab.classList.remove('border-indigo-400', 'text-indigo-300');
501
- singleContent.classList.remove('hidden');
502
- batchContent.classList.add('hidden');
503
- });
504
-
505
- batchTab.addEventListener('click', () => {
506
- batchTab.classList.add('border-indigo-400', 'text-indigo-300');
507
- batchTab.classList.remove('border-transparent', 'text-gray-300');
508
- singleTab.classList.add('border-transparent', 'text-gray-300');
509
- singleTab.classList.remove('border-indigo-400', 'text-indigo-300');
510
- batchContent.classList.remove('hidden');
511
- singleContent.classList.add('hidden');
512
- });
513
-
514
- // Toggle API key visibility
515
- toggleApiKeyBtn.addEventListener('click', () => {
516
- const type = apiKeyInput.getAttribute('type') === 'password' ? 'text' : 'password';
517
- apiKeyInput.setAttribute('type', type);
518
- toggleApiKeyBtn.innerHTML = type === 'password' ? '<i class="fas fa-eye"></i>' : '<i class="fas fa-eye-slash"></i>';
519
- });
520
-
521
- // Slider value updates
522
- maxTokensSlider.addEventListener('input', () => {
523
- maxTokensValue.textContent = maxTokensSlider.value;
524
- });
525
-
526
- temperatureSlider.addEventListener('input', () => {
527
- temperatureValue.textContent = temperatureSlider.value;
528
- });
529
-
530
- topPSlider.addEventListener('input', () => {
531
- topPValue.textContent = topPSlider.value;
532
- });
533
-
534
- // Example cards
535
- exampleCards.forEach(card => {
536
- card.addEventListener('click', () => {
537
- textInput.value = card.querySelector('p').textContent;
538
- });
539
- });
540
-
541
- // Clear buttons
542
- clearBtn.addEventListener('click', () => {
543
- textInput.value = '';
544
- resultsSection.classList.add('hidden');
545
- });
546
-
547
- batchClearBtn.addEventListener('click', () => {
548
- batchTextInput.value = '';
549
- resultsSection.classList.add('hidden');
550
- });
551
-
552
- // Analyze button
553
- analyzeBtn.addEventListener('click', async () => {
554
- const text = textInput.value.trim();
555
- if (!text) {
556
- showNotification('Please enter text to analyze', 'error');
557
- return;
558
- }
559
-
560
- const apiKey = apiKeyInput.value.trim();
561
- if (!apiKey) {
562
- showNotification('Please enter your API key', 'error');
563
- return;
564
- }
565
-
566
- showLoading(true);
567
-
568
- try {
569
- const response = await fetch('/v1/moderations', {
570
- method: 'POST',
571
- headers: {
572
- 'Content-Type': 'application/json',
573
- 'Authorization': `Bearer ${apiKey}`
574
- },
575
- body: JSON.stringify({
576
- input: text,
577
- model: document.getElementById('modelSelect').value
578
- })
579
- });
580
-
581
- if (!response.ok) {
582
- const errorData = await response.json();
583
- throw new Error(errorData.detail || 'An error occurred');
584
- }
585
-
586
- const data = await response.json();
587
- displayResults([data.results[0]]);
588
- } catch (error) {
589
- showNotification(`Error: ${error.message}`, 'error');
590
- } finally {
591
- showLoading(false);
592
- }
593
- });
594
-
595
- // Batch analyze button
596
- batchAnalyzeBtn.addEventListener('click', async () => {
597
- const texts = batchTextInput.value.trim().split('\\n').filter(text => text.trim());
598
- if (texts.length === 0) {
599
- showNotification('Please enter at least one text to analyze', 'error');
600
- return;
601
- }
602
-
603
- const apiKey = apiKeyInput.value.trim();
604
- if (!apiKey) {
605
- showNotification('Please enter your API key', 'error');
606
- return;
607
- }
608
-
609
- showLoading(true);
610
-
611
- try {
612
- const response = await fetch('/v1/moderations', {
613
- method: 'POST',
614
- headers: {
615
- 'Content-Type': 'application/json',
616
- 'Authorization': `Bearer ${apiKey}`
617
- },
618
- body: JSON.stringify({
619
- input: texts,
620
- model: document.getElementById('modelSelect').value
621
- })
622
- });
623
-
624
- if (!response.ok) {
625
- const errorData = await response.json();
626
- throw new Error(errorData.detail || 'An error occurred');
627
- }
628
-
629
- const data = await response.json();
630
- displayResults(data.results);
631
- } catch (error) {
632
- showNotification(`Error: ${error.message}`, 'error');
633
- } finally {
634
- showLoading(false);
635
- }
636
- });
637
-
638
- // Display results
639
- function displayResults(results) {
640
- resultsContainer.innerHTML = '';
641
-
642
- results.forEach((result, index) => {
643
- const isFlagged = result.flagged;
644
- const cardClass = isFlagged ? 'unsafe-gradient' : 'safe-gradient';
645
- const icon = isFlagged ? 'fas fa-exclamation-triangle' : 'fas fa-check-circle';
646
- const statusText = isFlagged ? 'UNSAFE' : 'SAFE';
647
- const statusDesc = isFlagged ?
648
- 'Content may contain inappropriate or harmful material.' :
649
- 'Content appears to be safe and appropriate.';
650
-
651
- const categories = Object.entries(result.categories)
652
- .filter(([_, value]) => value)
653
- .map(([key, _]) => key.replace('/', ' '))
654
- .join(', ');
655
-
656
- const resultCard = document.createElement('div');
657
- resultCard.className = `p-6 rounded-xl text-white ${cardClass} shadow-lg`;
658
- resultCard.innerHTML = `
659
- <div class="flex items-start">
660
- <div class="mr-4 mt-1">
661
- <i class="${icon} text-3xl"></i>
662
- </div>
663
- <div class="flex-1">
664
- <div class="flex justify-between items-start mb-2">
665
- <h3 class="text-xl font-bold">${statusText}</h3>
666
- <span class="text-sm bg-black/20 px-2 py-1 rounded">Result ${index + 1}</span>
667
- </div>
668
- <p class="mb-4">${statusDesc}</p>
669
- <div class="bg-black/20 p-4 rounded-lg mb-4">
670
- <p class="text-sm font-mono break-words">${result.text}</p>
671
- </div>
672
- ${isFlagged ? `
673
- <div class="mb-3">
674
- <h4 class="font-semibold mb-1">Flagged Categories:</h4>
675
- <p class="text-sm">${categories}</p>
676
- </div>
677
- ` : ''}
678
- <div class="grid grid-cols-2 md:grid-cols-4 gap-2 text-xs">
679
- ${Object.entries(result.category_scores).map(([category, score]) => `
680
- <div class="bg-black/20 p-2 rounded">
681
- <div class="font-medium">${category.replace('/', ' ')}</div>
682
- <div class="w-full bg-gray-700 rounded-full h-1.5 mt-1">
683
- <div class="bg-white h-1.5 rounded-full" style="width: ${score * 100}%"></div>
684
- </div>
685
- <div class="text-right mt-1">${(score * 100).toFixed(0)}%</div>
686
- </div>
687
- `).join('')}
688
- </div>
689
- </div>
690
- </div>
691
- `;
692
-
693
- resultsContainer.appendChild(resultCard);
694
- });
695
-
696
- resultsSection.classList.remove('hidden');
697
- resultsSection.scrollIntoView({ behavior: 'smooth' });
698
- }
699
-
700
- // Show/hide loading modal
701
- function showLoading(show) {
702
- if (show) {
703
- loadingModal.classList.remove('hidden');
704
- } else {
705
- loadingModal.classList.add('hidden');
706
- }
707
- }
708
-
709
- // Show notification
710
- function showNotification(message, type = 'info') {
711
- const notification = document.createElement('div');
712
- notification.className = `fixed top-4 right-4 p-4 rounded-lg shadow-lg z-50 ${
713
- type === 'error' ? 'bg-red-500' : 'bg-indigo-500'
714
- } text-white`;
715
- notification.innerHTML = `
716
- <div class="flex items-center">
717
- <i class="fas ${type === 'error' ? 'fa-exclamation-circle' : 'fa-info-circle'} mr-2"></i>
718
- <span>${message}</span>
719
- </div>
720
- `;
721
-
722
- document.body.appendChild(notification);
723
-
724
- setTimeout(() => {
725
- notification.style.opacity = '0';
726
- notification.style.transition = 'opacity 0.5s';
727
- setTimeout(() => {
728
- document.body.removeChild(notification);
729
- }, 500);
730
- }, 3000);
731
- }
732
- </script>
733
- </body>
734
- </html>
735
- """)
736
 
737
  def create_directories_and_files():
738
  os.makedirs('templates', exist_ok=True)
 
240
 
241
  return jsonify(get_performance_metrics())
242
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
 
244
  def create_directories_and_files():
245
  os.makedirs('templates', exist_ok=True)