diff --git a/api/requirements.txt b/api/requirements.txt
index f10ddd5..1f015fd 100644
--- a/api/requirements.txt
+++ b/api/requirements.txt
@@ -1,37 +1,37 @@
-anthropic
-
-asyncio
-elevenlabs
fastapi
+uvicorn
+gunicorn
+uvloop
fastapi-utilities
-ffmpeg-python
firebase-admin
google-api-python-client
google-auth
google-cloud-storage
google-generativeai
-gunicorn
+
+asyncio
httpx
+redis[hiredis]
+anthropic
+elevenlabs
openai
pycairo
pydantic
pydub
+pypdf[crypto]
python-dotenv
+ffmpeg-python
python-multipart
python-slugify
ruff
seewav
setuptools
-uvicorn
-uvloop
-redis[hiredis]
-async-web-search
lxml
beautifulsoup4
-pypdf[crypto]
\ No newline at end of file
+async-web-search
\ No newline at end of file
diff --git a/api/src/main.py b/api/src/main.py
index 4d88349..3f142d9 100644
--- a/api/src/main.py
+++ b/api/src/main.py
@@ -190,3 +190,12 @@ async def save_uploaded_files_endpoint(files: list[UploadFile], sessionId: str =
"""
result = await UploadedFiles(session_id=sessionId)._save_sources(files)
return result
+
+
+@app.delete("/delete-session/{sessionId}")
+def delete_session_endpoint(sessionId: str):
+ """
+ Delete audiocast session
+ """
+ SessionManager._delete_session(sessionId)
+ return "Deleted"
diff --git a/api/src/utils/generate_audiocast.py b/api/src/utils/generate_audiocast.py
index 5ba3530..2adfe1e 100644
--- a/api/src/utils/generate_audiocast.py
+++ b/api/src/utils/generate_audiocast.py
@@ -1,3 +1,5 @@
+import os
+
from fastapi import BackgroundTasks, HTTPException
from src.services.storage import StorageManager
@@ -36,6 +38,9 @@ def post_generate_audio(
waveform_utils.run_all()
except Exception as e:
print(f"Error in generate_audiocast background_tasks: {str(e)}")
+ finally:
+ if os.path.exists(audio_path):
+ os.remove(audio_path)
async def generate_audiocast(request: GenerateAudioCastRequest, background_tasks: BackgroundTasks):
diff --git a/api/src/utils/session_manager.py b/api/src/utils/session_manager.py
index 37f57e5..704779e 100644
--- a/api/src/utils/session_manager.py
+++ b/api/src/utils/session_manager.py
@@ -146,3 +146,7 @@ def on_snapshot(doc_snapshot, _changes, _read_time):
callback(info)
return doc_ref.on_snapshot(on_snapshot)
+
+ @staticmethod
+ def _delete_session(doc_id: str):
+ return DBManager()._delete_document(collections["audiora_sessions"], doc_id)
diff --git a/app/package.json b/app/package.json
index 02aaad1..1e69c2d 100644
--- a/app/package.json
+++ b/app/package.json
@@ -19,7 +19,6 @@
"test": "npm run test:integration && npm run test:unit"
},
"dependencies": {
- "bits-ui": "^0.21.16",
"canvas-confetti": "^1.9.3",
"clsx": "^2.1.1",
"copy-to-clipboard": "^3.3.3",
@@ -55,6 +54,7 @@
"@types/ramda": "^0.30.1",
"@types/throttle-debounce": "^5.0.2",
"autoprefixer": "^10.4.20",
+ "bits-ui": "^0.21.16",
"eslint": "^9.0.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.36.0",
diff --git a/app/src/lib/components/ChatContainer.svelte b/app/src/lib/components/ChatContainer.svelte
index 8def7c8..14ab83e 100644
--- a/app/src/lib/components/ChatContainer.svelte
+++ b/app/src/lib/components/ChatContainer.svelte
@@ -1,11 +1,17 @@
- {#if !$sessionCompleted$ && !$fetchingSource$ && !$audioSource$}
+ {#if !hasFinalResponse && !$sessionCompleted$ && !$fetchingSource$ && !$audioSource$}
diff --git a/app/src/lib/components/ManageAudioSourceDrawer.svelte b/app/src/lib/components/ManageAudioSourceDrawer.svelte
index 4e9df0e..4181045 100644
--- a/app/src/lib/components/ManageAudioSourceDrawer.svelte
+++ b/app/src/lib/components/ManageAudioSourceDrawer.svelte
@@ -77,8 +77,8 @@
-
diff --git a/app/src/lib/components/RenderExamples.svelte b/app/src/lib/components/RenderExamples.svelte
index fb4f041..6a3e3ea 100644
--- a/app/src/lib/components/RenderExamples.svelte
+++ b/app/src/lib/components/RenderExamples.svelte
@@ -29,7 +29,7 @@
{#each contentExamplesDict as [category, content]}
- {@const href = `/chat/${sessionId}?category=${category}`}
+ {@const href = `/chat/${sessionId}?category=${category}&chat`}
{/each}
diff --git a/app/src/lib/components/RootNav.svelte b/app/src/lib/components/RootNav.svelte
index dc00bf4..99df60e 100644
--- a/app/src/lib/components/RootNav.svelte
+++ b/app/src/lib/components/RootNav.svelte
@@ -1,7 +1,7 @@
-
Last 7 days
- {#each inLast7Days as item}
-
+
Last 7 days
+ {#each inLast7Days as item (item.sessionId)}
+
{/each}
-
Last month
- {#each inLast30Days as item}
-
+
Last month
+ {#each inLast30Days as item (item.sessionId)}
+
{/each}
diff --git a/app/src/lib/components/SidebarItem.svelte b/app/src/lib/components/SidebarItem.svelte
index 848c3f5..bd6eb49 100644
--- a/app/src/lib/components/SidebarItem.svelte
+++ b/app/src/lib/components/SidebarItem.svelte
@@ -1,6 +1,6 @@
+
+
+ (openDialog = true)}
+ >
+
+
+
+
+{#if openDialog}
+
+
+
+ Delete audiocast?
+
+ This action cannot be undone. This will permanently delete your audiocast data.
+
+
+
+
+ (openDialog = false)}>Cancel
+
+ Continue
+
+
+
+
+{/if}
diff --git a/app/src/lib/components/SlideSheet.svelte b/app/src/lib/components/SlideSheet.svelte
index 14837fb..19d4772 100644
--- a/app/src/lib/components/SlideSheet.svelte
+++ b/app/src/lib/components/SlideSheet.svelte
@@ -19,7 +19,7 @@
- Audiocasts
+ Audiocasts
diff --git a/app/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte b/app/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte
new file mode 100644
index 0000000..51dbd6a
--- /dev/null
+++ b/app/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte
@@ -0,0 +1,21 @@
+
+
+
+
+
diff --git a/app/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte b/app/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte
new file mode 100644
index 0000000..88b2cf7
--- /dev/null
+++ b/app/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte
@@ -0,0 +1,21 @@
+
+
+
+
+
diff --git a/app/src/lib/components/ui/alert-dialog/alert-dialog-content.svelte b/app/src/lib/components/ui/alert-dialog/alert-dialog-content.svelte
new file mode 100644
index 0000000..b6efc0d
--- /dev/null
+++ b/app/src/lib/components/ui/alert-dialog/alert-dialog-content.svelte
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/lib/components/ui/alert-dialog/alert-dialog-description.svelte b/app/src/lib/components/ui/alert-dialog/alert-dialog-description.svelte
new file mode 100644
index 0000000..972cc63
--- /dev/null
+++ b/app/src/lib/components/ui/alert-dialog/alert-dialog-description.svelte
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/app/src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte b/app/src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte
new file mode 100644
index 0000000..e843c0d
--- /dev/null
+++ b/app/src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/app/src/lib/components/ui/alert-dialog/alert-dialog-header.svelte b/app/src/lib/components/ui/alert-dialog/alert-dialog-header.svelte
new file mode 100644
index 0000000..88bf04b
--- /dev/null
+++ b/app/src/lib/components/ui/alert-dialog/alert-dialog-header.svelte
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/app/src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte b/app/src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte
new file mode 100644
index 0000000..659bb81
--- /dev/null
+++ b/app/src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte
@@ -0,0 +1,21 @@
+
+
+
diff --git a/app/src/lib/components/ui/alert-dialog/alert-dialog-portal.svelte b/app/src/lib/components/ui/alert-dialog/alert-dialog-portal.svelte
new file mode 100644
index 0000000..e227219
--- /dev/null
+++ b/app/src/lib/components/ui/alert-dialog/alert-dialog-portal.svelte
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/app/src/lib/components/ui/alert-dialog/alert-dialog-title.svelte b/app/src/lib/components/ui/alert-dialog/alert-dialog-title.svelte
new file mode 100644
index 0000000..594fe5e
--- /dev/null
+++ b/app/src/lib/components/ui/alert-dialog/alert-dialog-title.svelte
@@ -0,0 +1,14 @@
+
+
+
+
+
diff --git a/app/src/lib/components/ui/alert-dialog/index.ts b/app/src/lib/components/ui/alert-dialog/index.ts
new file mode 100644
index 0000000..be56dd7
--- /dev/null
+++ b/app/src/lib/components/ui/alert-dialog/index.ts
@@ -0,0 +1,40 @@
+import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
+
+import Title from "./alert-dialog-title.svelte";
+import Action from "./alert-dialog-action.svelte";
+import Cancel from "./alert-dialog-cancel.svelte";
+import Portal from "./alert-dialog-portal.svelte";
+import Footer from "./alert-dialog-footer.svelte";
+import Header from "./alert-dialog-header.svelte";
+import Overlay from "./alert-dialog-overlay.svelte";
+import Content from "./alert-dialog-content.svelte";
+import Description from "./alert-dialog-description.svelte";
+
+const Root = AlertDialogPrimitive.Root;
+const Trigger = AlertDialogPrimitive.Trigger;
+
+export {
+ Root,
+ Title,
+ Action,
+ Cancel,
+ Portal,
+ Footer,
+ Header,
+ Trigger,
+ Overlay,
+ Content,
+ Description,
+ //
+ Root as AlertDialog,
+ Title as AlertDialogTitle,
+ Action as AlertDialogAction,
+ Cancel as AlertDialogCancel,
+ Portal as AlertDialogPortal,
+ Footer as AlertDialogFooter,
+ Header as AlertDialogHeader,
+ Trigger as AlertDialogTrigger,
+ Overlay as AlertDialogOverlay,
+ Content as AlertDialogContent,
+ Description as AlertDialogDescription,
+};
diff --git a/app/src/lib/stores/sessionContext.svelte.ts b/app/src/lib/stores/sessionContext.svelte.ts
index ad62b72..21cd590 100644
--- a/app/src/lib/stores/sessionContext.svelte.ts
+++ b/app/src/lib/stores/sessionContext.svelte.ts
@@ -1,9 +1,11 @@
+import { browser } from '$app/environment';
+import { page } from '$app/stores';
import { getCustomSources$ } from '@/db/db.customSources';
import { getSession$ } from '@/db/db.session';
import type { ContentCategory } from '@/utils/types';
import { setContext, getContext } from 'svelte';
import { persisted } from 'svelte-persisted-store';
-import { derived, writable } from 'svelte/store';
+import { derived, get, writable } from 'svelte/store';
const CONTEXT_KEY = {};
export const SESSION_KEY = 'AUDIOCAST_SESSION';
@@ -26,13 +28,15 @@ export type Session = {
};
export function setSessionContext(sessionId: string) {
- const session$ = persisted(`${SESSION_KEY}_${sessionId}`, null);
const sessionId$ = writable(sessionId);
+ const session$ = persisted(`${SESSION_KEY}_${sessionId}`, null);
const sessionCompleted$ = derived(session$, ($session) => !!$session?.completed);
const fetchingSource$ = writable(false);
const audioSource$ = persisted(`AUDIOCAST_SOURCE_${sessionId}`, '');
+ const refreshSidebar$ = derived(page, ({ url }) => browser && url.searchParams.has('chat'));
+
return setContext(CONTEXT_KEY, {
session$,
sessionId$,
@@ -41,6 +45,7 @@ export function setSessionContext(sessionId: string) {
audioSource$,
customSources$: getCustomSources$(sessionId),
sessionModel$: getSession$(sessionId),
+ refreshSidebar$,
startSession: (category: ContentCategory) => {
session$.set({
id: sessionId,
diff --git a/app/src/lib/utils/session.utils.ts b/app/src/lib/utils/session.utils.ts
new file mode 100644
index 0000000..b53bb47
--- /dev/null
+++ b/app/src/lib/utils/session.utils.ts
@@ -0,0 +1,13 @@
+import type { ChatItem } from '@/stores/sessionContext.svelte';
+
+export const FINAL_RESPONSE_PREFIX = 'Ok, thanks for clarifying!';
+export const FINAL_RESPONSE_SUFFIX =
+ 'Please click the button below to start generating the audiocast.';
+
+export const isfinalResponse = (v: ChatItem) => v.content.includes(FINAL_RESPONSE_SUFFIX);
+
+export function getSummary(content: string) {
+ const replacePrefixRegex = new RegExp(FINAL_RESPONSE_PREFIX, 'gi');
+ const replaceSuffixRegex = new RegExp(FINAL_RESPONSE_SUFFIX, 'gi');
+ return content.replace(replacePrefixRegex, '').replace(replaceSuffixRegex, '').trim();
+}
diff --git a/app/src/routes/+layout.svelte b/app/src/routes/+layout.svelte
index 4683387..4ac0741 100644
--- a/app/src/routes/+layout.svelte
+++ b/app/src/routes/+layout.svelte
@@ -7,7 +7,7 @@
import { Toaster } from '$lib/components/ui/sonner';
import { setSessionContext } from '@/stores/sessionContext.svelte';
import RootNav from '@/components/RootNav.svelte';
- import SearchSidebar from '@/components/Sidebar.svelte';
+ import Sidebar from '@/components/Sidebar.svelte';
import { page } from '$app/stores';
import Spinner from '@/components/Spinner.svelte';
import { setAppContext } from '@/stores/appContext.svelte';
@@ -39,9 +39,7 @@
{#if browser}
- {#key sessionId}
-
- {/key}
+
{#key sessionId}
diff --git a/app/src/routes/+page.svelte b/app/src/routes/+page.svelte
index 79f6d6b..201dd39 100644
--- a/app/src/routes/+page.svelte
+++ b/app/src/routes/+page.svelte
@@ -21,14 +21,14 @@
searchTerm = '';
}
- function continueChat(category: ContentCategory) {
+ async function continueChat(category: ContentCategory) {
startSession(category);
const content = `${selectContent}\nCategory: ${category} `;
addChatItem({ id: uuid(), content, role: 'user', loading: false });
- const href = `/chat/${sessionId}?category=${category}`;
- goto(href);
+ const href = `/chat/${sessionId}?category=${category}&chat`;
+ return goto(href, { invalidateAll: true, replaceState: true });
}
diff --git a/app/src/routes/chat/[sessionId=sessionId]/+page.svelte b/app/src/routes/chat/[sessionId=sessionId]/+page.svelte
index 006806a..b4e30e8 100644
--- a/app/src/routes/chat/[sessionId=sessionId]/+page.svelte
+++ b/app/src/routes/chat/[sessionId=sessionId]/+page.svelte
@@ -1,15 +1,3 @@
-
-