mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage-server
synced 2026-04-11 18:08:16 +00:00
feat: recording analysis module with Deepgram + AI insights + Redis cache
- RecordingsModule: POST /api/recordings/analyze - Deepgram pre-recorded API: diarize, summarize, topics, sentiment, utterances - AI insights via OpenAI generateObject: call outcome, coaching, compliance, satisfaction - Redis cache: 7-day TTL per callId, check before hitting Deepgram/OpenAI - Generic getCache/setCache added to SessionService for cross-module use Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
53
src/recordings/recordings.controller.ts
Normal file
53
src/recordings/recordings.controller.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { Controller, Post, Body, Logger, HttpException } from '@nestjs/common';
|
||||
import { RecordingsService } from './recordings.service';
|
||||
import { SessionService } from '../auth/session.service';
|
||||
|
||||
const CACHE_TTL = 7 * 24 * 3600; // 7 days
|
||||
|
||||
@Controller('api/recordings')
|
||||
export class RecordingsController {
|
||||
private readonly logger = new Logger(RecordingsController.name);
|
||||
|
||||
constructor(
|
||||
private readonly recordings: RecordingsService,
|
||||
private readonly session: SessionService,
|
||||
) {}
|
||||
|
||||
@Post('analyze')
|
||||
async analyze(@Body() body: { recordingUrl: string; callId?: string }) {
|
||||
if (!body.recordingUrl) {
|
||||
throw new HttpException('recordingUrl required', 400);
|
||||
}
|
||||
|
||||
const cacheKey = body.callId ? `call:analysis:${body.callId}` : null;
|
||||
|
||||
// Check Redis cache first
|
||||
if (cacheKey) {
|
||||
try {
|
||||
const cached = await this.session.getCache(cacheKey);
|
||||
if (cached) {
|
||||
this.logger.log(`[RECORDING] Cache hit: ${cacheKey}`);
|
||||
return JSON.parse(cached);
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
this.logger.log(`[RECORDING] Cache miss — analyzing: ${body.recordingUrl} callId=${body.callId ?? 'none'}`);
|
||||
|
||||
try {
|
||||
const analysis = await this.recordings.analyzeRecording(body.recordingUrl);
|
||||
this.logger.log(`[RECORDING] Analysis complete: ${analysis.transcript.length} utterances, sentiment=${analysis.sentiment}`);
|
||||
|
||||
// Cache the result
|
||||
if (cacheKey) {
|
||||
this.session.setCache(cacheKey, JSON.stringify(analysis), CACHE_TTL)
|
||||
.catch(err => this.logger.warn(`[RECORDING] Cache write failed: ${err}`));
|
||||
}
|
||||
|
||||
return analysis;
|
||||
} catch (error: any) {
|
||||
this.logger.error(`[RECORDING] Analysis failed: ${error.message}`);
|
||||
throw new HttpException(error.message ?? 'Analysis failed', 502);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user