Merge pull request #5313 from zabirauf/u/zabirauf/speech-speed

feat: Added speech playback speed control for Call mode
This commit is contained in:
Timothy Jaeryang Baek 2024-09-19 02:44:27 +02:00 committed by GitHub
commit dd4cf102cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 64 additions and 7 deletions

View File

@ -1,15 +1,13 @@
<script lang="ts"> <script lang="ts">
import { config, models, settings, showCallOverlay } from '$lib/stores'; import { config, models, settings, showCallOverlay } from '$lib/stores';
import { onMount, tick, getContext, onDestroy, createEventDispatcher } from 'svelte'; import { onMount, tick, getContext, onDestroy, createEventDispatcher } from 'svelte';
import { DropdownMenu } from 'bits-ui';
import Dropdown from '$lib/components/common/Dropdown.svelte';
import { flyAndScale } from '$lib/utils/transitions';
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
import { import { blobToFile } from '$lib/utils';
blobToFile,
calculateSHA256,
extractSentencesForAudio,
findWordIndices
} from '$lib/utils';
import { generateEmoji } from '$lib/apis'; import { generateEmoji } from '$lib/apis';
import { synthesizeOpenAISpeech, transcribeAudio } from '$lib/apis/audio'; import { synthesizeOpenAISpeech, transcribeAudio } from '$lib/apis/audio';
@ -360,6 +358,7 @@
?.at(0) ?? undefined; ?.at(0) ?? undefined;
currentUtterance = new SpeechSynthesisUtterance(content); currentUtterance = new SpeechSynthesisUtterance(content);
currentUtterance.rate = speechRate;
if (voice) { if (voice) {
currentUtterance.voice = voice; currentUtterance.voice = voice;
@ -381,11 +380,12 @@
const playAudio = (audio) => { const playAudio = (audio) => {
if ($showCallOverlay) { if ($showCallOverlay) {
return new Promise((resolve) => { return new Promise((resolve) => {
const audioElement = document.getElementById('audioElement'); const audioElement = document.getElementById('audioElement') as HTMLAudioElement;
if (audioElement) { if (audioElement) {
audioElement.src = audio.src; audioElement.src = audio.src;
audioElement.muted = true; audioElement.muted = true;
audioElement.playbackRate = speechRate;
audioElement audioElement
.play() .play()
@ -430,6 +430,28 @@
let audioAbortController = new AbortController(); let audioAbortController = new AbortController();
// Audio speed control
let speechRate = 1;
let showSpeedMenu = false;
const speedOptions = [2, 1.75, 1.5, 1.25, 1, 0.75, 0.5];
const setSpeedRate = (rate: number) => {
speechRate = rate;
showSpeedMenu = false;
updateAudioSpeed();
};
const updateAudioSpeed = () => {
if (currentUtterance) {
currentUtterance.rate = speechRate;
}
const audioElement = document.getElementById('audioElement') as HTMLAudioElement;
if (audioElement) {
audioElement.playbackRate = speechRate;
}
};
// Audio cache map where key is the content and value is the Audio object. // Audio cache map where key is the content and value is the Audio object.
const audioCache = new Map(); const audioCache = new Map();
const emojiCache = new Map(); const emojiCache = new Map();
@ -918,6 +940,41 @@
</button> </button>
</div> </div>
<div class="relative">
<Dropdown bind:show={showSpeedMenu}>
<button class="p-2 rounded-full bg-gray-50 dark:bg-gray-900">
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<polygon points="8,5 8,19 19,12" fill="currentColor"/>
<path d="M12 2A10 10 0 0 0 12 22" fill="none" stroke="currentColor" stroke-width="2" stroke-dasharray="2,2"/>
<path d="M12 2A10 10 0 0 1 12 22" fill="none" stroke="currentColor" stroke-width="2"/>
</svg>
</button>
<div slot="content">
<DropdownMenu.Content
class="w-full max-w-[180px] rounded-lg px-1 py-1.5 border border-gray-300/30 dark:border-gray-700/50 z-[9999] bg-white dark:bg-gray-900 dark:text-white shadow-sm"
sideOffset={6}
side="top"
align="start"
transition={flyAndScale}
>
{#each speedOptions as speed}
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md {speechRate === speed ? 'bg-gray-200 dark:bg-gray-600' : ''}"
on:click={() => setSpeedRate(speed)}
>
<div class="flex items-center">
<div class="line-clamp-1">
{speed}x
</div>
</div>
</DropdownMenu.Item>
{/each}
</DropdownMenu.Content>
</div>
</Dropdown>
</div>
<div> <div>
<button <button
class=" p-3 rounded-full bg-gray-50 dark:bg-gray-900" class=" p-3 rounded-full bg-gray-50 dark:bg-gray-900"