From cea5f33e137c916cb7880b0dedb4463ad04a3690 Mon Sep 17 00:00:00 2001 From: Katerina Skroumpelou Date: Mon, 28 Aug 2023 18:22:03 +0300 Subject: [PATCH] feat(nx-dev): fixed error handling ] --- .../data-access-ai/src/lib/data-access-ai.ts | 7 +- nx-dev/feature-ai/src/lib/error-message.tsx | 2 +- nx-dev/nx-dev/pages/api/query-ai-handler.ts | 78 +++++++++++-------- nx-dev/util-ai/src/lib/moderation.ts | 4 +- nx-dev/util-ai/src/lib/utils.ts | 46 ++++++----- 5 files changed, 79 insertions(+), 58 deletions(-) diff --git a/nx-dev/data-access-ai/src/lib/data-access-ai.ts b/nx-dev/data-access-ai/src/lib/data-access-ai.ts index 4ab974360045c8..0e9ce7fccb33ea 100644 --- a/nx-dev/data-access-ai/src/lib/data-access-ai.ts +++ b/nx-dev/data-access-ai/src/lib/data-access-ai.ts @@ -27,7 +27,7 @@ export async function queryAi( ); if (!responseObj.ok) { - throw new Error(responseObj.statusText); + throw await responseObj.json(); } const response: { @@ -43,9 +43,8 @@ export async function queryAi( chatFullHistory = response.chatHistory; return response; - } catch (e) { - // TODO(katerina): Fix this to show the actual error - console.error('Error in fetch', e); + } catch (e: any) { + console.error('Error: ', e?.['message'] || e); throw e; } } diff --git a/nx-dev/feature-ai/src/lib/error-message.tsx b/nx-dev/feature-ai/src/lib/error-message.tsx index 233c3610aaaf6e..9e46d6aeef3adc 100644 --- a/nx-dev/feature-ai/src/lib/error-message.tsx +++ b/nx-dev/feature-ai/src/lib/error-message.tsx @@ -4,7 +4,7 @@ import { } from '@heroicons/react/24/outline'; export function ErrorMessage({ error }: { error: any }): JSX.Element { - if (error.data.no_results) { + if (error?.data?.no_results) { return (
diff --git a/nx-dev/nx-dev/pages/api/query-ai-handler.ts b/nx-dev/nx-dev/pages/api/query-ai-handler.ts index 577534725a0bd0..065aaa34ce9fc1 100644 --- a/nx-dev/nx-dev/pages/api/query-ai-handler.ts +++ b/nx-dev/nx-dev/pages/api/query-ai-handler.ts @@ -3,13 +3,12 @@ import { NextRequest } from 'next/server'; import { - ApplicationError, + CustomError, DEFAULT_MATCH_COUNT, DEFAULT_MATCH_THRESHOLD, MIN_CONTENT_LENGTH, PROMPT, PageSection, - UserError, checkEnvVariables, getListOfSources, getMessageFromResponse, @@ -32,17 +31,19 @@ export const config = { }; export default async function handler(request: NextRequest) { - checkEnvVariables(openAiKey, supabaseUrl, supabaseServiceKey); - const { query, aiResponse, chatFullHistory } = await request.json(); + try { + checkEnvVariables(openAiKey, supabaseUrl, supabaseServiceKey); + const { query, aiResponse, chatFullHistory } = await request.json(); - const supabaseClient: SupabaseClient = createClient( - supabaseUrl as string, - supabaseServiceKey as string - ); + const supabaseClient: SupabaseClient = createClient( + supabaseUrl as string, + supabaseServiceKey as string + ); - try { if (!query) { - throw new UserError('Missing query in request data'); + throw new CustomError('user_error', 'Missing query in request data', { + missing_query: true, + }); } // Moderate the content to comply with OpenAI T&C @@ -76,9 +77,13 @@ export default async function handler(request: NextRequest) { ); if (!embeddingResponseObj.ok) { - throw new ApplicationError('Failed to create embedding for question', { - data: embeddingResponseObj.status, - }); + throw new CustomError( + 'application_error', + 'Failed to create embedding for question', + { + data: embeddingResponseObj.status, + } + ); } const embeddingResponse = await embeddingResponseObj.json(); @@ -97,13 +102,19 @@ export default async function handler(request: NextRequest) { ); if (matchError) { - throw new ApplicationError('Failed to match page sections', matchError); + throw new CustomError( + 'application_error', + 'Failed to match page sections', + matchError + ); } // Note: this is experimental. I think it should work // mainly because we're testing previous response + query. if (!pageSections || pageSections.length === 0) { - throw new UserError('No results found.', { no_results: true }); + throw new CustomError('user_error', 'No results found.', { + no_results: true, + }); } const tokenizer = new GPT3Tokenizer({ type: 'gpt3' }); @@ -143,9 +154,13 @@ export default async function handler(request: NextRequest) { ); if (!responseObj.ok) { - throw new ApplicationError('Failed to generate completion', { - data: responseObj.status, - }); + throw new CustomError( + 'application_error', + 'Failed to generate completion', + { + data: responseObj.status, + } + ); } const response = await responseObj.json(); @@ -175,19 +190,18 @@ export default async function handler(request: NextRequest) { }, }); } catch (err: unknown) { - if (err instanceof UserError) { - console.error(err.message); - } else if (err instanceof ApplicationError) { - // Print out application errors with their additional data - console.error(`${err.message}: ${JSON.stringify(err.data)}`); - } else { - // Print out unexpected errors as is to help with debugging - console.error(err); - } - - // TODO: include more response info in debug environments - // OR RETURN RESPONSE WITH DIFFERENT ERROR STATUS - console.error(err); - throw err; + console.error('Error: ', err); + return new Response( + JSON.stringify({ + ...JSON.parse(JSON.stringify(err)), + message: err?.['message'], + }), + { + status: 500, + headers: { + 'content-type': 'application/json', + }, + } + ); } } diff --git a/nx-dev/util-ai/src/lib/moderation.ts b/nx-dev/util-ai/src/lib/moderation.ts index 381506a167911c..73240ddb607209 100644 --- a/nx-dev/util-ai/src/lib/moderation.ts +++ b/nx-dev/util-ai/src/lib/moderation.ts @@ -1,5 +1,5 @@ import { openAiAPICall } from './openai-call'; -import { UserError } from './utils'; +import { CustomError } from './utils'; export async function moderateContent( sanitizedQuery: string, @@ -15,7 +15,7 @@ export async function moderateContent( const [results] = moderationResponse.results; if (results.flagged) { - throw new UserError('Flagged content', { + throw new CustomError('user_error', 'Flagged content', { flagged: true, categories: results.categories, }); diff --git a/nx-dev/util-ai/src/lib/utils.ts b/nx-dev/util-ai/src/lib/utils.ts index 3c3f632dc492de..6a8a6b5ba58363 100644 --- a/nx-dev/util-ai/src/lib/utils.ts +++ b/nx-dev/util-ai/src/lib/utils.ts @@ -1,7 +1,4 @@ -import { - ChatCompletionRequestMessageRoleEnum, - CreateChatCompletionResponse, -} from 'openai'; +import { ChatCompletionRequestMessageRoleEnum } from 'openai'; export function checkEnvVariables( openAiKey?: string, @@ -9,32 +6,43 @@ export function checkEnvVariables( supabaseServiceKey?: string ) { if (!openAiKey) { - throw new ApplicationError('Missing environment variable NX_OPENAI_KEY'); + throw new CustomError( + 'application_error', + 'Missing environment variable NX_OPENAI_KEY', + { + missing_key: true, + } + ); } if (!supabaseUrl) { - throw new ApplicationError( - 'Missing environment variable NX_NEXT_PUBLIC_SUPABASE_URL' + throw new CustomError( + 'application_error', + 'Missing environment variable NX_NEXT_PUBLIC_SUPABASE_URL', + { missing_key: true } ); } if (!supabaseServiceKey) { - throw new ApplicationError( - 'Missing environment variable NX_SUPABASE_SERVICE_ROLE_KEY' + throw new CustomError( + 'application_error', + 'Missing environment variable NX_SUPABASE_SERVICE_ROLE_KEY', + { missing_key: true } ); } } -export class ApplicationError extends Error { - public type: string = 'application_error'; - constructor(message: string, public data: Record = {}) { - super(message); - } -} +export class CustomError extends Error { + public type: string; + public data: Record; -export class UserError extends ApplicationError { - public override type: string = 'user_error'; - constructor(message: string, data: Record = {}) { - super(message, data); + constructor( + type: string = 'application_error', + message: string, + data: Record = {} + ) { + super(message); + this.type = type; + this.data = data; } }