瀏覽代碼

enh: voice input support for knowledge text content

Timothy J. Baek 6 月之前
父節點
當前提交
05c18cd664

+ 2 - 1
src/lib/components/chat/MessageInput/VoiceRecording.svelte

@@ -11,6 +11,7 @@
 	const dispatch = createEventDispatcher();
 
 	export let recording = false;
+	export let className = ' p-2.5 w-full max-w-full';
 
 	let loading = false;
 	let confirmed = false;
@@ -282,7 +283,7 @@
 <div
 	class="{loading
 		? ' bg-gray-100/50 dark:bg-gray-850/50'
-		: 'bg-indigo-300/10 dark:bg-indigo-500/10 '} rounded-full flex p-2.5"
+		: 'bg-indigo-300/10 dark:bg-indigo-500/10 '} rounded-full flex {className}"
 >
 	<div class="flex items-center mr-1">
 		<button

+ 10 - 0
src/lib/components/icons/Mic.svelte

@@ -0,0 +1,10 @@
+<script lang="ts">
+	export let className = 'size-4';
+</script>
+
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class={className}>
+	<path d="M7 4a3 3 0 0 1 6 0v6a3 3 0 1 1-6 0V4Z" />
+	<path
+		d="M5.5 9.643a.75.75 0 0 0-1.5 0V10c0 3.06 2.29 5.585 5.25 5.954V17.5h-1.5a.75.75 0 0 0 0 1.5h4.5a.75.75 0 0 0 0-1.5h-1.5v-1.546A6.001 6.001 0 0 0 16 10v-.357a.75.75 0 0 0-1.5 0V10a4.5 4.5 0 0 1-9 0v-.357Z"
+	/>
+</svg>

+ 1 - 1
src/lib/components/workspace/Knowledge/Collection.svelte

@@ -698,7 +698,7 @@
 					<Pane>
 						<div class="flex-1 flex justify-start h-full max-h-full">
 							{#if selectedFile}
-								<div class=" flex flex-col w-full h-full max-h-full ml-2">
+								<div class=" flex flex-col w-full h-full max-h-full ml-2.5">
 									<div class="flex-shrink-0 mb-2 flex items-center">
 										{#if !showSidepanel}
 											<div class="-translate-x-2">

+ 70 - 7
src/lib/components/workspace/Knowledge/Collection/AddTextContentModal.svelte

@@ -9,10 +9,15 @@
 	import Modal from '$lib/components/common/Modal.svelte';
 	import RichTextInput from '$lib/components/common/RichTextInput.svelte';
 	import XMark from '$lib/components/icons/XMark.svelte';
+	import Mic from '$lib/components/icons/Mic.svelte';
+	import Tooltip from '$lib/components/common/Tooltip.svelte';
+	import VoiceRecording from '$lib/components/chat/MessageInput/VoiceRecording.svelte';
 	export let show = false;
 
 	let name = 'Untitled';
 	let content = '';
+
+	let voiceInput = false;
 </script>
 
 <Modal size="full" className="h-full bg-white dark:bg-gray-900" bind:show>
@@ -67,13 +72,71 @@
 				</div>
 			</div>
 
-			<div class="flex justify-end text-sm font-medium flex-shrink-0 mt-1 p-4">
-				<button
-					class=" px-3.5 py-2 bg-black text-white dark:bg-white dark:text-black transition rounded-full"
-					type="submit"
-				>
-					{$i18n.t('Save')}
-				</button>
+			<div
+				class="flex flex-row items-center justify-end text-sm font-medium flex-shrink-0 mt-1 p-4 gap-1.5"
+			>
+				<div class="">
+					{#if voiceInput}
+						<div class=" max-w-full w-64">
+							<VoiceRecording
+								bind:recording={voiceInput}
+								className="p-1"
+								on:cancel={() => {
+									voiceInput = false;
+								}}
+								on:confirm={(e) => {
+									const response = e.detail;
+									content = `${content}${response} `;
+
+									voiceInput = false;
+								}}
+							/>
+						</div>
+					{:else}
+						<Tooltip content={$i18n.t('Voice Input')}>
+							<button
+								class=" p-2 bg-gray-50 text-gray-700 dark:bg-gray-700 dark:text-white transition rounded-full"
+								type="button"
+								on:click={async () => {
+									try {
+										let stream = await navigator.mediaDevices
+											.getUserMedia({ audio: true })
+											.catch(function (err) {
+												toast.error(
+													$i18n.t(`Permission denied when accessing microphone: {{error}}`, {
+														error: err
+													})
+												);
+												return null;
+											});
+
+										if (stream) {
+											voiceInput = true;
+											const tracks = stream.getTracks();
+											tracks.forEach((track) => track.stop());
+										}
+										stream = null;
+									} catch {
+										toast.error($i18n.t('Permission denied when accessing microphone'));
+									}
+								}}
+							>
+								<Mic className="size-5" />
+							</button>
+						</Tooltip>
+					{/if}
+				</div>
+
+				<div class=" flex-shrink-0">
+					<Tooltip content={$i18n.t('Save')}>
+						<button
+							class=" px-3.5 py-2 bg-black text-white dark:bg-white dark:text-black transition rounded-full"
+							type="submit"
+						>
+							{$i18n.t('Save')}
+						</button>
+					</Tooltip>
+				</div>
 			</div>
 		</form>
 	</div>