| |
| 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) |