feat: dashboard UI + key API + realtime decode
Full HTML dashboard (dark theme, vanilla JS, no external deps) served at / and /dashboard with five tabs: system status (admin), file upload-to-transcribe with progress/result/downloads, job history with cancel/result modal, realtime mic demo over the existing WebSocket, and API key create/list. Backend: POST/GET /v1/keys (admin; raw key returned once, digest-only storage); KeyStore.list_keys(); EngineOwner.emit_hypothesis is now a real implementation (PCM16 chunk -> WAV -> realtime-lane decode with the single GPU lock) instead of a stub. Notebook: tunnel cell links /dashboard and smoke-checks the HTML. + 6 tests (dashboard public HTML, key create/list/scope, WAV header, emit_hypothesis cleanup). 153 tests pass, ruff clean, JS syntax verified with node --check.
This commit is contained in:
@@ -265,6 +265,13 @@ def cells() -> list[dict]:
|
||||
" print(open('/content/logs/server.log').read()[-1500:])\n"
|
||||
" raise SystemExit('서버 기동 실패')\n"
|
||||
"\n"
|
||||
"# 대시보드 HTML 스모크 (공개 — 키 불필요)\n"
|
||||
"try:\n"
|
||||
" d = urllib.request.urlopen('http://localhost:8000/dashboard', timeout=5)\n"
|
||||
" print('대시보드 HTML:', d.status, len(d.read()), 'bytes')\n"
|
||||
"except Exception as exc:\n"
|
||||
" print('대시보드 로드 실패:', exc)\n"
|
||||
"\n"
|
||||
"# 키 인증 검증 — RAW_KEY로 /v1/jobs 호출 → 200이어야 함 (401이면 종료)\n"
|
||||
"req = urllib.request.Request('http://localhost:8000/v1/jobs', headers={'X-API-Key': RAW_KEY})\n"
|
||||
"try:\n"
|
||||
@@ -290,7 +297,8 @@ def cells() -> list[dict]:
|
||||
"\n"
|
||||
"if TUNNEL_URL:\n"
|
||||
" print('🌐 Cloudflare 터널 (외부 접속):', TUNNEL_URL)\n"
|
||||
" print(' 대시보드 (API Docs):', TUNNEL_URL + '/docs')\n"
|
||||
" print(' 대시보드:', TUNNEL_URL + '/dashboard')\n"
|
||||
" print(' API Docs (Swagger):', TUNNEL_URL + '/docs')\n"
|
||||
" print(' 상태 (health):', TUNNEL_URL + '/health')\n"
|
||||
" # ── 외부 접속 검증 ──\n"
|
||||
" # Colab VM의 DNS가 새 trycloudflare 호스트를 해석 못 하는 경우가 있다\n"
|
||||
@@ -494,7 +502,8 @@ def cells() -> list[dict]:
|
||||
"### Cloudflare 터널로 외부에서 접속 (선택)\n\n"
|
||||
"서버 셀 10이 완료되면 `https://xxx.trycloudflare.com` 외부 접속 링크가 출력됩니다.\n"
|
||||
"- **임시 링크** — Colab 세션(서버 프로세스)이 살아 있는 동안만 유효하며, 세션 종료/재시작 시 닫힙니다.\n"
|
||||
"- `/docs`(Swagger 대시보드)와 `/health`는 별도 키 없이 열리지만, **실제 API 호출은 `X-API-Key`(RAW_KEY)가 필요**합니다.\n"
|
||||
"- `/dashboard`(전용 대시보드 UI)와 `/docs`(Swagger), `/health`는 별도 키 없이 열리지만,\n"
|
||||
" **실제 API 호출은 `X-API-Key`(RAW_KEY)가 필요**합니다. 대시보드 상단에 키를 저장하면 사용됩니다.\n"
|
||||
"- cloudflared는 셀 3에서 설치됩니다. 다운로드 실패 시 터널 없이 로컬(8000)에서 계속 사용할 수 있습니다.\n"
|
||||
"- 터널은 `http://localhost:8000`을 고정으로 바라봅니다. 다른 포트로 서버를 띄우면 터널이 연결되지 않습니다.\n"
|
||||
"- trycloudflare는 **인증 없는 Quick Tunnel**이라 URL만 알면 누구나 접근 가능합니다. 민감 데이터는 올리지 마세요.\n"
|
||||
|
||||
Reference in New Issue
Block a user