diff --git a/surfsense_backend/app/services/streaming_service.py b/surfsense_backend/app/services/streaming_service.py
index 2163f56..10f6fb7 100644
--- a/surfsense_backend/app/services/streaming_service.py
+++ b/surfsense_backend/app/services/streaming_service.py
@@ -132,7 +132,14 @@ class StreamingService:
self.message_annotations[3]["content"] = further_questions
# Return only the delta annotation
- annotation = {"type": "FURTHER_QUESTIONS", "content": further_questions}
+ annotation = {
+ "type": "FURTHER_QUESTIONS",
+ "data": [
+ question.get("question", "")
+ for question in further_questions
+ if question.get("question", "") != ""
+ ],
+ }
return f"8:[{json.dumps(annotation)}]\n"
def format_text_chunk(self, text: str) -> str:
diff --git a/surfsense_web/components/chat_v2/ChatCitation.tsx b/surfsense_web/components/chat_v2/ChatCitation.tsx
new file mode 100644
index 0000000..c5570b1
--- /dev/null
+++ b/surfsense_web/components/chat_v2/ChatCitation.tsx
@@ -0,0 +1,56 @@
+"use client"
+
+import React from "react";
+import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
+import { ExternalLink } from "lucide-react";
+
+export const CitationDisplay: React.FC<{index: number, node: any}> = ({index, node}) => {
+
+ const truncateText = (text: string, maxLength: number = 200) => {
+ if (text.length <= maxLength) return text;
+ return text.substring(0, maxLength) + '...';
+ };
+
+ const handleUrlClick = (e: React.MouseEvent, url: string) => {
+ e.preventDefault();
+ e.stopPropagation();
+ window.open(url, '_blank', 'noopener,noreferrer');
+ };
+
+ return (
+
+
+
+ {index + 1}
+
+
+
+ {/* External Link Button - Top Right */}
+ {node?.url && (
+
+ )}
+
+ {/* Heading */}
+
+ {node?.metadata?.group_name || 'Source'}
+
+
+ {/* Source */}
+
+ {node?.metadata?.title || 'Untitled'}
+
+
+ {/* Body */}
+
+ {truncateText(node?.text || 'No content available')}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/surfsense_web/components/chat_v2/ChatFurtherQuestions.tsx b/surfsense_web/components/chat_v2/ChatFurtherQuestions.tsx
new file mode 100644
index 0000000..ddfb3ea
--- /dev/null
+++ b/surfsense_web/components/chat_v2/ChatFurtherQuestions.tsx
@@ -0,0 +1,18 @@
+"use client";
+
+import { SuggestedQuestions } from "@llamaindex/chat-ui/widgets";
+import { getAnnotationData, Message, useChatUI } from "@llamaindex/chat-ui";
+
+export const ChatFurtherQuestions: React.FC<{message: Message}> = ({message}) => {
+ const annotations: string[][] = getAnnotationData(message, "FURTHER_QUESTIONS");
+ const { append, requestData } = useChatUI();
+
+ console.log('🔥 annotations', annotations);
+
+
+ if (annotations.length !== 1 || annotations[0].length === 0) {
+ return <>>;
+ }
+
+ return ;
+};
\ No newline at end of file
diff --git a/surfsense_web/components/chat_v2/ChatInterface.tsx b/surfsense_web/components/chat_v2/ChatInterface.tsx
index fba1ee0..90bb111 100644
--- a/surfsense_web/components/chat_v2/ChatInterface.tsx
+++ b/surfsense_web/components/chat_v2/ChatInterface.tsx
@@ -9,15 +9,14 @@ import {
useChatUI,
ChatMessage,
Message,
- getAnnotationData,
} from "@llamaindex/chat-ui";
import { Document } from "@/hooks/use-documents";
import { CustomChatInput } from "@/components/chat_v2/ChatInputGroup";
import { ResearchMode } from "@/components/chat";
import TerminalDisplay from "@/components/chat_v2/ChatTerminal";
import ChatSourcesDisplay from "@/components/chat_v2/ChatSources";
-import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
-import { ExternalLink } from "lucide-react";
+import { CitationDisplay } from "@/components/chat_v2/ChatCitation";
+import { ChatFurtherQuestions } from "@/components/chat_v2/ChatFurtherQuestions";
interface ChatInterfaceProps {
handler: ChatHandler;
@@ -30,59 +29,7 @@ interface ChatInterfaceProps {
researchMode?: ResearchMode;
onResearchModeChange?: (mode: ResearchMode) => void;
}
-
-const CitationDisplay: React.FC<{index: number, node: any}> = ({index, node}) => {
-
-
- const truncateText = (text: string, maxLength: number = 200) => {
- if (text.length <= maxLength) return text;
- return text.substring(0, maxLength) + '...';
- };
-
- const handleUrlClick = (e: React.MouseEvent, url: string) => {
- e.preventDefault();
- e.stopPropagation();
- window.open(url, '_blank', 'noopener,noreferrer');
- };
-
- return (
-
-
-
- {index + 1}
-
-
-
- {/* External Link Button - Top Right */}
- {node?.url && (
-
- )}
-
- {/* Heading */}
-
- {node?.metadata?.group_name || 'Source'}
-
-
- {/* Source */}
-
- {node?.metadata?.title || 'Untitled'}
-
-
- {/* Body */}
-
- {truncateText(node?.text || 'No content available')}
-
-
-
- );
-}
-
+
function ChatMessageDisplay({
message,
@@ -99,12 +46,15 @@ function ChatMessageDisplay({
>
{message.role === "assistant" ? (
-
+
-
+
+ {isLast && }
+
+
) : (
diff --git a/surfsense_web/components/chat_v2/ChatTerminal.tsx b/surfsense_web/components/chat_v2/ChatTerminal.tsx
index 61d1a9b..0300147 100644
--- a/surfsense_web/components/chat_v2/ChatTerminal.tsx
+++ b/surfsense_web/components/chat_v2/ChatTerminal.tsx
@@ -3,8 +3,8 @@
import React from "react";
import { getAnnotationData, Message } from "@llamaindex/chat-ui";
-export default function TerminalDisplay({ message }: { message: Message }) {
- const [isCollapsed, setIsCollapsed] = React.useState(true);
+export default function TerminalDisplay({ message, open }: { message: Message, open: boolean }) {
+ const [isCollapsed, setIsCollapsed] = React.useState(!open);
// Get the last assistant message that's not being typed
if (!message) {