Skip to content

Commit

Permalink
Merge pull request #178 from iceljc/features/refine-chat-window
Browse files Browse the repository at this point in the history
Features/refine chat window
  • Loading branch information
iceljc authored Aug 2, 2024
2 parents 21bd47d + eca3d10 commit dcd00e3
Show file tree
Hide file tree
Showing 20 changed files with 1,291 additions and 759 deletions.
1,771 changes: 1,081 additions & 690 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,11 @@
"svelte-link": "^1.4.0",
"svelte-player": "^0.0.21",
"svelte-select": "^5.7.0",
"svelte-splitpanes": "^0.8.0",
"svelte-splitpanes": "^8.0.5",
"svelte-viewport-info": "^1.0.1",
"svelvet": "^9.0.0",
"sweetalert2": "^11.6.13",
"swiper": "^10.3.1"
"swiper": "^10.3.1",
"uuid": "^10.0.0"
}
}
25 changes: 3 additions & 22 deletions src/lib/common/AudioGallery.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
<script>
import { AUDIO_ICON } from '$lib/helpers/utils/file';
import { afterUpdate, onMount } from 'svelte';
import AudioPlayer from './audio-player/AudioPlayer.svelte';
/** @type {any[]} */
export let files = [];
/** @type {import('$types').AudioFileModel[]} */
export let audios = [];
/** @type {string} */
export let containerClasses = "";
Expand All @@ -14,23 +12,6 @@
/** @type {boolean} */
export let disableDefaultStyles = false;
/** @type {any[]} */
let audios = [];
afterUpdate(() => {
if (files?.length > 0) {
audios = files.map(file => {
return {
name: file.file_name,
artist: '',
cover: file.file_cover || AUDIO_ICON,
url: file.file_data
};
});
}
});
</script>


Expand All @@ -39,6 +20,6 @@
class="{disableDefaultStyles ? '' : 'audio-gallery-list'} {containerClasses}"
style={`${containerStyles}`}
>
<AudioPlayer mutex audio={audios} />
<AudioPlayer audio={audios} />
</div>
{/if}
2 changes: 1 addition & 1 deletion src/lib/common/FileGallery.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { AUDIO_ICON, EXCEL_ICON, PDF_ICON, isAudio, isExcel, isPdf } from '$lib/helpers/utils/file';
import { LightboxGallery, GalleryThumbnail, GalleryImage } from 'svelte-lightbox';
/** @type {any[]} */
/** @type {import('$types').TextFileModel[]} */
export let files = [];
/** @type {boolean} */
Expand Down
31 changes: 20 additions & 11 deletions src/lib/common/MessageImageGallery.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<script>
import { onMount } from 'svelte';
import { PUBLIC_SERVICE_URL } from '$env/static/public';
import FileGallery from '$lib/common/FileGallery.svelte';
import { PUBLIC_SERVICE_URL } from '$env/static/public';
import { userStore } from '$lib/helpers/store';
import { isAudio } from '$lib/helpers/utils/file';
import { isAudio, AUDIO_ICON } from '$lib/helpers/utils/file';
import { isExternalUrl } from '$lib/helpers/utils/common';
import AudioGallery from './AudioGallery.svelte';
Expand All @@ -16,31 +16,40 @@
/** @type {() => Promise<any>} */
export let fetchFiles = () => Promise.resolve([]);
/** @type {any[]} */
/** @type {import('$types').TextFileModel[]} */
let textFiles = [];
/** @type {any[]} */
/** @type {import('$types').AudioFileModel[]} */
let audioFiles = [];
onMount(() => {
if (fetchFiles != null && fetchFiles != undefined) {
fetchFiles().then(data => {
// @ts-ignore
const validFiles = data?.filter(item => !!item.file_url)?.map(item => {
const validFiles = data?.filter(item => !!item.file_url) || [];
// @ts-ignore
textFiles = validFiles.filter(item => !isAudio(item.file_type)).map(item => {
return {
...item,
file_name: item.file_name,
file_type: item.file_type,
file_data: isExternalUrl(item.file_url) ? item.file_url : `${PUBLIC_SERVICE_URL}${item.file_url}?access_token=${$userStore?.token}`
};
}) || [];
// @ts-ignore
textFiles = validFiles.filter(item => !isAudio(item.file_type));
});
// @ts-ignore
audioFiles = validFiles.filter(item => isAudio(item.file_type));
audioFiles = validFiles.filter(item => isAudio(item.file_type)).map(item => {
return {
name: item.file_name,
cover: AUDIO_ICON,
artist: '',
url: isExternalUrl(item.file_url) ? item.file_url : `${PUBLIC_SERVICE_URL}${item.file_url}?access_token=${$userStore?.token}`
};
});;
});
}
});
</script>
<FileGallery
containerClasses={galleryClasses}
containerStyles={galleryStyles}
Expand All @@ -49,5 +58,5 @@
<AudioGallery
containerClasses={galleryClasses}
containerStyles={galleryStyles}
files={audioFiles}
audios={audioFiles}
/>
2 changes: 1 addition & 1 deletion src/lib/common/PlainPagination.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Row,
} from '@sveltestrap/sveltestrap';
/** @type {import('$lib/helpers/types').Pagination} */
/** @type {import('$types').Pagination} */
export let pagination = { page: 1, size: 10, count: 0 };
/** @type {(pageNum: number) => void} */
export let pageTo;
Expand Down
2 changes: 1 addition & 1 deletion src/lib/common/TablePagination.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import Link from 'svelte-link';
import { _ } from 'svelte-i18n'
/** @type {import('$lib/helpers/types').Pagination} */
/** @type {import('$types').Pagination} */
export let pagination;
/** @type {(pageNum: number) => void} */
export let pageTo;
Expand Down
6 changes: 3 additions & 3 deletions src/lib/common/audio-player/AudioPlayer.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script>
import {
initPlayer,
instances,
stopAll,
useAudioStore
} from "./store";
import { volumeEventHandlers, progressEventHandlers } from "./handlers";
Expand Down Expand Up @@ -43,7 +43,7 @@
wtBufTime,
} = useAudioStore(dispatch);
/** @type {{ name: string, artist?: string, url: string, cover: string, theme?: string }[]} */
/** @type {import('$types').AudioFileModel[]} */
export let audio;
/** @type {"list" | "random"} */
Expand Down Expand Up @@ -218,7 +218,7 @@
const play = () => {
if (mutex) {
instances.forEach((audio) => audio.pause());
stopAll();
}
if (player) {
Expand Down
79 changes: 79 additions & 0 deletions src/lib/common/audio-player/AudioSpeaker.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<script>
import { initSpeech, stopAll } from "$lib/common/audio-player/store";
import { onMount } from "svelte";
/** @type {string} */
export let text;
/** @type {boolean} */
export let mutex = true;
/** @type {string} */
export let containerClasses = "";
/** @type {string} */
export let containerStyles = "";
/** @type {boolean} */
export let disableDefaultStyles = false;
/** @type {boolean} */
let speaking = false;
/** @type {import('$types').SpeechModel} */
let speech;
onMount(() => {
speech = {
synth: window?.speechSynthesis,
utterThis: new SpeechSynthesisUtterance(),
stop: () => stop()
};
initSpeech(speech);
});
/** @param {string} transcript */
function utter(transcript) {
if (mutex) {
stopAll();
}
speaking = true;
speech.utterThis.text = transcript;
speech.synth.speak(speech.utterThis);
}
function speak() {
speaking = !speaking;
if (speaking) {
utter(text);
} else {
speech.synth.cancel();
}
}
const stop = () => {
speaking = false;
if (speech?.synth) {
speech.synth.cancel();
}
}
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
class="{disableDefaultStyles ? '' : 'chat-speaker-container'} {containerClasses}"
style={`${containerStyles}`}
on:click={() => speak()}
>
{#if !speaking}
<span>
<i class="bx bx-volume" />
</span>
{:else}
<span>
<i class="bx bx-volume-full" />
</span>
{/if}
</div>
26 changes: 26 additions & 0 deletions src/lib/common/audio-player/store.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { derived, writable } from "svelte/store";
import { secondToTime } from "./utils";
import { speechVoices } from "$lib/services/web-speech";

/** @type {HTMLAudioElement[]} */
export const instances = [];

/** @type {import('$types').SpeechModel[]} */
export const speechInstances = [];

/**
* @param {HTMLAudioElement} player
* @param {(name: string, detail?: any) => void} dispatch
Expand All @@ -13,6 +17,28 @@ export function initPlayer(player, dispatch) {
bindAudioEvent(player, dispatch);
}

/** @param {import('$types').SpeechModel} speech */
export function initSpeech(speech) {
const foundVoice = speech.synth.getVoices().find(x => speechVoices.includes(x.name));
if (foundVoice) {
speech.utterThis.voice = foundVoice;
}

speech.utterThis.pitch = 1;
speech.utterThis.rate = 1;
speech.synth.cancel();
speechInstances.push(speech);
}

export function stopAll() {
if (instances?.length > 0) {
instances.forEach(player => player.pause());
}
if (speechInstances?.length > 0) {
speechInstances.forEach(sp => sp.stop());
}
}

/**
* @param {HTMLAudioElement} player
* @param {(name: string, detail?: any) => void} dispatch
Expand Down
28 changes: 28 additions & 0 deletions src/lib/helpers/types.js → src/lib/helpers/types/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,34 @@
* @property {Date} created_time - The conversation created time.
*/


// File models
/**
* @typedef {Object} TextFileModel
* @property {string} file_name - The file name.
* @property {string} [file_type] - The file type.
* @property {string} file_data - The file data or url.
*/

/**
* @typedef {Object} AudioFileModel
* @property {string} name - The audio name.
* @property {string} [artist] - The audio author.
* @property {string} cover - The audio cover.
* @property {string} url - The audio url.
* @property {string} [theme] - The audio theme.
*/


// Speech
/**
* @typedef {Object} SpeechModel
* @property {SpeechSynthesis} synth
* @property {SpeechSynthesisUtterance} utterThis
* @property {() => void} stop
*/


/**
* @interface
* @class
Expand Down
10 changes: 10 additions & 0 deletions src/lib/scss/custom/components/_audio.scss
Original file line number Diff line number Diff line change
Expand Up @@ -335,4 +335,14 @@
100% {
transform: rotate(360deg);
}
}



.chat-speaker-container {
font-size: 20px;
color: var(--bs-primary);
span {
cursor: pointer;
}
}
Loading

0 comments on commit dcd00e3

Please sign in to comment.