From d83b1498645c99050b315f7f6a6b07a08e753621 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 29 Jan 2025 14:32:46 -0800 Subject: [PATCH] Fix the frontend for the HistoryList API --- .pre-commit-config.yaml | 2 +- app/frontend/src/api/api.ts | 340 +++++++++++++++------------------ app/frontend/src/api/models.ts | 152 +++++++-------- 3 files changed, 229 insertions(+), 265 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9585de49f2..aa106e2f47 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: hooks: - id: black - repo: https://github.com/pre-commit/mirrors-prettier - rev: v4.0.0-alpha.8 + rev: v3.1.0 hooks: - id: prettier types_or: [css, javascript, ts, tsx, html] diff --git a/app/frontend/src/api/api.ts b/app/frontend/src/api/api.ts index 40fc53f69e..df95f801b5 100644 --- a/app/frontend/src/api/api.ts +++ b/app/frontend/src/api/api.ts @@ -1,227 +1,191 @@ const BACKEND_URI = ""; -import { - ChatAppResponse, - ChatAppResponseOrError, - ChatAppRequest, - Config, - SimpleAPIResponse, - HistoryListApiResponse, - HistoryApiResponse, -} from "./models"; +import { ChatAppResponse, ChatAppResponseOrError, ChatAppRequest, Config, SimpleAPIResponse, HistoryListApiResponse, HistoryApiResponse } from "./models"; import { useLogin, getToken, isUsingAppServicesLogin } from "../authConfig"; -export async function getHeaders( - idToken: string | undefined, -): Promise> { - // If using login and not using app services, add the id token of the logged in account as the authorization - if (useLogin && !isUsingAppServicesLogin) { - if (idToken) { - return { Authorization: `Bearer ${idToken}` }; +export async function getHeaders(idToken: string | undefined): Promise> { + // If using login and not using app services, add the id token of the logged in account as the authorization + if (useLogin && !isUsingAppServicesLogin) { + if (idToken) { + return { Authorization: `Bearer ${idToken}` }; + } } - } - return {}; + return {}; } export async function configApi(): Promise { - const response = await fetch(`${BACKEND_URI}/config`, { - method: "GET", - }); + const response = await fetch(`${BACKEND_URI}/config`, { + method: "GET" + }); - return (await response.json()) as Config; + return (await response.json()) as Config; } -export async function askApi( - request: ChatAppRequest, - idToken: string | undefined, -): Promise { - const headers = await getHeaders(idToken); - const response = await fetch(`${BACKEND_URI}/ask`, { - method: "POST", - headers: { ...headers, "Content-Type": "application/json" }, - body: JSON.stringify(request), - }); - - if (response.status > 299 || !response.ok) { - throw Error(`Request failed with status ${response.status}`); - } - const parsedResponse: ChatAppResponseOrError = await response.json(); - if (parsedResponse.error) { - throw Error(parsedResponse.error); - } - - return parsedResponse as ChatAppResponse; +export async function askApi(request: ChatAppRequest, idToken: string | undefined): Promise { + const headers = await getHeaders(idToken); + const response = await fetch(`${BACKEND_URI}/ask`, { + method: "POST", + headers: { ...headers, "Content-Type": "application/json" }, + body: JSON.stringify(request) + }); + + if (response.status > 299 || !response.ok) { + throw Error(`Request failed with status ${response.status}`); + } + const parsedResponse: ChatAppResponseOrError = await response.json(); + if (parsedResponse.error) { + throw Error(parsedResponse.error); + } + + return parsedResponse as ChatAppResponse; } -export async function chatApi( - request: ChatAppRequest, - shouldStream: boolean, - idToken: string | undefined, -): Promise { - let url = `${BACKEND_URI}/chat`; - if (shouldStream) { - url += "/stream"; - } - const headers = await getHeaders(idToken); - return await fetch(url, { - method: "POST", - headers: { ...headers, "Content-Type": "application/json" }, - body: JSON.stringify(request), - }); +export async function chatApi(request: ChatAppRequest, shouldStream: boolean, idToken: string | undefined): Promise { + let url = `${BACKEND_URI}/chat`; + if (shouldStream) { + url += "/stream"; + } + const headers = await getHeaders(idToken); + return await fetch(url, { + method: "POST", + headers: { ...headers, "Content-Type": "application/json" }, + body: JSON.stringify(request) + }); } export async function getSpeechApi(text: string): Promise { - return await fetch("/speech", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - text: text, - }), - }) - .then((response) => { - if (response.status == 200) { - return response.blob(); - } else if (response.status == 400) { - console.log("Speech synthesis is not enabled."); - return null; - } else { - console.error("Unable to get speech synthesis."); - return null; - } + return await fetch("/speech", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + text: text + }) }) - .then((blob) => (blob ? URL.createObjectURL(blob) : null)); + .then(response => { + if (response.status == 200) { + return response.blob(); + } else if (response.status == 400) { + console.log("Speech synthesis is not enabled."); + return null; + } else { + console.error("Unable to get speech synthesis."); + return null; + } + }) + .then(blob => (blob ? URL.createObjectURL(blob) : null)); } export function getCitationFilePath(citation: string): string { - return `${BACKEND_URI}/content/${citation}`; + return `${BACKEND_URI}/content/${citation}`; } -export async function uploadFileApi( - request: FormData, - idToken: string, -): Promise { - const response = await fetch("/upload", { - method: "POST", - headers: await getHeaders(idToken), - body: request, - }); - - if (!response.ok) { - throw new Error(`Uploading files failed: ${response.statusText}`); - } - - const dataResponse: SimpleAPIResponse = await response.json(); - return dataResponse; +export async function uploadFileApi(request: FormData, idToken: string): Promise { + const response = await fetch("/upload", { + method: "POST", + headers: await getHeaders(idToken), + body: request + }); + + if (!response.ok) { + throw new Error(`Uploading files failed: ${response.statusText}`); + } + + const dataResponse: SimpleAPIResponse = await response.json(); + return dataResponse; } -export async function deleteUploadedFileApi( - filename: string, - idToken: string, -): Promise { - const headers = await getHeaders(idToken); - const response = await fetch("/delete_uploaded", { - method: "POST", - headers: { ...headers, "Content-Type": "application/json" }, - body: JSON.stringify({ filename }), - }); - - if (!response.ok) { - throw new Error(`Deleting file failed: ${response.statusText}`); - } - - const dataResponse: SimpleAPIResponse = await response.json(); - return dataResponse; +export async function deleteUploadedFileApi(filename: string, idToken: string): Promise { + const headers = await getHeaders(idToken); + const response = await fetch("/delete_uploaded", { + method: "POST", + headers: { ...headers, "Content-Type": "application/json" }, + body: JSON.stringify({ filename }) + }); + + if (!response.ok) { + throw new Error(`Deleting file failed: ${response.statusText}`); + } + + const dataResponse: SimpleAPIResponse = await response.json(); + return dataResponse; } export async function listUploadedFilesApi(idToken: string): Promise { - const response = await fetch(`/list_uploaded`, { - method: "GET", - headers: await getHeaders(idToken), - }); + const response = await fetch(`/list_uploaded`, { + method: "GET", + headers: await getHeaders(idToken) + }); - if (!response.ok) { - throw new Error(`Listing files failed: ${response.statusText}`); - } + if (!response.ok) { + throw new Error(`Listing files failed: ${response.statusText}`); + } - const dataResponse: string[] = await response.json(); - return dataResponse; + const dataResponse: string[] = await response.json(); + return dataResponse; } -export async function postChatHistoryApi( - item: any, - idToken: string, -): Promise { - const headers = await getHeaders(idToken); - const response = await fetch("/chat_history", { - method: "POST", - headers: { ...headers, "Content-Type": "application/json" }, - body: JSON.stringify(item), - }); - - if (!response.ok) { - throw new Error(`Posting chat history failed: ${response.statusText}`); - } - - const dataResponse: any = await response.json(); - return dataResponse; +export async function postChatHistoryApi(item: any, idToken: string): Promise { + const headers = await getHeaders(idToken); + const response = await fetch("/chat_history", { + method: "POST", + headers: { ...headers, "Content-Type": "application/json" }, + body: JSON.stringify(item) + }); + + if (!response.ok) { + throw new Error(`Posting chat history failed: ${response.statusText}`); + } + + const dataResponse: any = await response.json(); + return dataResponse; } -export async function getChatHistoryListApi( - count: number, - continuationToken: string | undefined, - idToken: string, -): Promise { - const headers = await getHeaders(idToken); - let url = `${BACKEND_URI}/chat_history/sessions?count=${count}`; - if (continuationToken) { - url += `&continuationToken=${continuationToken}`; - } - - const response = await fetch(url.toString(), { - method: "GET", - headers: { ...headers, "Content-Type": "application/json" }, - }); - - if (!response.ok) { - throw new Error(`Getting chat histories failed: ${response.statusText}`); - } - - const dataResponse: HistoryListApiResponse = await response.json(); - return dataResponse; +export async function getChatHistoryListApi(count: number, continuationToken: string | undefined, idToken: string): Promise { + const headers = await getHeaders(idToken); + let url = `${BACKEND_URI}/chat_history/sessions?count=${count}`; + if (continuationToken) { + url += `&continuationToken=${continuationToken}`; + } + + const response = await fetch(url.toString(), { + method: "GET", + headers: { ...headers, "Content-Type": "application/json" } + }); + + if (!response.ok) { + throw new Error(`Getting chat histories failed: ${response.statusText}`); + } + + const dataResponse: HistoryListApiResponse = await response.json(); + return dataResponse; } -export async function getChatHistoryApi( - id: string, - idToken: string, -): Promise { - const headers = await getHeaders(idToken); - const response = await fetch(`/chat_history/sessions/${id}`, { - method: "GET", - headers: { ...headers, "Content-Type": "application/json" }, - }); - - if (!response.ok) { - throw new Error(`Getting chat history failed: ${response.statusText}`); - } - - const dataResponse: HistoryApiResponse = await response.json(); - return dataResponse; +export async function getChatHistoryApi(id: string, idToken: string): Promise { + const headers = await getHeaders(idToken); + const response = await fetch(`/chat_history/sessions/${id}`, { + method: "GET", + headers: { ...headers, "Content-Type": "application/json" } + }); + + if (!response.ok) { + throw new Error(`Getting chat history failed: ${response.statusText}`); + } + + const dataResponse: HistoryApiResponse = await response.json(); + return dataResponse; } -export async function deleteChatHistoryApi( - id: string, - idToken: string, -): Promise { - const headers = await getHeaders(idToken); - const response = await fetch(`/chat_history/sessions/${id}`, { - method: "DELETE", - headers: { ...headers, "Content-Type": "application/json" }, - }); - - if (!response.ok) { - throw new Error(`Deleting chat history failed: ${response.statusText}`); - } +export async function deleteChatHistoryApi(id: string, idToken: string): Promise { + const headers = await getHeaders(idToken); + const response = await fetch(`/chat_history/sessions/${id}`, { + method: "DELETE", + headers: { ...headers, "Content-Type": "application/json" } + }); + + if (!response.ok) { + throw new Error(`Deleting chat history failed: ${response.statusText}`); + } } diff --git a/app/frontend/src/api/models.ts b/app/frontend/src/api/models.ts index 008912c34c..f560271325 100644 --- a/app/frontend/src/api/models.ts +++ b/app/frontend/src/api/models.ts @@ -1,123 +1,123 @@ export const enum RetrievalMode { - Hybrid = "hybrid", - Vectors = "vectors", - Text = "text", + Hybrid = "hybrid", + Vectors = "vectors", + Text = "text" } export const enum GPT4VInput { - TextAndImages = "textAndImages", - Images = "images", - Texts = "texts", + TextAndImages = "textAndImages", + Images = "images", + Texts = "texts" } export const enum VectorFieldOptions { - Embedding = "embedding", - ImageEmbedding = "imageEmbedding", - Both = "both", + Embedding = "embedding", + ImageEmbedding = "imageEmbedding", + Both = "both" } export type ChatAppRequestOverrides = { - retrieval_mode?: RetrievalMode; - semantic_ranker?: boolean; - semantic_captions?: boolean; - include_category?: string; - exclude_category?: string; - seed?: number; - top?: number; - temperature?: number; - minimum_search_score?: number; - minimum_reranker_score?: number; - prompt_template?: string; - prompt_template_prefix?: string; - prompt_template_suffix?: string; - suggest_followup_questions?: boolean; - use_oid_security_filter?: boolean; - use_groups_security_filter?: boolean; - use_gpt4v?: boolean; - gpt4v_input?: GPT4VInput; - vector_fields: VectorFieldOptions[]; - language: string; + retrieval_mode?: RetrievalMode; + semantic_ranker?: boolean; + semantic_captions?: boolean; + include_category?: string; + exclude_category?: string; + seed?: number; + top?: number; + temperature?: number; + minimum_search_score?: number; + minimum_reranker_score?: number; + prompt_template?: string; + prompt_template_prefix?: string; + prompt_template_suffix?: string; + suggest_followup_questions?: boolean; + use_oid_security_filter?: boolean; + use_groups_security_filter?: boolean; + use_gpt4v?: boolean; + gpt4v_input?: GPT4VInput; + vector_fields: VectorFieldOptions[]; + language: string; }; export type ResponseMessage = { - content: string; - role: string; + content: string; + role: string; }; export type Thoughts = { - title: string; - description: any; // It can be any output from the api - props?: { [key: string]: string }; + title: string; + description: any; // It can be any output from the api + props?: { [key: string]: string }; }; export type ResponseContext = { - data_points: string[]; - followup_questions: string[] | null; - thoughts: Thoughts[]; + data_points: string[]; + followup_questions: string[] | null; + thoughts: Thoughts[]; }; export type ChatAppResponseOrError = { - message: ResponseMessage; - delta: ResponseMessage; - context: ResponseContext; - session_state: any; - error?: string; + message: ResponseMessage; + delta: ResponseMessage; + context: ResponseContext; + session_state: any; + error?: string; }; export type ChatAppResponse = { - message: ResponseMessage; - delta: ResponseMessage; - context: ResponseContext; - session_state: any; + message: ResponseMessage; + delta: ResponseMessage; + context: ResponseContext; + session_state: any; }; export type ChatAppRequestContext = { - overrides?: ChatAppRequestOverrides; + overrides?: ChatAppRequestOverrides; }; export type ChatAppRequest = { - messages: ResponseMessage[]; - context?: ChatAppRequestContext; - session_state: any; + messages: ResponseMessage[]; + context?: ChatAppRequestContext; + session_state: any; }; export type Config = { - showGPT4VOptions: boolean; - showSemanticRankerOption: boolean; - showVectorOption: boolean; - showUserUpload: boolean; - showLanguagePicker: boolean; - showSpeechInput: boolean; - showSpeechOutputBrowser: boolean; - showSpeechOutputAzure: boolean; - showChatHistoryBrowser: boolean; - showChatHistoryCosmos: boolean; + showGPT4VOptions: boolean; + showSemanticRankerOption: boolean; + showVectorOption: boolean; + showUserUpload: boolean; + showLanguagePicker: boolean; + showSpeechInput: boolean; + showSpeechOutputBrowser: boolean; + showSpeechOutputAzure: boolean; + showChatHistoryBrowser: boolean; + showChatHistoryCosmos: boolean; }; export type SimpleAPIResponse = { - message?: string; + message?: string; }; export interface SpeechConfig { - speechUrls: (string | null)[]; - setSpeechUrls: (urls: (string | null)[]) => void; - audio: HTMLAudioElement; - isPlaying: boolean; - setIsPlaying: (isPlaying: boolean) => void; + speechUrls: (string | null)[]; + setSpeechUrls: (urls: (string | null)[]) => void; + audio: HTMLAudioElement; + isPlaying: boolean; + setIsPlaying: (isPlaying: boolean) => void; } export type HistoryListApiResponse = { - sessions: { - id: string; - entra_oid: string; - title: string; - timestamp: number; - }[]; - continuation_token?: string; + sessions: { + id: string; + entra_oid: string; + title: string; + timestamp: number; + }[]; + continuation_token?: string; }; export type HistoryApiResponse = { - id: string; - entra_oid: string; - answers: any; + id: string; + entra_oid: string; + answers: any; };