mirror of
https://github.com/arc53/DocsGPT.git
synced 2025-11-30 00:53:14 +00:00
(refactor:attachments) moved to new uploadSlice
This commit is contained in:
@@ -18,7 +18,7 @@ import {
|
||||
removeAttachment,
|
||||
selectAttachments,
|
||||
updateAttachment,
|
||||
} from '../conversation/conversationSlice';
|
||||
} from '../upload/uploadSlice';
|
||||
import { useDarkTheme } from '../hooks';
|
||||
import { ActiveState } from '../models/misc';
|
||||
import {
|
||||
|
||||
@@ -27,8 +27,11 @@ import {
|
||||
setConversation,
|
||||
updateConversationId,
|
||||
updateQuery,
|
||||
selectAttachments,
|
||||
} from './conversationSlice';
|
||||
import {
|
||||
selectCompletedAttachments,
|
||||
clearAttachments,
|
||||
} from '../upload/uploadSlice';
|
||||
|
||||
export default function Conversation() {
|
||||
const { t } = useTranslation();
|
||||
@@ -40,7 +43,7 @@ export default function Conversation() {
|
||||
const status = useSelector(selectStatus);
|
||||
const conversationId = useSelector(selectConversationId);
|
||||
const selectedAgent = useSelector(selectSelectedAgent);
|
||||
const attachments = useSelector(selectAttachments);
|
||||
const completedAttachments = useSelector(selectCompletedAttachments);
|
||||
|
||||
const [uploadModalState, setUploadModalState] =
|
||||
useState<ActiveState>('INACTIVE');
|
||||
@@ -109,8 +112,8 @@ export default function Conversation() {
|
||||
const trimmedQuestion = question.trim();
|
||||
if (trimmedQuestion === '') return;
|
||||
|
||||
const filesAttached = attachments
|
||||
.filter((a) => a.id && a.status === 'completed')
|
||||
const filesAttached = completedAttachments
|
||||
.filter((a) => a.id)
|
||||
.map((a) => ({ id: a.id as string, fileName: a.fileName }));
|
||||
|
||||
if (index !== undefined) {
|
||||
@@ -127,7 +130,7 @@ export default function Conversation() {
|
||||
handleFetchAnswer({ question: trimmedQuestion, index });
|
||||
}
|
||||
},
|
||||
[dispatch, handleFetchAnswer, attachments],
|
||||
[dispatch, handleFetchAnswer, completedAttachments],
|
||||
);
|
||||
|
||||
const handleFeedback = (query: Query, feedback: FEEDBACK, index: number) => {
|
||||
@@ -190,6 +193,7 @@ export default function Conversation() {
|
||||
query: { conversationId: null },
|
||||
}),
|
||||
);
|
||||
dispatch(clearAttachments());
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
setIdentifier,
|
||||
updateQuery,
|
||||
} from './sharedConversationSlice';
|
||||
import { selectCompletedAttachments } from '../upload/uploadSlice';
|
||||
|
||||
export const SharedConversation = () => {
|
||||
const navigate = useNavigate();
|
||||
@@ -34,6 +35,7 @@ export const SharedConversation = () => {
|
||||
const date = useSelector(selectDate);
|
||||
const apiKey = useSelector(selectClientAPIKey);
|
||||
const status = useSelector(selectStatus);
|
||||
const completedAttachments = useSelector(selectCompletedAttachments);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch<AppDispatch>();
|
||||
@@ -106,7 +108,19 @@ export const SharedConversation = () => {
|
||||
}) => {
|
||||
question = question.trim();
|
||||
if (question === '') return;
|
||||
!isRetry && dispatch(addQuery({ prompt: question })); //dispatch only new queries
|
||||
|
||||
const filesAttached = completedAttachments
|
||||
.filter((a) => a.id)
|
||||
.map((a) => ({ id: a.id as string, fileName: a.fileName }));
|
||||
|
||||
!isRetry &&
|
||||
dispatch(
|
||||
addQuery({
|
||||
prompt: question,
|
||||
attachments: filesAttached,
|
||||
}),
|
||||
); //dispatch only new queries
|
||||
|
||||
dispatch(fetchSharedAnswer({ question }));
|
||||
};
|
||||
useEffect(() => {
|
||||
|
||||
@@ -284,6 +284,7 @@ export function handleFetchSharedAnswerStreaming( //for shared conversations
|
||||
signal: AbortSignal,
|
||||
apiKey: string,
|
||||
history: Array<any> = [],
|
||||
attachments: string[] = [], // Add attachments parameter with default empty array
|
||||
onEvent: (event: MessageEvent) => void,
|
||||
): Promise<Answer> {
|
||||
history = history.map((item) => {
|
||||
@@ -300,6 +301,7 @@ export function handleFetchSharedAnswerStreaming( //for shared conversations
|
||||
history: JSON.stringify(history),
|
||||
api_key: apiKey,
|
||||
save_conversation: false,
|
||||
attachments: attachments.length > 0 ? attachments : undefined, // Add attachments to payload
|
||||
};
|
||||
conversationService
|
||||
.answerStream(payload, null, signal)
|
||||
@@ -355,6 +357,7 @@ export function handleFetchSharedAnswer(
|
||||
question: string,
|
||||
signal: AbortSignal,
|
||||
apiKey: string,
|
||||
attachments?: string[],
|
||||
): Promise<
|
||||
| {
|
||||
result: any;
|
||||
@@ -370,15 +373,18 @@ export function handleFetchSharedAnswer(
|
||||
title: any;
|
||||
}
|
||||
> {
|
||||
const payload = {
|
||||
question: question,
|
||||
api_key: apiKey,
|
||||
};
|
||||
|
||||
// Add attachments to payload if they exist
|
||||
if (attachments && attachments.length > 0) {
|
||||
payload.attachments = attachments;
|
||||
}
|
||||
|
||||
return conversationService
|
||||
.answer(
|
||||
{
|
||||
question: question,
|
||||
api_key: apiKey,
|
||||
},
|
||||
null,
|
||||
signal,
|
||||
)
|
||||
.answer(payload, null, signal)
|
||||
.then((response) => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
|
||||
@@ -22,7 +22,6 @@ export interface ConversationState {
|
||||
queries: Query[];
|
||||
status: Status;
|
||||
conversationId: string | null;
|
||||
attachments: Attachment[];
|
||||
}
|
||||
|
||||
export interface Answer {
|
||||
|
||||
@@ -3,23 +3,17 @@ import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||
import { getConversations } from '../preferences/preferenceApi';
|
||||
import { setConversations } from '../preferences/preferenceSlice';
|
||||
import store from '../store';
|
||||
import { selectCompletedAttachments } from '../upload/uploadSlice';
|
||||
import {
|
||||
handleFetchAnswer,
|
||||
handleFetchAnswerSteaming,
|
||||
} from './conversationHandlers';
|
||||
import {
|
||||
Answer,
|
||||
Query,
|
||||
Status,
|
||||
ConversationState,
|
||||
Attachment,
|
||||
} from './conversationModels';
|
||||
import { Answer, Query, Status, ConversationState } from './conversationModels';
|
||||
|
||||
const initialState: ConversationState = {
|
||||
queries: [],
|
||||
status: 'idle',
|
||||
conversationId: null,
|
||||
attachments: [],
|
||||
};
|
||||
|
||||
const API_STREAMING = import.meta.env.VITE_API_STREAMING === 'true';
|
||||
@@ -44,8 +38,8 @@ export const fetchAnswer = createAsyncThunk<
|
||||
|
||||
let isSourceUpdated = false;
|
||||
const state = getState() as RootState;
|
||||
const attachmentIds = state.conversation.attachments
|
||||
.filter((a) => a.id && a.status === 'completed')
|
||||
const attachmentIds = selectCompletedAttachments(state)
|
||||
.filter((a) => a.id)
|
||||
.map((a) => a.id) as string[];
|
||||
const currentConversationId = state.conversation.conversationId;
|
||||
const conversationIdToSend = isPreview ? null : currentConversationId;
|
||||
@@ -307,39 +301,11 @@ export const conversationSlice = createSlice({
|
||||
const { index, message } = action.payload;
|
||||
state.queries[index].error = message;
|
||||
},
|
||||
setAttachments: (state, action: PayloadAction<Attachment[]>) => {
|
||||
state.attachments = action.payload;
|
||||
},
|
||||
addAttachment: (state, action: PayloadAction<Attachment>) => {
|
||||
state.attachments.push(action.payload);
|
||||
},
|
||||
updateAttachment: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
taskId: string;
|
||||
updates: Partial<Attachment>;
|
||||
}>,
|
||||
) => {
|
||||
const index = state.attachments.findIndex(
|
||||
(att) => att.taskId === action.payload.taskId,
|
||||
);
|
||||
if (index !== -1) {
|
||||
state.attachments[index] = {
|
||||
...state.attachments[index],
|
||||
...action.payload.updates,
|
||||
};
|
||||
}
|
||||
},
|
||||
removeAttachment: (state, action: PayloadAction<string>) => {
|
||||
state.attachments = state.attachments.filter(
|
||||
(att) => att.taskId !== action.payload && att.id !== action.payload,
|
||||
);
|
||||
},
|
||||
|
||||
resetConversation: (state) => {
|
||||
state.queries = initialState.queries;
|
||||
state.status = initialState.status;
|
||||
state.conversationId = initialState.conversationId;
|
||||
state.attachments = initialState.attachments;
|
||||
handleAbort();
|
||||
},
|
||||
},
|
||||
@@ -365,11 +331,6 @@ export const selectQueries = (state: RootState) => state.conversation.queries;
|
||||
|
||||
export const selectStatus = (state: RootState) => state.conversation.status;
|
||||
|
||||
export const selectAttachments = (state: RootState) =>
|
||||
state.conversation.attachments;
|
||||
export const selectCompletedAttachments = (state: RootState) =>
|
||||
state.conversation.attachments.filter((att) => att.status === 'completed');
|
||||
|
||||
export const {
|
||||
addQuery,
|
||||
updateQuery,
|
||||
@@ -380,10 +341,8 @@ export const {
|
||||
updateStreamingSource,
|
||||
updateToolCalls,
|
||||
setConversation,
|
||||
setAttachments,
|
||||
addAttachment,
|
||||
updateAttachment,
|
||||
removeAttachment,
|
||||
setStatus,
|
||||
raiseError,
|
||||
resetConversation,
|
||||
} = conversationSlice.actions;
|
||||
export default conversationSlice.reducer;
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
handleFetchSharedAnswer,
|
||||
handleFetchSharedAnswerStreaming,
|
||||
} from './conversationHandlers';
|
||||
import { selectCompletedAttachments } from '../upload/uploadSlice';
|
||||
|
||||
const API_STREAMING = import.meta.env.VITE_API_STREAMING === 'true';
|
||||
interface SharedConversationsType {
|
||||
@@ -29,6 +30,10 @@ export const fetchSharedAnswer = createAsyncThunk<Answer, { question: string }>(
|
||||
async ({ question }, { dispatch, getState, signal }) => {
|
||||
const state = getState() as RootState;
|
||||
|
||||
const attachmentIds = selectCompletedAttachments(state)
|
||||
.filter((a) => a.id)
|
||||
.map((a) => a.id) as string[];
|
||||
|
||||
if (state.preference && state.sharedConversation.apiKey) {
|
||||
if (API_STREAMING) {
|
||||
await handleFetchSharedAnswerStreaming(
|
||||
@@ -36,7 +41,7 @@ export const fetchSharedAnswer = createAsyncThunk<Answer, { question: string }>(
|
||||
signal,
|
||||
state.sharedConversation.apiKey,
|
||||
state.sharedConversation.queries,
|
||||
|
||||
attachmentIds,
|
||||
(event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
// check if the 'end' event has been received
|
||||
@@ -92,6 +97,7 @@ export const fetchSharedAnswer = createAsyncThunk<Answer, { question: string }>(
|
||||
question,
|
||||
signal,
|
||||
state.sharedConversation.apiKey,
|
||||
attachmentIds,
|
||||
);
|
||||
if (answer) {
|
||||
let sourcesPrepped = [];
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
prefListenerMiddleware,
|
||||
prefSlice,
|
||||
} from './preferences/preferenceSlice';
|
||||
import uploadReducer from './upload/uploadSlice';
|
||||
|
||||
const key = localStorage.getItem('DocsGPTApiKey');
|
||||
const prompt = localStorage.getItem('DocsGPTPrompt');
|
||||
@@ -52,6 +53,7 @@ const store = configureStore({
|
||||
preference: prefSlice.reducer,
|
||||
conversation: conversationSlice.reducer,
|
||||
sharedConversation: sharedConversationSlice.reducer,
|
||||
upload: uploadReducer,
|
||||
},
|
||||
middleware: (getDefaultMiddleware) =>
|
||||
getDefaultMiddleware().concat(prefListenerMiddleware.middleware),
|
||||
|
||||
67
frontend/src/upload/uploadSlice.ts
Normal file
67
frontend/src/upload/uploadSlice.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||
import { RootState } from '../store';
|
||||
|
||||
export interface Attachment {
|
||||
fileName: string;
|
||||
progress: number;
|
||||
status: 'uploading' | 'processing' | 'completed' | 'failed';
|
||||
taskId: string;
|
||||
id?: string;
|
||||
token_count?: number;
|
||||
}
|
||||
|
||||
interface UploadState {
|
||||
attachments: Attachment[];
|
||||
}
|
||||
|
||||
const initialState: UploadState = {
|
||||
attachments: [],
|
||||
};
|
||||
|
||||
export const uploadSlice = createSlice({
|
||||
name: 'upload',
|
||||
initialState,
|
||||
reducers: {
|
||||
addAttachment: (state, action: PayloadAction<Attachment>) => {
|
||||
state.attachments.push(action.payload);
|
||||
},
|
||||
updateAttachment: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
taskId: string;
|
||||
updates: Partial<Attachment>;
|
||||
}>,
|
||||
) => {
|
||||
const index = state.attachments.findIndex(
|
||||
(att) => att.taskId === action.payload.taskId,
|
||||
);
|
||||
if (index !== -1) {
|
||||
state.attachments[index] = {
|
||||
...state.attachments[index],
|
||||
...action.payload.updates,
|
||||
};
|
||||
}
|
||||
},
|
||||
removeAttachment: (state, action: PayloadAction<string>) => {
|
||||
state.attachments = state.attachments.filter(
|
||||
(att) => att.taskId !== action.payload && att.id !== action.payload,
|
||||
);
|
||||
},
|
||||
clearAttachments: (state) => {
|
||||
state.attachments = [];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
addAttachment,
|
||||
updateAttachment,
|
||||
removeAttachment,
|
||||
clearAttachments,
|
||||
} = uploadSlice.actions;
|
||||
|
||||
export const selectAttachments = (state: RootState) => state.upload.attachments;
|
||||
export const selectCompletedAttachments = (state: RootState) =>
|
||||
state.upload.attachments.filter((att) => att.status === 'completed');
|
||||
|
||||
export default uploadSlice.reducer;
|
||||
Reference in New Issue
Block a user