Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 47 additions & 15 deletions frontend/app/[locale]/chat/internal/chatInterface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ export function ChatInterface() {
const handleSend = async () => {
if (!input.trim() && attachments.length === 0) return; // Allow sending attachments only, without text content

// Flag to track if we should reset button states in finally block
let shouldResetButtonStates = true;

// If in new conversation state, switch to conversation state after sending message
if (isNewConversation) {
setIsNewConversation(false);
Expand Down Expand Up @@ -373,6 +376,10 @@ export function ChatInterface() {
t("chatInterface.createDialogFailedButContinue"),
error
);
// Reset button states when conversation creation fails
setIsLoading(false);
setIsStreaming(false);
return;
}
}

Expand Down Expand Up @@ -594,20 +601,47 @@ export function ChatInterface() {

// Handle preprocessing result
if (!result.success) {
// Reset button states immediately when preprocessing fails
setIsLoading(false);
setIsStreaming(false);

// Remove from streaming conversations (both new and existing conversations)
if (currentConversationId) {
setStreamingConversations((prev) => {
const newSet = new Set(prev);
newSet.delete(currentConversationId);
return newSet;
});
}

setSessionMessages((prev) => {
const newMessages = { ...prev };
const lastMsg =
newMessages[currentConversationId]?.[
newMessages[currentConversationId].length - 1
];

if (lastMsg && lastMsg.role === ROLE_ASSISTANT) {
lastMsg.error = t("chatInterface.fileProcessingFailed", {
error: result.error,
});
// Handle error codes with internationalization
let errorMessage;
if (result.error === 'REQUEST_ENTITY_TOO_LARGE') {
errorMessage = t("chatInterface.fileSizeExceeded");
} else if (result.error === 'FILE_PARSING_FAILED') {
errorMessage = t("chatInterface.fileParsingFailed");
} else {
// For any other error, show a generic message without exposing technical details
errorMessage = t("chatInterface.fileProcessingFailed", {
error: "Unknown error"
});
}

lastMsg.content = errorMessage;
lastMsg.isComplete = true;
}

return newMessages;
});
shouldResetButtonStates = false; // Don't reset again in finally block
return;
}

Expand Down Expand Up @@ -810,10 +844,8 @@ export function ChatInterface() {
});
} else {
log.error(t("chatInterface.errorLabel"), error);
const errorMessage =
error instanceof Error
? error.message
: t("chatInterface.errorProcessingRequest");
// Show user-friendly error message instead of technical error details
const errorMessage = t("chatInterface.errorProcessingRequest");
setSessionMessages((prev) => {
const newMessages = { ...prev };
const lastMsg =
Expand Down Expand Up @@ -862,6 +894,12 @@ export function ChatInterface() {
});
}
}
} finally {
// Only reset button states if we should (not when preprocessing fails)
if (shouldResetButtonStates) {
setIsLoading(false);
setIsStreaming(false);
}
}
};

Expand Down Expand Up @@ -1085,10 +1123,7 @@ export function ChatInterface() {

setConversationLoadError((prev) => ({
...prev,
[dialog.conversation_id]:
error instanceof Error
? error.message
: "Failed to load conversation",
[dialog.conversation_id]: "Failed to load conversation",
}));
} finally {
// ensure loading state is cleared
Expand Down Expand Up @@ -1228,10 +1263,7 @@ export function ChatInterface() {

setConversationLoadError((prev) => ({
...prev,
[dialog.conversation_id]:
error instanceof Error
? error.message
: "Failed to load conversation",
[dialog.conversation_id]: "Failed to load conversation",
}));
} finally {
// ensure loading state is cleared
Expand Down
1 change: 1 addition & 0 deletions frontend/const/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const STATUS_CODES = {
SUCCESS: 200,

UNAUTHORIZED_HTTP: 401,
REQUEST_ENTITY_TOO_LARGE: 413,

INVALID_CREDENTIALS: 1002,
TOKEN_EXPIRED: 1003,
Expand Down
2 changes: 2 additions & 0 deletions frontend/public/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
"chatInterface.fileParsingCompleteWithTruncation": "File parsing complete: {{truncationInfo}}",
"chatInterface.truncationSeparator": "; ",
"chatInterface.fileProcessingFailed": "File processing failed: {{error}}",
"chatInterface.fileParsingFailed": "File parsing failed",
"chatInterface.fileSizeExceeded": "File size exceeds the limit, please upload smaller files",
"chatInterface.filePreprocessingStopped": "File parsing stopped",
"chatInterface.userCancelledRequest": "User canceled the request",
"chatInterface.conversationStopped": "Conversation stopped",
Expand Down
2 changes: 2 additions & 0 deletions frontend/public/locales/zh/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
"chatInterface.fileParsingCompleteWithTruncation": "文件解析完成:{{truncationInfo}}",
"chatInterface.truncationSeparator": ";",
"chatInterface.fileProcessingFailed": "文件处理失败: {{error}}",
"chatInterface.fileParsingFailed": "文件解析失败",
"chatInterface.fileSizeExceeded": "文件大小超出限制,请上传更小的文件",
"chatInterface.filePreprocessingStopped": "文件解析已停止",
"chatInterface.userCancelledRequest": "用户取消了请求",
"chatInterface.conversationStopped": "对话已停止",
Expand Down
5 changes: 5 additions & 0 deletions frontend/services/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,11 @@ export const fetchWithErrorHandling = async (url: string, options: RequestInit =
throw new ApiError(STATUS_CODES.TOKEN_EXPIRED, "Connection disconnected, session may have expired");
}

// Handle request entity too large error (413)
if (response.status === 413) {
throw new ApiError(STATUS_CODES.REQUEST_ENTITY_TOO_LARGE, "REQUEST_ENTITY_TOO_LARGE");
}

// Other HTTP errors
const errorText = await response.text();
throw new ApiError(response.status, errorText || `Request failed: ${response.status}`);
Expand Down
14 changes: 12 additions & 2 deletions frontend/services/conversationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,17 @@ export const conversationService = {
signal,
});

// Check if the response is successful
if (!response.ok) {
// Handle specific HTTP status codes with error codes for internationalization
if (response.status === 413) {
throw new Error('REQUEST_ENTITY_TOO_LARGE');
} else {
throw new Error('FILE_PARSING_FAILED');

}
}

if (!response.body) {
throw new Error("Response body is null");
}
Expand All @@ -713,8 +724,7 @@ export const conversationService = {
} catch (error) {
// If the error is caused by canceling the request, return a specific response instead of throwing an error
if (error instanceof Error && error.name === 'AbortError') {
log.log('文件预处理请求已被取消');
throw new Error('请求已被取消');
throw new Error('Request has been aborted');
}
// Other errors are thrown normally
throw error;
Expand Down