Replace ai-sandbox.oliver.solutions with optical-dev.oliver.solution across all config, env, docs, and source files. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
188 lines
No EOL
5.4 KiB
TypeScript
Executable file
188 lines
No EOL
5.4 KiB
TypeScript
Executable file
/**
|
|
* WebSocket Service Types and Utilities
|
|
* Provides type definitions and helper functions for WebSocket events
|
|
*/
|
|
|
|
// Event types that can be received from the WebSocket server
|
|
export interface WebSocketEvents {
|
|
message_update: {
|
|
message: {
|
|
id: string;
|
|
senderId: string;
|
|
text: string;
|
|
timestamp: string;
|
|
type: string;
|
|
highlighted: boolean;
|
|
attached_assets?: string[];
|
|
activates_visual_context?: boolean;
|
|
visualAsset?: {
|
|
filename: string;
|
|
displayReference: string;
|
|
};
|
|
};
|
|
};
|
|
|
|
ai_status_update: {
|
|
status: {
|
|
status: string;
|
|
updated_at: string;
|
|
};
|
|
};
|
|
|
|
moderator_status_update: {
|
|
moderator_status: {
|
|
current_section_id: string;
|
|
current_item_id: string;
|
|
current_section: string;
|
|
current_item: string;
|
|
progress: number;
|
|
};
|
|
};
|
|
|
|
theme_update: {
|
|
theme: {
|
|
id: string;
|
|
title: string;
|
|
description: string;
|
|
quotes: any[];
|
|
source: string;
|
|
created_at: string;
|
|
};
|
|
action: 'added' | 'updated' | 'deleted';
|
|
};
|
|
|
|
focus_group_update: {
|
|
llm_model: string;
|
|
reasoning_effort?: string;
|
|
verbosity?: string;
|
|
updated_at: string;
|
|
};
|
|
|
|
analytics_update: {
|
|
analytics: {
|
|
overview: any;
|
|
participation: any;
|
|
sentiment_analysis: any;
|
|
quality_metrics: any;
|
|
recommendations: string[];
|
|
};
|
|
};
|
|
|
|
conversation_state_update: {
|
|
state: {
|
|
status: string;
|
|
conversation_flow: any;
|
|
conversation_health: any;
|
|
};
|
|
};
|
|
}
|
|
|
|
// Helper function to convert WebSocket message to frontend message format
|
|
export function convertWebSocketMessage(wsMessage: WebSocketEvents['message_update']['message']) {
|
|
console.log('🔍 [GPT-5 CONVERTER] Input wsMessage:', JSON.stringify(wsMessage, null, 2));
|
|
|
|
if (!wsMessage) {
|
|
console.error('🔍 [GPT-5 CONVERTER] ERROR: wsMessage is null/undefined');
|
|
return null;
|
|
}
|
|
|
|
const converted = {
|
|
id: wsMessage.id,
|
|
senderId: wsMessage.senderId,
|
|
text: wsMessage.text,
|
|
timestamp: new Date(wsMessage.timestamp),
|
|
type: wsMessage.type,
|
|
highlighted: wsMessage.highlighted,
|
|
attached_assets: wsMessage.attached_assets || [],
|
|
activates_visual_context: wsMessage.activates_visual_context || false,
|
|
visualAsset: wsMessage.visualAsset
|
|
};
|
|
|
|
console.log('🔍 [GPT-5 CONVERTER] Output converted:', JSON.stringify(converted, null, 2));
|
|
return converted;
|
|
}
|
|
|
|
// Helper function to convert WebSocket theme to frontend theme format
|
|
export function convertWebSocketTheme(wsTheme: WebSocketEvents['theme_update']['theme']) {
|
|
return {
|
|
id: wsTheme.id,
|
|
title: wsTheme.title,
|
|
description: wsTheme.description,
|
|
quotes: wsTheme.quotes,
|
|
source: wsTheme.source as 'generated' | 'highlight',
|
|
created_at: wsTheme.created_at
|
|
};
|
|
}
|
|
|
|
// WebSocket event names as constants
|
|
export const WS_EVENTS = {
|
|
MESSAGE_UPDATE: 'message_update',
|
|
AI_STATUS_UPDATE: 'ai_status_update',
|
|
MODERATOR_STATUS_UPDATE: 'moderator_status_update',
|
|
THEME_UPDATE: 'theme_update',
|
|
FOCUS_GROUP_UPDATE: 'focus_group_update',
|
|
ANALYTICS_UPDATE: 'analytics_update',
|
|
CONVERSATION_STATE_UPDATE: 'conversation_state_update'
|
|
} as const;
|
|
|
|
// Connection status indicators
|
|
export enum WebSocketConnectionStatus {
|
|
DISCONNECTED = 'disconnected',
|
|
CONNECTING = 'connecting',
|
|
CONNECTED = 'connected',
|
|
RECONNECTING = 'reconnecting',
|
|
ERROR = 'error'
|
|
}
|
|
|
|
// Helper to get user-friendly connection status messages
|
|
export function getConnectionStatusMessage(status: WebSocketConnectionStatus, error?: string): string {
|
|
switch (status) {
|
|
case WebSocketConnectionStatus.DISCONNECTED:
|
|
return 'Disconnected from real-time updates';
|
|
case WebSocketConnectionStatus.CONNECTING:
|
|
return 'Connecting to real-time updates...';
|
|
case WebSocketConnectionStatus.CONNECTED:
|
|
return 'Connected to real-time updates';
|
|
case WebSocketConnectionStatus.RECONNECTING:
|
|
return 'Reconnecting to real-time updates...';
|
|
case WebSocketConnectionStatus.ERROR:
|
|
return error ? `Connection error: ${error}` : 'Connection error occurred';
|
|
default:
|
|
return 'Unknown connection status';
|
|
}
|
|
}
|
|
|
|
// Helper to determine if WebSocket should be used based on environment
|
|
export function shouldUseWebSocket(): boolean {
|
|
// WebSocket is enabled by default, can be disabled with VITE_DISABLE_WEBSOCKET
|
|
return import.meta.env.VITE_DISABLE_WEBSOCKET !== 'true';
|
|
}
|
|
|
|
// Helper to get the appropriate WebSocket server URL
|
|
export function getWebSocketUrl(): string {
|
|
// In development, connect to localhost backend
|
|
if (import.meta.env.DEV) {
|
|
return 'http://localhost:5137';
|
|
}
|
|
|
|
// If VITE_WEBSOCKET_URL is explicitly set, use that
|
|
if (import.meta.env.VITE_WEBSOCKET_URL) {
|
|
return import.meta.env.VITE_WEBSOCKET_URL;
|
|
}
|
|
|
|
// TEMP DEBUG: Try direct connection to backend bypassing Apache
|
|
// Add ?direct=1 to URL to test direct connection
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
if (urlParams.get('direct') === '1') {
|
|
console.log('🔧 USING DIRECT WEBSOCKET CONNECTION (bypassing Apache)');
|
|
return 'https://optical-dev.oliver.solution:5137';
|
|
}
|
|
|
|
// For production with Apache proxy, use the current origin
|
|
// The Apache proxy handles the routing to backend
|
|
const protocol = window.location.protocol === 'https:' ? 'https:' : 'http:';
|
|
const host = window.location.host; // includes port if any
|
|
|
|
// Use root domain since we specify full path in socket options
|
|
return `${protocol}//${host}`;
|
|
} |