Skip to content

Commit 50646ef

Browse files
[ADE-166] - Enhance Bedrock service and ChatPage error handling
- Added CONTENT_FILTERED_MESSAGE constant to provide user-friendly feedback when responses are filtered. - Implemented handleBedrockResponse method in BedrockService to manage content filtering and log filtered responses for analytics. - Updated invokeModel method to utilize the new response handling logic. - Improved error handling in ChatPage by creating a user-friendly error message when AI response fails.
1 parent f7cab9a commit 50646ef

File tree

2 files changed

+60
-3
lines changed

2 files changed

+60
-3
lines changed

frontend/src/common/services/ai/bedrock.service.ts

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { BedrockRuntimeClient, InvokeModelCommand } from '@aws-sdk/client-bedroc
22
import { fetchAuthSession } from '@aws-amplify/auth';
33
import { REGION } from '../../config/aws-config';
44

5+
export const CONTENT_FILTERED_MESSAGE = "I couldn't find an answer. Please try rephrasing your question or consult your healthcare provider.";
6+
57
export interface ChatMessage {
68
role: 'user' | 'assistant' | 'system';
79
content: string;
@@ -14,11 +16,24 @@ export interface ChatSession {
1416
updatedAt: Date;
1517
}
1618

19+
// Interfaces for Bedrock API responses
20+
interface BedrockResult {
21+
tokenCount: number;
22+
outputText: string;
23+
completionReason: 'CONTENT_FILTERED' | 'COMPLETE' | 'LENGTH' | 'STOP_SEQUENCE' | string;
24+
}
25+
26+
interface BedrockResponse {
27+
inputTextTokenCount: number;
28+
results: BedrockResult[];
29+
}
30+
1731
class BedrockService {
1832
private client: BedrockRuntimeClient | null = null;
1933
private readonly MODEL_ID = 'amazon.titan-text-lite-v1';
2034
private sessions: Map<string, ChatSession> = new Map();
2135
private isTestEnvironment: boolean;
36+
private contentFilteredCount: number = 0; // Track number of filtered responses
2237

2338
constructor() {
2439
// Check if we're in a test environment (Node.js environment with no window)
@@ -67,6 +82,37 @@ class BedrockService {
6782
}
6883
}
6984

85+
private handleBedrockResponse(parsedResponse: BedrockResponse, userPrompt?: string): string {
86+
// Check if we have results
87+
if (!parsedResponse.results || !parsedResponse.results.length) {
88+
throw new Error('Invalid response structure: missing results');
89+
}
90+
91+
const result = parsedResponse.results[0];
92+
93+
// Check for content filtering
94+
if (result.completionReason === "CONTENT_FILTERED") {
95+
// Increment counter for analytics
96+
this.contentFilteredCount++;
97+
98+
// Log for debugging if we have the original prompt
99+
if (userPrompt) {
100+
console.warn(`Content filtered response #${this.contentFilteredCount} for prompt: "${userPrompt.substring(0, 100)}..."`);
101+
} else {
102+
console.warn(`Content filtered response #${this.contentFilteredCount}`);
103+
}
104+
105+
return CONTENT_FILTERED_MESSAGE;
106+
}
107+
108+
// Check for other potential failure reasons
109+
if (result.completionReason && result.completionReason !== "COMPLETE") {
110+
console.warn(`Incomplete response with reason: ${result.completionReason}`);
111+
}
112+
113+
return result.outputText;
114+
}
115+
70116
private async invokeModel(prompt: string): Promise<string> {
71117
// In test environment, return a mock response
72118
if (this.isTestEnvironment || !this.client) {
@@ -92,8 +138,9 @@ class BedrockService {
92138
const command = new InvokeModelCommand(input);
93139
const response = await this.client.send(command);
94140
const responseBody = new TextDecoder().decode(response.body);
95-
const parsedResponse = JSON.parse(responseBody);
96-
return parsedResponse.results[0].outputText;
141+
const parsedResponse = JSON.parse(responseBody) as BedrockResponse;
142+
143+
return this.handleBedrockResponse(parsedResponse, prompt);
97144
} catch (error) {
98145
console.error('Error invoking Bedrock model:', error);
99146
throw error;
@@ -162,6 +209,11 @@ class BedrockService {
162209
public getAllSessions(): ChatSession[] {
163210
return Array.from(this.sessions.values());
164211
}
212+
213+
// Add a method to get stats
214+
public getContentFilteredStats(): { count: number } {
215+
return { count: this.contentFilteredCount };
216+
}
165217
}
166218

167219
export const bedrockService = new BedrockService();

frontend/src/pages/Chat/ChatPage.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,12 @@ const ChatPage = (): JSX.Element => {
7373
setMessages(prevMessages => [...prevMessages, assistantMessage]);
7474
} catch (error) {
7575
console.error('Error getting AI response:', error);
76-
// You could add error handling here, like showing an error message
76+
77+
// Create an error message to display to the user
78+
const errorMessage = "Sorry, something went wrong. Please try again.";
79+
80+
const assistantErrorMessage = chatService.createAssistantMessage(errorMessage);
81+
setMessages(prevMessages => [...prevMessages, assistantErrorMessage]);
7782
}
7883
};
7984

0 commit comments

Comments
 (0)