|
|
|
import os |
|
import subprocess |
|
import sys |
|
import time |
|
import json |
|
from pathlib import Path |
|
import signal |
|
import threading |
|
import shutil |
|
import http.server |
|
import socketserver |
|
import urllib.request |
|
import urllib.error |
|
|
|
def check_and_create_property_json(): |
|
"""Проверяет наличие property.json и создает его при необходимости""" |
|
property_path = Path("/app/agents/property.json") |
|
|
|
if not property_path.exists(): |
|
print(f"WARNING: {property_path} не найден, создаем файл...") |
|
|
|
property_data = { |
|
"name": "TEN Agent Example", |
|
"version": "0.0.1", |
|
"extensions": ["openai_chatgpt"], |
|
"description": "A basic voice agent with OpenAI", |
|
"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_path.parent.mkdir(parents=True, exist_ok=True) |
|
|
|
|
|
with open(property_path, 'w') as f: |
|
json.dump(property_data, f, indent=2) |
|
|
|
print(f"Файл {property_path} создан успешно") |
|
|
|
|
|
check_and_fix_ten_section() |
|
|
|
def check_and_fix_ten_section(): |
|
"""Проверяет наличие _ten секции во всех JSON файлах и добавляет её если нужно""" |
|
json_files = [ |
|
"/app/agents/voice_agent.json", |
|
"/app/agents/chat_agent.json", |
|
"/app/agents/manifest.json" |
|
] |
|
|
|
for file_path in json_files: |
|
path = Path(file_path) |
|
if path.exists(): |
|
try: |
|
with open(path, 'r') as f: |
|
data = json.load(f) |
|
|
|
|
|
if '_ten' not in data: |
|
print(f"Добавляем _ten секцию в {file_path}") |
|
data['_ten'] = {"version": "0.0.1"} |
|
|
|
|
|
with open(path, 'w') as f: |
|
json.dump(data, f, indent=2) |
|
|
|
print(f"Файл {file_path} обновлен") |
|
except Exception as e: |
|
print(f"Ошибка при обработке файла {file_path}: {e}") |
|
|
|
class ProxyHTTPRequestHandler(http.server.SimpleHTTPRequestHandler): |
|
def do_POST(self): |
|
print(f"Получен запрос: {self.path}") |
|
|
|
|
|
if self.path.startswith('/api/dev/v1/packages/reload') or self.path.startswith('/api/designer/v1/packages/reload'): |
|
try: |
|
print("Перенаправление на /graphs") |
|
with urllib.request.urlopen("http://localhost:8080/graphs") as response: |
|
data = response.read().decode('utf-8') |
|
|
|
|
|
if not data or "Invalid format" in data: |
|
print("Сервер вернул ошибку или пустой ответ, создаем свой ответ") |
|
|
|
property_path = Path("/app/agents/property.json") |
|
if property_path.exists(): |
|
try: |
|
with open(property_path, 'r') as f: |
|
property_data = json.load(f) |
|
graphs = property_data.get("graphs", []) |
|
except Exception as e: |
|
print(f"Ошибка чтения property.json: {e}") |
|
graphs = [] |
|
else: |
|
graphs = [] |
|
|
|
|
|
for graph in graphs: |
|
graph["id"] = graph.get("name", "").lower().replace(" ", "_") |
|
if "file" in graph: |
|
graph["file"] = graph["file"] |
|
else: |
|
try: |
|
|
|
graphs = json.loads(data) |
|
except json.JSONDecodeError: |
|
print(f"Ошибка разбора JSON из ответа сервера: {data}") |
|
graphs = [] |
|
|
|
|
|
formatted_response = { |
|
"data": graphs, |
|
"status": 200, |
|
"message": "Success" |
|
} |
|
|
|
response_data = json.dumps(formatted_response).encode('utf-8') |
|
|
|
|
|
self.send_response(200) |
|
self.send_header('Content-Type', 'application/json') |
|
self.send_header('Content-Length', len(response_data)) |
|
self.send_header('Access-Control-Allow-Origin', '*') |
|
self.end_headers() |
|
self.wfile.write(response_data) |
|
print(f"Отправлен ответ: {response_data.decode('utf-8')}") |
|
except urllib.error.URLError as e: |
|
print(f"Ошибка при перенаправлении: {e}") |
|
|
|
property_path = Path("/app/agents/property.json") |
|
if property_path.exists(): |
|
try: |
|
with open(property_path, 'r') as f: |
|
property_data = json.load(f) |
|
graphs = property_data.get("graphs", []) |
|
except Exception as e: |
|
print(f"Ошибка чтения property.json: {e}") |
|
graphs = [] |
|
else: |
|
graphs = [] |
|
|
|
|
|
for graph in graphs: |
|
graph["id"] = graph.get("name", "").lower().replace(" ", "_") |
|
if "file" in graph: |
|
graph["file"] = graph["file"] |
|
|
|
formatted_response = { |
|
"data": graphs, |
|
"status": 200, |
|
"message": "Success" |
|
} |
|
|
|
response_data = json.dumps(formatted_response).encode('utf-8') |
|
|
|
self.send_response(200) |
|
self.send_header('Content-Type', 'application/json') |
|
self.send_header('Content-Length', len(response_data)) |
|
self.send_header('Access-Control-Allow-Origin', '*') |
|
self.end_headers() |
|
self.wfile.write(response_data) |
|
print(f"Отправлен хардкодный ответ: {response_data.decode('utf-8')}") |
|
else: |
|
self.send_error(404, "Not Found") |
|
|
|
def do_OPTIONS(self): |
|
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 do_GET(self): |
|
print(f"Получен GET запрос: {self.path}") |
|
|
|
|
|
if self.path.startswith('/api/designer/v1/addons/extensions'): |
|
|
|
extensions = [ |
|
{ |
|
"id": "openai_chatgpt", |
|
"name": "OpenAI ChatGPT", |
|
"version": "0.0.1", |
|
"description": "Integration with OpenAI ChatGPT API", |
|
"nodes": [ |
|
{ |
|
"id": "openai_chatgpt", |
|
"name": "OpenAI ChatGPT", |
|
"category": "AI", |
|
"description": "Sends message to OpenAI ChatGPT API" |
|
} |
|
] |
|
} |
|
] |
|
|
|
formatted_response = { |
|
"data": extensions, |
|
"status": 200, |
|
"message": "Success" |
|
} |
|
|
|
response_data = json.dumps(formatted_response).encode('utf-8') |
|
|
|
self.send_response(200) |
|
self.send_header('Content-Type', 'application/json') |
|
self.send_header('Content-Length', len(response_data)) |
|
self.send_header('Access-Control-Allow-Origin', '*') |
|
self.end_headers() |
|
self.wfile.write(response_data) |
|
print(f"Отправлен ответ для extensions: {response_data.decode('utf-8')}") |
|
else: |
|
self.send_error(404, "Not Found") |
|
|
|
def run_proxy_server(): |
|
"""Запускает прокси-сервер на порту 49483""" |
|
handler = ProxyHTTPRequestHandler |
|
httpd = socketserver.TCPServer(("", 49483), handler) |
|
print("Прокси-сервер запущен на порту 49483") |
|
httpd.serve_forever() |
|
|
|
def check_files(): |
|
"""Проверяет и выводит информацию о важных файлах""" |
|
files_to_check = [ |
|
"/app/agents/property.json", |
|
"/app/agents/manifest.json", |
|
"/app/agents/voice_agent.json", |
|
"/app/agents/chat_agent.json", |
|
"/app/server/bin/api" |
|
] |
|
|
|
print("\n=== Проверка критических файлов ===") |
|
for file_path in files_to_check: |
|
path = Path(file_path) |
|
if path.exists(): |
|
if path.is_file(): |
|
size = path.stat().st_size |
|
print(f"✅ {file_path} (размер: {size} байт)") |
|
|
|
|
|
if file_path.endswith('.json'): |
|
try: |
|
with open(file_path, 'r') as f: |
|
content = json.load(f) |
|
print(f" Содержимое: {json.dumps(content, indent=2)}") |
|
except Exception as e: |
|
print(f" Ошибка чтения JSON: {e}") |
|
else: |
|
print(f"❌ {file_path} (это директория, а не файл)") |
|
else: |
|
print(f"❌ {file_path} (файл не найден)") |
|
|
|
print("\n=== Проверка структуры директорий ===") |
|
print("Содержимое /app/agents:") |
|
subprocess.run(["ls", "-la", "/app/agents"]) |
|
|
|
print("\nПроверка прав доступа:") |
|
subprocess.run(["stat", "/app/agents"]) |
|
subprocess.run(["stat", "/app/agents/property.json"]) |
|
|
|
def test_api(): |
|
"""Делает запрос к API для получения списка графов""" |
|
import urllib.request |
|
import urllib.error |
|
|
|
print("\n=== Тестирование API ===") |
|
try: |
|
|
|
time.sleep(3) |
|
with urllib.request.urlopen("http://localhost:8080/graphs") as response: |
|
data = response.read().decode('utf-8') |
|
print(f"Ответ /graphs: {data}") |
|
|
|
|
|
try: |
|
with urllib.request.urlopen("http://localhost:49483/api/designer/v1/packages/reload") as proxy_response: |
|
proxy_data = proxy_response.read().decode('utf-8') |
|
print(f"Ответ от прокси: {proxy_data}") |
|
except urllib.error.URLError as e: |
|
print(f"Ошибка запроса к прокси: {e}") |
|
|
|
except urllib.error.URLError as e: |
|
print(f"Ошибка запроса к API: {e}") |
|
except Exception as e: |
|
print(f"Неизвестная ошибка при запросе к API: {e}") |
|
|
|
def move_json_files_to_right_places(): |
|
"""Копирует JSON файлы в нужные директории для работы с TEN-Agent""" |
|
|
|
print("Создаем правильную структуру директорий для TEN-Agent...") |
|
|
|
target_dirs = [ |
|
"/app/agents", |
|
"/app/agents/examples", |
|
"/app/agents/examples/default", |
|
"/app/agents/extensions" |
|
] |
|
|
|
for dir_path in target_dirs: |
|
os.makedirs(dir_path, exist_ok=True) |
|
|
|
|
|
source_file = "/app/agents/voice_agent.json" |
|
target_file = "/app/agents/examples/voice_agent.json" |
|
if os.path.exists(source_file): |
|
shutil.copy2(source_file, target_file) |
|
print(f"Файл скопирован: {source_file} -> {target_file}") |
|
|
|
|
|
source_file = "/app/agents/chat_agent.json" |
|
target_file = "/app/agents/examples/chat_agent.json" |
|
if os.path.exists(source_file): |
|
shutil.copy2(source_file, target_file) |
|
print(f"Файл скопирован: {source_file} -> {target_file}") |
|
|
|
|
|
property_path = "/app/agents/property.json" |
|
if os.path.exists(property_path): |
|
try: |
|
with open(property_path, 'r') as f: |
|
property_data = json.load(f) |
|
|
|
|
|
for graph in property_data.get("graphs", []): |
|
if "file" in graph: |
|
graph["file"] = f"examples/{graph['file']}" |
|
|
|
|
|
with open(property_path, 'w') as f: |
|
json.dump(property_data, f, indent=2) |
|
|
|
print(f"Файл {property_path} обновлен с правильными путями") |
|
except Exception as e: |
|
print(f"Ошибка при обновлении {property_path}: {e}") |
|
|
|
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 |
|
|
|
|
|
check_and_create_property_json() |
|
|
|
|
|
move_json_files_to_right_places() |
|
|
|
|
|
check_files() |
|
|
|
|
|
print("Starting TEN-Agent API server on port 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_thread = threading.Thread(target=run_proxy_server) |
|
proxy_thread.daemon = True |
|
proxy_thread.start() |
|
|
|
|
|
print("Starting Playground UI in development mode on port 7860...") |
|
os.environ["PORT"] = "7860" |
|
os.environ["AGENT_SERVER_URL"] = "http://localhost:8080" |
|
os.environ["NEXT_PUBLIC_EDIT_GRAPH_MODE"] = "true" |
|
os.environ["NEXT_PUBLIC_DISABLE_CAMERA"] = "true" |
|
|
|
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: |
|
print("Shutting down...") |
|
except Exception as e: |
|
print(f"Error: {e}", file=sys.stderr) |
|
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()) |