Skip to content

Commit

Permalink
feat(nx-dev): fixed error handling
Browse files Browse the repository at this point in the history
]
  • Loading branch information
mandarini committed Aug 28, 2023
1 parent cccdbcb commit 45a584f
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 136 deletions.
7 changes: 3 additions & 4 deletions nx-dev/data-access-ai/src/lib/data-access-ai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export async function queryAi(
);

if (!responseObj.ok) {
throw new Error(responseObj.statusText);
throw await responseObj.json();
}

const response: {
Expand All @@ -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;
}
}
Expand Down
14 changes: 0 additions & 14 deletions nx-dev/data-access-ai/src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,3 @@ export function getChatResponse(
}),
});
}

export function sendAnalytics(
table: string,
analyticsData: { [key: string]: string | number | null }
): Promise<Response> {
return fetch('/api/ai-analytics', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
table,
analyticsData,
}),
});
}
2 changes: 1 addition & 1 deletion nx-dev/feature-ai/src/lib/error-message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<div className="rounded-md bg-yellow-50 p-4">
<div className="flex">
Expand Down
20 changes: 1 addition & 19 deletions nx-dev/feature-ai/src/lib/feed-container.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
getProcessedHistory,
queryAi,
sendAnalytics,
} from '@nx/nx-dev/data-access-ai';
import { getProcessedHistory, queryAi } from '@nx/nx-dev/data-access-ai';
import { sendCustomEvent } from '@nx/nx-dev/feature-analytics';
import { RefObject, useEffect, useRef, useState } from 'react';
import { ErrorMessage } from './error-message';
Expand Down Expand Up @@ -85,11 +81,6 @@ export function FeedContainer(): JSX.Element {
query,
...aiResponse.usage,
});
sendAnalytics('user_queries', {
action: 'ai_query',
query,
...aiResponse.usage,
});
} catch (error: any) {
setQueryError(error);
}
Expand All @@ -108,15 +99,6 @@ export function FeedContainer(): JSX.Element {
? JSON.stringify(lastQueryMetadata.sources)
: 'Could not retrieve last answer sources',
});
sendAnalytics('feedback', {
action: 'evaluation',
result: answer ? answer.content : 'Could not retrieve the answer',
query: question ? question.content : 'Could not retrieve the question',
response: null, // TODO: Use query metadata here
sources: lastQueryMetadata
? JSON.stringify(lastQueryMetadata.sources)
: 'Could not retrieve last answer sources',
});
};

return (
Expand Down
42 changes: 0 additions & 42 deletions nx-dev/nx-dev/pages/api/ai-analytics.ts

This file was deleted.

85 changes: 50 additions & 35 deletions nx-dev/nx-dev/pages/api/query-ai-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<any, 'public', any> = createClient(
supabaseUrl as string,
supabaseServiceKey as string
);
const supabaseClient: SupabaseClient<any, 'public', any> = 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
Expand Down Expand Up @@ -75,13 +76,18 @@ export default async function handler(request: NextRequest) {
openAiKey as string
);

const embeddingResponse = await embeddingResponseObj.json();

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: embeddingResponse,
}
);
}

const embeddingResponse = await embeddingResponseObj.json();
const {
data: [{ embedding }],
}: CreateEmbeddingResponse = embeddingResponse;
Expand All @@ -97,13 +103,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' });
Expand Down Expand Up @@ -142,14 +154,17 @@ export default async function handler(request: NextRequest) {
openAiKey as string
);

if (!responseObj.ok) {
throw new ApplicationError('Failed to generate completion', {
data: responseObj.status,
});
}

const response = await responseObj.json();

if (!responseObj.ok) {
throw new CustomError(
'application_error',
'Failed to generate completion',
{
data: response,
}
);
}
// Message asking to double-check
const callout: string =
'{% callout type="warning" title="Always double-check!" %}The results may not be accurate, so please always double check with our documentation.{% /callout %}\n';
Expand All @@ -175,19 +190,19 @@ 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);
}
console.error('Error: ', err);

// TODO: include more response info in debug environments
// OR RETURN RESPONSE WITH DIFFERENT ERROR STATUS
console.error(err);
throw err;
return new Response(
JSON.stringify({
...JSON.parse(JSON.stringify(err)),
message: err?.['message'],
}),
{
status: 500,
headers: {
'content-type': 'application/json',
},
}
);
}
}
4 changes: 2 additions & 2 deletions nx-dev/util-ai/src/lib/moderation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { openAiAPICall } from './openai-call';
import { UserError } from './utils';
import { CustomError } from './utils';

export async function moderateContent(
sanitizedQuery: string,
Expand All @@ -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,
});
Expand Down
46 changes: 27 additions & 19 deletions nx-dev/util-ai/src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,48 @@
import {
ChatCompletionRequestMessageRoleEnum,
CreateChatCompletionResponse,
} from 'openai';
import { ChatCompletionRequestMessageRoleEnum } from 'openai';

export function checkEnvVariables(
openAiKey?: string,
supabaseUrl?: string,
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<string, any> = {}) {
super(message);
}
}
export class CustomError extends Error {
public type: string;
public data: Record<string, any>;

export class UserError extends ApplicationError {
public override type: string = 'user_error';
constructor(message: string, data: Record<string, any> = {}) {
super(message, data);
constructor(
type: string = 'application_error',
message: string,
data: Record<string, any> = {}
) {
super(message);
this.type = type;
this.data = data;
}
}

Expand Down

0 comments on commit 45a584f

Please sign in to comment.