Starchik1 commited on
Commit
ceacad5
·
verified ·
1 Parent(s): bcd5aaa

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +273 -93
main.py CHANGED
@@ -9,7 +9,19 @@ import io
9
 
10
  app = Flask(__name__)
11
  app.config['SECRET_KEY'] = 'messenger-secret-key'
12
- socketio = SocketIO(app, cors_allowed_origins="*")
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  # Хранилища данных
15
  users = {}
@@ -525,9 +537,34 @@ HTML_TEMPLATE = '''
525
  justify-content: center;
526
  font-size: 16px;
527
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
528
  </style>
529
  </head>
530
  <body>
 
 
 
 
 
531
  <!-- Login Screen -->
532
  <div id="loginScreen" class="login-screen">
533
  <div style="text-align: center; margin-bottom: 30px;">
@@ -583,7 +620,7 @@ HTML_TEMPLATE = '''
583
  <div id="callScreen" class="call-screen">
584
  <div class="video-container">
585
  <div id="remoteVideoContainer" class="no-video remote-video">
586
- <div>Нет видео</div>
587
  </div>
588
  <video id="localVideo" class="local-video" autoplay playsinline muted></video>
589
  <div class="call-info">
@@ -619,7 +656,7 @@ HTML_TEMPLATE = '''
619
 
620
  <script src="https://cdn.socket.io/4.5.0/socket.io.min.js"></script>
621
  <script>
622
- const socket = io();
623
  let currentUser = null;
624
  let mediaRecorder = null;
625
  let audioChunks = [];
@@ -632,6 +669,8 @@ HTML_TEMPLATE = '''
632
  let callTimerInterval = null;
633
  let isMuted = false;
634
  let isVideoEnabled = true;
 
 
635
 
636
  // WebRTC configuration
637
  const rtcConfig = {
@@ -645,75 +684,155 @@ HTML_TEMPLATE = '''
645
  ]
646
  };
647
 
648
- // Socket events
649
- socket.on('registration_success', (data) => {
650
- currentUser = data;
651
- document.getElementById('loginScreen').style.display = 'none';
652
- document.getElementById('chatScreen').style.display = 'flex';
653
- });
 
 
 
 
 
 
 
 
 
 
 
654
 
655
- socket.on('user_list_update', (data) => {
656
- document.getElementById('onlineCount').textContent = data.count;
657
- updateUsersList(data.users || []);
658
- });
 
 
 
 
 
 
 
659
 
660
- socket.on('new_message', (message) => {
661
- displayMessage(message);
662
- });
 
 
 
 
 
 
 
 
 
 
 
663
 
664
- socket.on('new_voice_message', (data) => {
665
- displayVoiceMessage(data);
666
- });
 
667
 
668
- socket.on('incoming_call', (data) => {
669
- showIncomingCall(data.from_user, data.call_id, data.isVideo);
670
- });
 
 
 
671
 
672
- socket.on('call_answered', (data) => {
673
- if (data.answer) {
674
- startCall(data.isVideo, false);
675
- } else {
676
- alert('Пользователь отклонил звонок');
677
- hideCallScreen();
678
- }
679
- });
680
 
681
- socket.on('call_ended', () => {
682
- alert('Звонок завершен');
683
- endCall();
684
- });
685
 
686
- socket.on('webrtc_offer', async (data) => {
687
- if (!peerConnection) {
688
- await createPeerConnection(false);
689
- }
690
- await peerConnection.setRemoteDescription(new RTCSessionDescription(data.offer));
691
- const answer = await peerConnection.createAnswer();
692
- await peerConnection.setLocalDescription(answer);
693
-
694
- socket.emit('webrtc_answer', {
695
- answer: answer,
696
- to_user: data.from_user,
697
- call_id: data.call_id
698
  });
699
- });
700
 
701
- socket.on('webrtc_answer', async (data) => {
702
- if (peerConnection) {
703
- await peerConnection.setRemoteDescription(new RTCSessionDescription(data.answer));
704
- }
705
- });
706
 
707
- socket.on('webrtc_ice_candidate', async (data) => {
708
- if (peerConnection) {
709
- await peerConnection.addIceCandidate(new RTCIceCandidate(data.candidate));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
710
  }
711
- });
712
 
713
  // UI Functions
714
  function registerUser() {
715
  const username = document.getElementById('usernameInput').value.trim();
716
  if (username) {
 
 
 
717
  socket.emit('register', username);
718
  } else {
719
  alert('Введите имя пользователя');
@@ -724,12 +843,14 @@ HTML_TEMPLATE = '''
724
  const input = document.getElementById('messageInput');
725
  const text = input.value.trim();
726
 
727
- if (text) {
728
  socket.emit('message', {
729
  sender: currentUser.username,
730
  text: text
731
  });
732
  input.value = '';
 
 
733
  }
734
  }
735
 
@@ -843,11 +964,15 @@ HTML_TEMPLATE = '''
843
  reader.onload = function() {
844
  const base64Audio = reader.result.split(',')[1];
845
 
846
- socket.emit('voice_message', {
847
- audio_data: base64Audio,
848
- sender: currentUser.username,
849
- duration: duration
850
- });
 
 
 
 
851
  };
852
  reader.readAsDataURL(audioBlob);
853
 
@@ -881,6 +1006,11 @@ HTML_TEMPLATE = '''
881
 
882
  // Call Functions
883
  function startCallWithUser(targetUser, isVideo) {
 
 
 
 
 
884
  currentCall = {
885
  id: Date.now().toString(),
886
  target: targetUser,
@@ -912,22 +1042,28 @@ HTML_TEMPLATE = '''
912
 
913
  function acceptCall() {
914
  document.getElementById('incomingCallOverlay').style.display = 'none';
915
- socket.emit('call_answer', {
916
- call_id: currentCall.id,
917
- answer: true,
918
- to_user: currentCall.target,
919
- isVideo: currentCall.isVideo
920
- });
921
-
922
- startCall(currentCall.isVideo, true);
 
 
 
 
923
  }
924
 
925
  function rejectCall() {
926
- socket.emit('call_answer', {
927
- call_id: currentCall.id,
928
- answer: false,
929
- to_user: currentCall.target
930
- });
 
 
931
 
932
  document.getElementById('incomingCallOverlay').style.display = 'none';
933
  currentCall = null;
@@ -958,11 +1094,13 @@ HTML_TEMPLATE = '''
958
  const offer = await peerConnection.createOffer();
959
  await peerConnection.setLocalDescription(offer);
960
 
961
- socket.emit('webrtc_offer', {
962
- offer: offer,
963
- to_user: currentCall.target,
964
- call_id: currentCall.id
965
- });
 
 
966
  }
967
 
968
  // Start call timer
@@ -985,6 +1123,7 @@ HTML_TEMPLATE = '''
985
 
986
  // Handle incoming stream
987
  peerConnection.ontrack = (event) => {
 
988
  remoteStream = event.streams[0];
989
  const remoteVideo = document.getElementById('remoteVideoContainer');
990
 
@@ -1009,7 +1148,7 @@ HTML_TEMPLATE = '''
1009
 
1010
  // Handle ICE candidates
1011
  peerConnection.onicecandidate = (event) => {
1012
- if (event.candidate && currentCall) {
1013
  socket.emit('webrtc_ice_candidate', {
1014
  candidate: event.candidate,
1015
  to_user: currentCall.target
@@ -1023,6 +1162,10 @@ HTML_TEMPLATE = '''
1023
  document.getElementById('callStatus').textContent = 'Разговор';
1024
  }
1025
  };
 
 
 
 
1026
  }
1027
 
1028
  function showCallScreen(isVideo, status) {
@@ -1038,7 +1181,7 @@ HTML_TEMPLATE = '''
1038
 
1039
  function hideCallScreen() {
1040
  document.getElementById('callScreen').style.display = 'none';
1041
- document.getElementById('remoteVideoContainer').innerHTML = '<div>Нет видео</div>';
1042
  document.getElementById('remoteVideoContainer').className = 'no-video remote-video';
1043
 
1044
  if (callTimerInterval) {
@@ -1070,7 +1213,7 @@ HTML_TEMPLATE = '''
1070
  localStream = null;
1071
  }
1072
 
1073
- if (currentCall) {
1074
  socket.emit('call_end', {
1075
  to_user: currentCall.target,
1076
  call_id: currentCall.id
@@ -1134,6 +1277,18 @@ HTML_TEMPLATE = '''
1134
  sidebar.classList.remove('open');
1135
  }
1136
  });
 
 
 
 
 
 
 
 
 
 
 
 
1137
  </script>
1138
  </body>
1139
  </html>
@@ -1153,21 +1308,34 @@ def handle_connect():
1153
 
1154
  @socketio.on('disconnect')
1155
  def handle_disconnect():
 
 
 
 
1156
  for user_id, user_data in list(users.items()):
1157
  if user_data.get('sid') == request.sid:
 
1158
  # End any active calls
1159
  for call_id, call_data in list(active_calls.items()):
1160
- if call_data['from_user'] == user_data['username'] or call_data['to_user'] == user_data['username']:
1161
- emit('call_ended', room=call_data['to_sid'])
 
 
 
 
 
 
 
1162
  del active_calls[call_id]
1163
 
1164
  del users[user_id]
1165
  break
1166
 
1167
- emit('user_list_update', {
1168
- 'count': len(users),
1169
- 'users': [user_data['username'] for user_data in users.values()]
1170
- }, broadcast=True)
 
1171
 
1172
  @socketio.on('register')
1173
  def handle_register(username):
@@ -1267,7 +1435,14 @@ def handle_call_end(data):
1267
  call_id = data.get('call_id')
1268
  if call_id in active_calls:
1269
  call_data = active_calls[call_id]
1270
- emit('call_ended', room=call_data['to_sid'])
 
 
 
 
 
 
 
1271
  del active_calls[call_id]
1272
 
1273
  @socketio.on('webrtc_offer')
@@ -1337,8 +1512,13 @@ def cleanup_temp_files():
1337
  if __name__ == '__main__':
1338
  try:
1339
  print("Запуск мобильного мессенджера...")
1340
- print("Откройте: http://localhost:5000")
1341
- print("TURN сервер: relay1.expressturn.com:3480")
1342
- socketio.run(app, host='0.0.0.0', port=5000, debug=True)
 
 
 
 
 
1343
  finally:
1344
  cleanup_temp_files()
 
9
 
10
  app = Flask(__name__)
11
  app.config['SECRET_KEY'] = 'messenger-secret-key'
12
+ app.config['DEBUG'] = False
13
+
14
+ # Настройки для production среды
15
+ socketio = SocketIO(
16
+ app,
17
+ cors_allowed_origins="*",
18
+ ping_timeout=60,
19
+ ping_interval=25,
20
+ logger=True,
21
+ engineio_logger=False,
22
+ async_mode='eventlet',
23
+ max_http_buffer_size=100 * 1024 * 1024 # 100MB для больших файлов
24
+ )
25
 
26
  # Хранилища данных
27
  users = {}
 
537
  justify-content: center;
538
  font-size: 16px;
539
  }
540
+
541
+ .connection-status {
542
+ position: fixed;
543
+ top: 10px;
544
+ right: 10px;
545
+ padding: 5px 10px;
546
+ border-radius: 15px;
547
+ font-size: 12px;
548
+ z-index: 3000;
549
+ }
550
+
551
+ .connected {
552
+ background: #4CAF50;
553
+ color: white;
554
+ }
555
+
556
+ .disconnected {
557
+ background: #FF4444;
558
+ color: white;
559
+ }
560
  </style>
561
  </head>
562
  <body>
563
+ <!-- Connection Status -->
564
+ <div id="connectionStatus" class="connection-status disconnected" style="display: none;">
565
+ Подключение...
566
+ </div>
567
+
568
  <!-- Login Screen -->
569
  <div id="loginScreen" class="login-screen">
570
  <div style="text-align: center; margin-bottom: 30px;">
 
620
  <div id="callScreen" class="call-screen">
621
  <div class="video-container">
622
  <div id="remoteVideoContainer" class="no-video remote-video">
623
+ <div>Ожидание подключения...</div>
624
  </div>
625
  <video id="localVideo" class="local-video" autoplay playsinline muted></video>
626
  <div class="call-info">
 
656
 
657
  <script src="https://cdn.socket.io/4.5.0/socket.io.min.js"></script>
658
  <script>
659
+ let socket;
660
  let currentUser = null;
661
  let mediaRecorder = null;
662
  let audioChunks = [];
 
669
  let callTimerInterval = null;
670
  let isMuted = false;
671
  let isVideoEnabled = true;
672
+ let reconnectAttempts = 0;
673
+ const MAX_RECONNECT_ATTEMPTS = 5;
674
 
675
  // WebRTC configuration
676
  const rtcConfig = {
 
684
  ]
685
  };
686
 
687
+ function initializeSocket() {
688
+ // Получаем базовый URL для корректного подключения к WebSocket
689
+ const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
690
+ const host = window.location.host;
691
+
692
+ socket = io({
693
+ transports: ['websocket', 'polling'],
694
+ upgrade: true,
695
+ rememberUpgrade: true,
696
+ timeout: 10000,
697
+ pingTimeout: 60000,
698
+ pingInterval: 25000,
699
+ reconnection: true,
700
+ reconnectionAttempts: MAX_RECONNECT_ATTEMPTS,
701
+ reconnectionDelay: 1000,
702
+ reconnectionDelayMax: 5000
703
+ });
704
 
705
+ // Socket events
706
+ socket.on('connect', () => {
707
+ console.log('Connected to server');
708
+ updateConnectionStatus(true);
709
+ reconnectAttempts = 0;
710
+
711
+ // Re-register if we have a current user
712
+ if (currentUser) {
713
+ socket.emit('register', currentUser.username);
714
+ }
715
+ });
716
 
717
+ socket.on('disconnect', (reason) => {
718
+ console.log('Disconnected from server:', reason);
719
+ updateConnectionStatus(false);
720
+
721
+ if (reason === 'io server disconnect') {
722
+ // Server intentionally disconnected, try to reconnect
723
+ setTimeout(() => {
724
+ if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
725
+ socket.connect();
726
+ reconnectAttempts++;
727
+ }
728
+ }, 1000);
729
+ }
730
+ });
731
 
732
+ socket.on('connect_error', (error) => {
733
+ console.error('Connection error:', error);
734
+ updateConnectionStatus(false);
735
+ });
736
 
737
+ socket.on('registration_success', (data) => {
738
+ currentUser = data;
739
+ document.getElementById('loginScreen').style.display = 'none';
740
+ document.getElementById('chatScreen').style.display = 'flex';
741
+ updateConnectionStatus(true);
742
+ });
743
 
744
+ socket.on('user_list_update', (data) => {
745
+ document.getElementById('onlineCount').textContent = data.count;
746
+ updateUsersList(data.users || []);
747
+ });
 
 
 
 
748
 
749
+ socket.on('new_message', (message) => {
750
+ displayMessage(message);
751
+ });
 
752
 
753
+ socket.on('new_voice_message', (data) => {
754
+ displayVoiceMessage(data);
 
 
 
 
 
 
 
 
 
 
755
  });
 
756
 
757
+ socket.on('incoming_call', (data) => {
758
+ showIncomingCall(data.from_user, data.call_id, data.isVideo);
759
+ });
 
 
760
 
761
+ socket.on('call_answered', (data) => {
762
+ if (data.answer) {
763
+ startCall(data.isVideo, false);
764
+ } else {
765
+ alert('Пользователь отклонил звонок');
766
+ hideCallScreen();
767
+ }
768
+ });
769
+
770
+ socket.on('call_ended', () => {
771
+ alert('Звонок завершен');
772
+ endCall();
773
+ });
774
+
775
+ socket.on('webrtc_offer', async (data) => {
776
+ console.log('Received WebRTC offer');
777
+ if (!peerConnection) {
778
+ await createPeerConnection(false);
779
+ }
780
+ try {
781
+ await peerConnection.setRemoteDescription(new RTCSessionDescription(data.offer));
782
+ const answer = await peerConnection.createAnswer();
783
+ await peerConnection.setLocalDescription(answer);
784
+
785
+ socket.emit('webrtc_answer', {
786
+ answer: answer,
787
+ to_user: data.from_user,
788
+ call_id: data.call_id
789
+ });
790
+ } catch (error) {
791
+ console.error('Error handling WebRTC offer:', error);
792
+ }
793
+ });
794
+
795
+ socket.on('webrtc_answer', async (data) => {
796
+ console.log('Received WebRTC answer');
797
+ if (peerConnection) {
798
+ try {
799
+ await peerConnection.setRemoteDescription(new RTCSessionDescription(data.answer));
800
+ } catch (error) {
801
+ console.error('Error setting remote description:', error);
802
+ }
803
+ }
804
+ });
805
+
806
+ socket.on('webrtc_ice_candidate', async (data) => {
807
+ if (peerConnection && data.candidate) {
808
+ try {
809
+ await peerConnection.addIceCandidate(new RTCIceCandidate(data.candidate));
810
+ } catch (error) {
811
+ console.error('Error adding ICE candidate:', error);
812
+ }
813
+ }
814
+ });
815
+ }
816
+
817
+ function updateConnectionStatus(connected) {
818
+ const statusElement = document.getElementById('connectionStatus');
819
+ statusElement.style.display = 'block';
820
+ if (connected) {
821
+ statusElement.textContent = '✓ Подключено';
822
+ statusElement.className = 'connection-status connected';
823
+ } else {
824
+ statusElement.textContent = '✗ Отключено';
825
+ statusElement.className = 'connection-status disconnected';
826
  }
827
+ }
828
 
829
  // UI Functions
830
  function registerUser() {
831
  const username = document.getElementById('usernameInput').value.trim();
832
  if (username) {
833
+ if (!socket || !socket.connected) {
834
+ initializeSocket();
835
+ }
836
  socket.emit('register', username);
837
  } else {
838
  alert('Введите имя пользователя');
 
843
  const input = document.getElementById('messageInput');
844
  const text = input.value.trim();
845
 
846
+ if (text && socket && socket.connected) {
847
  socket.emit('message', {
848
  sender: currentUser.username,
849
  text: text
850
  });
851
  input.value = '';
852
+ } else if (!socket || !socket.connected) {
853
+ alert('Нет подключения к серверу');
854
  }
855
  }
856
 
 
964
  reader.onload = function() {
965
  const base64Audio = reader.result.split(',')[1];
966
 
967
+ if (socket && socket.connected) {
968
+ socket.emit('voice_message', {
969
+ audio_data: base64Audio,
970
+ sender: currentUser.username,
971
+ duration: duration
972
+ });
973
+ } else {
974
+ alert('Нет подключения для отправки голосового сообщения');
975
+ }
976
  };
977
  reader.readAsDataURL(audioBlob);
978
 
 
1006
 
1007
  // Call Functions
1008
  function startCallWithUser(targetUser, isVideo) {
1009
+ if (!socket || !socket.connected) {
1010
+ alert('Нет подключения к серверу');
1011
+ return;
1012
+ }
1013
+
1014
  currentCall = {
1015
  id: Date.now().toString(),
1016
  target: targetUser,
 
1042
 
1043
  function acceptCall() {
1044
  document.getElementById('incomingCallOverlay').style.display = 'none';
1045
+ if (socket && socket.connected) {
1046
+ socket.emit('call_answer', {
1047
+ call_id: currentCall.id,
1048
+ answer: true,
1049
+ to_user: currentCall.target,
1050
+ isVideo: currentCall.isVideo
1051
+ });
1052
+
1053
+ startCall(currentCall.isVideo, true);
1054
+ } else {
1055
+ alert('Нет подключения к серверу');
1056
+ }
1057
  }
1058
 
1059
  function rejectCall() {
1060
+ if (socket && socket.connected) {
1061
+ socket.emit('call_answer', {
1062
+ call_id: currentCall.id,
1063
+ answer: false,
1064
+ to_user: currentCall.target
1065
+ });
1066
+ }
1067
 
1068
  document.getElementById('incomingCallOverlay').style.display = 'none';
1069
  currentCall = null;
 
1094
  const offer = await peerConnection.createOffer();
1095
  await peerConnection.setLocalDescription(offer);
1096
 
1097
+ if (socket && socket.connected) {
1098
+ socket.emit('webrtc_offer', {
1099
+ offer: offer,
1100
+ to_user: currentCall.target,
1101
+ call_id: currentCall.id
1102
+ });
1103
+ }
1104
  }
1105
 
1106
  // Start call timer
 
1123
 
1124
  // Handle incoming stream
1125
  peerConnection.ontrack = (event) => {
1126
+ console.log('Received remote track:', event.track.kind);
1127
  remoteStream = event.streams[0];
1128
  const remoteVideo = document.getElementById('remoteVideoContainer');
1129
 
 
1148
 
1149
  // Handle ICE candidates
1150
  peerConnection.onicecandidate = (event) => {
1151
+ if (event.candidate && currentCall && socket && socket.connected) {
1152
  socket.emit('webrtc_ice_candidate', {
1153
  candidate: event.candidate,
1154
  to_user: currentCall.target
 
1162
  document.getElementById('callStatus').textContent = 'Разговор';
1163
  }
1164
  };
1165
+
1166
+ peerConnection.oniceconnectionstatechange = () => {
1167
+ console.log('ICE connection state:', peerConnection.iceConnectionState);
1168
+ };
1169
  }
1170
 
1171
  function showCallScreen(isVideo, status) {
 
1181
 
1182
  function hideCallScreen() {
1183
  document.getElementById('callScreen').style.display = 'none';
1184
+ document.getElementById('remoteVideoContainer').innerHTML = '<div>Ожидание подключения...</div>';
1185
  document.getElementById('remoteVideoContainer').className = 'no-video remote-video';
1186
 
1187
  if (callTimerInterval) {
 
1213
  localStream = null;
1214
  }
1215
 
1216
+ if (currentCall && socket && socket.connected) {
1217
  socket.emit('call_end', {
1218
  to_user: currentCall.target,
1219
  call_id: currentCall.id
 
1277
  sidebar.classList.remove('open');
1278
  }
1279
  });
1280
+
1281
+ // Initialize socket on load
1282
+ window.addEventListener('load', function() {
1283
+ initializeSocket();
1284
+ });
1285
+
1286
+ // Handle page visibility changes
1287
+ document.addEventListener('visibilitychange', function() {
1288
+ if (!document.hidden && (!socket || !socket.connected)) {
1289
+ initializeSocket();
1290
+ }
1291
+ });
1292
  </script>
1293
  </body>
1294
  </html>
 
1308
 
1309
  @socketio.on('disconnect')
1310
  def handle_disconnect():
1311
+ print(f'Client disconnected: {request.sid}')
1312
+
1313
+ # Find and remove the disconnected user
1314
+ disconnected_user = None
1315
  for user_id, user_data in list(users.items()):
1316
  if user_data.get('sid') == request.sid:
1317
+ disconnected_user = user_data['username']
1318
  # End any active calls
1319
  for call_id, call_data in list(active_calls.items()):
1320
+ if call_data['from_user'] == disconnected_user or call_data['to_user'] == disconnected_user:
1321
+ try:
1322
+ emit('call_ended', room=call_data['to_sid'])
1323
+ except:
1324
+ pass
1325
+ try:
1326
+ emit('call_ended', room=call_data['from_sid'])
1327
+ except:
1328
+ pass
1329
  del active_calls[call_id]
1330
 
1331
  del users[user_id]
1332
  break
1333
 
1334
+ if disconnected_user:
1335
+ emit('user_list_update', {
1336
+ 'count': len(users),
1337
+ 'users': [user_data['username'] for user_data in users.values()]
1338
+ }, broadcast=True)
1339
 
1340
  @socketio.on('register')
1341
  def handle_register(username):
 
1435
  call_id = data.get('call_id')
1436
  if call_id in active_calls:
1437
  call_data = active_calls[call_id]
1438
+ try:
1439
+ emit('call_ended', room=call_data['to_sid'])
1440
+ except:
1441
+ pass
1442
+ try:
1443
+ emit('call_ended', room=call_data['from_sid'])
1444
+ except:
1445
+ pass
1446
  del active_calls[call_id]
1447
 
1448
  @socketio.on('webrtc_offer')
 
1512
  if __name__ == '__main__':
1513
  try:
1514
  print("Запуск мобильного мессенджера...")
1515
+ print("Порт: 7860")
1516
+ socketio.run(
1517
+ app,
1518
+ host='0.0.0.0',
1519
+ port=7860,
1520
+ debug=False,
1521
+ allow_unsafe_werkzeug=True
1522
+ )
1523
  finally:
1524
  cleanup_temp_files()