diff --git a/surfsense_backend/app/agents/podcaster/nodes.py b/surfsense_backend/app/agents/podcaster/nodes.py
index ceb1bd64b..31a687763 100644
--- a/surfsense_backend/app/agents/podcaster/nodes.py
+++ b/surfsense_backend/app/agents/podcaster/nodes.py
@@ -99,10 +99,10 @@ async def create_merged_podcast_audio(
) -> dict[str, Any]:
"""Generate audio for each transcript and merge them into a single podcast file."""
- configuration = Configuration.from_runnable_config(config)
+ # configuration = Configuration.from_runnable_config(config)
starting_transcript = PodcastTranscriptEntry(
- speaker_id=1, dialog=f"Welcome to {configuration.podcast_title} Podcast."
+ speaker_id=1, dialog="Welcome to Surfsense Podcast."
)
transcript = state.podcast_transcript
diff --git a/surfsense_web/app/dashboard/[search_space_id]/client-layout.tsx b/surfsense_web/app/dashboard/[search_space_id]/client-layout.tsx
index e1e51c601..eceb7ecd4 100644
--- a/surfsense_web/app/dashboard/[search_space_id]/client-layout.tsx
+++ b/surfsense_web/app/dashboard/[search_space_id]/client-layout.tsx
@@ -1,7 +1,8 @@
"use client";
-import { useAtom } from "jotai";
+import { useAtom, useAtomValue } from "jotai";
import { Loader2, PanelRight } from "lucide-react";
+import { AnimatePresence, motion } from "motion/react";
import { usePathname, useRouter } from "next/navigation";
import { useTranslations } from "next-intl";
import type React from "react";
@@ -16,6 +17,7 @@ import { Separator } from "@/components/ui/separator";
import { SidebarInset, SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar";
import { useLLMPreferences } from "@/hooks/use-llm-configs";
import { cn } from "@/lib/utils";
+import { activeChatIdAtom } from "@/stores/chat/active-chat.atom";
import { chatUIAtom } from "@/stores/chat/chat-ui.atom";
export function DashboardClientLayout({
@@ -35,9 +37,26 @@ export function DashboardClientLayout({
const searchSpaceIdNum = Number(searchSpaceId);
const [chatUIState, setChatUIState] = useAtom(chatUIAtom);
+ const activeChatId = useAtomValue(activeChatIdAtom);
+ const [showIndicator, setShowIndicator] = useState(false);
const { isChatPannelOpen } = chatUIState;
+ // Check if we're on the researcher page
+ const isResearcherPage = pathname?.includes("/researcher");
+
+ // Show indicator when chat becomes active and panel is closed
+ useEffect(() => {
+ if (activeChatId && !isChatPannelOpen) {
+ setShowIndicator(true);
+ // Hide indicator after 5 seconds
+ const timer = setTimeout(() => setShowIndicator(false), 5000);
+ return () => clearTimeout(timer);
+ } else {
+ setShowIndicator(false);
+ }
+ }, [activeChatId, isChatPannelOpen]);
+
const { loading, error, isOnboardingComplete } = useLLMPreferences(searchSpaceIdNum);
const [hasCheckedOnboarding, setHasCheckedOnboarding] = useState(false);
@@ -161,24 +180,112 @@ export function DashboardClientLayout({
-
+ {/* Only show artifacts toggle on researcher page */}
+ {isResearcherPage && (
+
+ {
+ setChatUIState((prev) => ({
+ ...prev,
+ isChatPannelOpen: !isChatPannelOpen,
+ }));
+ setShowIndicator(false);
+ }}
+ className={cn(
+ "shrink-0 rounded-full p-2 transition-all duration-300 relative",
+ showIndicator
+ ? "bg-primary/20 hover:bg-primary/30 shadow-lg shadow-primary/25"
+ : "hover:bg-muted",
+ activeChatId && !showIndicator && "hover:bg-primary/10"
+ )}
+ title="Toggle Artifacts Panel"
+ whileHover={{ scale: 1.05 }}
+ whileTap={{ scale: 0.95 }}
+ >
+
+
+
+
+
+ {/* Pulsing indicator badge */}
+
+ {showIndicator && (
+
+
+
+
+
+
+ )}
+
+
+ )}
{children}
-
+ {/* Only render chat panel on researcher page */}
+ {isResearcherPage && }
diff --git a/surfsense_web/components/chat/ChatPanel/ChatPanelContainer.tsx b/surfsense_web/components/chat/ChatPanel/ChatPanelContainer.tsx
index a4eb30ef9..098d6324a 100644
--- a/surfsense_web/components/chat/ChatPanel/ChatPanelContainer.tsx
+++ b/surfsense_web/components/chat/ChatPanel/ChatPanelContainer.tsx
@@ -43,7 +43,7 @@ export function ChatPanelContainer() {
{isChatLoading || chatError ? (
diff --git a/surfsense_web/components/chat/ChatPanel/ChatPanelView.tsx b/surfsense_web/components/chat/ChatPanel/ChatPanelView.tsx
index 1d4ac4c71..848028e1f 100644
--- a/surfsense_web/components/chat/ChatPanel/ChatPanelView.tsx
+++ b/surfsense_web/components/chat/ChatPanel/ChatPanelView.tsx
@@ -1,7 +1,8 @@
"use client";
import { useAtom, useAtomValue } from "jotai";
-import { AlertCircle, Pencil, Play, Podcast, RefreshCw } from "lucide-react";
+import { AlertCircle, Pencil, Play, Podcast, RefreshCw, Sparkles } from "lucide-react";
+import { motion } from "motion/react";
import { useCallback, useContext, useTransition } from "react";
import { cn } from "@/lib/utils";
import { activeChatAtom } from "@/stores/chat/active-chat.atom";
@@ -41,23 +42,26 @@ export function ChatPanelView(props: ChatPanelViewProps) {
return (
-
+
{isChatPannelOpen ? (
{/* Show stale podcast warning if applicable */}
{podcastIsStale && (
-
+
-
-
-
Podcast is outdated
-
+
+
+
+
+
Podcast Outdated
+
{getPodcastStalenessMessage(
chatDetails?.state_version || 0,
podcast?.chat_state_version
@@ -65,41 +69,96 @@ export function ChatPanelView(props: ChatPanelViewProps) {
-
+
)}
-
{
- if (e.key === "Enter") {
- e.preventDefault();
- handleGeneratePost();
- }
- }}
- className={cn(
- "w-full space-y-3 rounded-xl p-3 transition-colors",
- podcastIsStale
- ? "bg-gradient-to-r from-amber-400/50 to-orange-300/50 dark:from-amber-500/30 dark:to-orange-600/30 hover:from-amber-400/60 hover:to-orange-300/60"
- : "bg-gradient-to-r from-slate-400/50 to-slate-200/50 dark:from-slate-400/30 dark:to-slate-800/60 hover:from-slate-400/60 hover:to-slate-200/60"
- )}
+
-
- {podcastIsStale ? (
-
- ) : (
-
+
{
+ if (e.key === "Enter") {
+ e.preventDefault();
+ handleGeneratePost();
+ }
+ }}
+ className={cn(
+ "relative w-full rounded-2xl p-4 transition-all duration-300 cursor-pointer group overflow-hidden",
+ "border-2",
+ podcastIsStale
+ ? "bg-gradient-to-br from-amber-500/10 via-orange-500/10 to-amber-500/10 dark:from-amber-500/20 dark:via-orange-500/20 dark:to-amber-500/20 border-amber-400/50 hover:border-amber-400 hover:shadow-lg hover:shadow-amber-500/20"
+ : "bg-gradient-to-br from-primary/10 via-primary/5 to-primary/10 border-primary/30 hover:border-primary/60 hover:shadow-lg hover:shadow-primary/20"
)}
-
+ >
+ {/* Background gradient animation */}
+
+
+
+
+
+
+ {podcastIsStale ? (
+
+ ) : (
+
+ )}
+
+
+
+ {podcastIsStale ? "Regenerate Podcast" : "Generate Podcast"}
+
+
+ {podcastIsStale
+ ? "Update with latest changes"
+ : "Create podcasts of your chat"}
+
+
+
+
+
+
-
- {podcastIsStale ? "Regenerate Podcast" : "Generate Podcast"}
-
-
+
) : (
-
+ {podcastIsStale ?
:
}
+
)}
{podcast ? (
{isChatPannelOpen ? (
) : podcast ? (
-
+
+
) : null}
) : null}
diff --git a/surfsense_web/components/chat/ChatPanel/ConfigModal.tsx b/surfsense_web/components/chat/ChatPanel/ConfigModal.tsx
index 2ee0d30cb..f1efdd089 100644
--- a/surfsense_web/components/chat/ChatPanel/ConfigModal.tsx
+++ b/surfsense_web/components/chat/ChatPanel/ConfigModal.tsx
@@ -44,8 +44,20 @@ export function ConfigModal(props: ConfigModalProps) {
e.stopPropagation()} align="end" className="bg-sidebar w-96 ">