mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage-server
synced 2026-04-12 02:18:18 +00:00
feat: rules engine — json-rules-engine integration with worklist scoring
- Self-contained NestJS module: types, storage (Redis+JSON), fact providers, action handlers - PriorityConfig CRUD (slider values for task weights, campaign weights, source weights) - Score action handler with SLA multiplier + campaign multiplier formula - Worklist consumer: scores and ranks items before returning - Hospital starter template (7 rules) - REST API: /api/rules/* (CRUD, priority-config, evaluate, templates) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { Module, forwardRef } from '@nestjs/common';
|
||||
import { PlatformModule } from '../platform/platform.module';
|
||||
import { OzonetelAgentModule } from '../ozonetel/ozonetel-agent.module';
|
||||
import { RulesEngineModule } from '../rules-engine/rules-engine.module';
|
||||
import { WorklistController } from './worklist.controller';
|
||||
import { WorklistService } from './worklist.service';
|
||||
import { MissedQueueService } from './missed-queue.service';
|
||||
@@ -8,7 +9,7 @@ import { MissedCallWebhookController } from './missed-call-webhook.controller';
|
||||
import { KookooCallbackController } from './kookoo-callback.controller';
|
||||
|
||||
@Module({
|
||||
imports: [PlatformModule, forwardRef(() => OzonetelAgentModule)],
|
||||
imports: [PlatformModule, forwardRef(() => OzonetelAgentModule), RulesEngineModule],
|
||||
controllers: [WorklistController, MissedCallWebhookController, KookooCallbackController],
|
||||
providers: [WorklistService, MissedQueueService],
|
||||
exports: [MissedQueueService],
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { PlatformGraphqlService } from '../platform/platform-graphql.service';
|
||||
import { WorklistConsumer } from '../rules-engine/consumers/worklist.consumer';
|
||||
|
||||
export type WorklistResponse = {
|
||||
missedCalls: any[];
|
||||
@@ -12,15 +13,33 @@ export type WorklistResponse = {
|
||||
export class WorklistService {
|
||||
private readonly logger = new Logger(WorklistService.name);
|
||||
|
||||
constructor(private readonly platform: PlatformGraphqlService) {}
|
||||
constructor(
|
||||
private readonly platform: PlatformGraphqlService,
|
||||
private readonly worklistConsumer: WorklistConsumer,
|
||||
) {}
|
||||
|
||||
async getWorklist(agentName: string, authHeader: string): Promise<WorklistResponse> {
|
||||
const [missedCalls, followUps, marketingLeads] = await Promise.all([
|
||||
const [rawMissedCalls, rawFollowUps, rawMarketingLeads] = await Promise.all([
|
||||
this.getMissedCalls(agentName, authHeader),
|
||||
this.getPendingFollowUps(agentName, authHeader),
|
||||
this.getAssignedLeads(agentName, authHeader),
|
||||
]);
|
||||
|
||||
// Tag each item with a type field for the scoring engine
|
||||
const combined = [
|
||||
...rawMissedCalls.map((item: any) => ({ ...item, type: 'missed' })),
|
||||
...rawFollowUps.map((item: any) => ({ ...item, type: 'follow-up' })),
|
||||
...rawMarketingLeads.map((item: any) => ({ ...item, type: 'lead' })),
|
||||
];
|
||||
|
||||
// Score and rank via rules engine
|
||||
const scored = await this.worklistConsumer.scoreAndRank(combined);
|
||||
|
||||
// Split back into the 3 categories
|
||||
const missedCalls = scored.filter((item: any) => item.type === 'missed');
|
||||
const followUps = scored.filter((item: any) => item.type === 'follow-up');
|
||||
const marketingLeads = scored.filter((item: any) => item.type === 'lead');
|
||||
|
||||
return {
|
||||
missedCalls,
|
||||
followUps,
|
||||
|
||||
Reference in New Issue
Block a user