From 3fc05a09bcc39e9e5df92538549f40f9fb9f5240 Mon Sep 17 00:00:00 2001 From: Chukwuma Nwaugha Date: Sat, 7 Dec 2024 11:50:14 +0000 Subject: [PATCH] Use chat box with widget everywhere (#25) * create an improved chatbox item with widgets * cleanup examples and example_card for use in chatbox_and_widget * hide chatbox on the home page * simplify the landing page with chat_box_and_widget * enhance ChatBoxAndWidget with search validation and additional text * allow overriding tools slot in chat_box_and_widget * add logic to upload and preview file attachments * improve chat_box attachment and attachment preview components * add endpoint to store file uploads * use the correct response_model type * refactor file upload handling to check for existing blobs and return GCS URL * refactor /store-file-upload endpoint to only accept single file * refactor ChatBoxAttachment to manage uploaded files with a writable store and limit file size to 10MB * refactor ChatBoxAttachment and ChatBoxAndWidget to use attachments context for managing uploaded files * render loading state and file_icon * add logic and enndpoint to summarize custom sources * cleanup * add caching for attachments summary in chat endpoint and update system message to include reference material * refactor attachment handling to use session-specific context and improve file upload logic * fix bug and cleanup * keep local audio_sources in sync with db * save attachments in background tasks as link custom sources * refactor custom source management to utilize FieldFilter for querying and enhance attachment handling with signed URLs * add GCS URL resolution and blob name extraction in storage manager * refactor audio source management and cleanup session context handling * add retry decorator, create decorators dir * use a backoff in get_signed_url_endpoint * use the new retry_decorator in get_signed_url_endpoint * default to openai for tts on dev env * store file uploads as plain text when preserve is not required * override loading message when generating first response with attachments * add auto_resize logic to textarea * move attachment preview to the top * add loading state and spinner to ChatBoxAndWidget; update ChatContainer and page to handle search submission * move chatbox and widget into own file * Add disabled state to ChatBoxAttachment and adjust spinner size in ChatBoxAndWidget * Refactor audiocast source generation and update related endpoints and classes --- api/src/main.py | 10 +- api/src/utils/audiocast_script_maker.py | 14 +-- api/src/utils/generate_audiocast.py | 16 +-- api/src/utils/generate_audiocast_source.py | 6 +- api/src/utils/prompt_templates/tts_prompt.py | 7 +- .../lib/components/ChatBoxAndWidget.svelte | 109 +++++++----------- .../lib/components/ChatBoxAndWidgetHOC.svelte | 46 ++++++++ .../lib/components/ChatBoxAttachment.svelte | 6 +- app/src/lib/components/ChatContainer.svelte | 13 +-- .../lib/components/ChatListActionItems.svelte | 2 +- app/src/routes/+page.svelte | 6 +- .../chat/[sessionId=sessionId]/+page.svelte | 2 +- 12 files changed, 129 insertions(+), 108 deletions(-) create mode 100644 app/src/lib/components/ChatBoxAndWidgetHOC.svelte diff --git a/api/src/main.py b/api/src/main.py index a2a4187..78b7513 100644 --- a/api/src/main.py +++ b/api/src/main.py @@ -31,7 +31,7 @@ from .utils.decorators.retry_decorator import RetryConfig, retry from .utils.detect_content_category import DetectContentCategoryRequest, detect_content_category from .utils.generate_audiocast import GenerateAudioCastRequest, GenerateAudiocastException, generate_audiocast -from .utils.generate_audiocast_source import GenerateAudiocastSource, generate_audiocast_source +from .utils.generate_audiocast_source import GenerateAiSourceRequest, generate_ai_source from .utils.get_audiocast import get_audiocast from .utils.get_session_title import GetSessionTitleModel, get_session_title from .utils.session_manager import SessionManager, SessionModel @@ -128,11 +128,11 @@ def get_audiocast_endpoint(session_id: str): return result -@app.post("/generate-audiocast-source", response_model=str) -async def generate_audiocast_source_endpoint(request: GenerateAudiocastSource): - source_content = await generate_audiocast_source(request) +@app.post("/generate-aisource", response_model=str) +async def generate_aisource_endpoint(request: GenerateAiSourceRequest): + source_content = await generate_ai_source(request) if not source_content: - raise HTTPException(status_code=500, detail="Failed to generate source content") + raise HTTPException(status_code=500, detail="Failed to generate aisource content") return source_content diff --git a/api/src/utils/audiocast_script_maker.py b/api/src/utils/audiocast_script_maker.py index 827d840..97d9a8d 100644 --- a/api/src/utils/audiocast_script_maker.py +++ b/api/src/utils/audiocast_script_maker.py @@ -13,27 +13,23 @@ class AudioScriptMaker: category: ContentCategory - def __init__(self, category: ContentCategory, source_content: str, compiled_custom_sources: str | None = None): + def __init__(self, category: ContentCategory, ai_source: str, compiled_custom_sources: str | None = None): self.category = category - self.source_content = source_content + self.ai_source = ai_source self.compiled_custom_sources = compiled_custom_sources def create(self, provider: AudioScriptProvider = "openai"): """ Create an audio script based on the source content Args: - category (ContentCategory): The content category - source_content (str): The audiocast source content + provider (AudioScriptProvider): Provider for generating the audio script Returns: str: streamlined audio script """ - print("Generating audio script...") - print(f"Category: {self.category}; Source content: {self.source_content}") - if self.compiled_custom_sources: - print(f"Custom sources: {self.compiled_custom_sources}") + print(f"Generating audio script...Category: {self.category}") prompt_maker = TTSPromptMaker(self.category, Metadata()) - system_prompt = prompt_maker.get_system_prompt(self.source_content, self.compiled_custom_sources) + system_prompt = prompt_maker.get_system_prompt(self.ai_source, self.compiled_custom_sources) if provider == "anthropic": audio_script = self.__use_anthropic(system_prompt) diff --git a/api/src/utils/generate_audiocast.py b/api/src/utils/generate_audiocast.py index 0e44454..7dd7585 100644 --- a/api/src/utils/generate_audiocast.py +++ b/api/src/utils/generate_audiocast.py @@ -11,7 +11,7 @@ from .audiocast_utils import GenerateAudioCastRequest from .chat_utils import ContentCategory from .custom_sources.base_utils import CustomSourceManager -from .generate_audiocast_source import GenerateAudiocastSource, generate_audiocast_source +from .generate_audiocast_source import GenerateAiSourceRequest, generate_ai_source from .session_manager import SessionManager from .waveform_utils import WaveformUtils @@ -90,21 +90,21 @@ async def retry_generation(): def update_session_info(info: str): db._update_info(info) - source_content = session_data.metadata.source if session_data and session_data.metadata else None + ai_source = session_data.metadata.source if session_data and session_data.metadata else None - if not source_content: + if not ai_source: update_session_info("Generating source content...") - source_content = await generate_audiocast_source( - GenerateAudiocastSource( + ai_source = await generate_ai_source( + GenerateAiSourceRequest( sessionId=session_id, category=category, preferenceSummary=summary, ), ) - if not source_content: + if not ai_source: raise GenerateAudiocastException( - status_code=500, detail="Failed to generate source content", session_id=session_id + status_code=500, detail="Failed to generate source material", session_id=session_id ) # get custom sources @@ -113,7 +113,7 @@ def update_session_info(info: str): # Generate audio script update_session_info("Generating audio script...") - script_maker = AudioScriptMaker(category, source_content, compiled_custom_sources) + script_maker = AudioScriptMaker(category, ai_source, compiled_custom_sources) audio_script = script_maker.create(provider="gemini") if not audio_script: diff --git a/api/src/utils/generate_audiocast_source.py b/api/src/utils/generate_audiocast_source.py index 9ce9481..c227e27 100644 --- a/api/src/utils/generate_audiocast_source.py +++ b/api/src/utils/generate_audiocast_source.py @@ -7,15 +7,15 @@ from src.utils.session_manager import SessionManager -class GenerateAudiocastSource(BaseModel): +class GenerateAiSourceRequest(BaseModel): sessionId: str category: ContentCategory preferenceSummary: str -async def generate_audiocast_source(request: GenerateAudiocastSource): +async def generate_ai_source(request: GenerateAiSourceRequest): """ - Generate audiocast source material based on user preferences. + Generate ai source material based on user preferences. """ preference_summary = request.preferenceSummary category = request.category diff --git a/api/src/utils/prompt_templates/tts_prompt.py b/api/src/utils/prompt_templates/tts_prompt.py index 697e53c..2243908 100644 --- a/api/src/utils/prompt_templates/tts_prompt.py +++ b/api/src/utils/prompt_templates/tts_prompt.py @@ -19,7 +19,7 @@ def get_tags(self) -> list[str]: """Get connection tags based on the number of speakers.""" return [f"" for i in range(1, 10)] - def get_system_prompt(self, source_content: str, compiled_custom_sources: str | None = None) -> str: + def get_system_prompt(self, ai_source: str, compiled_custom_sources: str | None = None) -> str: """ Generate an optimized system prompt for converting source contents into the appropriate format. """ @@ -28,7 +28,7 @@ def get_system_prompt(self, source_content: str, compiled_custom_sources: str | Your task is to transform the following source contents into a single, engaging {self.category} TTS-optimized audiocast script. Source Contents: - - AI-generated: {source_content} + - AI-generated: {ai_source} {"- User-provided: " + compiled_custom_sources if compiled_custom_sources else ""} Content Parameters: @@ -88,6 +88,9 @@ def get_system_prompt(self, source_content: str, compiled_custom_sources: str | - Treat the source contents as complimentary, transitioning smoothly between sections and segments - Exclude any unnecessary or incompatible details or information - Prioritize sections that greatly support the overall discussion/narrative + - Emphasize the user-provided contents if it greatly enhances the overall quality of the audiocast + - Tie core arguments, ideas and concepts back to reference source content + - Keep the overall flow natural and seamless Output Format Example for 2 speakers: Hello there! [Content Intro & Overview]. diff --git a/app/src/lib/components/ChatBoxAndWidget.svelte b/app/src/lib/components/ChatBoxAndWidget.svelte index b0c2c84..a2fee29 100644 --- a/app/src/lib/components/ChatBoxAndWidget.svelte +++ b/app/src/lib/components/ChatBoxAndWidget.svelte @@ -1,14 +1,3 @@ - - -
-
-
-

What can I help with?

-

Listen to anything, anytime

-
- - - {#if $sessionUploadItems$.length > 0} - - {/if} + + {#if $sessionUploadItems$.length > 0} + + {/if} -
-
- -
-
-
- -
- - - -
-
-
-
+
+
+ +
+
+
+ +
+ - -
- {#each examples as item, index (index)} - - {/each} +
-
+
diff --git a/app/src/lib/components/ChatBoxAndWidgetHOC.svelte b/app/src/lib/components/ChatBoxAndWidgetHOC.svelte new file mode 100644 index 0000000..1a36ba5 --- /dev/null +++ b/app/src/lib/components/ChatBoxAndWidgetHOC.svelte @@ -0,0 +1,46 @@ + + + + +
+
+
+

What can I help with?

+

Listen to anything, anytime

+
+ + + + +
+ {#each examples as item, index (index)} + + {/each} +
+
+
+
diff --git a/app/src/lib/components/ChatBoxAttachment.svelte b/app/src/lib/components/ChatBoxAttachment.svelte index 47b308f..1971e43 100644 --- a/app/src/lib/components/ChatBoxAttachment.svelte +++ b/app/src/lib/components/ChatBoxAttachment.svelte @@ -12,6 +12,8 @@ import { getAttachmentsContext } from '@/stores/attachmentsContext.svelte'; import { getSessionContext } from '@/stores/sessionContext.svelte'; + export let disabled = false; + const { sessionId$ } = getSessionContext(); const { addUploadItem, sessionUploadItems$, updateUploadItem } = getAttachmentsContext(); @@ -68,13 +70,15 @@ }) .finally(() => updateUploadItem(fileId, { loading: false })); } + + $: resolveDisabled = $sessionUploadItems$.length >= MAX_FILES || disabled;
diff --git a/app/src/routes/chat/[sessionId=sessionId]/+page.svelte b/app/src/routes/chat/[sessionId=sessionId]/+page.svelte index 25e08b2..b13074a 100644 --- a/app/src/routes/chat/[sessionId=sessionId]/+page.svelte +++ b/app/src/routes/chat/[sessionId=sessionId]/+page.svelte @@ -113,7 +113,7 @@ } - +