Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the chat input box #23

Merged
merged 6 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions api/src/utils/chat_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@
]

content_examples: Dict[ContentCategory, str] = {
"podcast": "Create a podcast exploring the intersection of ancient philosophy and artificial intelligence.",
"sermon": "Write a sermon connecting the teachings of Augustine with modern digital ethics.",
"audiodrama": "A reimagining of Homer's Odyssey set in a cyberpunk future.",
"lecture": "A lecture comparing Shakespeare's influence on modern social media communication.",
"commentary": "A commentary on how Classical music influences contemporary electronic genres.",
"voicenote": "A personal reflection on reading Plato's Republic in today's political climate.",
"interview": "An interview with an archaeologist using AI to uncover ancient Roman artifacts.",
"soundbite": "A quick take on how ancient Greek democracy shapes modern blockchain governance.",
"podcast": "Podcast exploring the intersection of ancient philosophy and AI",
"sermon": "Sermon connecting the teachings of Augustine with modern digital ethics",
"audiodrama": "Reimagining of Homer's Odyssey set in a cyberpunk future",
"lecture": "Lecture comparing Shakespeare's influence on modern social media",
"commentary": "Commentary on how Classical music influences contemporary electronic genres",
"voicenote": "Personal reflection on reading Plato's Republic in today's political climate",
"interview": "Interview with an archaeologist using AI to uncover ancient Roman artifacts",
"soundbite": "Quick take on how ancient Greek democracy shapes modern blockchain governance",
}

category_qualifiers: Dict[ContentCategory, str] = {
Expand Down
4 changes: 2 additions & 2 deletions app/src/lib/components/AutoDetectedCategory.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

<ChatListItem
type="assistant"
content="I auto-detected you want {categoryWithArticle}. Press NEXT to continue if correct."
content="I auto-detected you want {categoryWithArticle}. Press NEXT to continue."
/>

<Button
Expand All @@ -40,4 +40,4 @@
<ArrowRight class="w-4 ml-1 inline" />
</Button>

<ChatListItem type="assistant" content="Else, select your audiocast category" />
<ChatListItem type="assistant" content="Or select your audiocast category" />
93 changes: 93 additions & 0 deletions app/src/lib/components/ChatBoxAndWidget.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<script context="module">
const examples = [
{ icon: '🎨', text: 'Create image' },
{ icon: '💡', text: 'Get advice' },
{ icon: '🧠', text: 'Brainstorm' },
{ icon: '🎲', text: 'Surprise me' },
{ icon: '✍️', text: 'Help me write' },
{ text: 'More' }
];
</script>

<script lang="ts">
import { Button } from '@/components/ui/button';
import { Card } from '@/components/ui/card';
import { PaperclipIcon, ArrowUpIcon } from 'lucide-svelte';
import { createEventDispatcher } from 'svelte';

export let searchTerm = '';

const dispatch = createEventDispatcher<{
submitSearch: { value: string };
attach: void;
}>();

function handleKeyPress(ev: KeyboardEvent) {
if (ev.key === 'Enter' && !ev.shiftKey && searchTerm) {
ev.preventDefault();
dispatchSearch();
}
}

function dispatchSearch() {
if (!searchTerm.trim()) return;
dispatch('submitSearch', { value: searchTerm });
}
</script>

<div class="flex flex-col items-center max-lg:pt-16 md:justify-center h-full">
<div class="w-full max-w-3xl space-y-8">
<div class="text-center space-y-2">
<h1 class="md:text-4xl text-3xl font-semibold text-white">What can I help with?</h1>
<h3 class="text-base text-gray-400">Listen to anything, anytime</h3>
</div>

<Card class="bg-zinc-800/50 border-0 overflow-hidden">
<div class="flex items-center p-2">
<div class="flex-1">
<textarea
placeholder="Message Audiora"
class="w-full outline-none bg-transparent border-0 focus:ring-0 text-white placeholder-zinc-400 resize-none py-3 px-4"
rows={1}
tabindex={0}
bind:value={searchTerm}
on:keypress={handleKeyPress}
/>
</div>
</div>
<div class="flex flex-row-reverse items-center justify-between p-2 bg-zinc-800/30">
<slot name="tools">
<div class="flex items-center gap-2 px-2">
<Button variant="ghost" size="icon" class="text-zinc-400 hover:text-white" on:click>
<PaperclipIcon class="h-5 w-5" />
</Button>

<Button
variant="ghost"
size="icon"
class="text-zinc-400 hover:text-white"
disabled={!searchTerm}
on:click={dispatchSearch}
>
<ArrowUpIcon class="h-5 w-5" />
</Button>
</div>
</slot>
</div>
</Card>

<slot name="examples">
<div class="flex flex-wrap gap-2 justify-center">
{#each examples as item, index (index)}
<Button
variant="outline"
class="bg-zinc-800/50 border-zinc-700 text-zinc-300 hover:bg-zinc-700/50 hover:text-white"
>
<span class="mr-2">{item.icon}</span>
{item.text}
</Button>
{/each}
</div>
</slot>
</div>
</div>
26 changes: 14 additions & 12 deletions app/src/lib/components/ChatContainer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,18 @@
</div>
</div>

{#if !hasFinalResponse && !$sessionCompleted$ && !$fetchingSource$ && !$audioSource$}
<div class="shrink-0 w-full sm:max-w-xl lg:max-w-3xl max-w-full max-sm:px-4 px-1 py-4">
<ChatBoxContainer
bind:searchTerm
loading={navLoading}
showIcon
disabled={$sessionCompleted$ || disableTextInput}
on:keypress
on:click
/>
</div>
{/if}
<slot name="chatbox">
{#if !hasFinalResponse && !$sessionCompleted$ && !$fetchingSource$ && !$audioSource$}
<div class="shrink-0 w-full sm:max-w-xl lg:max-w-3xl max-w-full max-sm:px-4 px-1 py-4">
<ChatBoxContainer
bind:searchTerm
loading={navLoading}
showIcon
disabled={$sessionCompleted$ || disableTextInput}
on:keypress
on:click
/>
</div>
{/if}
</slot>
</div>
2 changes: 1 addition & 1 deletion app/src/lib/components/ChatListActionItems.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
})
.then((res) => {
$audioSource$ = res;
toast.success('Audiocast source generated successfully');
toast.success('AI-generated source material generated successfully');
})
.catch((error) => toast.error(error.message))
.finally(() => ($fetchingSource$ = false));
Expand Down
2 changes: 1 addition & 1 deletion app/src/lib/components/ExampleCard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<button
on:click={handleClick}
class="border no-underline hover:no-underline rounded-md group border-gray-600 p-4 bg-gray-900 hover:bg-gray-800"
class="border rounded-md min-h-[72px] md:h-28 group p-3 bg-zinc-800/50 border-zinc-700 text-zinc-300 hover:bg-zinc-700/50 transition-all hover:text-zinc-100"
>
<span class="text-sm">
{content}
Expand Down
28 changes: 12 additions & 16 deletions app/src/lib/components/RenderExamples.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,27 @@
import type { ContentCategory } from '@/utils/types';

export const contentExamples: Record<ContentCategory, string> = {
podcast:
'Create a podcast exploring the intersection of ancient philosophy and artificial intelligence.',
sermon: 'Write a sermon connecting the teachings of Augustine with modern digital ethics.',
audiodrama: "A reimagining of Homer's Odyssey set in a cyberpunk future.",
lecture: "A lecture comparing Shakespeare's influence on modern social media communication.",
commentary: 'A commentary on how Classical music influences contemporary electronic genres.',
voicenote: "A personal reflection on reading Plato's Republic in today's political climate.",
interview: 'An interview with an archaeologist using AI to uncover ancient Roman artifacts.',
soundbite: 'A quick take on how ancient Greek democracy shapes modern blockchain governance.'
podcast: 'Podcast exploring the intersection of ancient philosophy and AI',
sermon: 'Sermon connecting the teachings of Augustine with modern digital ethics',
audiodrama: "Reimagining of Homer's Odyssey set in a cyberpunk future",
lecture: "Lecture comparing Shakespeare's influence on modern social media",
commentary: 'Commentary on how Classical music influences contemporary electronic genres',
voicenote: "Personal reflection on reading Plato's Republic in today's political climate.",
interview: 'Interview with an archaeologist using AI to uncover ancient Roman artifacts',
soundbite: 'Quick take on how ancient Greek democracy shapes modern blockchain governance'
};
</script>

<script lang="ts">
import ExampleCard from './ExampleCard.svelte';
export let sessionId: string;

$: contentExamplesDict = Object.entries(contentExamples) as Array<
[category: ContentCategory, content: string]
>;
$: contentExamplesDict = (
Object.entries(contentExamples) as Array<[category: ContentCategory, content: string]>
).slice(0, 6);
</script>

<div class="w-full h-full block mt-16">
<div class="w-full mx-auto md:w-4/5 mb-6 text-center">
<h3 class="text-2xl sm:text-3xl font-semibold">Start with one</h3>
</div>
<div class="w-full h-full block">
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 pb-4">
{#each contentExamplesDict as [category, content]}
{@const href = `/chat/${sessionId}?category=${category}&chat`}
Expand Down
40 changes: 22 additions & 18 deletions app/src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<script lang="ts">
import RenderExamples from '@/components/RenderExamples.svelte';
import ChatContainer from '@/components/ChatContainer.svelte';
import { getSessionContext } from '@/stores/sessionContext.svelte.js';
import { uuid } from '@/utils/uuid';
import { goto } from '$app/navigation';
import type { ContentCategory } from '@/utils/types';
import RenderCategorySelection from '@/components/RenderCategorySelection.svelte';
import ChatBoxAndWidget from '@/components/ChatBoxAndWidget.svelte';
import { cn } from '@/utils/ui.utils';

const { sessionId$, addChatItem, startSession } = getSessionContext();

Expand All @@ -23,7 +24,7 @@

async function continueChat(category: ContentCategory) {
startSession(category);

const content = `${selectContent}\nCategory: ${category} `;
addChatItem({ id: uuid(), content, role: 'user', loading: false, createdAt: Date.now() });

Expand All @@ -36,20 +37,23 @@
<title>Audiora</title>
</svelte:head>

<ChatContainer
disableTextInput={triggerSelectCategory}
bind:searchTerm
on:click={handleSearch}
on:keypress={handleSearch}
<div
class={cn('overflow-auto w-full h-full flex items-center justify-center mx-auto px-4', {
'flex-col justify-start': triggerSelectCategory && selectContent
})}
>
<svelte:fragment slot="content">
{#if triggerSelectCategory && selectContent}
<RenderCategorySelection
content={selectContent}
on:selectCategory={({ detail }) => continueChat(detail.value)}
/>
{:else}
<RenderExamples {sessionId} />
{/if}
</svelte:fragment>
</ChatContainer>
<div class="sm:max-w-xl lg:max-w-3xl max-w-full w-full max-h-full">
<div class="scrollbar-y-1 w-full h-full block">
{#if triggerSelectCategory && selectContent}
<RenderCategorySelection
content={selectContent}
on:selectCategory={({ detail }) => continueChat(detail.value)}
/>
{:else}
<ChatBoxAndWidget bind:searchTerm on:submitSearch={handleSearch}>
<RenderExamples slot="examples" {sessionId} />
</ChatBoxAndWidget>
{/if}
</div>
</div>
</div>
Loading