Skip to content

Commit 9de835b

Browse files
committed
feat: add knowledge serve command with HTTP server
1 parent 2aeda41 commit 9de835b

File tree

1 file changed

+94
-0
lines changed
  • src/datapilot/core/knowledge

1 file changed

+94
-0
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,101 @@
11
import click
2+
import json
3+
from http.server import HTTPServer, BaseHTTPRequestHandler
4+
from urllib.parse import urlparse
5+
from urllib.request import Request, urlopen
6+
from urllib.error import URLError, HTTPError
7+
import re
28

39

410
@click.group()
511
def cli():
612
"""knowledge specific commands."""
713

14+
15+
@cli.command()
16+
@click.option('--port', default=3000, help='Port to run the server on')
17+
@click.pass_context
18+
def serve(ctx, port):
19+
"""Serve knowledge bases via HTTP server."""
20+
# Get configuration from parent context
21+
token = ctx.parent.obj.get('token')
22+
instance_name = ctx.parent.obj.get('instance_name')
23+
backend_url = ctx.parent.obj.get('backend_url')
24+
25+
if not token or not instance_name:
26+
click.echo("Error: API token and instance name are required. Use --token and --instance-name options or set them in config.", err=True)
27+
ctx.exit(1)
28+
29+
class KnowledgeBaseHandler(BaseHTTPRequestHandler):
30+
def do_GET(self):
31+
"""Handle GET requests."""
32+
path = urlparse(self.path).path
33+
34+
# Match /knowledge_bases/{uuid} pattern
35+
match = re.match(r'^/knowledge_bases/([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$', path)
36+
37+
if match:
38+
public_id = match.group(1)
39+
self.handle_knowledge_base(public_id)
40+
elif path == '/health':
41+
self.handle_health()
42+
else:
43+
self.send_error(404, "Not Found")
44+
45+
def handle_knowledge_base(self, public_id):
46+
"""Fetch and return knowledge base data."""
47+
url = f"{backend_url}/knowledge_bases/public/{public_id}"
48+
49+
headers = {
50+
'Authorization': f'Bearer {token}',
51+
'X-Tenant': instance_name,
52+
'Content-Type': 'application/json'
53+
}
54+
55+
req = Request(url, headers=headers)
56+
57+
try:
58+
with urlopen(req) as response:
59+
data = response.read()
60+
self.send_response(200)
61+
self.send_header('Content-Type', 'application/json')
62+
self.end_headers()
63+
self.wfile.write(data)
64+
except HTTPError as e:
65+
error_data = e.read().decode('utf-8') if e.read() else '{"error": "HTTP Error"}'
66+
self.send_response(e.code)
67+
self.send_header('Content-Type', 'application/json')
68+
self.end_headers()
69+
self.wfile.write(error_data.encode('utf-8'))
70+
except URLError as e:
71+
self.send_response(500)
72+
self.send_header('Content-Type', 'application/json')
73+
self.end_headers()
74+
error_msg = json.dumps({'error': str(e)})
75+
self.wfile.write(error_msg.encode('utf-8'))
76+
77+
def handle_health(self):
78+
"""Handle health check endpoint."""
79+
self.send_response(200)
80+
self.send_header('Content-Type', 'application/json')
81+
self.end_headers()
82+
self.wfile.write(json.dumps({'status': 'ok'}).encode('utf-8'))
83+
84+
def log_message(self, format, *args):
85+
"""Override to use click.echo for logging."""
86+
click.echo(f"{self.address_string()} - {format % args}")
87+
88+
server_address = ('', port)
89+
httpd = HTTPServer(server_address, KnowledgeBaseHandler)
90+
91+
click.echo(f"Starting knowledge base server on port {port}...")
92+
click.echo(f"Backend URL: {backend_url}")
93+
click.echo(f"Instance: {instance_name}")
94+
click.echo(f"Server running at http://localhost:{port}")
95+
96+
try:
97+
httpd.serve_forever()
98+
except KeyboardInterrupt:
99+
click.echo("\nShutting down server...")
100+
httpd.shutdown()
101+

0 commit comments

Comments
 (0)