Merge branch 'dev' into dev-kartik

This commit is contained in:
Kartik Datrika
2026-03-23 17:21:00 +05:30
6 changed files with 24 additions and 8 deletions

View File

@@ -82,6 +82,9 @@ export class AiChatController {
private async buildKnowledgeBase(auth: string): Promise<string> { private async buildKnowledgeBase(auth: string): Promise<string> {
const now = Date.now(); const now = Date.now();
if (this.knowledgeBase && now - this.kbLoadedAt < this.kbTtlMs) { if (this.knowledgeBase && now - this.kbLoadedAt < this.kbTtlMs) {
this.logger.log(
`KB cache hit (${this.knowledgeBase.length} chars, age ${Math.round((now - this.kbLoadedAt) / 1000)}s)`,
);
return this.knowledgeBase; return this.knowledgeBase;
} }
@@ -150,6 +153,7 @@ export class AiChatController {
} }
} catch (err) { } catch (err) {
this.logger.warn(`Failed to fetch clinics: ${err}`); this.logger.warn(`Failed to fetch clinics: ${err}`);
sections.push('## Clinics\nFailed to load clinic data.');
} }
try { try {
@@ -188,6 +192,7 @@ export class AiChatController {
} }
} catch (err) { } catch (err) {
this.logger.warn(`Failed to fetch health packages: ${err}`); this.logger.warn(`Failed to fetch health packages: ${err}`);
sections.push('\n## Health Packages\nFailed to load package data.');
} }
try { try {
@@ -211,6 +216,7 @@ export class AiChatController {
} }
} catch (err) { } catch (err) {
this.logger.warn(`Failed to fetch insurance partners: ${err}`); this.logger.warn(`Failed to fetch insurance partners: ${err}`);
sections.push('\n## Insurance Partners\nFailed to load insurance data.');
} }
this.knowledgeBase = this.knowledgeBase =
@@ -241,7 +247,11 @@ ${kb}`;
private async chatWithTools(userMessage: string, auth: string) { private async chatWithTools(userMessage: string, auth: string) {
const kb = await this.buildKnowledgeBase(auth); const kb = await this.buildKnowledgeBase(auth);
this.logger.log(`KB content preview: ${kb.substring(0, 300)}...`);
const systemPrompt = this.buildSystemPrompt(kb); const systemPrompt = this.buildSystemPrompt(kb);
this.logger.log(
`System prompt length: ${systemPrompt.length} chars, user message: "${userMessage.substring(0, 100)}"`,
);
const platformService = this.platform; const platformService = this.platform;
const { text, steps } = await generateText({ const { text, steps } = await generateText({

View File

@@ -62,7 +62,7 @@ export class CallAssistService {
const apptResult = await this.platform.queryWithAuth<any>( const apptResult = await this.platform.queryWithAuth<any>(
`{ appointments(first: 10, orderBy: [{ scheduledAt: DescNullsLast }]) { edges { node { `{ appointments(first: 10, orderBy: [{ scheduledAt: DescNullsLast }]) { edges { node {
id scheduledAt appointmentStatus doctorName department reasonForVisit patientId id scheduledAt status doctorName department reasonForVisit patientId
} } } }`, } } } }`,
undefined, undefined,
authHeader, authHeader,
@@ -77,7 +77,7 @@ export class CallAssistService {
? new Date(a.scheduledAt).toLocaleDateString('en-IN') ? new Date(a.scheduledAt).toLocaleDateString('en-IN')
: '?'; : '?';
parts.push( parts.push(
`- ${date}: ${a.doctorName ?? '?'} (${a.department ?? '?'}) — ${a.appointmentStatus}`, `- ${date}: ${a.doctorName ?? '?'} (${a.department ?? '?'}) — ${a.status}`,
); );
} }
} }

View File

@@ -60,7 +60,7 @@ export class SearchController {
this.platform this.platform
.queryWithAuth<any>( .queryWithAuth<any>(
`{ appointments(first: 50, orderBy: [{ scheduledAt: DescNullsLast }]) { edges { node { `{ appointments(first: 50, orderBy: [{ scheduledAt: DescNullsLast }]) { edges { node {
id scheduledAt doctorName department appointmentStatus patientId id scheduledAt doctorName department status patientId
} } } }`, } } } }`,
undefined, undefined,
authHeader, authHeader,

View File

@@ -169,6 +169,11 @@ export class MissedCallWebhookController {
durationSec: data.duration, durationSec: data.duration,
disposition: this.mapDisposition(data.disposition), disposition: this.mapDisposition(data.disposition),
}; };
// Set callback tracking fields for missed calls so they appear in the worklist
if (data.callStatus === 'MISSED') {
callData.callbackstatus = 'PENDING_CALLBACK';
callData.missedcallcount = 1;
}
if (data.recordingUrl) { if (data.recordingUrl) {
callData.recording = { callData.recording = {
primaryLinkUrl: data.recordingUrl, primaryLinkUrl: data.recordingUrl,

View File

@@ -50,15 +50,16 @@ export class MissedQueueService implements OnModuleInit {
let created = 0; let created = 0;
let updated = 0; let updated = 0;
// Ozonetel fromTime/toTime use HH:MM:SS format (time of day, filters within current day)
const now = new Date(); const now = new Date();
const fiveMinAgo = new Date(now.getTime() - 5 * 60 * 1000); const fiveMinAgo = new Date(now.getTime() - 5 * 60 * 1000);
const format = (d: Date) => d.toISOString().replace('T', ' ').slice(0, 19); const toHHMMSS = (d: Date) => d.toTimeString().slice(0, 8);
let abandonCalls: any[]; let abandonCalls: any[];
try { try {
abandonCalls = await this.ozonetel.getAbandonCalls({ abandonCalls = await this.ozonetel.getAbandonCalls({
fromTime: format(fiveMinAgo), fromTime: toHHMMSS(fiveMinAgo),
toTime: format(now), toTime: toHHMMSS(now),
}); });
} catch (err) { } catch (err) {
this.logger.warn(`Failed to fetch abandon calls: ${err}`); this.logger.warn(`Failed to fetch abandon calls: ${err}`);

View File

@@ -89,9 +89,9 @@ export class WorklistService {
authHeader: string, authHeader: string,
): Promise<any[]> { ): Promise<any[]> {
try { try {
// FIFO ordering (AscNullsLast) — oldest first. Filter to active callback statuses only. // FIFO ordering (AscNullsLast) — oldest first. No agentName filter — missed calls are a shared queue.
const data = await this.platform.queryWithAuth<any>( const data = await this.platform.queryWithAuth<any>(
`{ calls(first: 20, filter: { agentName: { eq: "${agentName}" }, callStatus: { eq: MISSED }, callbackstatus: { in: [PENDING_CALLBACK, CALLBACK_ATTEMPTED] } }, orderBy: [{ startedAt: AscNullsLast }]) { edges { node { `{ calls(first: 20, filter: { callStatus: { eq: MISSED }, callbackstatus: { in: [PENDING_CALLBACK, CALLBACK_ATTEMPTED] } }, orderBy: [{ startedAt: AscNullsLast }]) { edges { node {
id name createdAt id name createdAt
direction callStatus agentName direction callStatus agentName
callerNumber { primaryPhoneNumber } callerNumber { primaryPhoneNumber }