IRT-based measurement embedded in real platforms: social media, radio, and mobile. Real-time theta scoring, CUSUM drift detection, automated governance gates.
The CPVL engine scores psychometric data in real-time. Users interact through platforms they already use: no separate testing app required.
A full social media experience: posts, likes, comments, stories. Pop-up assessment questions appear naturally as users browse, measuring mood, engagement, and trust via IRT.
Live radio with real-time engagement scoring. Play/pause controls, listener counts, content engagement events feed directly into the CPVL IRT engine for content-level drift detection.
Cross-platform APK for Android and iOS. Same social feed, radio, and EMA popup experience. WebSocket-powered real-time scoring with offline queue support.
Full programmatic access to the CPVL engine: start sessions, administer items, score responses, run drift scans, audit governance gates.
20-page Docusaurus site covering architecture, deployment, configuration, REST API, gRPC, GPU acceleration, and step-by-step tutorials for EMA and radio integration.
Users interact with social/radio platforms. Every action: a like, a listen, a response: flows through WebSocket to the CPVL engine, which scores in real-time using IRT.
Browser connects via WebSocket to port 8200. Session is created with unique user ID.
Every 15-45 seconds, a pop-up question appears. Likert-scale responses (0-4) are sent back over WebSocket.
Response maps to 0/1. EAP estimates update theta. Standard error shrinks with each item. Aberrant response detection runs per-administration.
theta, SE, n_items, aberrant_risk sent back over WebSocket. Client updates the score bar and theta trajectory chart.
CUSUM scan detects if item parameters shift. If signaled, governance gates trigger quarantine or rollback.
With PyTorch + CUDA: CUSUM 16.1x faster, batch EAP 15.3x faster. Falls back to numpy on CPU.
Get up and running in 5 minutes. The platform is already live at cpvl.mediahubnetwork.net.
Navigate to cpvl.mediahubnetwork.net in your browser. You will see this landing page with links to Social Feed and Radio Channel.
https://cpvl.mediahubnetwork.net
Click "Social Feed" to enter the social platform. Posts appear in a feed. Every few seconds, a quick check-in question pops up. Answer it to generate psychometric data.
The bottom bar shows your real-time theta and standard error (SE). After 4+ responses, your measurement precision becomes meaningful. After 8 items, the session completes.
Switch to Radio from the nav bar. Pick a channel, press play. Engagement events (listen, like, share) are tracked. Feedback questions appear periodically.
All data is accessible programmatically. List instruments, start sessions, submit responses, and run drift scans via the REST API.
# Health check curl https://cpvl.mediahubnetwork.net/api/health # List instruments curl https://cpvl.mediahubnetwork.net/api/instruments # Start a session curl -X POST https://cpvl.mediahubnetwork.net/api/instruments/social_platform/sessions/start \ -H "Content-Type: application/json" \ -d '{"user_id": "test_user_01"}' # Get next item (IRT-adaptive) curl https://cpvl.mediahubnetwork.net/api/instruments/social_platform/sessions/test_user_01/next-item # Submit response (binary: 0=disagree, 1=agree) curl -X POST https://cpvl.mediahubnetwork.net/api/instruments/social_platform/sessions/respond \ -H "Content-Type: application/json" \ -d '{"user_id":"test_user_01","item_id":"mood_0","response":1,"response_time_ms":2500}' # Get current score curl https://cpvl.mediahubnetwork.net/api/instruments/social_platform/sessions/test_user_01/score
For real-time scoring, connect to the WebSocket server. Send EMA responses, receive live theta updates and drift alerts.
const ws = new WebSocket('wss://cpvl.mediahubnetwork.net/ws/social'); ws.onmessage = (e) => { const msg = JSON.parse(e.data); if (msg.type === 'ema_popup') { // Display question to user showQuestion(msg.data); } if (msg.type === 'score_update') { // Update theta display console.log(`theta=${msg.data.theta} SE=${msg.data.se}`); } }; // Submit a response ws.send(JSON.stringify({ type: 'respond_to_ema', item_id: 'mood_0', value: 3, // Likert 0-4 response_time_ms: 2500 }));
The Flutter app source is on the server. Build it on any machine with Flutter SDK installed.
# Copy from server scp -r sms@41.33.197.134:/home/sms/cpvl_backend/flutter_app ./ # Build APK cd flutter_app flutter pub get flutter build apk --release # APK output # build/app/outputs/flutter-apk/app-release.apk # Install on Android adb install build/app/outputs/flutter-apk/app-release.apk
REST API, gRPC services, and WebSocket messages. Full interactive docs at /api/docs.
import httpx BASE = "https://cpvl.mediahubnetwork.net/api" # Start session r = httpx.post(f"{BASE}/instruments/social_platform/sessions/start", json={"user_id": "user_01"}) # Get adaptive item r = httpx.get(f"{BASE}/instruments/social_platform/sessions/user_01/next-item") item = r.json() print(f"Next item: {item['item_id']} (b={item['difficulty']})") # Submit response r = httpx.post(f"{BASE}/instruments/social_platform/sessions/respond", json={"user_id": "user_01", "item_id": item["item_id"], "response": 1, "response_time_ms": 2500}) # Check score r = httpx.get(f"{BASE}/instruments/social_platform/sessions/user_01/score") score = r.json() print(f"theta={score['theta_hat']}, SE={score['se']}, N={score['n_items']}")
| Service | Methods | Description |
|---|---|---|
| HealthService | Check | Server health and readiness probes |
| InstrumentService | ListInstruments, GetInstrument, StartSession, NextItem, SubmitResponse, GetScore | Full IRT session management |
| SessionService | GetSession, ListSessions, UpdateSession | Session lifecycle management |
| DriftService | RunCUSUM, RunKSTest, GetDriftStatus | Distribution shift detection |
| GovernanceService | CheckRelease, AuditLog, RollbackVersion | Automated governance gates |
| BatchScoringService | ScoreBatch, GetBatchStatus | High-throughput batch scoring |
import grpc from server.grpc import cpvl_pb2, cpvl_pb2_grpc channel = grpc.insecure_channel("cpvl.mediahubnetwork.net:50051") stub = cpvl_pb2_grpc.InstrumentServiceStub(channel) # Start session resp = stub.StartSession(cpvl_pb2.StartSessionRequest( instrument_id="social_platform", user_id="user_01" )) # Get next item item = stub.NextItem(cpvl_pb2.NextItemRequest( instrument_id="social_platform", user_id="user_01" )) print(f"Item: {item.item_id}, b={item.difficulty}")
| Message Type | Direction | Fields |
|---|---|---|
welcome | Server to Client | user_id, platform, theta, se |
ema_popup | Server to Client | item_id, text, construct, scale[] |
respond_to_ema | Client to Server | item_id, value (0-4), response_time_ms |
score_update | Server to Client | theta, se, n_items, aberrant_risk, finished |
feed | Server to Client | posts[] (social feed) |
radio_feed | Server to Client | channels[] (radio channels) |
engage | Client to Server | content_id, event_type (like/share/listen/play) |
drift_check | Client to Server | Triggers CUSUM scan on user's response series |
drift_result | Server to Client | signals: {item_key: signaled} |
get_ema | Client to Server | Request an immediate EMA question |
# Install wscat npm install -g wscat # Connect to social platform wscat -c wss://cpvl.mediahubnetwork.net/ws/social # Request an EMA question > {"type": "get_ema"} # Respond to it > {"type": "respond_to_ema", "item_id": "mood_0", "value": 3, "response_time_ms": 2500} # Watch for score_update messages
The platform runs on cpvl.mediahubnetwork.net behind nginx. Use the manage script for all operations.
# SSH into the server ssh sms@41.33.197.134 # Check status of all services ~/cpvl-manage.sh status # Start all services ~/cpvl-manage.sh start # Stop all services ~/cpvl-manage.sh stop # Restart everything ~/cpvl-manage.sh restart # View server logs ~/cpvl-manage.sh logs # View iptables routing rules cat ~/routes.sh # Apply iptables rules (after editing routes.sh) echo 'root' | sudo -S bash ~/routes.sh
Everything runs on a single port (3080). Configure one proxy in nginx to forward to http://10.10.8.230:3080.
| Path | Routes To | Public URL |
|---|---|---|
/ | Landing page | cpvl.mediahubnetwork.net |
/social | Frontend (:3333) | cpvl.mediahubnetwork.net/social |
/radio | Frontend (:3333) | cpvl.mediahubnetwork.net/radio |
/api | REST API (:8000) | cpvl.mediahubnetwork.net/api |
/api/docs | Swagger UI (:8000) | cpvl.mediahubnetwork.net/api/docs |
/ws | WebSocket (:8200) | wss://cpvl.mediahubnetwork.net/ws |
/docs | Docusaurus (:3400) | cpvl.mediahubnetwork.net/docs |
| Port 50051 | gRPC (direct TCP) | cpvl.mediahubnetwork.net:50051 |
# Add ONE proxy host in Nginx Proxy Manager # Domain: cpvl.mediahubnetwork.net # Forward to: http://10.10.8.230:3080 # Enable: Websockets Support # Enable: Block Common Exploits (optional) # That's it. All paths are handled by the proxy: # / -> Landing page # /social -> Social Feed # /radio -> Radio Channel # /api -> REST API # /api/docs -> Swagger UI # /ws -> WebSocket # /docs -> Documentation # For gRPC, add a separate TCP proxy: # Port: 50051 -> 10.10.8.230:50051
cpvl_backend/ +-- cpvl/ # Core psychometric engine (zero deps) | +-- models.py # ItemParams, Session, ResponseRecord | +-- scoring.py # IRT MML EAP estimation | +-- drift.py # CUSUM + KS distribution shift | +-- governance.py # Automated release/quarantine gates | +-- loop.py # CPVLEngine orchestrator | +-- storage.py # InMemoryStore (+ SQLite/Postgres) | +-- gpu.py # PyTorch CUDA acceleration | +-- instruments.py # Pre-built instrument definitions +-- server/ # Production server | +-- app.py # FastAPI REST (30+ endpoints) | +-- grpc/server.py # gRPC (6 services) | +-- ws/realtime.py # WebSocket (real-time scoring) | +-- config.py # Environment configuration | +-- deps.py # Dependency injection | +-- main.py # Entrypoint (REST + gRPC + WS) +-- proto/cpvl.proto # gRPC service definitions +-- frontend/ # Next.js social/radio platform | +-- src/ | +-- app/ # Pages: social, radio, profile | +-- components/ # Feed, RadioPlayer, EMAPopup | +-- lib/ # WebSocket, API client +-- flutter_app/ # Flutter mobile app | +-- lib/ | +-- screens/ # Social, Radio, Profile screens | +-- widgets/ # PostCard, ChannelCard, EMAPopup | +-- services/ # WebSocket + REST services +-- docs/ # Docusaurus documentation (20 pages) +-- tests/ # 87 tests (33 core + 48 + 6 GPU) +-- analysis/ # Validation studies + figure generation +-- requirements.txt # Python dependencies +-- Dockerfile # Container build +-- docker-compose.yml # Full deployment stack +-- CPVL2.tex # Research paper (LaTeX) +-- demo.py # EMA + Radio demo runner +-- gpu_benchmark.py # GPU acceleration benchmarks
Flutter APK for Android. Build from source or use the web version.
Social feed, radio channel, real-time psychometric scoring in your pocket.
# 1. Copy Flutter app from server scp -r sms@41.33.197.134:/home/sms/cpvl_backend/flutter_app ./ # 2. Enter the project cd flutter_app # 3. Install Flutter dependencies flutter pub get # 4. Build release APK flutter build apk --release # 5. Output location # build/app/outputs/flutter-apk/app-release.apk # 6. Install on connected device adb install build/app/outputs/flutter-apk/app-release.apk # For iOS (requires macOS) flutter build ios --release open ios/Runner.xcworkspace
# Clone the project git clone ... && cd cpvl_backend # Build and run with Docker docker compose up -d --build # Services available at: # :3000 Frontend # :8000 REST API # :8200 WebSocket # :50051 gRPC