fix(chat): restrict to authenticated users only, fix overlay transparency
Some checks failed
ci/woodpecker/push/ci Pipeline failed
Some checks failed
ci/woodpecker/push/ci Pipeline failed
This commit is contained in:
@@ -4,12 +4,7 @@
|
||||
*/
|
||||
|
||||
import { useState, useCallback, useRef } from "react";
|
||||
import {
|
||||
sendChatMessage,
|
||||
streamChatMessage,
|
||||
streamGuestChat,
|
||||
type ChatMessage as ApiChatMessage,
|
||||
} from "@/lib/api/chat";
|
||||
import { streamChatMessage, type ChatMessage as ApiChatMessage } from "@/lib/api/chat";
|
||||
import { createConversation, updateConversation, getIdea, type Idea } from "@/lib/api/ideas";
|
||||
import { safeJsonParse, isMessageArray } from "@/lib/utils/safe-json";
|
||||
|
||||
@@ -219,8 +214,6 @@ export function useChat(options: UseChatOptions = {}): UseChatReturn {
|
||||
const controller = new AbortController();
|
||||
abortControllerRef.current = controller;
|
||||
|
||||
let streamingSucceeded = false;
|
||||
|
||||
try {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
let hasReceivedData = false;
|
||||
@@ -248,7 +241,6 @@ export function useChat(options: UseChatOptions = {}): UseChatReturn {
|
||||
});
|
||||
},
|
||||
() => {
|
||||
streamingSucceeded = true;
|
||||
setIsStreaming(false);
|
||||
abortControllerRef.current = null;
|
||||
resolve();
|
||||
@@ -279,140 +271,26 @@ export function useChat(options: UseChatOptions = {}): UseChatReturn {
|
||||
return;
|
||||
}
|
||||
|
||||
// Streaming failed - check if auth error, try guest mode
|
||||
const isAuthError =
|
||||
err instanceof Error &&
|
||||
(err.message.includes("403") ||
|
||||
err.message.includes("401") ||
|
||||
err.message.includes("auth") ||
|
||||
err.message.includes("Forbidden"));
|
||||
// Streaming failed — show error (no guest fallback, auth required)
|
||||
console.warn("Streaming failed", {
|
||||
error: err instanceof Error ? err : new Error(String(err)),
|
||||
});
|
||||
|
||||
if (isAuthError) {
|
||||
console.warn("Auth failed, trying guest chat mode");
|
||||
setMessages((prev) => {
|
||||
const withoutPlaceholder = prev.filter((m) => m.id !== assistantMessageId);
|
||||
messagesRef.current = withoutPlaceholder;
|
||||
return withoutPlaceholder;
|
||||
});
|
||||
setIsStreaming(false);
|
||||
setIsLoading(false);
|
||||
|
||||
// Try guest chat streaming
|
||||
try {
|
||||
await new Promise<void>((guestResolve, guestReject) => {
|
||||
let hasReceivedData = false;
|
||||
|
||||
streamGuestChat(
|
||||
request,
|
||||
(chunk: string) => {
|
||||
if (!hasReceivedData) {
|
||||
hasReceivedData = true;
|
||||
setIsLoading(false);
|
||||
setIsStreaming(true);
|
||||
setMessages((prev) => {
|
||||
const updated = [...prev, { ...placeholderMessage }];
|
||||
messagesRef.current = updated;
|
||||
return updated;
|
||||
});
|
||||
}
|
||||
|
||||
setMessages((prev) => {
|
||||
const updated = prev.map((msg) =>
|
||||
msg.id === assistantMessageId ? { ...msg, content: msg.content + chunk } : msg
|
||||
);
|
||||
messagesRef.current = updated;
|
||||
return updated;
|
||||
});
|
||||
},
|
||||
() => {
|
||||
streamingSucceeded = true;
|
||||
setIsStreaming(false);
|
||||
guestResolve();
|
||||
},
|
||||
(guestErr: Error) => {
|
||||
guestReject(guestErr);
|
||||
},
|
||||
controller.signal
|
||||
);
|
||||
});
|
||||
} catch (guestErr: unknown) {
|
||||
// Guest also failed
|
||||
setMessages((prev) => {
|
||||
const withoutPlaceholder = prev.filter((m) => m.id !== assistantMessageId);
|
||||
messagesRef.current = withoutPlaceholder;
|
||||
return withoutPlaceholder;
|
||||
});
|
||||
const errorMsg = guestErr instanceof Error ? guestErr.message : "Chat unavailable";
|
||||
setError(`Unable to connect to chat: ${errorMsg}`);
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Streaming failed — fall back to non-streaming
|
||||
console.warn("Streaming failed, falling back to non-streaming", {
|
||||
error: err instanceof Error ? err : new Error(String(err)),
|
||||
});
|
||||
|
||||
setMessages((prev) => {
|
||||
const withoutPlaceholder = prev.filter((m) => m.id !== assistantMessageId);
|
||||
messagesRef.current = withoutPlaceholder;
|
||||
return withoutPlaceholder;
|
||||
});
|
||||
setIsStreaming(false);
|
||||
|
||||
try {
|
||||
const response = await sendChatMessage(request);
|
||||
|
||||
const assistantMessage: Message = {
|
||||
id: `assistant-${Date.now().toString()}`,
|
||||
role: "assistant",
|
||||
content: response.message.content,
|
||||
createdAt: new Date().toISOString(),
|
||||
model: response.model,
|
||||
promptTokens: response.promptEvalCount ?? 0,
|
||||
completionTokens: response.evalCount ?? 0,
|
||||
totalTokens: (response.promptEvalCount ?? 0) + (response.evalCount ?? 0),
|
||||
};
|
||||
|
||||
setMessages((prev) => {
|
||||
const updated = [...prev, assistantMessage];
|
||||
messagesRef.current = updated;
|
||||
return updated;
|
||||
});
|
||||
|
||||
streamingSucceeded = true;
|
||||
} catch (fallbackErr: unknown) {
|
||||
const errorMsg =
|
||||
fallbackErr instanceof Error ? fallbackErr.message : "Failed to send message";
|
||||
setError("Unable to send message. Please try again.");
|
||||
onError?.(fallbackErr instanceof Error ? fallbackErr : new Error(errorMsg));
|
||||
console.error("Failed to send chat message", {
|
||||
error: fallbackErr,
|
||||
errorType: "LLM_ERROR",
|
||||
conversationId: conversationIdRef.current,
|
||||
messageLength: content.length,
|
||||
messagePreview: content.substring(0, 50),
|
||||
model,
|
||||
messageCount: messagesRef.current.length,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
|
||||
const errorMessage: Message = {
|
||||
id: `error-${String(Date.now())}`,
|
||||
role: "assistant",
|
||||
content: "Something went wrong. Please try again.",
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
setMessages((prev) => {
|
||||
const updated = [...prev, errorMessage];
|
||||
messagesRef.current = updated;
|
||||
return updated;
|
||||
});
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
const errorMsg = err instanceof Error ? err.message : "Chat unavailable";
|
||||
setError(`Chat error: ${errorMsg}`);
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
if (!streamingSucceeded) {
|
||||
return;
|
||||
}
|
||||
|
||||
const finalMessages = messagesRef.current;
|
||||
|
||||
const isFirstMessage =
|
||||
|
||||
Reference in New Issue
Block a user