3v324v23 commited on
Commit
bf2f692
·
1 Parent(s): bdcb812

Добавлен прокси для статического Playground UI, работающий с HuggingFace Space

Browse files
Files changed (1) hide show
  1. fallback.py +210 -5
fallback.py CHANGED
@@ -558,6 +558,196 @@ def run_proxy_server():
558
 
559
  return httpd
560
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
561
  def run_playground():
562
  """Запуск Playground UI"""
563
  logger.info("Starting Playground UI in development mode")
@@ -659,18 +849,33 @@ def run_playground():
659
  time.sleep(3)
660
  if playground_process.poll() is not None:
661
  logger.error(f"All Playground UI launch methods failed")
662
- raise RuntimeError(f"All Playground UI launch methods failed")
 
 
 
 
 
 
 
 
 
 
 
663
  else:
664
- logger.info("Skipping Playground launch as it's not critical for API functionality")
665
- logger.info("API server and proxy server will continue running")
 
 
 
 
666
  # Создаем заглушку для процесса
667
  playground_process = subprocess.Popen(
668
- ["tail", "-f", "/dev/null"], # Команда, которая никогда не завершится
669
  stdout=subprocess.PIPE,
670
  stderr=subprocess.PIPE,
671
  )
672
 
673
- logger.info("Playground UI started successfully or skipped")
674
  return playground_process
675
 
676
  def main():
 
558
 
559
  return httpd
560
 
561
+ def run_playground_proxy():
562
+ """Запускает прокси-сервер для обслуживания Playground UI и проксирования запросов к API"""
563
+ import http.server
564
+ import socketserver
565
+ from urllib.parse import urljoin, urlparse
566
+ import urllib.request
567
+ import urllib.error
568
+
569
+ class PlaygroundProxyHandler(http.server.SimpleHTTPRequestHandler):
570
+ def log_message(self, format, *args):
571
+ logger.info(f"PLAYGROUND-PROXY: {format % args}")
572
+
573
+ def do_GET(self):
574
+ # Проксирование запросов к API
575
+ if self.path.startswith('/api/'):
576
+ api_path = self.path[5:] # Удаляем '/api/' из пути
577
+ api_url = f"http://localhost:8080/{api_path}"
578
+
579
+ try:
580
+ logger.info(f"Proxying GET request to API: {api_url}")
581
+ with urllib.request.urlopen(api_url) as response:
582
+ data = response.read()
583
+ self.send_response(response.status)
584
+
585
+ # Копируем все заголовки из ответа API
586
+ for header, value in response.getheaders():
587
+ if header.lower() not in ('transfer-encoding', 'connection'):
588
+ self.send_header(header, value)
589
+
590
+ # Устанавливаем CORS заголовки
591
+ self.send_header('Access-Control-Allow-Origin', '*')
592
+ self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
593
+ self.send_header('Access-Control-Allow-Headers', 'Content-Type')
594
+
595
+ self.end_headers()
596
+ self.wfile.write(data)
597
+ except urllib.error.URLError as e:
598
+ logger.error(f"Error proxying GET request to API: {e}")
599
+ self.send_error(502, f"Error proxying to API: {e}")
600
+ return
601
+
602
+ # Проксирование запросов к серверу графического редактора
603
+ elif self.path.startswith('/designer/'):
604
+ designer_path = self.path[10:] # Удаляем '/designer/' из пути
605
+ designer_url = f"http://localhost:49483/{designer_path}"
606
+
607
+ try:
608
+ logger.info(f"Proxying GET request to designer: {designer_url}")
609
+ with urllib.request.urlopen(designer_url) as response:
610
+ data = response.read()
611
+ self.send_response(response.status)
612
+
613
+ # Копируем все заголовки из ответа дизайнера
614
+ for header, value in response.getheaders():
615
+ if header.lower() not in ('transfer-encoding', 'connection'):
616
+ self.send_header(header, value)
617
+
618
+ # Устанавливаем CORS заголовки
619
+ self.send_header('Access-Control-Allow-Origin', '*')
620
+ self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
621
+ self.send_header('Access-Control-Allow-Headers', 'Content-Type')
622
+
623
+ self.end_headers()
624
+ self.wfile.write(data)
625
+ except urllib.error.URLError as e:
626
+ logger.error(f"Error proxying GET request to designer: {e}")
627
+ self.send_error(502, f"Error proxying to designer: {e}")
628
+ return
629
+
630
+ # Перенаправление корневого пути на Playground UI
631
+ elif self.path == '/' or self.path == '':
632
+ self.send_response(302)
633
+ self.send_header('Location', 'https://ten-framework.github.io/TEN-Playground-Static/')
634
+ self.end_headers()
635
+ return
636
+
637
+ # Для всех остальных запросов пытаемся обслужить статический файл
638
+ else:
639
+ self.send_error(404, "File Not Found")
640
+
641
+ def do_POST(self):
642
+ # Проксирование POST запросов к API
643
+ if self.path.startswith('/api/'):
644
+ api_path = self.path[5:] # Удаляем '/api/' из пути
645
+ api_url = f"http://localhost:8080/{api_path}"
646
+
647
+ content_length = int(self.headers.get('Content-Length', 0))
648
+ post_data = self.rfile.read(content_length) if content_length > 0 else b''
649
+
650
+ try:
651
+ logger.info(f"Proxying POST request to API: {api_url}")
652
+ request = urllib.request.Request(
653
+ api_url,
654
+ data=post_data,
655
+ headers={k: v for k, v in self.headers.items() if k.lower() not in ('host', 'content-length')},
656
+ method='POST'
657
+ )
658
+
659
+ with urllib.request.urlopen(request) as response:
660
+ data = response.read()
661
+ self.send_response(response.status)
662
+
663
+ # Копируем все заголовки из ответа API
664
+ for header, value in response.getheaders():
665
+ if header.lower() not in ('transfer-encoding', 'connection'):
666
+ self.send_header(header, value)
667
+
668
+ # Устанавливаем CORS заголовки
669
+ self.send_header('Access-Control-Allow-Origin', '*')
670
+ self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
671
+ self.send_header('Access-Control-Allow-Headers', 'Content-Type')
672
+
673
+ self.end_headers()
674
+ self.wfile.write(data)
675
+ except urllib.error.URLError as e:
676
+ logger.error(f"Error proxying POST request to API: {e}")
677
+ self.send_error(502, f"Error proxying to API: {e}")
678
+
679
+ # Проксирование запросов к серверу графического редактора
680
+ elif self.path.startswith('/designer/'):
681
+ designer_path = self.path[10:] # Удаляем '/designer/' из пути
682
+ designer_url = f"http://localhost:49483/{designer_path}"
683
+
684
+ content_length = int(self.headers.get('Content-Length', 0))
685
+ post_data = self.rfile.read(content_length) if content_length > 0 else b''
686
+
687
+ try:
688
+ logger.info(f"Proxying POST request to designer: {designer_url}")
689
+ request = urllib.request.Request(
690
+ designer_url,
691
+ data=post_data,
692
+ headers={k: v for k, v in self.headers.items() if k.lower() not in ('host', 'content-length')},
693
+ method='POST'
694
+ )
695
+
696
+ with urllib.request.urlopen(request) as response:
697
+ data = response.read()
698
+ self.send_response(response.status)
699
+
700
+ # Копируем все заголовки из ответа дизайнера
701
+ for header, value in response.getheaders():
702
+ if header.lower() not in ('transfer-encoding', 'connection'):
703
+ self.send_header(header, value)
704
+
705
+ # Устанавливаем CORS заголовки
706
+ self.send_header('Access-Control-Allow-Origin', '*')
707
+ self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
708
+ self.send_header('Access-Control-Allow-Headers', 'Content-Type')
709
+
710
+ self.end_headers()
711
+ self.wfile.write(data)
712
+ except urllib.error.URLError as e:
713
+ logger.error(f"Error proxying POST request to designer: {e}")
714
+ self.send_error(502, f"Error proxying to designer: {e}")
715
+ else:
716
+ self.send_error(404, "Not Found")
717
+
718
+ def do_OPTIONS(self):
719
+ self.send_response(200)
720
+ self.send_header('Access-Control-Allow-Origin', '*')
721
+ self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
722
+ self.send_header('Access-Control-Allow-Headers', 'Content-Type, Authorization')
723
+ self.end_headers()
724
+
725
+ # Запуск прокси-сервера на порту 7860 (стандартный порт HF Space)
726
+ port = 7860
727
+ httpd = socketserver.ThreadingTCPServer(("", port), PlaygroundProxyHandler)
728
+ logger.info(f"Playground proxy server started on port {port}")
729
+ logger.info(f"Access Playground at: https://nitrox-ten.hf.space/")
730
+
731
+ # В отдельном потоке запускаем проверку доступности API сервера
732
+ def check_api_availability():
733
+ while True:
734
+ try:
735
+ # Проверка /graphs API
736
+ with urllib.request.urlopen("http://localhost:8080/graphs") as response:
737
+ if response.status == 200:
738
+ data = response.read().decode('utf-8')
739
+ logger.info(f"API /graphs endpoint is available: {data}")
740
+ except Exception as e:
741
+ logger.warning(f"API check failed: {e}")
742
+
743
+ time.sleep(30) # Проверяем каждые 30 секунд
744
+
745
+ api_check_thread = threading.Thread(target=check_api_availability, daemon=True)
746
+ api_check_thread.start()
747
+
748
+ # Запускаем сервер в основном потоке
749
+ httpd.serve_forever()
750
+
751
  def run_playground():
752
  """Запуск Playground UI"""
753
  logger.info("Starting Playground UI in development mode")
 
849
  time.sleep(3)
850
  if playground_process.poll() is not None:
851
  logger.error(f"All Playground UI launch methods failed")
852
+ logger.info("Starting playground proxy as fallback")
853
+
854
+ # Запускаем прокси-сервер для Playground
855
+ playground_thread = threading.Thread(target=run_playground_proxy, daemon=True)
856
+ playground_thread.start()
857
+
858
+ # Создаем заглушку для процесса
859
+ playground_process = subprocess.Popen(
860
+ ["tail", "-f", "/dev/null"],
861
+ stdout=subprocess.PIPE,
862
+ stderr=subprocess.PIPE,
863
+ )
864
  else:
865
+ logger.info("Starting playground proxy as fallback")
866
+
867
+ # Запускаем прокси-сервер для Playground
868
+ playground_thread = threading.Thread(target=run_playground_proxy, daemon=True)
869
+ playground_thread.start()
870
+
871
  # Создаем заглушку для процесса
872
  playground_process = subprocess.Popen(
873
+ ["tail", "-f", "/dev/null"],
874
  stdout=subprocess.PIPE,
875
  stderr=subprocess.PIPE,
876
  )
877
 
878
+ logger.info("Playground UI started successfully or proxy is running")
879
  return playground_process
880
 
881
  def main():