feat: enhance podcast generation with duplicate request prevention and improved UI feedback

This commit is contained in:
Anish Sarkar 2025-12-21 20:07:04 +05:30
parent e79e1187b2
commit 783ee9c154
6 changed files with 269 additions and 7 deletions

View file

@ -4,7 +4,13 @@
*/
import type { ChatModelAdapter, ChatModelRunOptions } from "@assistant-ui/react";
import { toast } from "sonner";
import { getBearerToken } from "@/lib/auth-utils";
import {
isPodcastGenerating,
looksLikePodcastRequest,
setActivePodcastTaskId,
} from "@/lib/chat/podcast-state";
interface NewChatAdapterConfig {
searchSpaceId: number;
@ -59,6 +65,21 @@ export function createNewChatAdapter(config: NewChatAdapterConfig): ChatModelAda
throw new Error("User query cannot be empty");
}
// Check if user is requesting a podcast while one is already generating
if (isPodcastGenerating() && looksLikePodcastRequest(userQuery)) {
toast.warning("A podcast is already being generated. Please wait for it to complete.");
// Return a message telling the user to wait
yield {
content: [
{
type: "text",
text: "A podcast is already being generated. Please wait for it to complete before requesting another one.",
},
],
};
return;
}
const token = getBearerToken();
if (!token) {
throw new Error("Not authenticated. Please log in again.");
@ -204,6 +225,20 @@ export function createNewChatAdapter(config: NewChatAdapterConfig): ChatModelAda
const existing = toolCalls.get(toolCallId);
if (existing) {
existing.result = output;
// If this is a podcast tool with status="processing", set the state immediately
// This ensures subsequent podcast requests are intercepted
if (
existing.toolName === "generate_podcast" &&
output &&
typeof output === "object" &&
"status" in output &&
output.status === "processing" &&
"task_id" in output &&
typeof output.task_id === "string"
) {
setActivePodcastTaskId(output.task_id);
}
}
yield { content: buildContent() };
break;
@ -245,6 +280,19 @@ export function createNewChatAdapter(config: NewChatAdapterConfig): ChatModelAda
const existing = toolCalls.get(toolCallId);
if (existing) {
existing.result = output;
// Set podcast state if processing
if (
existing.toolName === "generate_podcast" &&
output &&
typeof output === "object" &&
"status" in output &&
output.status === "processing" &&
"task_id" in output &&
typeof output.task_id === "string"
) {
setActivePodcastTaskId(output.task_id);
}
}
yield { content: buildContent() };
}

View file

@ -0,0 +1,74 @@
/**
* Module-level state for tracking active podcast generation.
* Used by the new-chat adapter to prevent duplicate podcast requests.
*/
type PodcastStateListener = (isGenerating: boolean) => void;
let _activePodcastTaskId: string | null = null;
const _listeners: Set<PodcastStateListener> = new Set();
/**
* Check if a podcast is currently being generated
*/
export function isPodcastGenerating(): boolean {
return _activePodcastTaskId !== null;
}
/**
* Get the active podcast task ID
*/
export function getActivePodcastTaskId(): string | null {
return _activePodcastTaskId;
}
/**
* Set the active podcast task ID (when podcast generation starts)
*/
export function setActivePodcastTaskId(taskId: string): void {
_activePodcastTaskId = taskId;
notifyListeners();
}
/**
* Clear the active podcast task ID (when podcast generation completes or errors)
*/
export function clearActivePodcastTaskId(): void {
_activePodcastTaskId = null;
notifyListeners();
}
/**
* Subscribe to podcast state changes
*/
export function subscribeToPodcastState(listener: PodcastStateListener): () => void {
_listeners.add(listener);
return () => {
_listeners.delete(listener);
};
}
function notifyListeners(): void {
const isGenerating = _activePodcastTaskId !== null;
for (const listener of _listeners) {
listener(isGenerating);
}
}
/**
* Check if a message looks like a podcast request
*/
export function looksLikePodcastRequest(message: string): boolean {
const podcastPatterns = [
/\bpodcast\b/i,
/\bcreate.*podcast\b/i,
/\bgenerate.*podcast\b/i,
/\bmake.*podcast\b/i,
/\bturn.*into.*podcast\b/i,
/\bpodcast.*about\b/i,
/\bgive.*podcast\b/i,
];
return podcastPatterns.some((pattern) => pattern.test(message));
}