mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage-server
synced 2026-04-11 18:08:16 +00:00
- Deepgram: multichannel=true + language=multi (captures both speakers, multilingual) - LLM speaker identification (agent vs customer from conversational cues) - Removed summarize=v2 (incompatible with multilingual) - SLA computation on call creation (lead.createdAt → call.startedAt elapsed %) - WebSocket: supervisor room + call:created broadcast for real-time updates - Maint: clear-analysis-cache endpoint + scanKeys/deleteCache on SessionService - AI chat: rules-engine context routing with dedicated system prompt Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
91 lines
2.9 KiB
TypeScript
91 lines
2.9 KiB
TypeScript
import {
|
|
WebSocketGateway,
|
|
WebSocketServer,
|
|
SubscribeMessage,
|
|
MessageBody,
|
|
ConnectedSocket,
|
|
} from '@nestjs/websockets';
|
|
import { Logger, Inject, forwardRef } from '@nestjs/common';
|
|
import { Server, Socket } from 'socket.io';
|
|
import type { EnrichedCallEvent, DispositionPayload } from './call-events.types';
|
|
import { CallEventsService } from './call-events.service';
|
|
|
|
@WebSocketGateway({
|
|
cors: {
|
|
origin: process.env.CORS_ORIGIN ?? 'http://localhost:5173',
|
|
credentials: true,
|
|
},
|
|
namespace: '/call-events',
|
|
})
|
|
export class CallEventsGateway {
|
|
@WebSocketServer()
|
|
server: Server;
|
|
|
|
private readonly logger = new Logger(CallEventsGateway.name);
|
|
|
|
constructor(
|
|
@Inject(forwardRef(() => CallEventsService))
|
|
private readonly callEventsService: CallEventsService,
|
|
) {}
|
|
|
|
// Push enriched call event to a specific agent's room
|
|
pushCallEvent(agentName: string, event: EnrichedCallEvent) {
|
|
const room = `agent:${agentName}`;
|
|
this.logger.log(`Pushing ${event.eventType} event to room ${room}`);
|
|
this.server.to(room).emit('call:incoming', event);
|
|
}
|
|
|
|
// Broadcast to supervisors when a new call record is created
|
|
broadcastCallCreated(callData: any) {
|
|
this.logger.log('Broadcasting call:created to supervisor room');
|
|
this.server.to('supervisor').emit('call:created', callData);
|
|
}
|
|
|
|
// Supervisor registers to receive real-time updates
|
|
@SubscribeMessage('supervisor:register')
|
|
handleSupervisorRegister(@ConnectedSocket() client: Socket) {
|
|
client.join('supervisor');
|
|
this.logger.log(`Supervisor registered (socket: ${client.id})`);
|
|
client.emit('supervisor:registered', { room: 'supervisor' });
|
|
}
|
|
|
|
// Agent registers when they open the Call Desk page
|
|
@SubscribeMessage('agent:register')
|
|
handleAgentRegister(
|
|
@ConnectedSocket() client: Socket,
|
|
@MessageBody() agentName: string,
|
|
) {
|
|
const room = `agent:${agentName}`;
|
|
client.join(room);
|
|
this.logger.log(
|
|
`Agent ${agentName} registered in room ${room} (socket: ${client.id})`,
|
|
);
|
|
client.emit('agent:registered', { agentName, room });
|
|
}
|
|
|
|
// Agent sends disposition after a call
|
|
@SubscribeMessage('call:disposition')
|
|
async handleDisposition(
|
|
@ConnectedSocket() client: Socket,
|
|
@MessageBody() payload: DispositionPayload,
|
|
) {
|
|
this.logger.log(
|
|
`Disposition received from ${payload.agentName}: ${payload.disposition}`,
|
|
);
|
|
await this.callEventsService.handleDisposition(payload);
|
|
client.emit('call:disposition:ack', {
|
|
status: 'saved',
|
|
callSid: payload.callSid,
|
|
});
|
|
return payload;
|
|
}
|
|
|
|
handleConnection(client: Socket) {
|
|
this.logger.log(`Client connected: ${client.id}`);
|
|
}
|
|
|
|
handleDisconnect(client: Socket) {
|
|
this.logger.log(`Client disconnected: ${client.id}`);
|
|
}
|
|
}
|