| | |
| | import http.server |
| | import json |
| | import os |
| | import sys |
| | import datetime |
| | import traceback |
| | from pathlib import Path |
| |
|
| | |
| | AGENT_DIR = os.environ.get("TEN_AGENT_DIR", "/tmp/ten_user/agents") |
| |
|
| | class TENAgentHandler(http.server.BaseHTTPRequestHandler): |
| | def _set_headers(self, content_type="application/json"): |
| | self.send_response(200) |
| | self.send_header('Content-type', content_type) |
| | 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, X-Requested-With') |
| | self.end_headers() |
| | |
| | def do_OPTIONS(self): |
| | self._set_headers() |
| | |
| | def log_request(self, code='-', size='-'): |
| | |
| | |
| | if self.path != '/health': |
| | super().log_request(code, size) |
| | |
| | def do_GET(self): |
| | try: |
| | print(f"GET request: {self.path}") |
| | |
| | |
| | if self.path in ["/graphs", "/api/graphs"]: |
| | |
| | try: |
| | property_file = Path(AGENT_DIR) / "property.json" |
| | if not property_file.exists(): |
| | print("⚠️ Property file not found at", property_file) |
| | |
| | create_basic_property_file(property_file) |
| | |
| | with open(property_file, "r") as f: |
| | property_data = json.load(f) |
| | |
| | graphs = property_data.get("graphs", []) |
| | print(f"✅ Returning {len(graphs)} graphs from property.json") |
| | print(f"Graphs: {json.dumps(graphs, indent=2)}") |
| | |
| | self._set_headers() |
| | self.wfile.write(json.dumps(graphs).encode()) |
| | except Exception as e: |
| | print(f"Error reading property.json: {e}") |
| | traceback.print_exc() |
| | |
| | |
| | fallback_graphs = [ |
| | { |
| | "name": "Voice Agent (Fallback)", |
| | "description": "Basic voice agent with OpenAI", |
| | "file": "voice_agent.json" |
| | } |
| | ] |
| | self._set_headers() |
| | self.wfile.write(json.dumps(fallback_graphs).encode()) |
| | |
| | elif self.path in ["/health", "/"]: |
| | |
| | self._set_headers() |
| | self.wfile.write(json.dumps({ |
| | "status": "ok", |
| | "time": str(datetime.datetime.now()), |
| | "message": "TEN Agent API wrapper is running" |
| | }).encode()) |
| | |
| | elif self.path == "/list": |
| | |
| | self._set_headers() |
| | self.wfile.write(json.dumps([]).encode()) |
| | |
| | elif self.path.startswith("/dev-tmp/"): |
| | |
| | self._set_headers() |
| | self.wfile.write(json.dumps({}).encode()) |
| | |
| | elif self.path == "/vector/document/preset/list": |
| | |
| | self._set_headers() |
| | self.wfile.write(json.dumps([]).encode()) |
| | |
| | |
| | elif self.path.startswith("/api/designer/") or self.path.startswith("/api/dev/"): |
| | if "/packages/reload" in self.path: |
| | |
| | property_file = Path(AGENT_DIR) / "property.json" |
| | if property_file.exists(): |
| | with open(property_file, "r") as f: |
| | property_data = json.load(f) |
| | |
| | graphs = property_data.get("graphs", []) |
| | response_data = { |
| | "data": graphs, |
| | "status": 200, |
| | "message": "Success" |
| | } |
| | else: |
| | response_data = { |
| | "data": [], |
| | "status": 200, |
| | "message": "Success" |
| | } |
| | |
| | self._set_headers() |
| | self.wfile.write(json.dumps(response_data).encode()) |
| | else: |
| | self._set_headers() |
| | self.wfile.write(json.dumps({"data": [], "status": 200, "message": "Success"}).encode()) |
| | |
| | else: |
| | |
| | self.send_error(404, "Not found") |
| | except Exception as e: |
| | print(f"Error handling GET request: {e}") |
| | traceback.print_exc() |
| | self.send_error(500, f"Internal server error: {e}") |
| | |
| | def do_POST(self): |
| | try: |
| | print(f"POST request: {self.path}") |
| | |
| | |
| | content_length = int(self.headers['Content-Length']) if 'Content-Length' in self.headers else 0 |
| | post_data = self.rfile.read(content_length) |
| | |
| | try: |
| | request_data = json.loads(post_data) if content_length > 0 else {} |
| | except json.JSONDecodeError: |
| | request_data = {} |
| | |
| | print(f"Request data: {request_data}") |
| | |
| | if self.path == "/ping": |
| | |
| | self._set_headers() |
| | self.wfile.write(json.dumps({"status": "ok"}).encode()) |
| | |
| | elif self.path == "/token/generate": |
| | |
| | |
| | self._set_headers() |
| | response = { |
| | "token": "dummy_token_for_agora", |
| | "request_id": request_data.get("RequestId", ""), |
| | "channel_name": request_data.get("ChannelName", ""), |
| | "uid": request_data.get("Uid", 0) |
| | } |
| | self.wfile.write(json.dumps(response).encode()) |
| | |
| | elif self.path == "/start": |
| | |
| | self._set_headers() |
| | |
| | session_id = "fallback-session-" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") |
| | self.wfile.write(json.dumps({ |
| | "status": "ok", |
| | "session_id": session_id |
| | }).encode()) |
| | |
| | elif self.path == "/stop": |
| | |
| | self._set_headers() |
| | self.wfile.write(json.dumps({"status": "ok"}).encode()) |
| | |
| | elif self.path.startswith("/vector/document/"): |
| | |
| | self._set_headers() |
| | self.wfile.write(json.dumps({"status": "ok", "message": "Operation completed"}).encode()) |
| | |
| | |
| | elif self.path.startswith("/api/designer/") or self.path.startswith("/api/dev/"): |
| | self._set_headers() |
| | self.wfile.write(json.dumps({"data": {}, "status": 200, "message": "Success"}).encode()) |
| | |
| | else: |
| | |
| | self.send_error(404, "Not found") |
| | except Exception as e: |
| | print(f"Error handling POST request: {e}") |
| | traceback.print_exc() |
| | self.send_error(500, f"Internal server error: {e}") |
| |
|
| | def create_basic_property_file(filepath): |
| | """Создает базовый property.json файл""" |
| | print(f"Creating basic property.json file at {filepath}") |
| | |
| | |
| | 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" |
| | } |
| | ] |
| | } |
| | |
| | try: |
| | |
| | filepath.parent.mkdir(exist_ok=True, parents=True) |
| | |
| | with open(filepath, "w") as f: |
| | json.dump(property_data, f, indent=2) |
| | print(f"✅ Created property.json at {filepath}") |
| | |
| | |
| | create_basic_graph_files(filepath.parent) |
| | |
| | return True |
| | except Exception as e: |
| | print(f"❌ Error creating property.json: {e}") |
| | traceback.print_exc() |
| | return False |
| |
|
| | def create_basic_graph_files(dir_path): |
| | """Создает базовые файлы графов""" |
| | print(f"Creating basic graph files in {dir_path}") |
| | |
| | |
| | voice_agent = { |
| | "_ten": {"version": "0.0.1"}, |
| | "nodes": [ |
| | { |
| | "id": "start", |
| | "type": "start", |
| | "data": {"x": 100, "y": 100} |
| | }, |
| | { |
| | "id": "openai_chatgpt", |
| | "type": "openai_chatgpt", |
| | "data": { |
| | "x": 300, |
| | "y": 200, |
| | "properties": { |
| | "model": "gpt-3.5-turbo", |
| | "temperature": 0.7, |
| | "system_prompt": "You are a helpful assistant." |
| | } |
| | } |
| | }, |
| | { |
| | "id": "end", |
| | "type": "end", |
| | "data": {"x": 500, "y": 100} |
| | } |
| | ], |
| | "edges": [ |
| | { |
| | "id": "start_to_chatgpt", |
| | "source": "start", |
| | "target": "openai_chatgpt" |
| | }, |
| | { |
| | "id": "chatgpt_to_end", |
| | "source": "openai_chatgpt", |
| | "target": "end" |
| | } |
| | ], |
| | "groups": [], |
| | "templates": [], |
| | "root": "start" |
| | } |
| | |
| | try: |
| | with open(dir_path / "voice_agent.json", "w") as f: |
| | json.dump(voice_agent, f, indent=2) |
| | print(f"✅ Created voice_agent.json") |
| | |
| | |
| | chat_agent = dict(voice_agent) |
| | chat_agent["nodes"][1]["data"]["properties"]["system_prompt"] = "You are a helpful chat assistant." |
| | |
| | with open(dir_path / "chat_agent.json", "w") as f: |
| | json.dump(chat_agent, f, indent=2) |
| | print(f"✅ Created chat_agent.json") |
| | |
| | |
| | manifest = { |
| | "_ten": {"version": "0.0.1"}, |
| | "name": "default", |
| | "agents": [ |
| | { |
| | "name": "voice_agent", |
| | "description": "A simple voice agent", |
| | "type": "voice" |
| | }, |
| | { |
| | "name": "chat_agent", |
| | "description": "A text chat agent", |
| | "type": "chat" |
| | } |
| | ] |
| | } |
| | |
| | with open(dir_path / "manifest.json", "w") as f: |
| | json.dump(manifest, f, indent=2) |
| | print(f"✅ Created manifest.json") |
| | |
| | return True |
| | except Exception as e: |
| | print(f"❌ Error creating graph files: {e}") |
| | traceback.print_exc() |
| | return False |
| |
|
| | def run(server_class=http.server.HTTPServer, handler_class=TENAgentHandler, port=8080): |
| | server_address = ('', port) |
| | httpd = server_class(server_address, handler_class) |
| | print(f"Starting API server on port {port}...") |
| | print(f"Using agent directory: {AGENT_DIR}") |
| | |
| | |
| | agent_dir_path = Path(AGENT_DIR) |
| | if not agent_dir_path.exists(): |
| | print(f"WARNING: Agent directory {AGENT_DIR} does not exist, creating it...") |
| | agent_dir_path.mkdir(exist_ok=True, parents=True) |
| | |
| | |
| | property_file = agent_dir_path / "property.json" |
| | if not property_file.exists(): |
| | print(f"WARNING: property.json not found in {AGENT_DIR}") |
| | create_basic_property_file(property_file) |
| | else: |
| | print(f"✅ Using existing property.json at {property_file}") |
| | |
| | try: |
| | with open(property_file, "r") as f: |
| | property_data = json.load(f) |
| | print(f"Property.json content: {json.dumps(property_data, indent=2)}") |
| | except Exception as e: |
| | print(f"Error reading property.json: {e}") |
| | |
| | try: |
| | print(f"✅ API server is ready to receive requests!") |
| | httpd.serve_forever() |
| | except KeyboardInterrupt: |
| | print("Shutting down API server...") |
| | except Exception as e: |
| | print(f"Error in API server: {e}") |
| | traceback.print_exc() |
| |
|
| | if __name__ == "__main__": |
| | port = int(os.environ.get("API_PORT", 8080)) |
| | run(port=port) |