tango-app-api-audio-analytics 1.0.17 → 1.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -455,7 +455,7 @@ Only return the JSON array, no other text.`;
|
|
|
455
455
|
|
|
456
456
|
// ======================= CHAT STREAM API =======================
|
|
457
457
|
|
|
458
|
-
const CHAT_STREAM_API = 'http://
|
|
458
|
+
const CHAT_STREAM_API = 'http://65.2.124.154:8000/api/chat/stream';
|
|
459
459
|
|
|
460
460
|
/**
|
|
461
461
|
* Chat Stream API - Streams response from external AI chat API
|
|
@@ -528,4 +528,86 @@ export async function chatStream( req, res ) {
|
|
|
528
528
|
}
|
|
529
529
|
}
|
|
530
530
|
|
|
531
|
+
/**
|
|
532
|
+
* AI Stream Response - Calls external chat stream API and returns all chunks as JSON array
|
|
533
|
+
* @param {Object} req - Express request object
|
|
534
|
+
* @param {Object} res - Express response object
|
|
535
|
+
* Returns: [{ text: "..." }, { text: "..." }, ...]
|
|
536
|
+
*/
|
|
537
|
+
export async function aiStreamResponse( req, res ) {
|
|
538
|
+
try {
|
|
539
|
+
/* eslint-disable camelcase */
|
|
540
|
+
const { user_id, session_id, session_date, session_timezone, message, config } = req.body;
|
|
541
|
+
|
|
542
|
+
logger.info( { message: 'Received ai-stream-response request', user_id, session_id } );
|
|
543
|
+
|
|
544
|
+
// Map camelCase to snake_case for external API
|
|
545
|
+
const payload = {
|
|
546
|
+
user_id: user_id,
|
|
547
|
+
session_id: session_id,
|
|
548
|
+
session_date: session_date,
|
|
549
|
+
session_timezone: session_timezone,
|
|
550
|
+
message,
|
|
551
|
+
config: {
|
|
552
|
+
selected_stores: config.selected_stores,
|
|
553
|
+
date_range: config.date_range,
|
|
554
|
+
selected_products: config.selected_products,
|
|
555
|
+
},
|
|
556
|
+
};
|
|
557
|
+
/* eslint-enable camelcase */
|
|
558
|
+
|
|
559
|
+
const response = await fetch( CHAT_STREAM_API, {
|
|
560
|
+
method: 'POST',
|
|
561
|
+
headers: {
|
|
562
|
+
'Content-Type': 'application/json',
|
|
563
|
+
'Accept': 'text/event-stream',
|
|
564
|
+
'Referer': '',
|
|
565
|
+
},
|
|
566
|
+
body: JSON.stringify( payload ),
|
|
567
|
+
} );
|
|
568
|
+
|
|
569
|
+
if ( !response.ok ) {
|
|
570
|
+
logger.error( response, `External Chat Stream API error: ${response.status} ${response.statusText}` );
|
|
571
|
+
return res.sendError( `External API error: ${response.statusText}`, response.status );
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
const chunks = [];
|
|
575
|
+
const decoder = new TextDecoder();
|
|
576
|
+
|
|
577
|
+
for await ( const chunk of response.body ) {
|
|
578
|
+
const text = decoder.decode( chunk, { stream: true } );
|
|
579
|
+
|
|
580
|
+
// Parse SSE lines: "data: {...}" or plain text
|
|
581
|
+
const lines = text.split( '\n' );
|
|
582
|
+
for ( const line of lines ) {
|
|
583
|
+
const trimmed = line.trim();
|
|
584
|
+
if ( !trimmed ) continue;
|
|
585
|
+
|
|
586
|
+
if ( trimmed.startsWith( 'data:' ) ) {
|
|
587
|
+
const content = trimmed.slice( 5 ).trim();
|
|
588
|
+
if ( content && content !== '[DONE]' ) {
|
|
589
|
+
try {
|
|
590
|
+
const parsed = JSON.parse( content );
|
|
591
|
+
// Extract text from common SSE formats
|
|
592
|
+
const textValue = parsed.text ?? parsed.content ?? parsed.delta ?? parsed.message ?? JSON.stringify( parsed );
|
|
593
|
+
if ( textValue ) chunks.push( { text: textValue } );
|
|
594
|
+
} catch {
|
|
595
|
+
if ( content ) chunks.push( { text: content } );
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
} else {
|
|
599
|
+
chunks.push( { text: trimmed } );
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
logger.info( { message: 'ai-stream-response completed', chunkCount: chunks.length } );
|
|
605
|
+
|
|
606
|
+
return res.sendSuccess( chunks );
|
|
607
|
+
} catch ( error ) {
|
|
608
|
+
logger.error( { error: error, function: 'aiStreamResponse' } );
|
|
609
|
+
return res.sendError( error.message || 'Internal Server Error', 500 );
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
531
613
|
|
|
@@ -3,7 +3,7 @@ import express from 'express';
|
|
|
3
3
|
import { validate } from 'tango-app-api-middleware';
|
|
4
4
|
import { createCohortValid, createBulkCohortValid, updateCohortValid, getCohortValid, listCohortsByClientValid, deleteCohortValid } from '../dtos/audioAnalytics.dtos.js';
|
|
5
5
|
import { cohortAnalysisCardValid, conversationsListValid, conversationDetailsValid, chatHistoryListValid, getChatValid, getGeminiResponseValid } from '../dtos/audioAnalytics.dtos.js';
|
|
6
|
-
import { createCohort, createBulkCohort, updateCohort, deleteCohort, getCohort, listCohortsByClient, chatHistoryList, getChat, getGeminiResponse } from '../controllers/audioAnalytics.controller.js';
|
|
6
|
+
import { createCohort, createBulkCohort, updateCohort, deleteCohort, getCohort, listCohortsByClient, chatHistoryList, getChat, getGeminiResponse, aiStreamResponse } from '../controllers/audioAnalytics.controller.js';
|
|
7
7
|
import { getCohortAnalysisCard } from '../controllers/cohortAnalytics.controller.js';
|
|
8
8
|
import { getConversationsList, getConversationDetails } from '../controllers/conversationAnalytics.controller.js';
|
|
9
9
|
|
|
@@ -36,5 +36,7 @@ audioAnalyticsrouter.post( '/conversations/:conversationId', validate( conversat
|
|
|
36
36
|
// Gemini Suggestion Prompts API Route
|
|
37
37
|
audioAnalyticsrouter.post( '/gemini/suggestions', validate( getGeminiResponseValid ), getGeminiResponse );
|
|
38
38
|
|
|
39
|
+
// AI streaming response route
|
|
40
|
+
audioAnalyticsrouter.post( '/ai-stream-response', aiStreamResponse );
|
|
39
41
|
|
|
40
42
|
export default audioAnalyticsrouter;
|