From cccdbcb8b6c9c985f521a6909dcbd1f3ba07a1b4 Mon Sep 17 00:00:00 2001 From: Katerina Skroumpelou Date: Mon, 28 Aug 2023 17:03:18 +0300 Subject: [PATCH] feat(nx-dev): move supabase analytics to edge --- .../data-access-ai/src/lib/data-access-ai.ts | 24 ----------- nx-dev/data-access-ai/src/lib/utils.ts | 16 ++++++- nx-dev/feature-ai/src/lib/feed-container.tsx | 9 ++-- nx-dev/nx-dev/pages/api/ai-analytics.ts | 42 +++++++++++++++++++ nx-dev/nx-dev/pages/api/query-ai-handler.ts | 17 ++++---- nx-dev/util-ai/package.json | 3 +- 6 files changed, 71 insertions(+), 40 deletions(-) create mode 100644 nx-dev/nx-dev/pages/api/ai-analytics.ts 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 0991abc9186350..4ab974360045c8 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 @@ -1,11 +1,3 @@ -// based on: -// https://github.com/supabase-community/nextjs-openai-doc-search/blob/main/pages/api/vector-search.ts - -import { - PostgrestSingleResponse, - SupabaseClient, - createClient, -} from '@supabase/supabase-js'; import { CreateCompletionResponseUsage } from 'openai'; import { MAX_HISTORY_LENGTH, ChatItem } from '@nx/nx-dev/util-ai'; import { getChatResponse } from './utils'; @@ -66,19 +58,3 @@ export function resetHistory() { export function getHistory(): ChatItem[] { return chatFullHistory; } - -//TODO(katerina): move this to the edge function -export async function sendFeedbackAnalytics(feedback: {}): Promise< - PostgrestSingleResponse -> { - return {} as any; - // return supabaseClient.from('feedback').insert(feedback); -} - -//TODO(katerina): move this to the edge function -export async function sendQueryAnalytics(queryInfo: {}) { - // const { error } = await supabaseClient.from('user_queries').insert(queryInfo); - // if (error) { - // console.error('Error storing the query info in Supabase: ', error); - // } -} diff --git a/nx-dev/data-access-ai/src/lib/utils.ts b/nx-dev/data-access-ai/src/lib/utils.ts index e9305c276c3c59..445022fbbe0d1e 100644 --- a/nx-dev/data-access-ai/src/lib/utils.ts +++ b/nx-dev/data-access-ai/src/lib/utils.ts @@ -29,7 +29,7 @@ export function getChatResponse( query: string, chatFullHistory: ChatItem[], aiResponse?: string -) { +): Promise { return fetch('/api/query-ai-handler', { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -40,3 +40,17 @@ export function getChatResponse( }), }); } + +export function sendAnalytics( + table: string, + analyticsData: { [key: string]: string | number | null } +): Promise { + return fetch('/api/ai-analytics', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + table, + analyticsData, + }), + }); +} diff --git a/nx-dev/feature-ai/src/lib/feed-container.tsx b/nx-dev/feature-ai/src/lib/feed-container.tsx index ee96f6517c5e41..e262b16a46d341 100644 --- a/nx-dev/feature-ai/src/lib/feed-container.tsx +++ b/nx-dev/feature-ai/src/lib/feed-container.tsx @@ -1,9 +1,7 @@ import { - ChatItem, getProcessedHistory, queryAi, - sendFeedbackAnalytics, - sendQueryAnalytics, + sendAnalytics, } from '@nx/nx-dev/data-access-ai'; import { sendCustomEvent } from '@nx/nx-dev/feature-analytics'; import { RefObject, useEffect, useRef, useState } from 'react'; @@ -12,6 +10,7 @@ import { Feed } from './feed/feed'; import { LoadingState } from './loading-state'; import { Prompt } from './prompt'; import { formatMarkdownSources } from './utils'; +import { ChatItem } from '@nx/nx-dev/util-ai'; interface LastQueryMetadata { sources: string[]; @@ -86,7 +85,7 @@ export function FeedContainer(): JSX.Element { query, ...aiResponse.usage, }); - sendQueryAnalytics({ + sendAnalytics('user_queries', { action: 'ai_query', query, ...aiResponse.usage, @@ -109,7 +108,7 @@ export function FeedContainer(): JSX.Element { ? JSON.stringify(lastQueryMetadata.sources) : 'Could not retrieve last answer sources', }); - sendFeedbackAnalytics({ + sendAnalytics('feedback', { action: 'evaluation', result: answer ? answer.content : 'Could not retrieve the answer', query: question ? question.content : 'Could not retrieve the question', diff --git a/nx-dev/nx-dev/pages/api/ai-analytics.ts b/nx-dev/nx-dev/pages/api/ai-analytics.ts new file mode 100644 index 00000000000000..e0a6f1178fad49 --- /dev/null +++ b/nx-dev/nx-dev/pages/api/ai-analytics.ts @@ -0,0 +1,42 @@ +import { checkEnvVariables } from '@nx/nx-dev/util-ai'; +import { SupabaseClient, createClient } from '@supabase/supabase-js'; +import { NextRequest } from 'next/server'; + +const supabaseUrl = process.env['NX_NEXT_PUBLIC_SUPABASE_URL']; +const supabaseServiceKey = process.env['NX_SUPABASE_SERVICE_ROLE_KEY_ACTUAL']; +export const config = { + runtime: 'edge', +}; + +export default async function handler(request: NextRequest) { + checkEnvVariables('not-needed', supabaseUrl, supabaseServiceKey); + const { table, analyticsData } = await request.json(); + + const supabaseClient: SupabaseClient = createClient( + supabaseUrl as string, + supabaseServiceKey as string + ); + + try { + const result = await supabaseClient.from(table).insert(analyticsData); + + return new Response(JSON.stringify(result), { + status: 200, + headers: { + 'content-type': 'application/json', + }, + }); + } catch (e) { + return new Response( + JSON.stringify({ + error: 'Error saving feedback in Supabase.', + }), + { + status: 500, + headers: { + 'content-type': 'application/json', + }, + } + ); + } +} 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 faf12c19cbbbf1..577534725a0bd0 100644 --- a/nx-dev/nx-dev/pages/api/query-ai-handler.ts +++ b/nx-dev/nx-dev/pages/api/query-ai-handler.ts @@ -1,3 +1,6 @@ +// based on: +// https://github.com/supabase-community/nextjs-openai-doc-search/blob/main/pages/api/vector-search.ts + import { NextRequest } from 'next/server'; import { ApplicationError, @@ -21,9 +24,8 @@ import { CreateCompletionResponseUsage, CreateEmbeddingResponse } from 'openai'; import GPT3Tokenizer from 'gpt3-tokenizer'; const supabaseUrl = process.env['NX_NEXT_PUBLIC_SUPABASE_URL']; -const supabaseServiceKey = process.env['NX_SUPABASE_SERVICE_ROLE_KEY']; +const supabaseServiceKey = process.env['NX_SUPABASE_SERVICE_ROLE_KEY_ACTUAL']; const openAiKey = process.env['NX_OPENAI_KEY']; -let supabaseClient: SupabaseClient; export const config = { runtime: 'edge', @@ -33,13 +35,10 @@ export default async function handler(request: NextRequest) { checkEnvVariables(openAiKey, supabaseUrl, supabaseServiceKey); const { query, aiResponse, chatFullHistory } = await request.json(); - // This does not make sense since Edge functions are containerized? - if (!supabaseClient) { - supabaseClient = createClient( - supabaseUrl as string, - supabaseServiceKey as string - ); - } + const supabaseClient: SupabaseClient = createClient( + supabaseUrl as string, + supabaseServiceKey as string + ); try { if (!query) { diff --git a/nx-dev/util-ai/package.json b/nx-dev/util-ai/package.json index 33fcee60ea0a9c..aa059580b8e195 100644 --- a/nx-dev/util-ai/package.json +++ b/nx-dev/util-ai/package.json @@ -2,7 +2,8 @@ "name": "@nx/nx-dev/util-ai", "version": "0.0.1", "dependencies": { - "tslib": "^2.3.0" + "tslib": "^2.3.0", + "openai": "~3.3.0" }, "type": "commonjs", "main": "./src/index.js",