synced with upstream

This commit is contained in:
ManishMadan2882
2024-07-26 15:36:27 +05:30
20 changed files with 611 additions and 527 deletions

View File

@@ -1,9 +1,22 @@
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,
@@ -11,18 +24,6 @@ import {
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);
@@ -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 } })),
);
};

View File

@@ -1,8 +1,9 @@
import { useEffect, useRef } from 'react';
import { useParams } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { Query } from './conversationModels';
import { Fragment, useEffect, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate, useParams } from 'react-router-dom';
import conversationService from '../api/services/conversationService';
import ConversationBubble from './ConversationBubble';
import Send from '../assets/send.svg';
import Spinner from '../assets/spinner.svg';
@@ -15,7 +16,6 @@ import {
selectQueries,
} from './sharedConversationSlice';
import { useSelector } from 'react-redux';
import { Fragment } from 'react';
const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com';
const SharedConversation = () => {
const params = useParams();
@@ -64,7 +64,8 @@ const SharedConversation = () => {
}
const fetchQueris = () => {
identifier &&
fetch(`${apiHost}/api/shared_conversation/${identifier}`)
conversationService
.getSharedConversation(identifier || '')
.then((res) => {
if (res.status === 404 || res.status === 400)
navigate('/pagenotfound');
@@ -200,5 +201,3 @@ const SharedConversation = () => {
</div>
);
};
export default SharedConversation;

View File

@@ -1,11 +1,9 @@
import { Answer, FEEDBACK } from './conversationModels';
import conversationService from '../api/services/conversationService';
import { Doc } from '../preferences/preferenceApi';
const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com';
import { Answer, FEEDBACK } from './conversationModels';
function getDocPath(selectedDocs: Doc | null): string {
let docPath = 'default';
if (selectedDocs) {
let namePath = selectedDocs.name;
if (selectedDocs.language === namePath) {
@@ -27,10 +25,10 @@ function getDocPath(selectedDocs: Doc | null): string {
docPath = selectedDocs.docLink;
}
}
return docPath;
}
export function fetchAnswerApi(
export function handleFetchAnswer(
question: string,
signal: AbortSignal,
selectedDocs: Doc | null,
@@ -57,27 +55,22 @@ export function fetchAnswerApi(
}
> {
const docPath = getDocPath(selectedDocs);
//in history array remove all keys except prompt and response
history = history.map((item) => {
return { prompt: item.prompt, response: item.response };
});
return fetch(apiHost + '/api/answer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
question: question,
history: history,
active_docs: docPath,
conversation_id: conversationId,
prompt_id: promptId,
chunks: chunks,
token_limit: token_limit,
}),
signal,
})
return conversationService
.answer(
{
question: question,
history: history,
active_docs: docPath,
conversation_id: conversationId,
prompt_id: promptId,
chunks: chunks,
token_limit: token_limit,
},
signal,
)
.then((response) => {
if (response.ok) {
return response.json();
@@ -97,7 +90,7 @@ export function fetchAnswerApi(
});
}
export function fetchAnswerSteaming(
export function handleFetchAnswerSteaming(
question: string,
signal: AbortSignal,
selectedDocs: Doc | null,
@@ -109,29 +102,23 @@ export function fetchAnswerSteaming(
onEvent: (event: MessageEvent) => void,
): Promise<Answer> {
const docPath = getDocPath(selectedDocs);
history = history.map((item) => {
return { prompt: item.prompt, response: item.response };
});
return new Promise<Answer>((resolve, reject) => {
const body = {
question: question,
active_docs: docPath,
history: JSON.stringify(history),
conversation_id: conversationId,
prompt_id: promptId,
chunks: chunks,
token_limit: token_limit,
};
fetch(apiHost + '/stream', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
signal,
})
conversationService
.answerStream(
{
question: question,
active_docs: docPath,
history: JSON.stringify(history),
conversation_id: conversationId,
prompt_id: promptId,
chunks: chunks,
token_limit: token_limit,
},
signal,
)
.then((response) => {
if (!response.body) throw Error('No response body');
@@ -179,7 +166,8 @@ export function fetchAnswerSteaming(
});
});
}
export function searchEndpoint(
export function handleSearch(
question: string,
selectedDocs: Doc | null,
conversation_id: string | null,
@@ -188,50 +176,40 @@ export function searchEndpoint(
token_limit: number,
) {
const docPath = getDocPath(selectedDocs);
const body = {
question: question,
active_docs: docPath,
conversation_id,
history,
chunks: chunks,
token_limit: token_limit,
};
return fetch(`${apiHost}/api/search`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
})
return conversationService
.search({
question: question,
active_docs: docPath,
conversation_id,
history,
chunks: chunks,
token_limit: token_limit,
})
.then((response) => response.json())
.then((data) => {
return data;
})
.catch((err) => console.log(err));
}
export function sendFeedback(
export function handleSendFeedback(
prompt: string,
response: string,
feedback: FEEDBACK,
) {
return fetch(`${apiHost}/api/feedback`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
return conversationService
.feedback({
question: prompt,
answer: response,
feedback: feedback,
}),
}).then((response) => {
if (response.ok) {
return Promise.resolve();
} else {
return Promise.reject();
}
});
})
.then((response) => {
if (response.ok) {
return Promise.resolve();
} else {
return Promise.reject();
}
});
}
export function fetchSharedAnswerSteaming( //for shared conversations

View File

@@ -1,10 +1,14 @@
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
import store from '../store';
import { fetchAnswerApi, fetchAnswerSteaming } from './conversationApi';
import { searchEndpoint } from './conversationApi';
import { Answer, ConversationState, Query, Status } from './conversationModels';
import { getConversations } from '../preferences/preferenceApi';
import { setConversations } from '../preferences/preferenceSlice';
import store from '../store';
import {
handleFetchAnswer,
handleFetchAnswerSteaming,
handleSearch,
} from './conversationHandlers';
import { Answer, ConversationState, Query, Status } from './conversationModels';
const initialState: ConversationState = {
queries: [],
@@ -20,7 +24,7 @@ export const fetchAnswer = createAsyncThunk<Answer, { question: string }>(
const state = getState() as RootState;
if (state.preference) {
if (API_STREAMING) {
await fetchAnswerSteaming(
await handleFetchAnswerSteaming(
question,
signal,
state.preference.selectedDocs!,
@@ -45,7 +49,7 @@ export const fetchAnswer = createAsyncThunk<Answer, { question: string }>(
console.error('Failed to fetch conversations: ', error);
});
searchEndpoint(
handleSearch(
//search for sources post streaming
question,
state.preference.selectedDocs!,
@@ -89,7 +93,7 @@ export const fetchAnswer = createAsyncThunk<Answer, { question: string }>(
},
);
} else {
const answer = await fetchAnswerApi(
const answer = await handleFetchAnswer(
question,
signal,
state.preference.selectedDocs!,