Skip to content

Commit

Permalink
Merge pull request arc53#1040 from siiddhantt/enhancement/reusable-ap…
Browse files Browse the repository at this point in the history
…i-client

enhancement: reusable api client in frontend
  • Loading branch information
dartpain authored Jul 25, 2024
2 parents 56a16b8 + 0c062a8 commit 43d6e78
Show file tree
Hide file tree
Showing 19 changed files with 604 additions and 511 deletions.
78 changes: 31 additions & 47 deletions frontend/src/Navigation.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,48 @@
import { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import { NavLink, useNavigate } from 'react-router-dom';

import conversationService from './api/services/conversationService';
import userService from './api/services/userService';
import Add from './assets/add.svg';
import DocsGPT3 from './assets/cute_docsgpt3.svg';
import Discord from './assets/discord.svg';
import Expand from './assets/expand.svg';
import Github from './assets/github.svg';
import Hamburger from './assets/hamburger.svg';
import HamburgerDark from './assets/hamburger-dark.svg';
import Hamburger from './assets/hamburger.svg';
import Info from './assets/info.svg';
import SettingGear from './assets/settingGear.svg';
import Twitter from './assets/TwitterX.svg';
import Add from './assets/add.svg';
import UploadIcon from './assets/upload.svg';
import SourceDropdown from './components/SourceDropdown';
import {
setConversation,
updateConversationId,
} from './conversation/conversationSlice';
import ConversationTile from './conversation/ConversationTile';
import { useDarkTheme, useMediaQuery, useOutsideAlerter } from './hooks';
import DeleteConvModal from './modals/DeleteConvModal';
import { ActiveState } from './models/misc';
import APIKeyModal from './preferences/APIKeyModal';
import DeleteConvModal from './modals/DeleteConvModal';

import { Doc, getConversations, getDocs } from './preferences/preferenceApi';
import {
selectApiKeyStatus,
selectConversationId,
selectConversations,
selectModalStateDeleteConv,
selectSelectedDocs,
selectSelectedDocsStatus,
selectSourceDocs,
setSelectedDocs,
selectConversations,
setConversations,
selectConversationId,
selectModalStateDeleteConv,
setModalStateDeleteConv,
setSelectedDocs,
setSourceDocs,
} from './preferences/preferenceSlice';
import {
setConversation,
updateConversationId,
} from './conversation/conversationSlice';
import { useMediaQuery, useOutsideAlerter } from './hooks';
import Upload from './upload/Upload';
import { Doc, getConversations, getDocs } from './preferences/preferenceApi';
import SelectDocsModal from './preferences/SelectDocsModal';
import ConversationTile from './conversation/ConversationTile';
import { useDarkTheme } from './hooks';
import SourceDropdown from './components/SourceDropdown';
import { useTranslation } from 'react-i18next';
import Upload from './upload/Upload';

interface NavigationProps {
navOpen: boolean;
setNavOpen: React.Dispatch<React.SetStateAction<boolean>>;
Expand Down Expand Up @@ -85,7 +87,6 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
useState<ActiveState>('INACTIVE');

const navRef = useRef(null);
const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com';

const navigate = useNavigate();

Expand All @@ -106,19 +107,17 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
}

const handleDeleteAllConversations = () => {
fetch(`${apiHost}/api/delete_all_conversations`, {
method: 'POST',
})
conversationService
.deleteAll({})
.then(() => {
fetchConversations();
})
.catch((error) => console.error(error));
};

const handleDeleteConversation = (id: string) => {
fetch(`${apiHost}/api/delete_conversation?id=${id}`, {
method: 'POST',
})
conversationService
.delete(id, {})
.then(() => {
fetchConversations();
})
Expand All @@ -128,17 +127,9 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
const handleDeleteClick = (doc: Doc) => {
const docPath = `indexes/local/${doc.name}`;

fetch(`${apiHost}/api/delete_old?path=${docPath}`, {
method: 'GET',
})
userService
.deletePath(docPath)
.then(() => {
// remove the image element from the DOM
// const imageElement = document.querySelector(
// `#img-${index}`,
// ) as HTMLElement;
// const parentElement = imageElement.parentNode as HTMLElement;
// parentElement.parentNode?.removeChild(parentElement);

return getDocs();
})
.then((updatedDocs) => {
Expand All @@ -153,10 +144,8 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
};

const handleConversationClick = (index: string) => {
// fetch the conversation from the server and setConversation in the store
fetch(`${apiHost}/api/get_single_conversation?id=${index}`, {
method: 'GET',
})
conversationService
.getConversation(index)
.then((response) => response.json())
.then((data) => {
navigate('/');
Expand All @@ -173,13 +162,8 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
name: string;
id: string;
}) {
await fetch(`${apiHost}/api/update_conversation_name`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(updatedConversation),
})
await conversationService
.update(updatedConversation)
.then((response) => response.json())
.then((data) => {
if (data) {
Expand Down
69 changes: 69 additions & 0 deletions frontend/src/api/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
const baseURL = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com';

const defaultHeaders = {
'Content-Type': 'application/json',
};

const apiClient = {
get: (url: string, headers = {}, signal?: AbortSignal): Promise<any> =>
fetch(`${baseURL}${url}`, {
method: 'GET',
headers: {
...defaultHeaders,
...headers,
},
signal,
}).then((response) => {
return response;
}),

post: (
url: string,
data: any,
headers = {},
signal?: AbortSignal,
): Promise<any> =>
fetch(`${baseURL}${url}`, {
method: 'POST',
headers: {
...defaultHeaders,
...headers,
},
body: JSON.stringify(data),
signal,
}).then((response) => {
return response;
}),

put: (
url: string,
data: any,
headers = {},
signal?: AbortSignal,
): Promise<any> =>
fetch(`${baseURL}${url}`, {
method: 'PUT',
headers: {
...defaultHeaders,
...headers,
},
body: JSON.stringify(data),
signal,
}).then((response) => {
return response;
}),

delete: (url: string, headers = {}, signal?: AbortSignal): Promise<any> =>
fetch(`${baseURL}${url}`, {
method: 'DELETE',
headers: {
...defaultHeaders,
...headers,
},
signal,
}).then((response) => {
return response;
}),
};

export default apiClient;
33 changes: 33 additions & 0 deletions frontend/src/api/endpoints.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const endpoints = {
USER: {
DOCS: '/api/combine',
DOCS_CHECK: '/api/docs_check',
API_KEYS: '/api/get_api_keys',
CREATE_API_KEY: '/api/create_api_key',
DELETE_API_KEY: '/api/delete_api_key',
PROMPTS: '/api/get_prompts',
CREATE_PROMPT: '/api/create_prompt',
DELETE_PROMPT: '/api/delete_prompt',
UPDATE_PROMPT: '/api/update_prompt',
SINGLE_PROMPT: (id: string) => `/api/get_single_prompt?id=${id}`,
DELETE_PATH: (docPath: string) => `/api/delete_old?path=${docPath}`,
TASK_STATUS: (task_id: string) => `/api/task_status?task_id=${task_id}`,
},
CONVERSATION: {
ANSWER: '/api/answer',
ANSWER_STREAMING: '/stream',
SEARCH: '/api/search',
FEEDBACK: '/api/feedback',
CONVERSATION: (id: string) => `/api/get_single_conversation?id=${id}`,
CONVERSATIONS: '/api/get_conversations',
SHARE_CONVERSATION: (isPromptable: boolean) =>
`/api/share?isPromptable=${isPromptable}`,
SHARED_CONVERSATION: (identifier: string) =>
`/api/shared_conversation/${identifier}`,
DELETE: (id: string) => `/api/delete_conversation?id=${id}`,
DELETE_ALL: '/api/delete_all_conversations',
UPDATE: '/api/update_conversation_name',
},
};

export default endpoints;
32 changes: 32 additions & 0 deletions frontend/src/api/services/conversationService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import apiClient from '../client';
import endpoints from '../endpoints';

const conversationService = {
answer: (data: any, signal: AbortSignal): Promise<any> =>
apiClient.post(endpoints.CONVERSATION.ANSWER, data, {}, signal),
answerStream: (data: any, signal: AbortSignal): Promise<any> =>
apiClient.post(endpoints.CONVERSATION.ANSWER_STREAMING, data, {}, signal),
search: (data: any): Promise<any> =>
apiClient.post(endpoints.CONVERSATION.SEARCH, data),
feedback: (data: any): Promise<any> =>
apiClient.post(endpoints.CONVERSATION.FEEDBACK, data),
getConversation: (id: string): Promise<any> =>
apiClient.get(endpoints.CONVERSATION.CONVERSATION(id)),
getConversations: (): Promise<any> =>
apiClient.get(endpoints.CONVERSATION.CONVERSATIONS),
shareConversation: (isPromptable: boolean, data: any): Promise<any> =>
apiClient.post(
endpoints.CONVERSATION.SHARE_CONVERSATION(isPromptable),
data,
),
getSharedConversation: (identifier: string): Promise<any> =>
apiClient.get(endpoints.CONVERSATION.SHARED_CONVERSATION(identifier)),
delete: (id: string, data: any): Promise<any> =>
apiClient.post(endpoints.CONVERSATION.DELETE(id), data),
deleteAll: (data: any): Promise<any> =>
apiClient.post(endpoints.CONVERSATION.DELETE_ALL, data),
update: (data: any): Promise<any> =>
apiClient.post(endpoints.CONVERSATION.UPDATE, data),
};

export default conversationService;
28 changes: 28 additions & 0 deletions frontend/src/api/services/userService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import apiClient from '../client';
import endpoints from '../endpoints';

const userService = {
getDocs: (): Promise<any> => apiClient.get(endpoints.USER.DOCS),
checkDocs: (data: any): Promise<any> =>
apiClient.post(endpoints.USER.DOCS_CHECK, data),
getAPIKeys: (): Promise<any> => apiClient.get(endpoints.USER.API_KEYS),
createAPIKey: (data: any): Promise<any> =>
apiClient.post(endpoints.USER.CREATE_API_KEY, data),
deleteAPIKey: (data: any): Promise<any> =>
apiClient.post(endpoints.USER.DELETE_API_KEY, data),
getPrompts: (): Promise<any> => apiClient.get(endpoints.USER.PROMPTS),
createPrompt: (data: any): Promise<any> =>
apiClient.post(endpoints.USER.CREATE_PROMPT, data),
deletePrompt: (data: any): Promise<any> =>
apiClient.post(endpoints.USER.DELETE_PROMPT, data),
updatePrompt: (data: any): Promise<any> =>
apiClient.post(endpoints.USER.UPDATE_PROMPT, data),
getSinglePrompt: (id: string): Promise<any> =>
apiClient.get(endpoints.USER.SINGLE_PROMPT(id)),
deletePath: (docPath: string): Promise<any> =>
apiClient.get(endpoints.USER.DELETE_PATH(docPath)),
getTaskStatus: (task_id: string): Promise<any> =>
apiClient.get(endpoints.USER.TASK_STATUS(task_id)),
};

export default userService;
29 changes: 15 additions & 14 deletions frontend/src/conversation/Conversation.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
import { Fragment, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import { useDarkTheme } from '../hooks';

import ArrowDown from '../assets/arrow-down.svg';
import Send from '../assets/send.svg';
import SendDark from '../assets/send_dark.svg';
import ShareIcon from '../assets/share.svg';
import SpinnerDark from '../assets/spinner-dark.svg';
import Spinner from '../assets/spinner.svg';
import RetryIcon from '../components/RetryIcon';
import Hero from '../Hero';
import { useDarkTheme } from '../hooks';
import { ShareConversationModal } from '../modals/ShareConversationModal';
import { selectConversationId } from '../preferences/preferenceSlice';
import { AppDispatch } from '../store';
import ConversationBubble from './ConversationBubble';
import { handleSendFeedback } from './conversationHandlers';
import { FEEDBACK, Query } from './conversationModels';
import {
addQuery,
fetchAnswer,
selectQueries,
selectStatus,
updateQuery,
} from './conversationSlice';
import { selectConversationId } from '../preferences/preferenceSlice';
import Send from './../assets/send.svg';
import SendDark from './../assets/send_dark.svg';
import Spinner from './../assets/spinner.svg';
import SpinnerDark from './../assets/spinner-dark.svg';
import { FEEDBACK, Query } from './conversationModels';
import { sendFeedback } from './conversationApi';
import { useTranslation } from 'react-i18next';
import ArrowDown from './../assets/arrow-down.svg';
import RetryIcon from '../components/RetryIcon';
import ShareIcon from '../assets/share.svg';
import { ShareConversationModal } from '../modals/ShareConversationModal';

export default function Conversation() {
const queries = useSelector(selectQueries);
Expand Down Expand Up @@ -112,7 +113,7 @@ export default function Conversation() {
const handleFeedback = (query: Query, feedback: FEEDBACK, index: number) => {
const prevFeedback = query.feedback;
dispatch(updateQuery({ index, query: { feedback } }));
sendFeedback(query.prompt, query.response!, feedback).catch(() =>
handleSendFeedback(query.prompt, query.response!, feedback).catch(() =>
dispatch(updateQuery({ index, query: { feedback: prevFeedback } })),
);
};
Expand Down
Loading

0 comments on commit 43d6e78

Please sign in to comment.