File size: 12,450 Bytes
58cec34 2839144 d7f0eff 3c7d3b0 86f3bf2 eeea7be 58cec34 d7f0eff 3c7d3b0 d7f0eff 3c7d3b0 d7f0eff 3c7d3b0 d7f0eff 3c7d3b0 d7f0eff 3c7d3b0 74e8d5b eeea7be 2455e56 11ddd3d 2455e56 74e8d5b eeea7be 74e8d5b 11ddd3d 74e8d5b 2455e56 eeea7be 3c7d3b0 eeea7be 2455e56 eeea7be 11ddd3d 74e8d5b 11ddd3d 2455e56 11ddd3d eeea7be 2455e56 74e8d5b eeea7be d7f0eff eeea7be 2455e56 eeea7be 74e8d5b eeea7be d7f0eff eeea7be 11ddd3d eeea7be d7f0eff 2839144 d7f0eff 2839144 3c7d3b0 eeea7be 3c7d3b0 eeea7be d7f0eff 3c7d3b0 d7f0eff |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
#!/usr/bin/env python3
import os
import subprocess
import sys
import time
from pathlib import Path
import signal
import shutil
import http.client
import socketserver
from http.server import HTTPServer, BaseHTTPRequestHandler
import threading
def main():
processes = []
try:
# Пути к исполняемым файлам
api_binary = Path("/app/server/bin/api")
playground_dir = Path("/app/playground")
# Проверяем существование файлов
if not api_binary.exists():
print(f"ERROR: API binary not found at {api_binary}", file=sys.stderr)
return 1
if not playground_dir.exists():
print(f"ERROR: Playground directory not found at {playground_dir}", file=sys.stderr)
return 1
# Создаем директорию для логов с правами доступа
log_dir = "/tmp/ten_agent"
os.makedirs(log_dir, exist_ok=True)
# Даем всем права на запись в директорию логов
os.chmod(log_dir, 0o777)
# Запускаем API сервер с правильными переменными окружения
print("Starting TEN-Agent API server on port 8080...")
api_server_env = os.environ.copy()
api_server_env["LOG_PATH"] = log_dir
api_server_env["LOG_STDOUT"] = "true"
api_server_env["WORKERS_MAX"] = "4" # Устанавливаем значение для WORKERS_MAX
api_server_process = subprocess.Popen([str(api_binary)], env=api_server_env)
processes.append(api_server_process)
# Даем время API серверу запуститься
time.sleep(3)
# Запускаем Playground UI на порту 3000
print("Starting Playground UI on port 3000...")
playground_env = os.environ.copy()
playground_env["AGENT_SERVER_URL"] = "http://localhost:8080" # Подключаемся к локальному API серверу
playground_env["NODE_ENV"] = "production" # Убедимся, что запускаем в production режиме
playground_env["PORT"] = "3000" # Указываем порт через переменную окружения
# Запускаем Next.js с правильными параметрами (без -- --port)
playground_process = subprocess.Popen(
"cd /app/playground && pnpm start", # Удаляем лишние параметры
shell=True,
env=playground_env
)
processes.append(playground_process)
# Даем время Playground UI запуститься
time.sleep(5)
# Создаем эффективный прокси-сервер
class ProxyHandler(BaseHTTPRequestHandler):
# Отключаем логирование каждого запроса
def log_message(self, format, *args):
if args and args[0].startswith('GET /?logs=container'):
return # Игнорируем логи для запросов логов контейнера
sys.stderr.write("%s - - [%s] %s\n" %
(self.client_address[0],
self.log_date_time_string(),
format % args))
def do_GET(self):
self._handle_request('GET')
def do_POST(self):
self._handle_request('POST')
def do_PUT(self):
self._handle_request('PUT')
def do_DELETE(self):
self._handle_request('DELETE')
def do_OPTIONS(self):
self._handle_request('OPTIONS')
def _handle_request(self, method):
try:
# Определяем, какой сервер должен обработать запрос
target_host = 'localhost'
# API endpoints идут на порт 8080 (API сервер)
if self.path.startswith('/health') or \
self.path.startswith('/list') or \
self.path.startswith('/graphs') or \
self.path.startswith('/start') or \
self.path.startswith('/stop') or \
self.path.startswith('/ping') or \
self.path.startswith('/token') or \
self.path.startswith('/dev-tmp') or \
self.path.startswith('/vector'):
target_port = 8080
else:
# Все остальные запросы (включая / и UI assets) идут на порт 3000 (Playground)
target_port = 3000
# Пробуем подключиться к целевому серверу
conn = http.client.HTTPConnection(target_host, target_port, timeout=30)
# Получаем данные запроса для POST/PUT
body = None
if method in ['POST', 'PUT']:
content_length = int(self.headers.get('Content-Length', 0))
body = self.rfile.read(content_length) if content_length > 0 else None
# Копируем все заголовки запроса
headers = {k: v for k, v in self.headers.items()}
# Исправляем Host заголовок
headers['Host'] = f"{target_host}:{target_port}"
# Отправляем запрос на правильный сервер
conn.request(method, self.path, body=body, headers=headers)
# Получаем ответ
response = conn.getresponse()
# Отправляем статус ответа
self.send_response(response.status)
# Копируем все заголовки ответа
for header, value in response.getheaders():
if header.lower() != 'transfer-encoding': # Исключаем заголовок transfer-encoding
self.send_header(header, value)
# Завершаем заголовки
self.end_headers()
# Отправляем тело ответа
chunk_size = 8192
while True:
chunk = response.read(chunk_size)
if not chunk:
break
self.wfile.write(chunk)
# Закрываем соединение
conn.close()
except Exception as e:
print(f"Proxy error for {method} {self.path}: {str(e)}", file=sys.stderr)
# Для запросов мониторинга не показываем ошибку
if self.path == '/?logs=container':
self.send_response(200)
self.send_header('Content-type', 'text/plain')
self.end_headers()
self.wfile.write(b"OK")
return
# Отправляем страницу с ошибкой и разъяснением
self.send_response(500)
self.send_header('Content-type', 'text/html; charset=utf-8')
self.end_headers()
error_message = f"""
<!DOCTYPE html>
<html>
<head>
<title>TEN Agent - Error</title>
<meta charset="utf-8">
<style>
body {{ font-family: Arial, sans-serif; line-height: 1.6; max-width: 800px; margin: 0 auto; padding: 20px; }}
h1 {{ color: #dc3545; }}
.error {{ background: #f8d7da; border-left: 4px solid #dc3545; padding: 15px; margin-bottom: 20px; }}
pre {{ background: #f8f9fa; padding: 10px; border-radius: 5px; overflow-x: auto; }}
</style>
</head>
<body>
<h1>Произошла ошибка при обработке запроса</h1>
<div class="error">
<p><strong>Детали ошибки:</strong> {str(e)}</p>
<p>Целевой порт: {target_port}</p>
</div>
<p>Система пытается запустить все компоненты. Попробуйте обновить страницу через минуту.</p>
</body>
</html>
"""
self.wfile.write(error_message.encode('utf-8'))
# Запускаем HTTP прокси-сервер
port = 7860 # Hugging Face Space ожидает сервер на порту 7860
print(f"Starting proxy server on port {port}...")
# Разрешаем повторное использование адреса и порта
class ReuseAddressServer(socketserver.ThreadingTCPServer):
allow_reuse_address = True
daemon_threads = True
server = ReuseAddressServer(('0.0.0.0', port), ProxyHandler)
# Запускаем сервер
server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True
server_thread.start()
# Продолжаем выполнение, чтобы можно было обработать сигналы остановки
while True:
# Проверяем, что все процессы еще живы
if not api_server_process.poll() is None:
print("API server has stopped, restarting...")
api_server_process = subprocess.Popen([str(api_binary)], env=api_server_env)
processes = [p for p in processes if p != api_server_process]
processes.append(api_server_process)
if not playground_process.poll() is None:
print("Playground UI has stopped, restarting...")
playground_process = subprocess.Popen(
"cd /app/playground && pnpm start",
shell=True,
env=playground_env
)
processes = [p for p in processes if p != playground_process]
processes.append(playground_process)
time.sleep(10)
except KeyboardInterrupt:
print("Shutting down...")
finally:
# Завершаем все процессы при выходе
for proc in processes:
try:
if proc and proc.poll() is None:
proc.terminate()
proc.wait(timeout=5)
except:
if proc and proc.poll() is None:
proc.kill()
# Останавливаем сервер
if 'server' in locals():
server.shutdown()
return 0
if __name__ == "__main__":
# Корректная обработка сигналов завершения
signal.signal(signal.SIGINT, lambda sig, frame: sys.exit(0))
signal.signal(signal.SIGTERM, lambda sig, frame: sys.exit(0))
sys.exit(main()) |