feat(chat): add guest chat mode for unauthenticated users
Some checks failed
ci/woodpecker/push/ci Pipeline failed
Some checks failed
ci/woodpecker/push/ci Pipeline failed
- Add POST /api/chat/guest endpoint (no auth required) - Add proxyGuestChat() method using configurable LLM endpoint - Add streamGuestChat() function to frontend chat API - Modify useChat to fall back to guest mode on auth errors (403/401) - Remove !user check from ChatInput disabled prop - Configure guest LLM via env vars: GUEST_LLM_URL, GUEST_LLM_API_KEY, GUEST_LLM_MODEL - Default guest LLM: http://10.1.1.42:11434/v1 (Ollama) with llama3.2 model
This commit is contained in:
@@ -7,6 +7,7 @@ import { useState, useCallback, useRef } from "react";
|
||||
import {
|
||||
sendChatMessage,
|
||||
streamChatMessage,
|
||||
streamGuestChat,
|
||||
type ChatMessage as ApiChatMessage,
|
||||
} from "@/lib/api/chat";
|
||||
import { createConversation, updateConversation, getIdea, type Idea } from "@/lib/api/ideas";
|
||||
@@ -278,10 +279,69 @@ export function useChat(options: UseChatOptions = {}): UseChatReturn {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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)),
|
||||
});
|
||||
// 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"));
|
||||
|
||||
if (isAuthError) {
|
||||
console.warn("Auth failed, trying guest chat mode");
|
||||
|
||||
// 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);
|
||||
|
||||
Reference in New Issue
Block a user