mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-29 19:35:20 +02:00
feat: enhance podcast generation with duplicate request prevention and improved UI feedback
This commit is contained in:
parent
e79e1187b2
commit
783ee9c154
6 changed files with 269 additions and 7 deletions
|
|
@ -4,13 +4,67 @@ Podcast generation tool for the new chat agent.
|
|||
This module provides a factory function for creating the generate_podcast tool
|
||||
that submits a Celery task for background podcast generation. The frontend
|
||||
polls for completion and auto-updates when the podcast is ready.
|
||||
|
||||
Duplicate request prevention:
|
||||
- Only one podcast can be generated at a time per search space
|
||||
- Uses Redis to track active podcast tasks
|
||||
- Returns a friendly message if a podcast is already being generated
|
||||
"""
|
||||
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
import redis
|
||||
from langchain_core.tools import tool
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
# Redis connection for tracking active podcast tasks
|
||||
# Uses the same Redis instance as Celery
|
||||
REDIS_URL = os.getenv("CELERY_BROKER_URL", "redis://localhost:6379/0")
|
||||
_redis_client: redis.Redis | None = None
|
||||
|
||||
|
||||
def get_redis_client() -> redis.Redis:
|
||||
"""Get or create Redis client for podcast task tracking."""
|
||||
global _redis_client
|
||||
if _redis_client is None:
|
||||
_redis_client = redis.from_url(REDIS_URL, decode_responses=True)
|
||||
return _redis_client
|
||||
|
||||
|
||||
def get_active_podcast_key(search_space_id: int) -> str:
|
||||
"""Generate Redis key for tracking active podcast task."""
|
||||
return f"podcast:active:{search_space_id}"
|
||||
|
||||
|
||||
def get_active_podcast_task(search_space_id: int) -> str | None:
|
||||
"""Check if there's an active podcast task for this search space."""
|
||||
try:
|
||||
client = get_redis_client()
|
||||
return client.get(get_active_podcast_key(search_space_id))
|
||||
except Exception:
|
||||
# If Redis is unavailable, allow the request (fail open)
|
||||
return None
|
||||
|
||||
|
||||
def set_active_podcast_task(search_space_id: int, task_id: str) -> None:
|
||||
"""Mark a podcast task as active for this search space."""
|
||||
try:
|
||||
client = get_redis_client()
|
||||
# Set with 30-minute expiry as safety net (podcast should complete before this)
|
||||
client.setex(get_active_podcast_key(search_space_id), 1800, task_id)
|
||||
except Exception as e:
|
||||
print(f"[generate_podcast] Warning: Could not set active task in Redis: {e}")
|
||||
|
||||
|
||||
def clear_active_podcast_task(search_space_id: int) -> None:
|
||||
"""Clear the active podcast task for this search space."""
|
||||
try:
|
||||
client = get_redis_client()
|
||||
client.delete(get_active_podcast_key(search_space_id))
|
||||
except Exception as e:
|
||||
print(f"[generate_podcast] Warning: Could not clear active task in Redis: {e}")
|
||||
|
||||
|
||||
def create_generate_podcast_tool(
|
||||
search_space_id: int,
|
||||
|
|
@ -49,6 +103,10 @@ def create_generate_podcast_tool(
|
|||
The tool will start generating a podcast in the background.
|
||||
The podcast will be available once generation completes.
|
||||
|
||||
IMPORTANT: Only one podcast can be generated at a time. If a podcast
|
||||
is already being generated, this tool will return a message asking
|
||||
the user to wait.
|
||||
|
||||
Args:
|
||||
source_content: The text content to convert into a podcast.
|
||||
This can be a summary, research findings, or any text
|
||||
|
|
@ -59,11 +117,23 @@ def create_generate_podcast_tool(
|
|||
|
||||
Returns:
|
||||
A dictionary containing:
|
||||
- status: "processing" (task submitted) or "error"
|
||||
- task_id: The Celery task ID for polling status
|
||||
- status: "processing" (task submitted), "already_generating", or "error"
|
||||
- task_id: The Celery task ID for polling status (if processing)
|
||||
- title: The podcast title
|
||||
- message: Status message for the user
|
||||
"""
|
||||
try:
|
||||
# Check if a podcast is already being generated for this search space
|
||||
active_task_id = get_active_podcast_task(search_space_id)
|
||||
if active_task_id:
|
||||
print(f"[generate_podcast] Blocked duplicate request. Active task: {active_task_id}")
|
||||
return {
|
||||
"status": "already_generating",
|
||||
"task_id": active_task_id,
|
||||
"title": podcast_title,
|
||||
"message": "A podcast is already being generated. Please wait for it to complete before requesting another one.",
|
||||
}
|
||||
|
||||
# Import Celery task here to avoid circular imports
|
||||
from app.tasks.celery_tasks.podcast_tasks import (
|
||||
generate_content_podcast_task,
|
||||
|
|
@ -78,6 +148,9 @@ def create_generate_podcast_tool(
|
|||
user_prompt=user_prompt,
|
||||
)
|
||||
|
||||
# Mark this task as active
|
||||
set_active_podcast_task(search_space_id, task.id)
|
||||
|
||||
print(f"[generate_podcast] Submitted Celery task: {task.id}")
|
||||
|
||||
# Return immediately with task_id for polling
|
||||
|
|
|
|||
|
|
@ -135,10 +135,16 @@ You have access to the following tools:
|
|||
- Use this when the user asks to create, generate, or make a podcast.
|
||||
- Trigger phrases: "give me a podcast about", "create a podcast", "generate a podcast", "make a podcast", "turn this into a podcast"
|
||||
- Args:
|
||||
- source_content: The text content to convert into a podcast (e.g., a summary, research findings, or conversation)
|
||||
- source_content: The text content to convert into a podcast. This MUST be comprehensive and include:
|
||||
* If discussing the current conversation: Include a detailed summary of the FULL chat history (all user questions and your responses)
|
||||
* If based on knowledge base search: Include the key findings and insights from the search results
|
||||
* You can combine both: conversation context + search results for richer podcasts
|
||||
* The more detailed the source_content, the better the podcast quality
|
||||
- podcast_title: Optional title for the podcast (default: "SurfSense Podcast")
|
||||
- user_prompt: Optional instructions for podcast style/format (e.g., "Make it casual and fun")
|
||||
- Returns: A podcast with audio that the user can listen to and download
|
||||
- Returns: A task_id for tracking. The podcast will be generated in the background.
|
||||
- IMPORTANT: Only one podcast can be generated at a time. If a podcast is already being generated, the tool will return status "already_generating".
|
||||
- After calling this tool, inform the user that podcast generation has started and they will see the player when it's ready (takes 3-5 minutes).
|
||||
</tools>
|
||||
<tool_call_examples>
|
||||
- User: "Fetch all my notes and what's in them?"
|
||||
|
|
@ -148,10 +154,14 @@ You have access to the following tools:
|
|||
- Call: `search_knowledge_base(query="React migration", connectors_to_search=["SLACK_CONNECTOR"], start_date="YYYY-MM-DD", end_date="YYYY-MM-DD")`
|
||||
|
||||
- User: "Give me a podcast about AI trends based on what we discussed"
|
||||
- First search for relevant content, then call: `generate_podcast(source_content="[summarized content from search]", podcast_title="AI Trends Podcast")`
|
||||
- First search for relevant content, then call: `generate_podcast(source_content="Based on our conversation and search results: [detailed summary of chat + search findings]", podcast_title="AI Trends Podcast")`
|
||||
|
||||
- User: "Create a podcast summary of this conversation"
|
||||
- Call: `generate_podcast(source_content="[summary of the conversation so far]", podcast_title="Conversation Summary")`
|
||||
- Call: `generate_podcast(source_content="Complete conversation summary:\n\nUser asked about [topic 1]:\n[Your detailed response]\n\nUser then asked about [topic 2]:\n[Your detailed response]\n\n[Continue for all exchanges in the conversation]", podcast_title="Conversation Summary")`
|
||||
|
||||
- User: "Make a podcast about quantum computing"
|
||||
- First search: `search_knowledge_base(query="quantum computing")`
|
||||
- Then: `generate_podcast(source_content="Key insights about quantum computing from the knowledge base:\n\n[Comprehensive summary of all relevant search results with key facts, concepts, and findings]", podcast_title="Quantum Computing Explained")`
|
||||
</tool_call_examples>{citation_section}
|
||||
"""
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue