WebSocket API¶
Diese Seite dokumentiert die wichtigsten Socket.IO WebSocket-Endpunkte und Events.
Verbindung
LLARS nutzt zwei Socket.IO-Endpunkte:
- Backend: http://localhost:55080 mit Pfad /socket.io/
- Collaboration (YJS): http://localhost:55080/collab mit Pfad /collab/socket.io/ (nginx → Port 8082)
Verbindung herstellen¶
Client-Setup (JavaScript)¶
import { io } from 'socket.io-client'
const socket = io('http://localhost:55080', {
path: '/socket.io/',
auth: {
token: 'Bearer <access_token>'
},
transports: ['websocket', 'polling']
})
socket.on('connect', () => {
console.log('Connected:', socket.id)
})
socket.on('connect_error', (error) => {
console.error('Connection failed:', error)
})
Authentifizierung¶
Alle Namespaces außer dem Default-Namespace erfordern JWT-Authentifizierung:
Namespaces¶
LLARS verwendet verschiedene Namespaces für unterschiedliche Funktionen:
| Namespace | Beschreibung | Auth Required |
|---|---|---|
/ |
Default (Health Check) | ❌ |
/chat |
Chat-Streaming | ✅ |
/rag |
RAG-Dokument-Updates | ✅ |
/collab |
LaTeX/Markdown Collaboration (separater Socket-Server) | ✅ |
/judge |
LLM Evaluator Updates | ✅ |
/admin |
Docker Monitor, DB Explorer | ✅ (Admin) |
/oncoco |
OnCoCo Analyse | ✅ |
Hinweis: Die Collaboration-WebSockets laufen über einen separaten Socket.IO-Server hinter /collab.
Dadurch ist es ein eigener Endpoint mit eigenem Event-Set, nicht nur ein Namespace.
Chat Namespace (/chat)¶
Events (Client → Server)¶
chat:message¶
Sendet eine Chat-Nachricht.
socket.emit('chat:message', {
chatbot_id: 1,
session_id: 'unique-session-id',
message: 'Hallo, wie geht es dir?',
conversation_id: null, // null für neue Konversation
include_sources: true
})
chat:stop¶
Stoppt die aktuelle Streaming-Antwort.
Events (Server → Client)¶
chat:delta¶
Streaming-Token der Antwort.
socket.on('chat:delta', (data) => {
// data = { delta: 'Hallo', session_id: '...' }
responseText += data.delta
})
chat:done¶
Antwort abgeschlossen.
socket.on('chat:done', (data) => {
// data = {
// session_id: '...',
// conversation_id: 1,
// message_id: 42,
// sources: [...],
// tokens: { input: 150, output: 200 }
// }
})
chat:error¶
Fehler während der Verarbeitung.
socket.on('chat:error', (data) => {
// data = { error: 'Rate limit exceeded', code: 'RATE_LIMIT' }
})
RAG Namespace (/rag)¶
Events (Client → Server)¶
rag:subscribe¶
Abonniert Updates für eine Collection.
rag:unsubscribe¶
Beendet Abonnement.
Events (Server → Client)¶
document:progress¶
Fortschritt der Dokumentverarbeitung.
socket.on('document:progress', (data) => {
// data = {
// document_id: 1,
// status: 'processing', // 'pending' | 'processing' | 'indexed' | 'failed'
// progress: 50, // 0-100
// step: 'Creating embeddings',
// error: null
// }
})
document:indexed¶
Dokument erfolgreich indexiert.
socket.on('document:indexed', (data) => {
// data = {
// document_id: 1,
// chunk_count: 45,
// collection_id: 1
// }
})
collection:updated¶
Collection-Statistiken aktualisiert.
socket.on('collection:updated', (data) => {
// data = {
// collection_id: 1,
// total_documents: 10,
// total_chunks: 450,
// pending_documents: 2
// }
})
Collab Namespace (/collab)¶
Für LaTeX und Markdown Echtzeit-Kollaboration (YJS).
Events (Client → Server)¶
collab:join¶
Workspace beitreten.
socket.emit('collab:join', {
workspace_id: 1,
document_id: 5,
type: 'latex' // 'latex' | 'markdown'
})
collab:sync¶
YJS-Sync-Update senden.
collab:awareness¶
Awareness-Update (Cursor-Position, etc.).
socket.emit('collab:awareness', {
document_id: 5,
state: {
user: { name: 'Max', color: '#b0ca97' },
cursor: { line: 10, ch: 5 }
}
})
collab:leave¶
Workspace verlassen.
Events (Server → Client)¶
collab:sync¶
YJS-Sync-Update von anderem Client.
socket.on('collab:sync', (data) => {
// data = { document_id: 5, update: '<base64>' }
Y.applyUpdate(ydoc, decodeUpdate(data.update))
})
collab:awareness¶
Awareness-Update von anderem Client.
socket.on('collab:awareness', (data) => {
// data = {
// document_id: 5,
// client_id: 'abc123',
// state: { user: {...}, cursor: {...} }
// }
})
collab:users¶
Liste aktiver Benutzer im Dokument.
socket.on('collab:users', (data) => {
// data = {
// document_id: 5,
// users: [
// { id: 1, name: 'Max', color: '#b0ca97', cursor: {...} }
// ]
// }
})
Judge Namespace (/judge)¶
Events (Client → Server)¶
judge:subscribe¶
Session-Updates abonnieren.
Events (Server → Client)¶
judge:progress¶
Fortschritt der Judge-Session.
socket.on('judge:progress', (data) => {
// data = {
// session_id: 1,
// completed: 25,
// total: 100,
// current_comparison: {
// thread_id: 5,
// pillar: 'Relevanz'
// }
// }
})
judge:result¶
Einzelnes Vergleichsergebnis.
socket.on('judge:result', (data) => {
// data = {
// session_id: 1,
// comparison_id: 42,
// winner: 'A',
// confidence: 0.85,
// pillar: 'Relevanz'
// }
})
judge:completed¶
Session abgeschlossen.
socket.on('judge:completed', (data) => {
// data = {
// session_id: 1,
// total_comparisons: 100,
// summary: {...}
// }
})
Admin Namespace (/admin)¶
Nur für Admins
Dieser Namespace erfordert Admin-Berechtigungen.
Docker Monitor¶
docker:subscribe¶
Docker-Updates abonnieren.
docker:stats (Server → Client)¶
Container-Statistiken.
socket.on('docker:stats', (data) => {
// data = {
// containers: [
// {
// id: 'abc123',
// name: 'llars_flask_service',
// status: 'running',
// cpu_percent: 2.5,
// memory_mb: 512,
// memory_limit_mb: 2048
// }
// ],
// summary: {
// total: 8,
// running: 8,
// total_cpu: 15.2,
// total_memory_mb: 4096
// }
// }
})
docker:logs¶
Container-Logs abonnieren.
socket.emit('docker:logs', {
container_id: 'abc123',
tail: 100
})
socket.on('docker:logs', (data) => {
// data = {
// container_id: 'abc123',
// logs: ['[2025-12-01 10:00:00] INFO: ...', ...]
// }
})
DB Explorer¶
db:list_tables¶
Alle Tabellen auflisten.
socket.emit('db:list_tables')
socket.on('db:tables', (data) => {
// data = { tables: ['users', 'chatbots', 'rag_documents', ...] }
})
db:query¶
Tabelle abfragen.
socket.emit('db:query', {
table: 'users',
limit: 50,
offset: 0,
order_by: 'created_at',
order_dir: 'desc',
filters: { role: 'admin' }
})
socket.on('db:result', (data) => {
// data = {
// table: 'users',
// rows: [...],
// total: 150,
// columns: ['id', 'username', 'email', ...]
// }
})
OnCoCo Namespace (/oncoco)¶
Events¶
oncoco:analyze¶
Analyse starten.
oncoco:result¶
Analyse-Ergebnis.
socket.on('oncoco:result', (data) => {
// data = {
// categories: [
// { name: 'Greeting', confidence: 0.95 },
// { name: 'Question', confidence: 0.82 }
// ],
// analysis_id: 'xyz'
// }
})
Fehlerbehandlung¶
Reconnection¶
Socket.IO reconnect automatisch bei Verbindungsabbruch:
socket.on('reconnect', (attemptNumber) => {
console.log('Reconnected after', attemptNumber, 'attempts')
// Re-subscribe to rooms/namespaces
})
socket.on('reconnect_error', (error) => {
console.error('Reconnection failed:', error)
})
Error Events¶
Timeout¶
socket.emit('chat:message', data, (response) => {
// Acknowledgement callback (optional)
if (response.error) {
console.error('Message failed:', response.error)
}
})
Best Practices¶
1. Namespace-Trennung¶
const chatSocket = io('/chat', { auth: { token } })
const ragSocket = io('/rag', { auth: { token } })