Docfile commited on
Commit
5242158
·
verified ·
1 Parent(s): c6c3547

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +123 -496
app.py CHANGED
@@ -1,536 +1,163 @@
1
- from flask import Flask, render_template, request, jsonify, redirect, url_for
2
  import requests
3
  from bs4 import BeautifulSoup
4
  import random
5
  import string
6
  import json
7
  import threading
8
- import os
9
- import time
10
- from datetime import datetime
11
 
12
  app = Flask(__name__)
13
 
14
- # Configuration globale
15
- config = {
16
- 'base_url': "https://ivoire-startup-tracker-edithbrou.replit.app",
17
- 'accounts_file': "accounts_data.json",
18
- 'is_running': False,
19
- 'progress': {
20
- 'total': 0,
21
- 'current': 0,
22
- 'success': 0,
23
- 'failed': 0,
24
- 'last_username': '',
25
- 'last_status': '',
26
- 'start_time': None,
27
- 'end_time': None
28
- }
29
  }
30
 
31
- # Fonction pour générer un nom d'utilisateur aléatoire (min 80 caractères)
32
- def generate_random_username(min_length=80, max_length=100):
33
- """Génère un nom d'utilisateur aléatoire d'au moins 80 caractères"""
34
- length = random.randint(min_length, max_length)
35
  return ''.join(random.choice(string.ascii_lowercase) for _ in range(length))
36
 
37
- # Fonction pour générer une adresse email aléatoire
38
  def generate_random_email():
39
- """Génère une adresse email aléatoire"""
40
- username = ''.join(random.choice(string.ascii_lowercase) for _ in range(12))
41
  domains = ["gmail.com", "yahoo.com", "outlook.com", "example.com"]
42
  return f"{username}@{random.choice(domains)}"
43
 
44
- # Fonction pour générer un mot de passe aléatoire
45
- def generate_random_password(length=12):
46
- """Génère un mot de passe aléatoire"""
47
- chars = string.ascii_letters + string.digits + "!@#$%^&*"
48
  return ''.join(random.choice(chars) for _ in range(length))
49
 
50
- # Fonction pour créer un compte
 
 
 
51
  def create_account(is_startup_rep=False):
52
- """Crée un compte sur le site web"""
53
- register_url = f"{config['base_url']}/register"
54
-
55
- # Première requête pour récupérer le token CSRF
56
  session = requests.Session()
57
- try:
58
- response = session.get(register_url)
59
-
60
- if response.status_code != 200:
61
- return {'success': False, 'error': f"Erreur lors de l'accès à la page: {response.status_code}"}
62
-
63
- # Extraire le token CSRF
64
- soup = BeautifulSoup(response.text, 'html.parser')
65
- csrf_token = soup.find('input', {'id': 'csrf_token'}).get('value')
66
-
67
- if not csrf_token:
68
- return {'success': False, 'error': "Impossible de trouver le token CSRF"}
69
-
70
- # Générer des informations de compte aléatoires
71
- username = generate_random_username()
72
- email = generate_random_email()
73
- password = generate_random_password()
74
-
75
- # Préparer les données du formulaire
76
- form_data = {
77
- 'csrf_token': csrf_token,
78
- 'username': username,
79
- 'email': email,
80
- 'password': password,
81
- 'confirm_password': password,
82
- 'submit': 'Register'
83
- }
84
-
85
- # Ajouter l'option startup rep si nécessaire
86
- if is_startup_rep:
87
- form_data['is_startup_rep'] = 'y'
88
-
89
- # Envoyer le formulaire
90
- headers = {
91
- 'Referer': register_url,
92
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
93
- }
94
-
95
- response = session.post(register_url, data=form_data, headers=headers)
96
-
97
- result = {
98
- 'success': response.status_code == 200 or response.status_code == 302,
99
  'username': username,
100
  'email': email,
101
  'password': password,
102
- 'is_startup_rep': is_startup_rep,
103
- 'created_at': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
104
- 'status_code': response.status_code
105
  }
106
-
107
- return result
108
-
109
- except Exception as e:
110
- return {'success': False, 'error': str(e)}
111
 
112
- # Fonction pour créer plusieurs comptes en arrière-plan
113
- def create_accounts_background(num_accounts, startup_ratio=0.3):
114
- config['progress'] = {
115
- 'total': num_accounts,
116
- 'current': 0,
117
- 'success': 0,
118
- 'failed': 0,
119
- 'last_username': '',
120
- 'last_status': 'Démarrage...',
121
- 'start_time': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
122
- 'end_time': None
123
- }
124
-
125
- # Charger les comptes existants
126
- accounts = []
127
- if os.path.exists(config['accounts_file']):
128
- try:
129
- with open(config['accounts_file'], 'r') as f:
130
- accounts = json.load(f)
131
- except:
132
- accounts = []
133
 
134
  for i in range(num_accounts):
135
- if not config['is_running']:
136
- break
137
-
138
  is_startup = random.random() < startup_ratio
139
-
140
- config['progress']['current'] = i + 1
141
- config['progress']['last_status'] = f"Création du compte {i+1}/{num_accounts}..."
142
-
143
- result = create_account(is_startup_rep=is_startup)
144
-
145
- if result.get('success', False):
146
- config['progress']['success'] += 1
147
- config['progress']['last_username'] = result['username']
148
- config['progress']['last_status'] = f"Compte {i+1} créé avec succès"
149
- accounts.append(result)
150
- else:
151
- config['progress']['failed'] += 1
152
- config['progress']['last_status'] = f"Échec de la création du compte {i+1}: {result.get('error', 'Erreur inconnue')}"
153
-
154
- # Enregistrer les données régulièrement
155
- with open(config['accounts_file'], 'w') as f:
156
- json.dump(accounts, f, indent=2)
157
-
158
- # Petite pause pour éviter de surcharger le serveur
159
- time.sleep(1)
160
-
161
- config['is_running'] = False
162
- config['progress']['end_time'] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
163
- config['progress']['last_status'] = "Terminé"
164
-
165
- # Enregistrement final
166
- with open(config['accounts_file'], 'w') as f:
167
- json.dump(accounts, f, indent=2)
168
 
169
  # Routes Flask
170
- @app.route('/')
 
171
  def index():
172
- return render_template('index.html', config=config)
 
 
 
 
 
 
 
 
 
 
 
173
 
174
- @app.route('/start', methods=['POST'])
175
  def start():
176
- if config['is_running']:
177
- return jsonify({"status": "error", "message": "Une génération est déjà en cours"})
178
-
179
- num_accounts = int(request.form.get('num_accounts', 10))
180
- startup_ratio = float(request.form.get('startup_ratio', 0.3))
181
-
182
- config['is_running'] = True
 
183
 
184
- # Démarrer le processus en arrière-plan
185
- thread = threading.Thread(target=create_accounts_background, args=(num_accounts, startup_ratio))
186
- thread.daemon = True
187
  thread.start()
188
 
189
- return jsonify({"status": "success", "message": "Génération démarrée"})
190
-
191
- @app.route('/stop', methods=['POST'])
192
- def stop():
193
- config['is_running'] = False
194
- return jsonify({"status": "success", "message": "Arrêt demandé"})
195
 
196
- @app.route('/progress')
197
  def progress():
198
- return jsonify(config['progress'])
199
-
200
- @app.route('/accounts')
201
- def view_accounts():
202
- page = int(request.args.get('page', 1))
203
- per_page = 20
204
-
205
- accounts = []
206
- if os.path.exists(config['accounts_file']):
207
- try:
208
- with open(config['accounts_file'], 'r') as f:
209
- accounts = json.load(f)
210
- except:
211
- accounts = []
212
-
213
- total_accounts = len(accounts)
214
- total_pages = (total_accounts + per_page - 1) // per_page
215
-
216
- start_idx = (page - 1) * per_page
217
- end_idx = start_idx + per_page
218
-
219
- current_accounts = accounts[start_idx:end_idx]
220
-
221
- return render_template(
222
- 'accounts.html',
223
- accounts=current_accounts,
224
- page=page,
225
- total_pages=total_pages,
226
- total_accounts=total_accounts
227
- )
228
 
229
- if __name__ == '__main__':
230
- # Créer le dossier templates s'il n'existe pas
231
- if not os.path.exists('templates'):
232
- os.makedirs('templates')
233
-
234
- # Créer les templates HTML
235
- with open('templates/index.html', 'w') as f:
236
- f.write('''
237
- <!DOCTYPE html>
238
- <html lang="fr">
239
- <head>
240
- <meta charset="UTF-8">
241
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
242
- <title>Générateur de comptes automatique</title>
243
- <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
244
- <style>
245
- body { background-color: #f5f5f5; }
246
- .card { box-shadow: 0 4px 8px rgba(0,0,0,0.1); }
247
- .progress { height: 25px; }
248
- #status-display { height: 200px; overflow-y: auto; }
249
- </style>
250
- </head>
251
- <body>
252
- <div class="container mt-5">
253
- <div class="row">
254
- <div class="col-md-12 mb-4">
255
- <div class="card">
256
- <div class="card-header bg-primary text-white">
257
- <h3 class="card-title mb-0">Générateur de comptes - Startup Côte d'Ivoire</h3>
258
- </div>
259
- <div class="card-body">
260
- <form id="generator-form">
261
- <div class="row mb-3">
262
- <div class="col-md-6">
263
- <label for="num_accounts" class="form-label">Nombre de comptes à créer</label>
264
- <input type="number" class="form-control" id="num_accounts" name="num_accounts" min="1" max="1000" value="10">
265
- </div>
266
- <div class="col-md-6">
267
- <label for="startup_ratio" class="form-label">Ratio de représentants de startup (%)</label>
268
- <input type="number" class="form-control" id="startup_ratio" name="startup_ratio" min="0" max="100" value="30">
269
- </div>
270
- </div>
271
- <div class="d-grid gap-2 d-md-flex justify-content-md-center">
272
- <button type="submit" id="start-btn" class="btn btn-success btn-lg">
273
- <i class="fas fa-play"></i> Démarrer
274
- </button>
275
- <button type="button" id="stop-btn" class="btn btn-danger btn-lg">
276
- <i class="fas fa-stop"></i> Arrêter
277
- </button>
278
- <a href="/accounts" class="btn btn-primary btn-lg">
279
- <i class="fas fa-list"></i> Voir les comptes
280
- </a>
281
- </div>
282
- </form>
283
- </div>
284
- </div>
285
- </div>
286
-
287
- <div class="col-md-12">
288
- <div class="card">
289
- <div class="card-header bg-info text-white">
290
- <h4 class="card-title mb-0">Progression</h4>
291
- </div>
292
- <div class="card-body">
293
- <div class="progress mb-3">
294
- <div id="progress-bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 0%">0%</div>
295
- </div>
296
-
297
- <div class="row text-center mb-3">
298
- <div class="col">
299
- <div class="card bg-light">
300
- <div class="card-body">
301
- <h5>Total</h5>
302
- <h3 id="total-count">0</h3>
303
- </div>
304
- </div>
305
- </div>
306
- <div class="col">
307
- <div class="card bg-success text-white">
308
- <div class="card-body">
309
- <h5>Réussis</h5>
310
- <h3 id="success-count">0</h3>
311
- </div>
312
- </div>
313
- </div>
314
- <div class="col">
315
- <div class="card bg-danger text-white">
316
- <div class="card-body">
317
- <h5>Échecs</h5>
318
- <h3 id="failed-count">0</h3>
319
- </div>
320
- </div>
321
- </div>
322
- </div>
323
-
324
- <div class="card mb-3">
325
- <div class="card-header">
326
- <h5>Dernier statut</h5>
327
- </div>
328
- <div class="card-body">
329
- <p id="last-status">-</p>
330
- <p>Dernier compte créé: <span id="last-username" class="text-primary fw-bold">-</span></p>
331
- </div>
332
- </div>
333
-
334
- <div class="row">
335
- <div class="col-md-6">
336
- <p>Heure de début: <span id="start-time">-</span></p>
337
- </div>
338
- <div class="col-md-6 text-end">
339
- <p>Heure de fin: <span id="end-time">-</span></p>
340
- </div>
341
- </div>
342
- </div>
343
- </div>
344
- </div>
345
- </div>
346
- </div>
347
-
348
- <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
349
- <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"></script>
350
- <script>
351
- document.addEventListener('DOMContentLoaded', function() {
352
- // Formulaire de génération
353
- document.getElementById('generator-form').addEventListener('submit', function(e) {
354
- e.preventDefault();
355
-
356
- const numAccounts = document.getElementById('num_accounts').value;
357
- const startupRatio = document.getElementById('startup_ratio').value / 100;
358
-
359
- fetch('/start', {
360
- method: 'POST',
361
- headers: {
362
- 'Content-Type': 'application/x-www-form-urlencoded',
363
- },
364
- body: `num_accounts=${numAccounts}&startup_ratio=${startupRatio}`
365
- })
366
- .then(response => response.json())
367
- .then(data => {
368
- if (data.status === 'success') {
369
- startProgressUpdates();
370
- } else {
371
- alert(data.message);
372
- }
373
- });
374
- });
375
-
376
- // Bouton d'arrêt
377
- document.getElementById('stop-btn').addEventListener('click', function() {
378
- fetch('/stop', {
379
- method: 'POST'
380
- })
381
- .then(response => response.json())
382
- .then(data => {
383
- alert(data.message);
384
- });
385
- });
386
-
387
- // Mettre à jour la progression
388
- function updateProgress() {
389
- fetch('/progress')
390
- .then(response => response.json())
391
- .then(data => {
392
- const progressPercent = data.total > 0 ? Math.round((data.current / data.total) * 100) : 0;
393
-
394
- document.getElementById('progress-bar').style.width = `${progressPercent}%`;
395
- document.getElementById('progress-bar').textContent = `${progressPercent}%`;
396
-
397
- document.getElementById('total-count').textContent = data.total;
398
- document.getElementById('success-count').textContent = data.success;
399
- document.getElementById('failed-count').textContent = data.failed;
400
-
401
- document.getElementById('last-status').textContent = data.last_status;
402
- document.getElementById('last-username').textContent = data.last_username || '-';
403
-
404
- document.getElementById('start-time').textContent = data.start_time || '-';
405
- document.getElementById('end-time').textContent = data.end_time || '-';
406
- });
407
- }
408
-
409
- let progressInterval;
410
-
411
- function startProgressUpdates() {
412
- // Arrêter l'intervalle précédent s'il existe
413
- if (progressInterval) {
414
- clearInterval(progressInterval);
415
- }
416
-
417
- // Mettre à jour immédiatement
418
- updateProgress();
419
-
420
- // Puis toutes les 2 secondes
421
- progressInterval = setInterval(updateProgress, 2000);
422
- }
423
-
424
- // Vérifier si une génération est déjà en cours au chargement de la page
425
- updateProgress();
426
- });
427
- </script>
428
- </body>
429
- </html>
430
- ''')
431
-
432
- with open('templates/accounts.html', 'w') as f:
433
- f.write('''
434
- <!DOCTYPE html>
435
- <html lang="fr">
436
- <head>
437
- <meta charset="UTF-8">
438
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
439
- <title>Liste des comptes générés</title>
440
- <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
441
- <style>
442
- body { background-color: #f5f5f5; }
443
- .card { box-shadow: 0 4px 8px rgba(0,0,0,0.1); }
444
- .username-cell {
445
- max-width: 200px;
446
- overflow: hidden;
447
- text-overflow: ellipsis;
448
- white-space: nowrap;
449
- }
450
- .pagination { margin-bottom: 0; }
451
- </style>
452
- </head>
453
- <body>
454
- <div class="container mt-5">
455
- <div class="row">
456
- <div class="col-md-12 mb-4">
457
- <div class="card">
458
- <div class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
459
- <h3 class="mb-0">Liste des comptes générés</h3>
460
- <a href="/" class="btn btn-light">Retour au générateur</a>
461
- </div>
462
- <div class="card-body">
463
- <div class="alert alert-info">
464
- Total des comptes générés: {{ total_accounts }}
465
- </div>
466
-
467
- <div class="table-responsive">
468
- <table class="table table-striped table-hover">
469
- <thead>
470
- <tr>
471
- <th>#</th>
472
- <th>Nom d'utilisateur</th>
473
- <th>Email</th>
474
- <th>Mot de passe</th>
475
- <th>Startup Rep</th>
476
- <th>Date de création</th>
477
- <th>Statut</th>
478
- </tr>
479
- </thead>
480
- <tbody>
481
- {% for account in accounts %}
482
- <tr>
483
- <td>{{ (page - 1) * 20 + loop.index }}</td>
484
- <td class="username-cell" title="{{ account.username }}">{{ account.username }}</td>
485
- <td>{{ account.email }}</td>
486
- <td>{{ account.password }}</td>
487
- <td>{% if account.is_startup_rep %}Oui{% else %}Non{% endif %}</td>
488
- <td>{{ account.created_at }}</td>
489
- <td>
490
- {% if account.success %}
491
- <span class="badge bg-success">Succès</span>
492
- {% else %}
493
- <span class="badge bg-danger">Échec</span>
494
- {% endif %}
495
- </td>
496
- </tr>
497
- {% endfor %}
498
- </tbody>
499
- </table>
500
- </div>
501
-
502
- {% if total_pages > 1 %}
503
- <div class="d-flex justify-content-center mt-4">
504
- <nav aria-label="Page navigation">
505
- <ul class="pagination">
506
- <li class="page-item {% if page == 1 %}disabled{% endif %}">
507
- <a class="page-link" href="{{ url_for('view_accounts', page=page-1) if page > 1 else '#' }}">Précédent</a>
508
- </li>
509
-
510
- {% for p in range(1, total_pages + 1) %}
511
- {% if p == page %}
512
- <li class="page-item active"><span class="page-link">{{ p }}</span></li>
513
- {% else %}
514
- <li class="page-item"><a class="page-link" href="{{ url_for('view_accounts', page=p) }}">{{ p }}</a></li>
515
- {% endif %}
516
- {% endfor %}
517
-
518
- <li class="page-item {% if page == total_pages %}disabled{% endif %}">
519
- <a class="page-link" href="{{ url_for('view_accounts', page=page+1) if page < total_pages else '#' }}">Suivant</a>
520
- </li>
521
- </ul>
522
- </nav>
523
- </div>
524
- {% endif %}
525
- </div>
526
- </div>
527
- </div>
528
- </div>
529
- </div>
530
-
531
- <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
532
- </body>
533
- </html>
534
- ''')
535
-
536
- app.run(debug=True)
 
1
+ from flask import Flask, request, jsonify, redirect, url_for
2
  import requests
3
  from bs4 import BeautifulSoup
4
  import random
5
  import string
6
  import json
7
  import threading
 
 
 
8
 
9
  app = Flask(__name__)
10
 
11
+ # Fichier JSON pour sauvegarder la progression
12
+ JSON_FILE = "accounts.json"
13
+
14
+ # Variable globale pour suivre la progression
15
+ progress_data = {
16
+ "accounts": [],
17
+ "total": 0,
18
+ "created": 0,
19
+ "in_progress": False
 
 
 
 
 
 
20
  }
21
 
22
+ # Fonctions de génération aléatoire
23
+
24
+ def generate_random_username(length=80):
25
+ """Génère un nom d'utilisateur aléatoire avec une chaîne continue d'au moins 80 caractères."""
26
  return ''.join(random.choice(string.ascii_lowercase) for _ in range(length))
27
 
 
28
  def generate_random_email():
29
+ """Génère une adresse email aléatoire avec un nom court."""
30
+ username = ''.join(random.choice(string.ascii_lowercase) for _ in range(8))
31
  domains = ["gmail.com", "yahoo.com", "outlook.com", "example.com"]
32
  return f"{username}@{random.choice(domains)}"
33
 
34
+ def generate_random_password(length=10):
35
+ """Génère un mot de passe aléatoire."""
36
+ chars = string.ascii_letters + string.digits + string.punctuation
 
37
  return ''.join(random.choice(chars) for _ in range(length))
38
 
39
+ # URL du site à enregistrer
40
+ BASE_URL = "https://ivoire-startup-tracker-edithbrou.replit.app"
41
+ REGISTER_URL = f"{BASE_URL}/register"
42
+
43
  def create_account(is_startup_rep=False):
44
+ """Crée un compte sur le site et renvoie les informations du compte en cas de succès."""
 
 
 
45
  session = requests.Session()
46
+ response = session.get(REGISTER_URL)
47
+
48
+ if response.status_code != 200:
49
+ print(f"Erreur lors de l'accès à la page d'inscription: {response.status_code}")
50
+ return False
51
+
52
+ soup = BeautifulSoup(response.text, 'html.parser')
53
+ csrf_input = soup.find('input', {'id': 'csrf_token'})
54
+ if not csrf_input:
55
+ print("Impossible de trouver le token CSRF")
56
+ return False
57
+ csrf_token = csrf_input.get('value')
58
+
59
+ # Utilisation d'un nom d'utilisateur d'au moins 80 caractères
60
+ username = generate_random_username(80)
61
+ email = generate_random_email()
62
+ password = generate_random_password()
63
+
64
+ form_data = {
65
+ 'csrf_token': csrf_token,
66
+ 'username': username,
67
+ 'email': email,
68
+ 'password': password,
69
+ 'confirm_password': password,
70
+ 'submit': 'Register'
71
+ }
72
+ if is_startup_rep:
73
+ form_data['is_startup_rep'] = 'y'
74
+
75
+ headers = {
76
+ 'Referer': REGISTER_URL,
77
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
78
+ }
79
+
80
+ response = session.post(REGISTER_URL, data=form_data, headers=headers)
81
+ if response.status_code in [200, 302]:
82
+ print(f"Compte créé avec succès: {username}")
83
+ account = {
 
 
 
 
84
  'username': username,
85
  'email': email,
86
  'password': password,
87
+ 'is_startup_rep': is_startup_rep
 
 
88
  }
89
+ return account
90
+ else:
91
+ print(f"Échec de la création du compte: {response.status_code}")
92
+ return False
 
93
 
94
+ def create_multiple_accounts(num_accounts, startup_ratio=0.3):
95
+ """Crée plusieurs comptes en tâche de fond et met à jour le fichier JSON de progression."""
96
+ global progress_data
97
+ progress_data["in_progress"] = True
98
+ progress_data["total"] = num_accounts
99
+ progress_data["created"] = 0
100
+ progress_data["accounts"] = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
 
102
  for i in range(num_accounts):
 
 
 
103
  is_startup = random.random() < startup_ratio
104
+ print(f"\nCréation du compte {i+1}/{num_accounts}...")
105
+ account = create_account(is_startup_rep=is_startup)
106
+ if account:
107
+ progress_data["accounts"].append(account)
108
+ progress_data["created"] += 1
109
+ # Écriture dans le fichier JSON après chaque création
110
+ with open(JSON_FILE, "w") as f:
111
+ json.dump(progress_data, f, indent=2)
112
+
113
+ progress_data["in_progress"] = False
114
+ # Mise à jour finale du fichier JSON
115
+ with open(JSON_FILE, "w") as f:
116
+ json.dump(progress_data, f, indent=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
 
118
  # Routes Flask
119
+
120
+ @app.route("/")
121
  def index():
122
+ return '''
123
+ <h1>Gestion de création de comptes</h1>
124
+ <form action="/start" method="post">
125
+ <label for="num">Nombre de comptes à créer:</label>
126
+ <input type="number" id="num" name="num" value="5" min="1"><br><br>
127
+ <label for="startup_ratio">Ratio de représentants startup (0-1):</label>
128
+ <input type="text" id="startup_ratio" name="startup_ratio" value="0.3"><br><br>
129
+ <button type="submit">Start</button>
130
+ </form>
131
+ <br>
132
+ <a href="/progress">Voir la progression</a>
133
+ '''
134
 
135
+ @app.route("/start", methods=["POST"])
136
  def start():
137
+ try:
138
+ num = int(request.form.get("num", 5))
139
+ except ValueError:
140
+ num = 5
141
+ try:
142
+ startup_ratio = float(request.form.get("startup_ratio", 0.3))
143
+ except ValueError:
144
+ startup_ratio = 0.3
145
 
146
+ # Démarrer la création en tâche de fond
147
+ thread = threading.Thread(target=create_multiple_accounts, args=(num, startup_ratio))
 
148
  thread.start()
149
 
150
+ return redirect(url_for("index"))
 
 
 
 
 
151
 
152
+ @app.route("/progress")
153
  def progress():
154
+ """Retourne le fichier JSON de progression ou les données globales en cas d'absence du fichier."""
155
+ try:
156
+ with open(JSON_FILE, "r") as f:
157
+ data = json.load(f)
158
+ except Exception as e:
159
+ data = progress_data
160
+ return jsonify(data)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
 
162
+ if __name__ == "__main__":
163
+ app.run(debug=True)