|
|
|
import os |
|
import subprocess |
|
import sys |
|
import time |
|
import json |
|
from pathlib import Path |
|
import signal |
|
import threading |
|
import shutil |
|
import logging |
|
import urllib.request |
|
import urllib.error |
|
import tempfile |
|
import http.server |
|
import socketserver |
|
from typing import Dict, Any, Optional, Union |
|
|
|
|
|
logging.basicConfig(level=logging.INFO, |
|
format='%(asctime)s [%(levelname)s] %(message)s', |
|
datefmt='%Y-%m-%d %H:%M:%S') |
|
|
|
logger = logging.getLogger('ten-agent') |
|
|
|
|
|
AGENTS_DIR = Path("/app/agents") |
|
PROPERTY_JSON = AGENTS_DIR / "property.json" |
|
MANIFEST_JSON = AGENTS_DIR / "manifest.json" |
|
VOICE_AGENT_JSON = AGENTS_DIR / "voice_agent.json" |
|
CHAT_AGENT_JSON = AGENTS_DIR / "chat_agent.json" |
|
API_BINARY = Path("/app/server/bin/api") |
|
PLAYGROUND_DIR = Path("/app/playground") |
|
BACKUP_DIR = Path("/app/backup") |
|
|
|
|
|
PROXY_PORT = 9090 |
|
API_PORT = 8080 |
|
|
|
def ensure_directory_permissions(directory_path): |
|
"""Обеспечиваем правильные разрешения для директории""" |
|
directory = Path(directory_path) |
|
if not directory.exists(): |
|
logger.info(f"Создание директории {directory}") |
|
directory.mkdir(parents=True, exist_ok=True) |
|
|
|
|
|
subprocess.run(["chmod", "-R", "777", str(directory)]) |
|
logger.info(f"Права доступа для {directory} установлены") |
|
|
|
def backup_file(filepath): |
|
"""Создает резервную копию файла""" |
|
src_path = Path(filepath) |
|
if not src_path.exists(): |
|
logger.warning(f"Невозможно создать резервную копию: {filepath} не существует") |
|
return |
|
|
|
BACKUP_DIR.mkdir(parents=True, exist_ok=True) |
|
dest_path = BACKUP_DIR / f"{src_path.name}.bak" |
|
|
|
try: |
|
shutil.copy2(src_path, dest_path) |
|
logger.info(f"Резервная копия создана: {dest_path}") |
|
except Exception as e: |
|
logger.error(f"Ошибка при создании резервной копии {filepath}: {e}") |
|
|
|
def update_property_json(): |
|
"""Проверяет существующий property.json и добавляет поле predefined_graphs, если его нет""" |
|
if not PROPERTY_JSON.exists(): |
|
logger.info(f"{PROPERTY_JSON} не существует, нет необходимости в обновлении") |
|
return False |
|
|
|
try: |
|
with open(PROPERTY_JSON, 'r') as f: |
|
data = json.load(f) |
|
|
|
need_update = False |
|
|
|
|
|
if "predefined_graphs" not in data: |
|
logger.info(f"{PROPERTY_JSON} не содержит поле predefined_graphs") |
|
need_update = True |
|
elif not isinstance(data["predefined_graphs"], list): |
|
logger.warning(f"{PROPERTY_JSON} содержит predefined_graphs, но это не массив") |
|
need_update = True |
|
|
|
if not need_update: |
|
logger.info(f"{PROPERTY_JSON} уже содержит корректное поле predefined_graphs") |
|
return False |
|
|
|
|
|
backup_file(PROPERTY_JSON) |
|
|
|
|
|
property_data = { |
|
"_ten": {}, |
|
"name": "TEN Agent Example", |
|
"version": "0.0.1", |
|
"extensions": ["openai_chatgpt"], |
|
"description": "A basic voice agent with OpenAI", |
|
"predefined_graphs": [ |
|
{ |
|
"name": "Voice Agent", |
|
"description": "Basic voice agent with OpenAI", |
|
"file": "voice_agent.json" |
|
}, |
|
{ |
|
"name": "Chat Agent", |
|
"description": "Simple chat agent", |
|
"file": "chat_agent.json" |
|
} |
|
] |
|
} |
|
|
|
|
|
for key, value in data.items(): |
|
if key not in property_data and key != "predefined_graphs" and key != "graphs": |
|
property_data[key] = value |
|
|
|
|
|
property_data["graphs"] = property_data["predefined_graphs"] |
|
|
|
|
|
with open(PROPERTY_JSON, 'w') as f: |
|
json.dump(property_data, f, indent=2) |
|
|
|
logger.info(f"{PROPERTY_JSON} успешно обновлен с корректным полем predefined_graphs") |
|
return True |
|
except Exception as e: |
|
logger.error(f"Ошибка при обновлении {PROPERTY_JSON}: {e}") |
|
return False |
|
|
|
def check_and_create_property_json(): |
|
"""Проверяет наличие property.json и создает его при необходимости""" |
|
if not PROPERTY_JSON.exists(): |
|
logger.warning(f"{PROPERTY_JSON} не найден, создаем файл...") |
|
|
|
property_data = { |
|
"_ten": {}, |
|
"name": "TEN Agent Example", |
|
"version": "0.0.1", |
|
"extensions": ["openai_chatgpt"], |
|
"description": "A basic voice agent with OpenAI", |
|
"predefined_graphs": [ |
|
{ |
|
"name": "Voice Agent", |
|
"description": "Basic voice agent with OpenAI", |
|
"file": "voice_agent.json" |
|
}, |
|
{ |
|
"name": "Chat Agent", |
|
"description": "Simple chat agent", |
|
"file": "chat_agent.json" |
|
} |
|
], |
|
"graphs": [ |
|
{ |
|
"name": "Voice Agent", |
|
"description": "Basic voice agent with OpenAI", |
|
"file": "voice_agent.json" |
|
}, |
|
{ |
|
"name": "Chat Agent", |
|
"description": "Simple chat agent", |
|
"file": "chat_agent.json" |
|
} |
|
] |
|
} |
|
|
|
|
|
PROPERTY_JSON.parent.mkdir(parents=True, exist_ok=True) |
|
|
|
|
|
with tempfile.NamedTemporaryFile(mode='w', delete=False) as temp_file: |
|
json.dump(property_data, temp_file, indent=2) |
|
temp_path = temp_file.name |
|
|
|
|
|
try: |
|
shutil.copy2(temp_path, PROPERTY_JSON) |
|
os.chmod(PROPERTY_JSON, 0o666) |
|
logger.info(f"Файл {PROPERTY_JSON} создан успешно") |
|
except Exception as e: |
|
logger.error(f"Ошибка при создании {PROPERTY_JSON}: {e}") |
|
finally: |
|
os.unlink(temp_path) |
|
|
|
def check_and_create_agent_files(): |
|
"""Проверяет наличие всех необходимых файлов агентов и создает их при необходимости""" |
|
|
|
|
|
if not MANIFEST_JSON.exists(): |
|
manifest_data = { |
|
"name": "default", |
|
"agents": [ |
|
{ |
|
"name": "voice_agent", |
|
"description": "A simple voice agent" |
|
}, |
|
{ |
|
"name": "chat_agent", |
|
"description": "A text chat agent" |
|
} |
|
] |
|
} |
|
|
|
with open(MANIFEST_JSON, 'w') as f: |
|
json.dump(manifest_data, f, indent=2) |
|
os.chmod(MANIFEST_JSON, 0o666) |
|
logger.info(f"Файл {MANIFEST_JSON} создан") |
|
|
|
|
|
if not VOICE_AGENT_JSON.exists(): |
|
voice_agent_data = { |
|
"nodes": [], |
|
"edges": [], |
|
"groups": [], |
|
"templates": [], |
|
"root": None |
|
} |
|
|
|
with open(VOICE_AGENT_JSON, 'w') as f: |
|
json.dump(voice_agent_data, f, indent=2) |
|
os.chmod(VOICE_AGENT_JSON, 0o666) |
|
logger.info(f"Файл {VOICE_AGENT_JSON} создан") |
|
|
|
|
|
if not CHAT_AGENT_JSON.exists(): |
|
chat_agent_data = { |
|
"nodes": [], |
|
"edges": [], |
|
"groups": [], |
|
"templates": [], |
|
"root": None |
|
} |
|
|
|
with open(CHAT_AGENT_JSON, 'w') as f: |
|
json.dump(chat_agent_data, f, indent=2) |
|
os.chmod(CHAT_AGENT_JSON, 0o666) |
|
logger.info(f"Файл {CHAT_AGENT_JSON} создан") |
|
|
|
def check_files(): |
|
"""Проверяет и выводит информацию о важных файлах""" |
|
files_to_check = [ |
|
PROPERTY_JSON, |
|
MANIFEST_JSON, |
|
VOICE_AGENT_JSON, |
|
CHAT_AGENT_JSON, |
|
API_BINARY |
|
] |
|
|
|
logger.info("=== Проверка критических файлов ===") |
|
for file_path in files_to_check: |
|
path = Path(file_path) |
|
if path.exists(): |
|
if path.is_file(): |
|
size = path.stat().st_size |
|
logger.info(f"✅ {file_path} (размер: {size} байт)") |
|
|
|
|
|
if str(file_path).endswith('.json'): |
|
try: |
|
with open(file_path, 'r') as f: |
|
content = json.load(f) |
|
logger.info(f" Содержимое: {json.dumps(content, indent=2)}") |
|
except Exception as e: |
|
logger.error(f" Ошибка чтения JSON: {e}") |
|
else: |
|
logger.warning(f"❌ {file_path} (это директория, а не файл)") |
|
else: |
|
logger.error(f"❌ {file_path} (файл не найден)") |
|
|
|
logger.info("=== Проверка структуры директорий ===") |
|
logger.info(f"Содержимое {AGENTS_DIR}:") |
|
subprocess.run(["ls", "-la", str(AGENTS_DIR)]) |
|
|
|
logger.info("Проверка прав доступа:") |
|
subprocess.run(["stat", str(AGENTS_DIR)]) |
|
subprocess.run(["stat", str(PROPERTY_JSON)]) |
|
|
|
def analyze_api_response(response_data): |
|
"""Анализирует ответ API и выводит диагностическую информацию""" |
|
try: |
|
|
|
if not response_data or response_data.strip() == "": |
|
logger.error("API вернул пустой ответ") |
|
return None |
|
|
|
json_data = json.loads(response_data) |
|
|
|
|
|
if isinstance(json_data, list): |
|
logger.info(f"API вернул список с {len(json_data)} элементами") |
|
if len(json_data) > 0: |
|
logger.info(f"Структура первого элемента: {json.dumps(json_data[0], indent=2)}") |
|
return json_data |
|
elif isinstance(json_data, dict): |
|
logger.info(f"API вернул словарь с ключами: {list(json_data.keys())}") |
|
|
|
if "code" in json_data: |
|
logger.error(f"API вернул ошибку с кодом: {json_data['code']}") |
|
if "msg" in json_data: |
|
logger.error(f"Сообщение ошибки: {json_data['msg']}") |
|
return json_data |
|
else: |
|
logger.warning(f"API вернул неожиданный тип данных: {type(json_data)}") |
|
return json_data |
|
except json.JSONDecodeError as e: |
|
logger.error(f"Ошибка декодирования JSON: {e}") |
|
logger.error(f"Сырые данные: {response_data}") |
|
return None |
|
except Exception as e: |
|
logger.error(f"Ошибка при анализе ответа API: {e}") |
|
return None |
|
|
|
def test_api(): |
|
"""Делает запрос к API для получения списка графов""" |
|
logger.info("=== Тестирование API ===") |
|
try: |
|
|
|
time.sleep(3) |
|
|
|
|
|
try: |
|
proxy_url = f"http://localhost:{PROXY_PORT}/graphs" |
|
logger.info(f"Проверка прокси-сервера по адресу: {proxy_url}") |
|
with urllib.request.urlopen(proxy_url) as response: |
|
data = response.read().decode('utf-8') |
|
logger.info(f"Ответ прокси-сервера: {data}") |
|
json_data = analyze_api_response(data) |
|
if json_data and isinstance(json_data, list) and len(json_data) > 0: |
|
logger.info("Прокси-сервер возвращает корректные данные о графах") |
|
return |
|
except Exception as e: |
|
logger.warning(f"Ошибка при проверке прокси-сервера: {e}") |
|
|
|
|
|
with urllib.request.urlopen("http://localhost:8080/graphs") as response: |
|
data = response.read().decode('utf-8') |
|
logger.info(f"Ответ /graphs: {data}") |
|
|
|
|
|
json_data = analyze_api_response(data) |
|
|
|
|
|
if json_data is None: |
|
logger.error("Не удалось проанализировать ответ API") |
|
|
|
generate_fresh_property_json() |
|
restart_api_server() |
|
elif isinstance(json_data, list): |
|
if len(json_data) > 0: |
|
logger.info(f"API вернул {len(json_data)} графов") |
|
else: |
|
logger.warning("API вернул пустой список графов") |
|
|
|
if PROPERTY_JSON.exists(): |
|
logger.info("Пробуем обновить существующий property.json...") |
|
if update_property_json(): |
|
restart_api_server() |
|
elif isinstance(json_data, dict) and "code" in json_data: |
|
logger.warning("API вернул ошибку, исправляем property.json") |
|
generate_fresh_property_json() |
|
restart_api_server() |
|
except urllib.error.URLError as e: |
|
logger.error(f"Ошибка запроса к API: {e}") |
|
except Exception as e: |
|
logger.error(f"Неизвестная ошибка при запросе к API: {e}") |
|
|
|
def generate_fresh_property_json(): |
|
"""Создает полностью новый property.json с оптимальной структурой""" |
|
logger.info("Создание нового property.json с оптимальной структурой") |
|
|
|
|
|
if PROPERTY_JSON.exists(): |
|
backup_file(PROPERTY_JSON) |
|
|
|
|
|
property_data = { |
|
"_ten": {}, |
|
"name": "TEN Agent Example", |
|
"version": "0.0.1", |
|
"extensions": ["openai_chatgpt"], |
|
"description": "A basic voice agent with OpenAI", |
|
"predefined_graphs": [ |
|
{ |
|
"name": "Voice Agent", |
|
"description": "Basic voice agent with OpenAI", |
|
"file": "voice_agent.json" |
|
}, |
|
{ |
|
"name": "Chat Agent", |
|
"description": "Simple chat agent", |
|
"file": "chat_agent.json" |
|
} |
|
], |
|
"graphs": [ |
|
{ |
|
"name": "Voice Agent", |
|
"description": "Basic voice agent with OpenAI", |
|
"file": "voice_agent.json" |
|
}, |
|
{ |
|
"name": "Chat Agent", |
|
"description": "Simple chat agent", |
|
"file": "chat_agent.json" |
|
} |
|
] |
|
} |
|
|
|
|
|
with tempfile.NamedTemporaryFile(mode='w', delete=False) as temp_file: |
|
json.dump(property_data, temp_file, indent=2) |
|
temp_path = temp_file.name |
|
|
|
|
|
try: |
|
shutil.copy2(temp_path, PROPERTY_JSON) |
|
try: |
|
os.chmod(PROPERTY_JSON, 0o666) |
|
except Exception as e: |
|
logger.warning(f"Невозможно изменить права доступа для {PROPERTY_JSON}: {e}") |
|
logger.info(f"Новый файл {PROPERTY_JSON} создан успешно") |
|
except Exception as e: |
|
logger.error(f"Ошибка при создании {PROPERTY_JSON}: {e}") |
|
finally: |
|
os.unlink(temp_path) |
|
|
|
def restart_api_server(): |
|
"""Перезапускает API сервер""" |
|
logger.info("Перезапускаем API сервер...") |
|
|
|
|
|
try: |
|
subprocess.run(["pkill", "-f", str(API_BINARY)]) |
|
time.sleep(1) |
|
except Exception as e: |
|
logger.warning(f"Ошибка при остановке API сервера: {e}") |
|
|
|
|
|
try: |
|
new_process = subprocess.Popen([str(API_BINARY)]) |
|
logger.info("API сервер успешно перезапущен") |
|
time.sleep(2) |
|
return new_process |
|
except Exception as e: |
|
logger.error(f"Ошибка при запуске API сервера: {e}") |
|
return None |
|
|
|
def run_simple_proxy(): |
|
"""Запускает встроенный прокси-сервер""" |
|
import http.server |
|
import socketserver |
|
import json |
|
|
|
|
|
GRAPHS_DATA = [ |
|
{ |
|
"name": "Voice Agent", |
|
"description": "Voice Agent with OpenAI", |
|
"file": "voice_agent.json", |
|
"id": "voice_agent", |
|
"package": "default" |
|
}, |
|
{ |
|
"name": "Chat Agent", |
|
"description": "Chat Agent", |
|
"file": "chat_agent.json", |
|
"id": "chat_agent", |
|
"package": "default" |
|
} |
|
] |
|
|
|
|
|
DESIGNER_DATA = { |
|
"success": True, |
|
"packages": [ |
|
{ |
|
"name": "default", |
|
"description": "Default package", |
|
"graphs": [ |
|
{ |
|
"name": "Voice Agent", |
|
"description": "Voice Agent with OpenAI", |
|
"file": "voice_agent.json", |
|
"id": "voice_agent", |
|
"package": "default" |
|
}, |
|
{ |
|
"name": "Chat Agent", |
|
"description": "Chat Agent", |
|
"file": "chat_agent.json", |
|
"id": "chat_agent", |
|
"package": "default" |
|
} |
|
] |
|
} |
|
] |
|
} |
|
|
|
class SimpleProxyHandler(http.server.BaseHTTPRequestHandler): |
|
def do_GET(self): |
|
logger.info(f"PROXY: GET запрос: {self.path}") |
|
|
|
|
|
if self.path == "/graphs": |
|
logger.info("PROXY: Возвращаем заготовленные данные о графах") |
|
self._send_response(200, json.dumps(GRAPHS_DATA)) |
|
return |
|
|
|
|
|
if self.path.startswith("/api/designer/") or self.path.startswith("/api/dev/"): |
|
logger.info(f"PROXY: Обработка запроса к Designer API: {self.path}") |
|
self._send_response(200, json.dumps(DESIGNER_DATA)) |
|
return |
|
|
|
|
|
try: |
|
self._proxy_to_api("GET") |
|
except Exception as e: |
|
logger.error(f"PROXY: Ошибка при проксировании GET запроса: {e}") |
|
|
|
self._send_response(200, json.dumps({"success": True})) |
|
|
|
def do_POST(self): |
|
logger.info(f"PROXY: POST запрос: {self.path}") |
|
|
|
|
|
if self.path.startswith("/api/designer/") or self.path.startswith("/api/dev/"): |
|
logger.info(f"PROXY: Обработка POST запроса к Designer API: {self.path}") |
|
self._send_response(200, json.dumps({"success": True})) |
|
return |
|
|
|
|
|
try: |
|
self._proxy_to_api("POST") |
|
except Exception as e: |
|
logger.error(f"PROXY: Ошибка при проксировании POST запроса: {e}") |
|
|
|
self._send_response(200, json.dumps({"success": True})) |
|
|
|
def do_OPTIONS(self): |
|
logger.info(f"PROXY: OPTIONS запрос: {self.path}") |
|
self.send_response(200) |
|
self.send_header('Access-Control-Allow-Origin', '*') |
|
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS') |
|
self.send_header('Access-Control-Allow-Headers', 'Content-Type') |
|
self.end_headers() |
|
|
|
def _proxy_to_api(self, method): |
|
"""Проксирует запрос к API серверу""" |
|
url = f"http://localhost:{API_PORT}{self.path}" |
|
logger.info(f"PROXY: Проксирование запроса к API: {url}") |
|
|
|
req = urllib.request.Request(url, method=method) |
|
|
|
|
|
for header, value in self.headers.items(): |
|
if header.lower() not in ["host", "content-length"]: |
|
req.add_header(header, value) |
|
|
|
|
|
if method == "POST": |
|
content_length = int(self.headers.get('Content-Length', 0)) |
|
body = self.rfile.read(content_length) |
|
req.data = body |
|
|
|
|
|
with urllib.request.urlopen(req) as response: |
|
|
|
self.send_response(response.status) |
|
|
|
|
|
for header, value in response.getheaders(): |
|
if header.lower() != "transfer-encoding": |
|
self.send_header(header, value) |
|
|
|
|
|
self.send_header('Access-Control-Allow-Origin', '*') |
|
self.end_headers() |
|
|
|
|
|
self.wfile.write(response.read()) |
|
|
|
def _send_response(self, status_code, data): |
|
"""Отправляет ответ с указанным статусом и данными""" |
|
self.send_response(status_code) |
|
self.send_header('Content-Type', 'application/json') |
|
self.send_header('Access-Control-Allow-Origin', '*') |
|
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS') |
|
self.send_header('Access-Control-Allow-Headers', 'Content-Type') |
|
self.end_headers() |
|
|
|
if isinstance(data, str): |
|
self.wfile.write(data.encode('utf-8')) |
|
else: |
|
self.wfile.write(data) |
|
|
|
def log_message(self, format, *args): |
|
"""Перенаправляем логи сервера в наш логгер""" |
|
logger.debug(f"PROXY: {self.address_string()} - {format % args}") |
|
|
|
|
|
try: |
|
|
|
try: |
|
server = socketserver.TCPServer(("", PROXY_PORT), SimpleProxyHandler) |
|
logger.info(f"Встроенный прокси-сервер успешно запущен на порту {PROXY_PORT}") |
|
server.serve_forever() |
|
except OSError as e: |
|
|
|
alt_port = PROXY_PORT + 1 |
|
logger.warning(f"Не удалось запустить прокси на порту {PROXY_PORT}, пробуем порт {alt_port}") |
|
try: |
|
server = socketserver.TCPServer(("", alt_port), SimpleProxyHandler) |
|
logger.info(f"Встроенный прокси-сервер успешно запущен на порту {alt_port}") |
|
|
|
os.environ["NEXT_PUBLIC_DESIGNER_API_URL"] = f"http://localhost:{alt_port}" |
|
os.environ["AGENT_SERVER_URL"] = f"http://localhost:{alt_port}" |
|
server.serve_forever() |
|
except Exception as inner_e: |
|
logger.error(f"Не удалось запустить прокси-сервер даже на альтернативном порту: {inner_e}") |
|
|
|
try: |
|
server = socketserver.TCPServer(("", 0), SimpleProxyHandler) |
|
_, dynamic_port = server.server_address |
|
logger.info(f"Встроенный прокси-сервер успешно запущен на динамическом порту {dynamic_port}") |
|
|
|
os.environ["NEXT_PUBLIC_DESIGNER_API_URL"] = f"http://localhost:{dynamic_port}" |
|
os.environ["AGENT_SERVER_URL"] = f"http://localhost:{dynamic_port}" |
|
server.serve_forever() |
|
except Exception as last_e: |
|
logger.error(f"Все попытки запустить прокси-сервер не удались: {last_e}") |
|
|
|
return |
|
except Exception as e: |
|
logger.error(f"Критическая ошибка в прокси-сервере: {e}") |
|
|
|
def main(): |
|
processes = [] |
|
try: |
|
|
|
if not API_BINARY.exists(): |
|
logger.error(f"API binary не найден: {API_BINARY}") |
|
return 1 |
|
|
|
if not PLAYGROUND_DIR.exists(): |
|
logger.error(f"Playground директория не найдена: {PLAYGROUND_DIR}") |
|
return 1 |
|
|
|
|
|
tmp_files_script = Path(__file__).parent / "create_tmp_agents.sh" |
|
if tmp_files_script.exists(): |
|
logger.info(f"Запуск скрипта создания временных файлов: {tmp_files_script}") |
|
try: |
|
os.chmod(tmp_files_script, 0o755) |
|
subprocess.run(["bash", str(tmp_files_script)]) |
|
logger.info("Скрипт создания временных файлов успешно выполнен") |
|
except Exception as e: |
|
logger.error(f"Ошибка при запуске скрипта создания временных файлов: {e}") |
|
else: |
|
logger.warning(f"Скрипт {tmp_files_script} не найден") |
|
|
|
|
|
ensure_directory_permissions(AGENTS_DIR) |
|
ensure_directory_permissions(BACKUP_DIR) |
|
|
|
|
|
check_and_create_property_json() |
|
|
|
|
|
update_property_json() |
|
|
|
|
|
check_and_create_agent_files() |
|
|
|
|
|
check_files() |
|
|
|
|
|
logger.info("Запуск TEN-Agent API сервера на порту 8080...") |
|
api_process = subprocess.Popen([str(API_BINARY)]) |
|
processes.append(api_process) |
|
|
|
|
|
test_thread = threading.Thread(target=test_api) |
|
test_thread.daemon = True |
|
test_thread.start() |
|
|
|
|
|
proxy_script = Path(__file__).parent / "proxy_server.py" |
|
logger.info(f"Проверка наличия прокси-сервера по пути: {proxy_script}") |
|
|
|
|
|
autonomous_proxy_script = Path(__file__).parent / "start_proxy.sh" |
|
try: |
|
if autonomous_proxy_script.exists(): |
|
logger.info(f"Запуск автономного прокси-сервера через: {autonomous_proxy_script}") |
|
os.chmod(autonomous_proxy_script, 0o755) |
|
proxy_process = subprocess.Popen(["bash", str(autonomous_proxy_script)]) |
|
processes.append(proxy_process) |
|
logger.info("Автономный прокси-сервер запущен") |
|
else: |
|
logger.warning(f"Скрипт {autonomous_proxy_script} не найден") |
|
except Exception as e: |
|
logger.error(f"Ошибка при запуске автономного прокси-сервера: {e}") |
|
|
|
|
|
|
|
if proxy_script.exists(): |
|
logger.info(f"Найден файл прокси-сервера: {proxy_script}") |
|
proxy_process = subprocess.Popen([sys.executable, str(proxy_script)], env=dict(os.environ, PROXY_PORT=str(PROXY_PORT))) |
|
processes.append(proxy_process) |
|
else: |
|
|
|
alt_path = Path("./proxy_server.py") |
|
logger.info(f"Поиск альтернативного пути: {alt_path}") |
|
if alt_path.exists(): |
|
logger.info(f"Найден файл прокси-сервера по альтернативному пути: {alt_path}") |
|
proxy_process = subprocess.Popen([sys.executable, str(alt_path)], env=dict(os.environ, PROXY_PORT=str(PROXY_PORT))) |
|
processes.append(proxy_process) |
|
else: |
|
|
|
try: |
|
logger.info("Попытка запуска proxy_server.py через subprocess...") |
|
proxy_process = subprocess.Popen([sys.executable, "-m", "proxy_server"], env=dict(os.environ, PROXY_PORT=str(PROXY_PORT))) |
|
processes.append(proxy_process) |
|
logger.info("Прокси-сервер запущен через модуль") |
|
except Exception as e: |
|
logger.warning(f"Не удалось запустить прокси-сервер через модуль: {e}") |
|
|
|
|
|
logger.info("Создание встроенного прокси-сервера...") |
|
|
|
try: |
|
|
|
proxy_thread = threading.Thread(target=run_simple_proxy) |
|
proxy_thread.daemon = True |
|
proxy_thread.start() |
|
logger.info(f"Встроенный прокси-сервер запущен на порту {PROXY_PORT}") |
|
except Exception as e: |
|
logger.error(f"Серьезная ошибка при запуске встроенного прокси-сервера: {e}") |
|
|
|
|
|
|
|
os.environ["PORT"] = "7860" |
|
os.environ["AGENT_SERVER_URL"] = f"http://localhost:{PROXY_PORT}" |
|
os.environ["NEXT_PUBLIC_EDIT_GRAPH_MODE"] = "true" |
|
os.environ["NEXT_PUBLIC_DISABLE_CAMERA"] = "true" |
|
|
|
|
|
os.environ["NEXT_PUBLIC_DEV_MODE"] = "false" |
|
os.environ["NEXT_PUBLIC_API_BASE_URL"] = "/api/agents" |
|
os.environ["NEXT_PUBLIC_DESIGNER_API_URL"] = f"http://localhost:{PROXY_PORT}" |
|
|
|
|
|
playground_process = subprocess.Popen( |
|
["pnpm", "dev"], |
|
cwd=str(PLAYGROUND_DIR), |
|
env=os.environ |
|
) |
|
processes.append(playground_process) |
|
|
|
|
|
for proc in processes: |
|
proc.wait() |
|
|
|
except KeyboardInterrupt: |
|
logger.info("Завершение работы...") |
|
except Exception as e: |
|
logger.error(f"Ошибка: {e}") |
|
finally: |
|
|
|
for proc in processes: |
|
if proc and proc.poll() is None: |
|
proc.terminate() |
|
try: |
|
proc.wait(timeout=5) |
|
except subprocess.TimeoutExpired: |
|
proc.kill() |
|
|
|
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()) |