Skip to content

Commit f63333e

Browse files
Merge pull request #49 from ModusCreateOrg/ADE-166
[ADE-166] - Enhance Bedrock service and ChatPage error handling
2 parents 1c95358 + 02ef9a1 commit f63333e

File tree

9 files changed

+86
-8
lines changed

9 files changed

+86
-8
lines changed

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

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { BedrockRuntimeClient, InvokeModelCommand } from '@aws-sdk/client-bedrock-runtime';
22
import { fetchAuthSession } from '@aws-amplify/auth';
33
import { REGION } from '../../config/aws-config';
4+
import i18n from '../../utils/i18n';
5+
6+
// This function gets the translated message from i18n
7+
const getContentFilteredMessage = (): string => {
8+
return i18n.t('ai.content_filtered', { ns: 'errors' });
9+
};
410

511
export interface ChatMessage {
612
role: 'user' | 'assistant' | 'system';
@@ -14,11 +20,24 @@ export interface ChatSession {
1420
updatedAt: Date;
1521
}
1622

23+
// Interfaces for Bedrock API responses
24+
interface BedrockResult {
25+
tokenCount: number;
26+
outputText: string;
27+
completionReason: 'CONTENT_FILTERED' | 'COMPLETE' | 'LENGTH' | 'STOP_SEQUENCE' | string;
28+
}
29+
30+
interface BedrockResponse {
31+
inputTextTokenCount: number;
32+
results: BedrockResult[];
33+
}
34+
1735
class BedrockService {
1836
private client: BedrockRuntimeClient | null = null;
1937
private readonly MODEL_ID = 'amazon.titan-text-lite-v1';
2038
private sessions: Map<string, ChatSession> = new Map();
2139
private isTestEnvironment: boolean;
40+
private contentFilteredCount: number = 0; // Track number of filtered responses
2241

2342
constructor() {
2443
// Check if we're in a test environment (Node.js environment with no window)
@@ -67,6 +86,27 @@ class BedrockService {
6786
}
6887
}
6988

89+
private handleBedrockResponse(parsedResponse: BedrockResponse): string {
90+
// Check if we have results
91+
if (!parsedResponse.results || !parsedResponse.results.length) {
92+
throw new Error('Invalid response structure: missing results');
93+
}
94+
95+
const result = parsedResponse.results[0];
96+
97+
// Check for content filtering
98+
if (result.completionReason === "CONTENT_FILTERED") {
99+
// Increment counter for analytics
100+
this.contentFilteredCount++;
101+
102+
// Return the translated message
103+
return getContentFilteredMessage();
104+
}
105+
106+
107+
return result.outputText;
108+
}
109+
70110
private async invokeModel(prompt: string): Promise<string> {
71111
// In test environment, return a mock response
72112
if (this.isTestEnvironment || !this.client) {
@@ -92,8 +132,9 @@ class BedrockService {
92132
const command = new InvokeModelCommand(input);
93133
const response = await this.client.send(command);
94134
const responseBody = new TextDecoder().decode(response.body);
95-
const parsedResponse = JSON.parse(responseBody);
96-
return parsedResponse.results[0].outputText;
135+
const parsedResponse = JSON.parse(responseBody) as BedrockResponse;
136+
137+
return this.handleBedrockResponse(parsedResponse);
97138
} catch (error) {
98139
console.error('Error invoking Bedrock model:', error);
99140
throw error;
@@ -162,6 +203,11 @@ class BedrockService {
162203
public getAllSessions(): ChatSession[] {
163204
return Array.from(this.sessions.values());
164205
}
206+
207+
// Add a method to get stats
208+
public getContentFilteredStats(): { count: number } {
209+
return { count: this.contentFilteredCount };
210+
}
165211
}
166212

167213
export const bedrockService = new BedrockService();

frontend/src/common/utils/i18n/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ i18n
1919
// languages, namespaces, and resources
2020
supportedLngs: ['en', 'es', 'fr'],
2121
fallbackLng: 'en',
22-
ns: ['account', 'auth', 'common', 'home', 'user'],
22+
ns: ['account', 'auth', 'common', 'errors', 'home', 'user'],
2323
defaultNS: 'common',
2424
resources: { en, es, fr },
2525

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"chat": {
3+
"general": "Sorry, something went wrong. Please try again."
4+
},
5+
"ai": {
6+
"content_filtered": "I couldn't find an answer. Please try rephrasing your question or consult your healthcare provider."
7+
}
8+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import account from './account.json';
22
import auth from './auth.json';
33
import common from './common.json';
4+
import errors from './errors.json';
45
import home from './home.json';
56
import user from './user.json';
67

7-
export default { account, auth, common, home, user };
8+
export default { account, auth, common, errors, home, user };
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"chat": {
3+
"general": "Lo siento, algo salió mal. Por favor, inténtalo de nuevo."
4+
},
5+
"ai": {
6+
"content_filtered": "No pude encontrar una respuesta. Intenta reformular tu pregunta o consulta a tu proveedor de salud."
7+
}
8+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import account from './account.json';
22
import auth from './auth.json';
33
import common from './common.json';
4+
import errors from './errors.json';
45
import home from './home.json';
56
import user from './user.json';
67

7-
export default { account, auth, common, home, user };
8+
export default { account, auth, common, errors, home, user };
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"chat": {
3+
"general": "Désolé, une erreur s'est produite. Veuillez réessayer."
4+
},
5+
"ai": {
6+
"content_filtered": "Je n'ai pas pu trouver de réponse. Veuillez reformuler votre question ou consulter votre prestataire de soins de santé."
7+
}
8+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import account from './account.json';
22
import auth from './auth.json';
33
import common from './common.json';
4+
import errors from './errors.json';
45
import home from './home.json';
56
import user from './user.json';
67

7-
export default { account, auth, common, home, user };
8+
export default { account, auth, common, errors, home, user };

frontend/src/pages/Chat/ChatPage.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import './ChatPage.scss';
1515
* @returns JSX
1616
*/
1717
const ChatPage = (): JSX.Element => {
18-
const { t } = useTranslation();
18+
const { t } = useTranslation(['common', 'errors']);
1919
const [messages, setMessages] = useState<ChatMessageData[]>([]);
2020
const location = useLocation();
2121
const prevPathRef = useRef(location.pathname);
@@ -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+
// Use i18n directly with the full namespace and key
78+
const errorMessage = t('chat.general', { ns: 'errors' });
79+
80+
const assistantErrorMessage = chatService.createAssistantMessage(errorMessage);
81+
setMessages(prevMessages => [...prevMessages, assistantErrorMessage]);
7782
}
7883
};
7984

0 commit comments

Comments
 (0)