2:I[7012,["4765","static/chunks/4765-f5afdf8061f456f3.js","9856","static/chunks/9856-3b185291364d9bef.js","6687","static/chunks/app/docs/%5B...slug%5D/page-e07536548216bee4.js"],"MarkdownRenderer"] 4:I[9856,["4765","static/chunks/4765-f5afdf8061f456f3.js","9856","static/chunks/9856-3b185291364d9bef.js","6687","static/chunks/app/docs/%5B...slug%5D/page-e07536548216bee4.js"],""] 5:I[4126,[],""] 7:I[9630,[],""] 8:I[4278,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"HeadingProvider"] 9:I[1476,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"Header"] a:I[3167,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"Sidebar"] b:I[7409,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"PageFrame"] 3:T41fc, # Admin Panel Integration Guide This guide covers the VoiceAssist admin panel integration with the main web app, including cross-app navigation, real-time event streaming, and voice session monitoring. **Admin Panel URL:** https://admin.asimo.io ## Table of Contents 1. [Overview](#overview) 2. [Cross-App Navigation](#cross-app-navigation) 3. [Conversations Management](#conversations-management) 4. [Clinical Contexts & PHI](#clinical-contexts--phi) 5. [Voice Monitor & TT Pipeline](#voice-monitor--tt-pipeline) 6. [Real-Time Events](#real-time-events) 7. [API Reference](#api-reference) 8. [Configuration](#configuration) --- ## Overview The admin panel provides a centralized interface for monitoring and managing the VoiceAssist platform. Key capabilities include: - **Conversations Management**: View all user conversations with full message history - **Clinical Contexts**: Access and audit PHI data with HIPAA-compliant logging - **Voice Monitoring**: Real-time visibility into voice sessions and the Thinker-Talker pipeline - **System Metrics**: Database pools, Redis connections, and WebSocket sessions - **Real-Time Events**: Live event streaming via WebSocket with Redis pub/sub ### Architecture ``` ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ Admin Panel │ │ Web App │ │ Docs Site │ │ admin.asimo.io │────▶│ dev.asimo.io │────▶│ docs.asimo.io │ └────────┬────────┘ └────────┬────────┘ └─────────────────┘ │ │ └───────────┬───────────┘ ▼ ┌─────────────────────┐ │ API Gateway │ │ /api/admin/panel/* │ └──────────┬──────────┘ │ ┌──────────┴──────────┐ │ │ ┌────▼────┐ ┌─────▼────┐ │ Database │ │ Redis │ │PostgreSQL│ │ Pub/Sub │ └──────────┘ └──────────┘ ``` --- ## Cross-App Navigation The admin panel integrates seamlessly with other VoiceAssist applications through a unified navigation system. ### Navigation Configuration The navigation configuration is defined in `/apps/admin-panel/src/config/externalLinks.ts`: ```typescript export interface ExternalApp { id: string; name: string; url: string; description: string; icon: string; } export const externalApps: ExternalApp[] = [ { id: "web-app", name: "VoiceAssist App", url: "https://dev.asimo.io", description: "Main voice assistant application", icon: "MessageSquare", }, { id: "docs", name: "Documentation", url: "https://docs.asimo.io", description: "Technical documentation", icon: "Book", }, ]; ``` ### Using the AppSwitcher Component The `AppSwitcher` component provides a dropdown menu for navigating between applications: ```tsx import { AppSwitcher } from "@/components/AppSwitcher"; // In your header component ; ``` ### Environment Variables Configure application URLs via environment variables: ```env VITE_WEB_APP_URL=https://dev.asimo.io VITE_DOCS_URL=https://docs.asimo.io VITE_ADMIN_URL=https://admin.asimo.io ``` --- ## Conversations Management The Conversations page provides administrators with visibility into all user conversations. ### Accessing Conversations Navigate to **Conversations** in the admin sidebar to view: - All conversations across all users - Message count and creation time - Last activity timestamp - Conversation title and status ### Conversation List API ```http GET /api/admin/panel/conversations ``` Query parameters: - `user_id` (optional): Filter by user - `page` (optional): Page number (default: 1) - `page_size` (optional): Results per page (default: 50) - `sort_by` (optional): Sort field (created_at, updated_at, message_count) - `sort_order` (optional): asc or desc Response: ```json { "conversations": [ { "id": "conv-uuid", "user_id": "user-uuid", "user_email": "user@example.com", "title": "Conversation Title", "message_count": 42, "created_at": "2025-12-01T10:00:00Z", "updated_at": "2025-12-01T15:30:00Z" } ], "total": 100, "page": 1, "page_size": 50 } ``` ### Viewing Conversation Details ```http GET /api/admin/panel/conversations/{conversation_id} ``` Returns the full conversation with all messages: ```json { "id": "conv-uuid", "user_id": "user-uuid", "user_email": "user@example.com", "title": "Conversation Title", "messages": [ { "id": "msg-uuid", "role": "user", "content": "Hello, I have a question...", "created_at": "2025-12-01T10:00:00Z" }, { "id": "msg-uuid-2", "role": "assistant", "content": "I'd be happy to help...", "created_at": "2025-12-01T10:00:05Z" } ], "created_at": "2025-12-01T10:00:00Z", "updated_at": "2025-12-01T15:30:00Z" } ``` --- ## Clinical Contexts & PHI The Clinical Contexts page provides HIPAA-compliant access to Protected Health Information (PHI). ### PHI Access Requirements - All PHI access is logged with admin user ID, timestamp, and target user - PHI data is masked by default until explicitly revealed - Access requires appropriate admin role permissions ### Clinical Context List ```http GET /api/admin/panel/clinical-contexts ``` Query parameters: - `user_id` (optional): Filter by user - `has_phi` (optional): Filter by PHI presence (true/false) - `page` (optional): Page number - `page_size` (optional): Results per page Response with masked PHI: ```json { "contexts": [ { "id": "ctx-uuid", "user_id": "user-uuid", "user_email": "user@example.com", "has_phi": true, "phi_masked": { "conditions": ["[REDACTED]"], "medications": ["[REDACTED]"], "allergies": ["[REDACTED]"] }, "created_at": "2025-12-01T10:00:00Z", "updated_at": "2025-12-01T15:30:00Z" } ], "total": 25, "page": 1, "page_size": 50 } ``` ### Revealing PHI To reveal PHI data (logged for audit): ```http POST /api/admin/panel/clinical-contexts/{context_id}/reveal ``` Response includes unmasked PHI: ```json { "id": "ctx-uuid", "phi": { "conditions": ["Hypertension", "Type 2 Diabetes"], "medications": ["Metformin 500mg", "Lisinopril 10mg"], "allergies": ["Penicillin"] }, "revealed_at": "2025-12-01T16:00:00Z", "revealed_by": "admin@example.com" } ``` ### Audit Logging All PHI access events are published to the real-time event stream: ```json { "type": "phi.accessed", "timestamp": "2025-12-01T16:00:00Z", "user_id": "admin-uuid", "user_email": "admin@example.com", "resource_id": "ctx-uuid", "resource_type": "clinical_context", "data": { "target_user_id": "user-uuid" } } ``` --- ## Voice Monitor & TT Pipeline The Voice Monitor provides real-time visibility into voice sessions and the Thinker-Talker (TT) pipeline. ### Voice Sessions Tab View all active voice sessions: | Field | Description | | ---------- | ------------------------------------------ | | Session ID | Unique WebSocket session identifier | | User | Email of connected user | | Status | connected, speaking, listening, processing | | Duration | Time since connection | | Voice | Selected TTS voice | | Quality | Audio quality preset | ### TT Pipeline Tab Monitor the Thinker-Talker pipeline components: #### TT Sessions Active Thinker-Talker sessions with state information: - **Session ID**: Unique TT session identifier - **State**: idle, thinking, speaking, listening, tool_executing - **Thinker Model**: Active LLM model - **Current Tool**: Currently executing tool (if any) - **Latency**: Round-trip processing time #### TT Contexts Active context windows with expiration tracking: - **Context ID**: Unique context identifier - **Session ID**: Parent TT session - **Created**: Context creation time - **Expires**: TTL expiration time - **Size**: Context token count #### Quality Presets Available audio quality configurations: | Preset | Sample Rate | Bit Depth | Buffer Size | | ------ | ----------- | --------- | ----------- | | high | 48000 Hz | 24-bit | 4096 | | medium | 44100 Hz | 16-bit | 2048 | | low | 22050 Hz | 16-bit | 1024 | ### Analytics Tab Voice pipeline performance metrics: - **Tool Call Frequency**: Bar chart of most-used tools - **KB Performance**: Knowledge base query latency - **Average Latency**: TT pipeline response time - **Error Rate**: Failed voice sessions percentage ### API Endpoints ```http # Get active voice sessions GET /api/admin/panel/voice/sessions # Get TT pipeline state GET /api/admin/panel/voice/tt-sessions GET /api/admin/panel/voice/tt-contexts GET /api/admin/panel/voice/quality-presets # Get TT analytics GET /api/admin/panel/voice/tt-analytics # Cleanup expired contexts POST /api/admin/panel/voice/tt-contexts/cleanup # Disconnect a voice session POST /api/admin/panel/voice/sessions/{session_id}/disconnect ``` --- ## Real-Time Events The admin panel receives real-time events via WebSocket, powered by Redis pub/sub. ### WebSocket Connection Connect to the admin WebSocket endpoint: ```typescript const ws = new WebSocket("wss://admin.asimo.io/api/admin/panel/ws"); ``` ### Event Types | Event Type | Description | | -------------------------- | --------------------------- | | `session.connected` | User connected to WebSocket | | `session.disconnected` | User disconnected | | `conversation.created` | New conversation started | | `conversation.updated` | Conversation modified | | `message.created` | New message added | | `clinical_context.created` | New clinical context | | `clinical_context.updated` | Context modified | | `phi.accessed` | PHI data revealed (audit) | | `phi.detected` | PHI detected in message | | `voice.session_started` | Voice session began | | `voice.session_ended` | Voice session ended | | `voice.session_error` | Voice session error | | `tt.state_changed` | TT pipeline state change | | `tt.tool_called` | TT tool execution | | `tt.context_created` | TT context created | | `tt.context_expired` | TT context expired | | `system.alert` | System alert notification | | `system.health_changed` | Health status change | | `user.logged_in` | User login | | `user.logged_out` | User logout | | `user.created` | New user registered | ### Event Payload Format ```json { "type": "admin_event", "payload": { "type": "voice.session_started", "timestamp": "2025-12-01T16:00:00Z", "user_id": "user-uuid", "user_email": "user@example.com", "session_id": "ws-session-uuid", "resource_id": "voice-session-uuid", "resource_type": "voice_session", "data": { "session_type": "realtime", "voice": "alloy" } } } ``` ### Subscribing to Events Filter events by type: ```typescript ws.send( JSON.stringify({ type: "subscribe", payload: { event_types: ["voice.session_started", "voice.session_ended"], }, }), ); ``` ### Using the React Hook ```tsx import { useRealtimeEvents } from "@/hooks/useRealtimeEvents"; function VoiceMonitor() { const { status, events, metrics, connect, disconnect } = useRealtimeEvents({ autoConnect: true, eventFilter: ["voice.session_started", "voice.session_ended"], onEvent: (event) => { console.log("New event:", event); }, onMetrics: (metrics) => { console.log("Metrics update:", metrics); }, }); return (

Connection: {status}

Events received: {events.length}

); } ``` ### Metrics Updates The WebSocket also receives periodic metrics: ```json { "type": "metrics_update", "payload": { "active_websocket_sessions": 42, "database_pool": { "pool_size": 20, "checked_out": 5, "overflow": 0 }, "redis_pool": { "total_connections": 10, "available_connections": 8 }, "timestamp": "2025-12-01T16:00:00Z" } } ``` --- ## API Reference ### Admin Panel Endpoints All endpoints require admin authentication. | Method | Endpoint | Description | | ------ | ------------------------------------------------- | ----------------------- | | GET | `/api/admin/panel/conversations` | List conversations | | GET | `/api/admin/panel/conversations/{id}` | Get conversation detail | | GET | `/api/admin/panel/clinical-contexts` | List clinical contexts | | GET | `/api/admin/panel/clinical-contexts/{id}` | Get context detail | | POST | `/api/admin/panel/clinical-contexts/{id}/reveal` | Reveal PHI | | GET | `/api/admin/panel/voice/sessions` | List voice sessions | | POST | `/api/admin/panel/voice/sessions/{id}/disconnect` | Disconnect session | | GET | `/api/admin/panel/voice/tt-sessions` | List TT sessions | | GET | `/api/admin/panel/voice/tt-contexts` | List TT contexts | | POST | `/api/admin/panel/voice/tt-contexts/cleanup` | Cleanup contexts | | GET | `/api/admin/panel/voice/quality-presets` | Get quality presets | | GET | `/api/admin/panel/voice/tt-analytics` | Get TT analytics | | WS | `/api/admin/panel/ws` | Real-time events | ### Authentication All admin API requests require a valid JWT token in the Authorization header: ```http Authorization: Bearer ``` ### Error Responses ```json { "detail": "Not authorized to access this resource", "status_code": 403 } ``` --- ## Configuration ### Environment Variables ```env # API Gateway ADMIN_PANEL_ENABLED=true ADMIN_PANEL_CORS_ORIGINS=https://admin.asimo.io # Redis (for real-time events) REDIS_URL=redis://localhost:6379 ADMIN_EVENTS_CHANNEL=admin:events # Database DATABASE_URL=postgresql://user:pass@localhost/voiceassist # JWT JWT_SECRET=your-secret-key JWT_ALGORITHM=HS256 ``` ### Redis Pub/Sub Configuration The admin event publisher uses Redis pub/sub for broadcasting events: ```python from app.services.admin_event_publisher import ( AdminEventPublisher, publish_voice_session_started, publish_phi_accessed, ) # Start the publisher publisher = AdminEventPublisher.get_instance() await publisher.start() # Publish events await publish_voice_session_started( user_id="user-uuid", session_id="session-uuid", session_type="realtime", voice="alloy" ) ``` ### Feature Flags ```env # Enable/disable admin features FEATURE_ADMIN_VOICE_MONITOR=true FEATURE_ADMIN_REALTIME_EVENTS=true FEATURE_ADMIN_PHI_ACCESS=true ``` --- ## Troubleshooting ### WebSocket Connection Issues 1. Check that the admin panel is properly authenticated 2. Verify Redis is running and accessible 3. Check for CORS configuration issues ```bash # Test Redis connection redis-cli ping # Check Redis pub/sub redis-cli SUBSCRIBE admin:events ``` ### Missing Events 1. Verify the event publisher is started during app initialization 2. Check that events are being published from the source ```python # In main.py startup @app.on_event("startup") async def startup(): publisher = AdminEventPublisher.get_instance() await publisher.start() ``` ### PHI Access Denied 1. Verify admin user has appropriate role 2. Check audit log for access attempts 3. Confirm context ID exists --- ## Related Documentation - [Thinker-Talker Pipeline](../THINKER_TALKER_PIPELINE.md) - [Voice Mode Pipeline](../VOICE_MODE_PIPELINE.md) - [Security & Compliance](../SECURITY_COMPLIANCE.md) - [HIPAA Compliance Matrix](../HIPAA_COMPLIANCE_MATRIX.md) - [WebSocket Protocol](../WEBSOCKET_PROTOCOL.md) 6:["slug","admin/ADMIN_PANEL_INTEGRATION_GUIDE","c"] 0:["X7oMT3VrOffzp0qvbeOas",[[["",{"children":["docs",{"children":[["slug","admin/ADMIN_PANEL_INTEGRATION_GUIDE","c"],{"children":["__PAGE__?{\"slug\":[\"admin\",\"ADMIN_PANEL_INTEGRATION_GUIDE\"]}",{}]}]}]},"$undefined","$undefined",true],["",{"children":["docs",{"children":[["slug","admin/ADMIN_PANEL_INTEGRATION_GUIDE","c"],{"children":["__PAGE__",{},[["$L1",["$","div",null,{"children":[["$","div",null,{"className":"mb-6 flex items-center justify-between gap-4","children":[["$","div",null,{"children":[["$","p",null,{"className":"text-sm text-gray-500 dark:text-gray-400","children":"Docs / Raw"}],["$","h1",null,{"className":"text-3xl font-bold text-gray-900 dark:text-white","children":"Admin Panel Integration Guide"}],["$","p",null,{"className":"text-sm text-gray-600 dark:text-gray-400","children":["Sourced from"," ",["$","code",null,{"className":"font-mono text-xs","children":["docs/","admin/ADMIN_PANEL_INTEGRATION_GUIDE.md"]}]]}]]}],["$","a",null,{"href":"https://github.com/mohammednazmy/VoiceAssist/edit/main/docs/admin/ADMIN_PANEL_INTEGRATION_GUIDE.md","target":"_blank","rel":"noreferrer","className":"inline-flex items-center gap-2 rounded-md border border-gray-200 dark:border-gray-700 px-3 py-1.5 text-sm text-gray-700 dark:text-gray-200 hover:border-primary-500 dark:hover:border-primary-400 hover:text-primary-700 dark:hover:text-primary-300","children":"Edit on GitHub"}]]}],["$","div",null,{"className":"rounded-lg border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 p-6","children":["$","$L2",null,{"content":"$3"}]}],["$","div",null,{"className":"mt-6 flex flex-wrap gap-2 text-sm","children":[["$","$L4",null,{"href":"/reference/all-docs","className":"inline-flex items-center gap-1 rounded-md bg-gray-100 px-3 py-1 text-gray-700 hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700","children":"← All documentation"}],["$","$L4",null,{"href":"/","className":"inline-flex items-center gap-1 rounded-md bg-gray-100 px-3 py-1 text-gray-700 hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700","children":"Home"}]]}]]}],null],null],null]},[null,["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children","docs","children","$6","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[null,["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children","docs","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/7f586cdbbaa33ff7.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","className":"h-full","children":["$","body",null,{"className":"__className_f367f3 h-full bg-white dark:bg-gray-900","children":[["$","a",null,{"href":"#main-content","className":"skip-to-content","children":"Skip to main content"}],["$","$L8",null,{"children":[["$","$L9",null,{}],["$","$La",null,{}],["$","main",null,{"id":"main-content","className":"lg:pl-64","role":"main","aria-label":"Documentation content","children":["$","$Lb",null,{"children":["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]]}]]}]}]],null],null],["$Lc",null]]]] c:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Admin Panel Integration Guide | Docs | VoiceAssist Docs"}],["$","meta","3",{"name":"description","content":"Comprehensive guide for the VoiceAssist admin panel with cross-app navigation, real-time events, and voice monitoring"}],["$","meta","4",{"name":"keywords","content":"VoiceAssist,documentation,medical AI,voice assistant,healthcare,HIPAA,API"}],["$","meta","5",{"name":"robots","content":"index, follow"}],["$","meta","6",{"name":"googlebot","content":"index, follow"}],["$","link","7",{"rel":"canonical","href":"https://assistdocs.asimo.io"}],["$","meta","8",{"property":"og:title","content":"VoiceAssist Documentation"}],["$","meta","9",{"property":"og:description","content":"Comprehensive documentation for VoiceAssist - Enterprise Medical AI Assistant"}],["$","meta","10",{"property":"og:url","content":"https://assistdocs.asimo.io"}],["$","meta","11",{"property":"og:site_name","content":"VoiceAssist Docs"}],["$","meta","12",{"property":"og:type","content":"website"}],["$","meta","13",{"name":"twitter:card","content":"summary"}],["$","meta","14",{"name":"twitter:title","content":"VoiceAssist Documentation"}],["$","meta","15",{"name":"twitter:description","content":"Comprehensive documentation for VoiceAssist - Enterprise Medical AI Assistant"}],["$","meta","16",{"name":"next-size-adjust"}]] 1:null