Initial commit

This commit is contained in:
pluja
2023-08-26 10:36:05 +02:00
commit a3543ee13a
76 changed files with 6165 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
import { transcriptions } from '$lib/stores';
import { browser, dev } from '$app/environment';
import { PUBLIC_INTERNAL_API_HOST } from '$env/static/public';
import { CLIENT_API_HOST } from '$lib/utils';
/** @type {import('./$types').PageLoad} */
export async function load({ fetch }) {
// Use different endpoints for server-side and client-side
const endpoint = browser ? `${CLIENT_API_HOST}/api/transcriptions` : `${PUBLIC_INTERNAL_API_HOST}/api/transcriptions`;
console.log(endpoint);
const response = await fetch(endpoint);
const ts = await response.json();
if (ts) {
transcriptions.update(_ => ts.length > 0 ? ts : []);
} else {
transcriptions.update(_ => []);
}
}

View File

@@ -0,0 +1,5 @@
<script>
import "../app.css";
</script>
<slot />

View File

@@ -0,0 +1,11 @@
/** @type {import('./$types').PageLoad} */
import {getRandomSentence} from "$lib/utils";
export async function load() {
const randomSentence = getRandomSentence();
return {
randomSentence: randomSentence
};
};

View File

@@ -0,0 +1,126 @@
<script>
import { Toaster } from 'svelte-french-toast';
import { transcriptions } from '$lib/stores';
import { browser, dev } from '$app/environment';
import { CLIENT_WS_HOST } from '$lib/utils';
import { onMount, onDestroy } from 'svelte';
import ModalTranscriptionForm from '$lib/components/ModalTranscriptionForm.svelte';
import ModalDownloadOptions from '$lib/components/ModalDownloadOptions.svelte';
import ModalTranslationForm from '$lib/components/ModalTranslationForm.svelte';
import SuccessTranscription from '$lib/components/SuccessTranscription.svelte';
import PendingTranscription from '$lib/components/PendingTranscription.svelte';
import PendingTranslation from '$lib/components/PendingTranslation.svelte';
import ErrorTranscription from '$lib/components/ErrorTranscription.svelte';
//export let data;
let socket;
export let data;
function connect() {
if (!browser) {
console.log('Server, not connecting');
return;
}
let new_uri = '';
var loc = window.location;
if (loc.protocol === 'https:') {
new_uri = 'wss:';
} else {
new_uri = 'ws:';
}
new_uri += '//' + (CLIENT_WS_HOST == '' ? loc.host : CLIENT_WS_HOST);
new_uri += '/ws/transcriptions';
console.log('Connecting to: ', new_uri);
socket = new WebSocket(new_uri);
socket.onopen = () => console.log('WebSocket is connected...');
socket.onerror = (error) => console.log('WebSocket Error: ', error);
socket.onclose = (event) => {
console.log('WebSocket is closed with code: ', event.code, ' and reason: ', event.reason);
setTimeout(() => {
console.log('Reconnecting...');
connect();
}, 1000);
};
socket.onmessage = (event) => {
let update = JSON.parse(event.data);
// use update to update the store
transcriptions.update(transcriptions => {
let index = transcriptions.findIndex(tr => tr.id === update.id);
if (index >= 0) {
// replace the item at index
transcriptions[index] = update;
} else {
// add the new item
transcriptions.push(update);
}
return transcriptions; // return a new object to trigger reactivity
});
};
}
onMount(() => {
connect();
});
let downloadTranscription = null;
let handleDownload = (event) => {
downloadTranscription = event.detail; // this will be the transcription to download
modalDownloadOptions.showModal(); // show the modal
};
let translateTranscription = null;
let handleTranslate = (event) => {
translateTranscription = event.detail; // this will be the transcription to translate
modalTranslation.showModal(); // show the modal
};
onDestroy(() => {
if (socket) {
socket.close(1000);
}
});
</script>
<Toaster />
<ModalDownloadOptions tr={downloadTranscription} />
<ModalTranslationForm tr={translateTranscription} />
<ModalTranscriptionForm />
<header>
<h1 class="flex items-center justify-center space-x-4 font-bold text-4xl mt-8">
<span>
<img class="w-20 h-20" src="/logo.svg" alt="Logo: a cloud whispering" />
</span>
<span> Whishper </span>
</h1>
<h2 class="text-md text-center opacity-70 font-mono">{data.randomSentence}</h2>
</header>
<main class="card w-4/6 bg-neutral text-neutral-content mx-auto mt-4 mb-8">
<button
class="btn btn-primary mx-auto max-w-md mt-8 btn-md"
onclick="modalNewTranscription.showModal()">✨ new transcription</button
>
<div class="card-body items-center text-center mb-0">
{#if $transcriptions.length > 0}
{#each $transcriptions as tr (tr.id)}
{#if tr.status == 2}
<SuccessTranscription {tr} on:download={handleDownload} on:translate={handleTranslate} />
{/if}
{#if tr.status < 2 && tr.status >= 0}
<PendingTranscription {tr} />
{/if}
{#if tr.status == 3}
<PendingTranslation {tr} />
{/if}
{#if tr.status < 0}
<ErrorTranscription {tr} />
{/if}
{/each}
{:else}
<p class="text-center font-bold text-2xl">🔮 No transcriptions yet 🔮</p>
{/if}
</div>
</main>

View File

@@ -0,0 +1,17 @@
/** @type {import('./$types').PageLoad} */
import { currentTranscription } from '$lib/stores';
import { PUBLIC_INTERNAL_API_HOST } from '$env/static/public';
import { CLIENT_API_HOST } from '$lib/utils';
import { browser } from '$app/environment';
export async function load({params}) {
// Fetch json from /api/transcriptions/{id}
let id = params.id;
// Use different endpoints for server-side and client-side
const endpoint = browser ? `${CLIENT_API_HOST}/api/transcriptions` : `${PUBLIC_INTERNAL_API_HOST}/api/transcriptions`;
const response = await fetch(`${endpoint}/${id}`);
const ts = await response.json();
// Set currentTranscription to the fetched transcription
currentTranscription.set(ts);
};

View File

@@ -0,0 +1,45 @@
<script>
/** @type {import('./$types').PageData} */
import toast, { Toaster } from 'svelte-french-toast';
import Editor from '$lib/components/Editor.svelte';
import {currentVideoPlayerTime, currentTranscription} from '$lib/stores';
import { CLIENT_API_HOST } from '$lib/utils';
let video;
let tolerance = 0.1; // Tolerance level in seconds
let canPlay = false;
$: if(canPlay && video && Math.abs(video.currentTime - $currentVideoPlayerTime) > tolerance) {
console.log(video.currentTime, $currentVideoPlayerTime)
video.currentTime = $currentVideoPlayerTime;
}
</script>
<Toaster />
{#if $currentTranscription}
<div class="grid grid-cols-3 h-screen overflow-hidden">
<div class="col-span-1 bg-transparent overflow-hidden">
<div class="h-full w-full relative">
<video id="video"
controls
bind:this={video}
on:timeupdate={(e) => $currentVideoPlayerTime.set(e.target.currentTime)}
on:canplay={() => canPlay = true}
on:loadedmetadata={() => canPlay = true}
class="absolute top-0 left-0 h-full w-full">
<source src="{CLIENT_API_HOST}/api/video/{$currentTranscription.fileName}" type="video/mp4" />
<track kind="captions" />
</video>
</div>
</div>
<div class="col-span-2 bg-content overflow-auto">
<Editor />
</div>
</div>
{:else}
<div class="flex items-center justify-center w-screen h-screen">
<h1>
<span class="loading loading-bars loading-lg" />
</h1>
</div>
{/if}