atlasbot: add internal endpoint and portal wiring
This commit is contained in:
parent
689bf10995
commit
c8662a624e
@ -28,6 +28,7 @@ spec:
|
||||
{{ with secret "kv/data/atlas/shared/chat-ai-keys-runtime" }}
|
||||
export CHAT_KEY_MATRIX="{{ .Data.data.matrix }}"
|
||||
export CHAT_KEY_HOMEPAGE="{{ .Data.data.homepage }}"
|
||||
export AI_ATLASBOT_TOKEN="{{ .Data.data.homepage }}"
|
||||
{{ end }}
|
||||
{{ with secret "kv/data/atlas/shared/portal-e2e-client" }}
|
||||
export PORTAL_E2E_CLIENT_ID="{{ .Data.data.client_id }}"
|
||||
@ -66,6 +67,10 @@ spec:
|
||||
value: qwen2.5-coder:7b-instruct-q4_0
|
||||
- name: AI_CHAT_TIMEOUT_SEC
|
||||
value: "480"
|
||||
- name: AI_ATLASBOT_ENDPOINT
|
||||
value: http://atlasbot.comms.svc.cluster.local:8090/v1/answer
|
||||
- name: AI_ATLASBOT_TIMEOUT_SEC
|
||||
value: "5"
|
||||
- name: AI_NODE_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
|
||||
@ -16,7 +16,7 @@ spec:
|
||||
labels:
|
||||
app: atlasbot
|
||||
annotations:
|
||||
checksum/atlasbot-configmap: manual-atlasbot-24
|
||||
checksum/atlasbot-configmap: manual-atlasbot-25
|
||||
vault.hashicorp.com/agent-inject: "true"
|
||||
vault.hashicorp.com/role: "comms"
|
||||
vault.hashicorp.com/agent-inject-secret-turn-secret: "kv/data/atlas/comms/turn-shared-secret"
|
||||
@ -87,6 +87,11 @@ spec:
|
||||
value: "480"
|
||||
- name: ATLASBOT_THINKING_INTERVAL_SEC
|
||||
value: "120"
|
||||
- name: ATLASBOT_HTTP_PORT
|
||||
value: "8090"
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8090
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
|
||||
15
services/comms/atlasbot-service.yaml
Normal file
15
services/comms/atlasbot-service.yaml
Normal file
@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: atlasbot
|
||||
namespace: comms
|
||||
labels:
|
||||
app: atlasbot
|
||||
spec:
|
||||
selector:
|
||||
app: atlasbot
|
||||
ports:
|
||||
- name: http
|
||||
port: 8090
|
||||
targetPort: 8090
|
||||
type: ClusterIP
|
||||
@ -14,6 +14,7 @@ resources:
|
||||
- guest-register-deployment.yaml
|
||||
- guest-register-service.yaml
|
||||
- atlasbot-deployment.yaml
|
||||
- atlasbot-service.yaml
|
||||
- wellknown.yaml
|
||||
- atlasbot-rbac.yaml
|
||||
- mas-secrets-ensure-rbac.yaml
|
||||
|
||||
@ -5,6 +5,7 @@ import re
|
||||
import ssl
|
||||
import threading
|
||||
import time
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
from typing import Any
|
||||
from urllib import error, parse, request
|
||||
|
||||
@ -1089,6 +1090,62 @@ def _normalize_reply(value: Any) -> str:
|
||||
return text
|
||||
|
||||
|
||||
# Internal HTTP endpoint for cluster answers (website uses this).
|
||||
class _AtlasbotHandler(BaseHTTPRequestHandler):
|
||||
server_version = "AtlasbotHTTP/1.0"
|
||||
|
||||
def _write_json(self, status: int, payload: dict[str, Any]):
|
||||
body = json.dumps(payload).encode("utf-8")
|
||||
self.send_response(status)
|
||||
self.send_header("Content-Type", "application/json")
|
||||
self.send_header("Content-Length", str(len(body)))
|
||||
self.end_headers()
|
||||
self.wfile.write(body)
|
||||
|
||||
def _authorized(self) -> bool:
|
||||
if not ATLASBOT_INTERNAL_TOKEN:
|
||||
return True
|
||||
token = self.headers.get("X-Internal-Token", "")
|
||||
return token == ATLASBOT_INTERNAL_TOKEN
|
||||
|
||||
def do_GET(self): # noqa: N802
|
||||
if self.path == "/health":
|
||||
self._write_json(200, {"status": "ok"})
|
||||
return
|
||||
self._write_json(404, {"error": "not_found"})
|
||||
|
||||
def do_POST(self): # noqa: N802
|
||||
if self.path != "/v1/answer":
|
||||
self._write_json(404, {"error": "not_found"})
|
||||
return
|
||||
if not self._authorized():
|
||||
self._write_json(401, {"error": "unauthorized"})
|
||||
return
|
||||
try:
|
||||
length = int(self.headers.get("Content-Length", "0"))
|
||||
except ValueError:
|
||||
length = 0
|
||||
raw = self.rfile.read(length) if length > 0 else b""
|
||||
try:
|
||||
payload = json.loads(raw.decode("utf-8")) if raw else {}
|
||||
except json.JSONDecodeError:
|
||||
self._write_json(400, {"error": "invalid_json"})
|
||||
return
|
||||
prompt = str(payload.get("prompt") or payload.get("question") or "").strip()
|
||||
if not prompt:
|
||||
self._write_json(400, {"error": "missing_prompt"})
|
||||
return
|
||||
inventory = node_inventory_live()
|
||||
answer = structured_answer(prompt, inventory=inventory, metrics_summary="")
|
||||
self._write_json(200, {"answer": answer})
|
||||
|
||||
|
||||
def _start_http_server():
|
||||
server = HTTPServer(("0.0.0.0", ATLASBOT_HTTP_PORT), _AtlasbotHandler)
|
||||
thread = threading.Thread(target=server.serve_forever, daemon=True)
|
||||
thread.start()
|
||||
|
||||
|
||||
# Conversation state.
|
||||
history = collections.defaultdict(list) # (room_id, sender|None) -> list[str] (short transcript)
|
||||
|
||||
@ -1326,6 +1383,7 @@ def login_with_retry():
|
||||
|
||||
def main():
|
||||
load_kb()
|
||||
_start_http_server()
|
||||
token = login_with_retry()
|
||||
try:
|
||||
room_id = resolve_alias(token, ROOM_ALIAS)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user