diff --git a/api/src/main.py b/api/src/main.py index 47672f5..4d88349 100644 --- a/api/src/main.py +++ b/api/src/main.py @@ -7,15 +7,15 @@ from fastapi.responses import JSONResponse, StreamingResponse from fastapi_utilities import add_timer_middleware -from src.services.storage import StorageManager -from src.utils.chat_request import chat_request -from src.utils.chat_utils import ( +from .services.storage import StorageManager +from .utils.chat_request import chat_request +from .utils.chat_utils import ( SessionChatItem, SessionChatRequest, ) -from src.utils.custom_sources.base_utils import SourceContent -from src.utils.custom_sources.extract_url_content import ExtractURLContent, ExtractURLContentRequest -from src.utils.custom_sources.generate_url_source import ( +from .utils.custom_sources.base_utils import SourceContent +from .utils.custom_sources.extract_url_content import ExtractURLContent, ExtractURLContentRequest +from .utils.custom_sources.generate_url_source import ( CustomSourceManager, CustomSourceModel, DeleteCustomSourcesRequest, @@ -23,17 +23,13 @@ GetCustomSourcesRequest, generate_custom_source, ) -from src.utils.custom_sources.save_copied_source import CopiedPasteSourceRequest, save_copied_source -from src.utils.custom_sources.save_uploaded_sources import UploadedFiles -from src.utils.generate_audiocast import ( - GenerateAudioCastRequest, - GenerateAudioCastResponse, - generate_audiocast, -) -from src.utils.generate_audiocast_source import GenerateAudiocastSource, generate_audiocast_source -from src.utils.get_audiocast import get_audiocast -from src.utils.get_session_title import GetSessionTitleModel, get_session_title -from src.utils.session_manager import SessionManager +from .utils.custom_sources.save_copied_source import CopiedPasteSourceRequest, save_copied_source +from .utils.custom_sources.save_uploaded_sources import UploadedFiles +from .utils.generate_audiocast import GenerateAudioCastRequest, generate_audiocast +from .utils.generate_audiocast_source import GenerateAudiocastSource, generate_audiocast_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 app = FastAPI(title="Audiora", version="1.0.0") @@ -96,7 +92,7 @@ def on_finish(text: str): return StreamingResponse(response, media_type="text/event-stream") -@app.post("/audiocast/generate", response_model=GenerateAudioCastResponse) +@app.post("/audiocast/generate", response_model=str) async def generate_audiocast_endpoint( request: GenerateAudioCastRequest, background_tasks: BackgroundTasks, @@ -104,7 +100,7 @@ async def generate_audiocast_endpoint( return await generate_audiocast(request, background_tasks) -@app.get("/audiocast/{session_id}", response_model=GenerateAudioCastResponse) +@app.get("/audiocast/{session_id}", response_model=SessionModel) def get_audiocast_endpoint(session_id: str): result = get_audiocast(session_id) return result diff --git a/api/src/services/storage.py b/api/src/services/storage.py index 9793d03..a8b2097 100644 --- a/api/src/services/storage.py +++ b/api/src/services/storage.py @@ -31,7 +31,7 @@ class UploadItemParams: class StorageManager: - def check_blob_exists(self, root_path: str, filename: str): + def check_blob_exists(self, filename: str, root_path=BLOB_BASE_URI): """check if a file exists in the bucket""" blobname = f"{root_path}/{filename}" blobs = listBlobs(prefix=root_path) diff --git a/api/src/utils/audiocast_utils.py b/api/src/utils/audiocast_utils.py index 089611c..70e66ed 100644 --- a/api/src/utils/audiocast_utils.py +++ b/api/src/utils/audiocast_utils.py @@ -11,12 +11,6 @@ class GenerateAudioCastRequest(BaseModel): category: ContentCategory -class GenerateAudioCastResponse(BaseModel): - script: str - source_content: str - created_at: str | None - - class GenerateAudiocastDict(TypedDict): url: str script: str diff --git a/api/src/utils/generate_audiocast.py b/api/src/utils/generate_audiocast.py index 62a3575..e0cf400 100644 --- a/api/src/utils/generate_audiocast.py +++ b/api/src/utils/generate_audiocast.py @@ -1,14 +1,9 @@ -from datetime import datetime - from fastapi import BackgroundTasks, HTTPException from src.services.storage import StorageManager from src.utils.audio_manager import AudioManager, AudioManagerConfig from src.utils.audiocast_script_maker import AudioScriptMaker -from src.utils.audiocast_utils import ( - GenerateAudioCastRequest, - GenerateAudioCastResponse, -) +from src.utils.audiocast_utils import GenerateAudioCastRequest from src.utils.chat_utils import ContentCategory from src.utils.custom_sources.base_utils import CustomSourceManager from src.utils.generate_audiocast_source import GenerateAudiocastSource, generate_audiocast_source @@ -65,19 +60,6 @@ def update_session_info(info: str): session_data = SessionManager.data(session_id) source_content = session_data.metadata.source if session_data and session_data.metadata else None - if not source_content: - update_session_info("Generating source content...") - source_content = await generate_audiocast_source( - GenerateAudiocastSource( - sessionId=session_id, - category=category, - preferenceSummary=summary, - ), - ) - - session_data = SessionManager.data(session_id) - source_content = session_data.metadata.source if session_data and session_data.metadata else None - if not source_content: update_session_info("Generating source content...") source_content = await generate_audiocast_source( @@ -116,8 +98,4 @@ def update_session_info(info: str): audio_script, ) - return GenerateAudioCastResponse( - script=audio_script, - source_content=source_content, - created_at=datetime.now().strftime("%Y-%m-%d %H:%M"), - ) + return "Audiocast generated successfully!" diff --git a/api/src/utils/get_audiocast.py b/api/src/utils/get_audiocast.py index f26601c..eb5f06a 100644 --- a/api/src/utils/get_audiocast.py +++ b/api/src/utils/get_audiocast.py @@ -1,18 +1,20 @@ -from datetime import datetime - from fastapi import HTTPException from src.services.storage import StorageManager -from src.utils.generate_audiocast import GenerateAudioCastResponse -from src.utils.session_manager import SessionManager + +from .decorators import process_time +from .session_manager import SessionManager +@process_time() def get_audiocast(session_id: str): """ - Get audiocast based on session id + Get audiocast based on session_id """ try: - StorageManager().download_from_gcs(session_id) + exists = StorageManager().check_blob_exists(session_id) + if not exists: + raise except Exception: raise HTTPException( status_code=404, @@ -26,13 +28,4 @@ def get_audiocast(session_id: str): detail=f"Audiocast not found for session_id: {session_id}", ) - metadata = session_data.metadata - source = metadata.source if metadata else "" - transcript = metadata.transcript if metadata else "" - title = metadata.title if metadata and metadata.title else "Untitled" - - created_at = None - if session_data.created_at: - created_at = datetime.fromisoformat(session_data.created_at).strftime("%Y-%m-%d %H:%M") - - return GenerateAudioCastResponse(script=transcript, source_content=source, created_at=created_at) + return session_data.__dict__ diff --git a/app/src/app.html b/app/src/app.html index e3f2247..6b01ab9 100644 --- a/app/src/app.html +++ b/app/src/app.html @@ -9,6 +9,7 @@ + diff --git a/app/src/lib/components/AudiocastPageAction.svelte b/app/src/lib/components/AudiocastPageAction.svelte index a505716..57ccf65 100644 --- a/app/src/lib/components/AudiocastPageAction.svelte +++ b/app/src/lib/components/AudiocastPageAction.svelte @@ -1,9 +1,9 @@ -
+
- {session.category} + {category} - {#if session.metadata?.title} -

{session.metadata.title}

- {/if} +

{title}

diff --git a/app/src/lib/components/AudiocastPageSkeletonLoader.svelte b/app/src/lib/components/AudiocastPageSkeletonLoader.svelte index 797466f..d33ed2e 100644 --- a/app/src/lib/components/AudiocastPageSkeletonLoader.svelte +++ b/app/src/lib/components/AudiocastPageSkeletonLoader.svelte @@ -1,5 +1,4 @@ -
- +
diff --git a/app/src/lib/components/ChatListActionItems.svelte b/app/src/lib/components/ChatListActionItems.svelte index 9074fa7..e4455ed 100644 --- a/app/src/lib/components/ChatListActionItems.svelte +++ b/app/src/lib/components/ChatListActionItems.svelte @@ -1,9 +1,3 @@ - - + + diff --git a/app/src/lib/components/RootNav.svelte b/app/src/lib/components/RootNav.svelte index 6dc678b..dc00bf4 100644 --- a/app/src/lib/components/RootNav.svelte +++ b/app/src/lib/components/RootNav.svelte @@ -1,13 +1,10 @@
- -
- {#if pathname.match(/chat\/\S+/g)} - - - - - New Audiocast - - {/if} -
diff --git a/app/src/lib/components/Sidebar.svelte b/app/src/lib/components/Sidebar.svelte index c61a5dc..f055dfb 100644 --- a/app/src/lib/components/Sidebar.svelte +++ b/app/src/lib/components/Sidebar.svelte @@ -12,6 +12,8 @@ import { getAppContext } from '../stores/appContext.svelte'; import HeadphoneOff from 'lucide-svelte/icons/headphone-off'; import cs from 'clsx'; + import { page } from '$app/stores'; + import NewAudiocastButton from './NewAudiocastButton.svelte'; const dispatch = createEventDispatcher<{ clickItem: void }>(); @@ -48,6 +50,8 @@ function dispatchClickItem() { dispatch('clickItem'); } + + $: rootPath = $page.url.pathname === '/';
- {#if $openSettingsDrawer$} - {#if !inLast24Hrs.length && !inLast7Days.length && !inLast30Days.length} -
-
- - Your audiocasts will appear here -
+ {#if !rootPath} + + {/if} + + {#if !inLast24Hrs.length && !inLast7Days.length && !inLast30Days.length} +
+
+ + Your audiocasts will appear here
- {/if} +
{/if}
diff --git a/app/src/lib/db/db.session.ts b/app/src/lib/db/db.session.ts index 28117ed..86a1c49 100644 --- a/app/src/lib/db/db.session.ts +++ b/app/src/lib/db/db.session.ts @@ -5,13 +5,13 @@ import { dbRefs } from '@/services/firebase'; import { docData } from './db.utils'; import type { SessionModel } from '@/utils/types'; -export const getSession$ = (sessionId: string) => { +export const getSession$ = (sessionId: string, startValue: SessionModel | null = null) => { const ref = dbRefs.docRef('audiora_sessions', sessionId) as DocumentReference; - return docData(ref).pipe( + const obs = docData(ref).pipe( switchMap((v) => of(v)), distinctUntilChanged((a, b) => equals(a, b)), shareReplay(1), - catchError(() => of(null)), - startWith(null) + catchError(() => of(null)) ); + return startValue ? obs.pipe(startWith(startValue)) : obs; }; diff --git a/app/src/routes/+layout.svelte b/app/src/routes/+layout.svelte index 4fd7a7a..4683387 100644 --- a/app/src/routes/+layout.svelte +++ b/app/src/routes/+layout.svelte @@ -11,6 +11,8 @@ import { page } from '$app/stores'; import Spinner from '@/components/Spinner.svelte'; import { setAppContext } from '@/stores/appContext.svelte'; + import { onMount } from 'svelte'; + import { getAnalytics, logEvent } from 'firebase/analytics'; export let data; @@ -18,6 +20,13 @@ $: setAppContext(); $: setSessionContext(sessionId); + + onMount(() => { + logEvent(getAnalytics(), 'page_view', { + page_title: 'Welcome', + page_path: '/' + }); + }); @@ -28,22 +37,20 @@
- - {#if !browser} -
- -
- {:else} {#key sessionId} {/key} + {:else} +
+ +
{/if}
diff --git a/app/src/routes/audiocast/[sessionId=sessionId]/+layout.svelte b/app/src/routes/audiocast/[sessionId=sessionId]/+layout.svelte index ebfad72..fdada26 100644 --- a/app/src/routes/audiocast/[sessionId=sessionId]/+layout.svelte +++ b/app/src/routes/audiocast/[sessionId=sessionId]/+layout.svelte @@ -2,6 +2,8 @@ import { getSessionContext } from '@/stores/sessionContext.svelte'; import { Button } from '@/components/ui/button'; const { session$, sessionModel$ } = getSessionContext(); + + $: $sessionModel$; @@ -19,6 +21,6 @@ >Generate Audiocast
-{:else if $sessionModel$} +{:else} {/if} diff --git a/app/src/routes/audiocast/[sessionId=sessionId]/+layout.ts b/app/src/routes/audiocast/[sessionId=sessionId]/+layout.ts new file mode 100644 index 0000000..620c55f --- /dev/null +++ b/app/src/routes/audiocast/[sessionId=sessionId]/+layout.ts @@ -0,0 +1,13 @@ +import { error } from '@sveltejs/kit'; +import type { LayoutLoad } from './$types'; +import { getSession$ } from '@/db/db.session'; +import { firstValueFrom } from 'rxjs'; + +export const load: LayoutLoad = async ({ params }) => { + const sessionModel = await firstValueFrom(getSession$(params.sessionId)); + if (!sessionModel) error(404, 'Session not found'); + + return { + sessionModel + }; +}; diff --git a/app/src/routes/audiocast/[sessionId=sessionId]/+layout.server.ts b/app/src/routes/audiocast/[sessionId=sessionId]/+page.server.ts similarity index 100% rename from app/src/routes/audiocast/[sessionId=sessionId]/+layout.server.ts rename to app/src/routes/audiocast/[sessionId=sessionId]/+page.server.ts diff --git a/app/src/routes/audiocast/[sessionId=sessionId]/+page.svelte b/app/src/routes/audiocast/[sessionId=sessionId]/+page.svelte index 8a9b004..6243f80 100644 --- a/app/src/routes/audiocast/[sessionId=sessionId]/+page.svelte +++ b/app/src/routes/audiocast/[sessionId=sessionId]/+page.svelte @@ -6,12 +6,6 @@ title?: string; }; - type GenerateAudiocastResponse = { - script: string; - source_content: string; - created_at?: string; - }; - function parseScript(script: string) { const matches = [...script.matchAll(/<(Speaker\d+)>(.*?)<\/Speaker\d+>/gs)]; return matches.map(([, speaker, content]) => `**${speaker}**: ${content}`).join('\n\n'); @@ -20,7 +14,7 @@ -
- {#if sessionModel} - - {/if} +
+ {#await getAudiocast(sessionId)} -
+
{#if generating} @@ -95,8 +89,8 @@
{/if}
- {:then data} -
+ {:then} +
+ {#if sessionModel.metadata?.transcript} + + Audio Transcript + +
+ {#await parse(parseScript(sessionModel.metadata.transcript)) then parsedContent} + {@html parsedContent} + {/await} +
+
+
+ {/if} + + {#if sessionModel.metadata?.source} + + {/if} + Show Waveform @@ -118,29 +131,11 @@ - - - Audio Transcript - -
- {#await parse(parseScript(data.script)) then parsedContent} - {@html parsedContent} - {/await} -
-
-
- -
- {#if sessionModel} - {@const sessionTitle = sessionModel.metadata?.title || 'Untitled'} - - - - {/if} + + +
{:catch error}
Error: {String(error)}
diff --git a/app/src/routes/chat/[sessionId=sessionId]/+page.svelte b/app/src/routes/chat/[sessionId=sessionId]/+page.svelte index 12e1adc..006806a 100644 --- a/app/src/routes/chat/[sessionId=sessionId]/+page.svelte +++ b/app/src/routes/chat/[sessionId=sessionId]/+page.svelte @@ -1,3 +1,15 @@ + +