(refactor:attachments) moved to new uploadSlice

This commit is contained in:
ManishMadan2882
2025-06-09 17:10:12 +05:30
parent b2df431fa4
commit c0d385b983
9 changed files with 122 additions and 65 deletions

View File

@@ -18,7 +18,7 @@ import {
removeAttachment,
selectAttachments,
updateAttachment,
} from '../conversation/conversationSlice';
} from '../upload/uploadSlice';
import { useDarkTheme } from '../hooks';
import { ActiveState } from '../models/misc';
import {

View File

@@ -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(() => {

View File

@@ -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(() => {

View File

@@ -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();

View File

@@ -22,7 +22,6 @@ export interface ConversationState {
queries: Query[];
status: Status;
conversationId: string | null;
attachments: Attachment[];
}
export interface Answer {

View File

@@ -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;

View File

@@ -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 = [];

View File

@@ -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),

View 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;