adds three-letter language picker

This commit is contained in:
Sara
2023-10-13 23:35:19 +02:00
parent 3555cc3a3c
commit 47fc52af11
8 changed files with 593 additions and 78 deletions

View File

@@ -0,0 +1,496 @@
import Script from "next/script";
// type Script = 'Latn' | 'Ethi' | 'Arab' | 'Beng' | 'Cyrl' | 'Taml' | 'Hant' | 'Hans' | 'Grek' | 'Gujr' | 'Hebr'| 'Deva'| 'Armn' | 'Jpan' | 'Knda' | 'Geor';
type LanguageOption = {
value: string | undefined;
name: string;
script?: string;
};
const supportedLanguages: LanguageOption[] = [
{ value: "afr", name: "Afrikaans", script: "Latn" },
{
value: "amh",
name: "Amharic",
script: "Ethi",
},
{
value: "arb",
name: "Modern Standard Arabic",
script: "Arab",
},
{
value: "ary",
name: "Moroccan Arabic",
script: "Arab",
},
{
value: "arz",
name: "Egyptian Arabic",
script: "Arab",
},
{
value: "asm",
name: "Assamese",
script: "Beng",
},
{
value: "azj",
name: "North Azerbaijani",
script: "Latn",
},
{
value: "bel",
name: "Belarusian",
script: "Cyrl",
},
{
value: "ben",
name: "Bengali",
script: "Beng",
},
{
value: "bos",
name: "Bosnian",
script: "Latn",
},
{
value: "bul",
name: "Bulgarian",
script: "Cyrl",
},
{
value: "cat",
name: "Catalan",
script: "Latn",
},
{
value: "ceb",
name: "Cebuano",
script: "Latn",
},
{
value: "ces",
name: "Czech",
script: "Latn",
},
{
value: "ckb",
name: "Central Kurdish",
script: "Arab",
},
{
value: "cmn",
name: "Mandarin Chinese",
script: "Hans",
},
{
value: "cmn_Ha",
name: "Mandarin Chinese",
script: "Hant",
},
{
value: "cym",
name: "Welsh",
script: "Latn",
},
{
value: "dan",
name: "Danish",
script: "Latn",
},
{
value: "deu",
name: "German",
script: "Latn",
},
{
value: "ell",
name: "Greek",
script: "Grek",
},
{
value: "eng",
name: "English",
script: "Latn",
},
{
value: "est",
name: "Estonian",
script: "Latn",
},
{
value: "eus",
name: "Basque",
script: "Latn",
},
{
value: "fin",
name: "Finnish",
script: "Latn",
},
{
value: "fra",
name: "French",
script: "Latn",
},
{
value: "gaz",
name: "West Central Oromo",
script: "Latn",
},
{
value: "gle",
name: "Irish",
script: "Latn",
},
{
value: "glg",
name: "Galician",
script: "Latn",
},
{
value: "guj",
name: "Gujarati",
script: "Gujr",
},
{
value: "heb",
name: "Hebrew",
script: "Hebr",
},
{
value: "hin",
name: "Hindi",
script: "Deva",
},
{
value: "hrv",
name: "Croatian",
script: "Latn",
},
{
value: "hun",
name: "Hungarian",
script: "Latn",
},
{
value: "hye",
name: "Armenian",
script: "Armn",
},
{
value: "ibo",
name: "Igbo",
script: "Latn",
},
{
value: "ind",
name: "Indonesian",
script: "Latn",
},
{
value: "isl",
name: "Icelandic",
script: "Latn",
},
{
value: "ita",
name: "Italian",
script: "Latn",
},
{
value: "jav",
name: "Javanese",
script: "Latn",
},
{
value: "jpn",
name: "Japanese",
script: "Jpan",
},
{
value: "kan",
name: "Kannada",
script: "Knda",
},
{
value: "kat",
name: "Georgian",
script: "Geor",
},
{
value: "kaz",
name: "Kazakh",
script: "Cyrl",
},
{
value: "khk",
name: "Halh Mongolian",
script: "Cyrl",
},
{
value: "khm",
name: "Khmer",
script: "Khmr",
},
{
value: "kir",
name: "Kyrgyz",
script: "Cyrl",
},
{
value: "kor",
name: "Korean",
script: "Kore",
},
{
value: "lao",
name: "Lao",
script: "Laoo",
},
{
value: "lit",
name: "Lithuanian",
script: "Latn",
},
{
value: "lug",
name: "Ganda",
script: "Latn",
},
{
value: "luo",
name: "Luo",
script: "Latn",
},
{
value: "lvs",
name: "Standard Latvian",
script: "Latn",
},
{
value: "mai",
name: "Maithili",
script: "Deva",
},
{
value: "mal",
name: "Malayalam",
script: "Mlym",
},
{
value: "mar",
name: "Marathi",
script: "Deva",
},
{
value: "mkd",
name: "Macedonian",
script: "Cyrl",
},
{
value: "mlt",
name: "Maltese",
script: "Latn",
},
{
value: "mni",
name: "Meitei",
script: "Beng",
},
{
value: "mya",
name: "Burmese",
script: "Mymr",
},
{
value: "nld",
name: "Dutch",
script: "Latn",
},
{
value: "nno",
name: "Norwegian Nynorsk",
script: "Latn",
},
{
value: "nob",
name: "Norwegian Bokmål",
script: "Latn",
},
{
value: "npi",
name: "Nepali",
script: "Deva",
},
{
value: "nya",
name: "Nyanja",
script: "Latn",
},
{
value: "ory",
name: "Odia",
script: "Orya",
},
{
value: "pan",
name: "Punjabi",
script: "Guru",
},
{
value: "pbt",
name: "Southern Pashto",
script: "Arab",
},
{
value: "pes",
name: "Western Persian",
script: "Arab",
},
{
value: "pol",
name: "Polish",
script: "Latn",
},
{
value: "por",
name: "Portuguese",
script: "Latn",
},
{
value: "ron",
name: "Romanian",
script: "Latn",
},
{
value: "rus",
name: "Russian",
script: "Cyrl",
},
{
value: "slk",
name: "Slovak",
script: "Latn",
},
{
value: "slv",
name: "Slovenian",
script: "Latn",
},
{
value: "sna",
name: "Shona",
script: "Latn",
},
{
value: "snd",
name: "Sindhi",
script: "Arab",
},
{
value: "som",
name: "Somali",
script: "Latn",
},
{
value: "spa",
name: "Spanish",
script: "Latn",
},
{
value: "srp",
name: "Serbian",
script: "Cyrl",
},
{
value: "swe",
name: "Swedish",
script: "Latn",
},
{
value: "swh",
name: "Swahili",
script: "Latn",
},
{
value: "tam",
name: "Tamil",
script: "Taml",
},
{
value: "tel",
name: "Telugu",
script: "Telu",
},
{
value: "tgk",
name: "Tajik",
script: "Cyrl",
},
{
value: "tgl",
name: "Tagalog",
script: "Latn",
},
{
value: "tha",
name: "Thai",
script: "Thai",
},
{
value: "tur",
name: "Turkish",
script: "Latn",
},
{
value: "ukr",
name: "Ukrainian",
script: "Cyrl",
},
{
value: "urd",
name: "Urdu",
script: "Arab",
},
{
value: "uzn",
name: "Northern Uzbek",
script: "Latn",
},
{
value: "vie",
name: "Vietnamese",
script: "Latn",
},
{
value: "yor",
name: "Yoruba",
script: "Latn",
},
{
value: "yue",
name: "Cantonese",
script: "Hant",
},
{
value: "zsm",
name: "Standard Malay",
script: "Latn",
},
{
value: "zul",
name: "Zulu",
script: "Latn",
},
];
const supportedLatinLanguages = supportedLanguages.filter(
(lan) => lan.script == "Latn",
);
supportedLatinLanguages.push({ value: undefined, name: "None" });
export { supportedLatinLanguages };
export default supportedLanguages;

View File

@@ -41,14 +41,7 @@ const TranscriptRecord = (details: TranscriptDetails) => {
const webRTC = useWebRTC(stream, details.params.transcriptId, api);
const webSockets = useWebSockets(details.params.transcriptId);
const {
loading,
permissionOk,
permissionDenied,
audioDevices,
requestPermission,
getAudioStream,
} = useAudioDevice();
const { audioDevices, getAudioStream } = useAudioDevice();
const [hasRecorded, setHasRecorded] = useState(false);
const [transcriptStarted, setTranscriptStarted] = useState(false);
@@ -115,7 +108,10 @@ const TranscriptRecord = (details: TranscriptDetails) => {
you start recording.
</div>
) : (
<LiveTrancription text={webSockets.transcriptText} />
<LiveTrancription
text={webSockets.transcriptText}
translateText={webSockets.translateText}
/>
)}
</div>
</div>

View File

@@ -25,7 +25,7 @@ const useCreateTranscript = (): CreateTranscript => {
const requestParameters: V1TranscriptsCreateRequest = {
createTranscript: {
name: params.name || "Weekly All-Hands", // Default
targetLanguage: params.targetLanguage || "en", // Default
targetLanguage: params.targetLanguage || "eng", // Default
},
};

View File

@@ -1,14 +1,19 @@
type LiveTranscriptionProps = {
text: string;
translateText: string;
};
export default function LiveTrancription(props: LiveTranscriptionProps) {
return (
<div className="text-center p-4">
<p className="text-lg md:text-xl font-bold line-clamp-4">
{/* Nous allons prendre quelques appels téléphoniques et répondre à quelques questions */}
{props.text}
{props.translateText ? props.translateText : props.text}
</p>
{props.translateText && (
<p className="text-base md:textlg font-bold line-clamp-4">
{props.text}
</p>
)}
</div>
);
}

View File

@@ -1,20 +1,15 @@
"use client";
import React, { useEffect, useState } from "react";
import useWebRTC from "../useWebRTC";
import useTranscript from "../useTranscript";
import { useWebSockets } from "../useWebSockets";
import useAudioDevice from "../useAudioDevice";
import "../../styles/button.css";
import { Topic } from "../webSocketTypes";
import getApi from "../../lib/getApi";
import About from "../../(aboutAndPrivacy)/about";
import Privacy from "../../(aboutAndPrivacy)/privacy";
import { lockWakeState, releaseWakeState } from "../../lib/wakeLock";
import { useRouter } from "next/navigation";
import createTranscript from "../createTranscript";
import { GetTranscript } from "../../api";
import { Router } from "next/router";
import useCreateTranscript from "../createTranscript";
import SelectSearch from "react-select-search";
import { supportedLatinLanguages } from "../../supportedLanguages";
import "react-select-search/style.css";
const TranscriptCreate = () => {
// const transcript = useTranscript(stream, api);
@@ -27,6 +22,10 @@ const TranscriptCreate = () => {
};
const [targetLanguage, setTargetLanguage] = useState<string>();
const onLanguageChange = (newval) => {
typeof newval === "string" && setTargetLanguage(newval);
};
const createTranscript = useCreateTranscript();
const send = () => {
@@ -38,70 +37,75 @@ const TranscriptCreate = () => {
router.push(`/transcripts/${createTranscript.response.id}/record`);
}, [createTranscript.response]);
const {
loading,
permissionOk,
permissionDenied,
audioDevices,
requestPermission,
getAudioStream,
} = useAudioDevice();
const { loading, permissionOk, permissionDenied, requestPermission } =
useAudioDevice();
return (
<>
<div></div>
<div className="max-h-full overflow-auto">
<div className="grid grid-cols-1 lg:grid-cols-2 grid-rows-mobile-inner lg:grid-rows-1 gap-2 lg:gap-4 h-full">
<section className="flex flex-col w-full h-full items-center justify-evenly p-4 md:px-6 md:py-8">
<div>
<div className="flex flex-col max-w-xl items-center justify-center">
<h1 className="text-2xl font-bold mb-2">
Welcome to reflector.media
</h1>
<p>
Reflector is a transcription and summarization pipeline that
transforms audio into knowledge. The output is meeting minutes
and topic summaries enabling topic-specific analyses stored in
your systems of record. This is accomplished on your
infrastructure without 3rd parties keeping your data
private, secure, and organized.
</p>
<About buttonText="Learn more" />
<input type="text" onChange={nameChange} />
<button onClick={() => setTargetLanguage("fr")}>Language</button>
<h2 className="text-2xl font-bold mt-4 mb-2">
Audio Permissions
</h2>
{loading ? (
<p className="text-center">Checking permission...</p>
) : permissionOk ? (
<> Microphone permission granted </>
) : (
<>
<p className="text-center">
In order to use Reflector, we kindly request permission to
access your microphone during meetings and events.
<br />
<Privacy buttonText="Privacy policy" />
<br />
{permissionDenied
? "Permission to use your microphone was denied, please change the permission setting in your browser and refresh this page."
: "Please grant permission to continue."}
</p>
<button
className="mt-4 bg-blue-400 hover:bg-blue-500 focus-visible:bg-blue-500 text-white font-bold py-2 px-4 rounded m-auto"
onClick={requestPermission}
disabled={permissionDenied}
>
{permissionDenied ? "Access denied" : "Grant Permission"}
</button>
</>
)}
</div>
<button onClick={send} disabled={!permissionOk}>
{createTranscript.loading ? "loading" : "Send"}
</button>
<div className="flex flex-col max-w-xl items-center justify-center">
<h1 className="text-2xl font-bold mb-2">
Welcome to reflector.media
</h1>
<p>
Reflector is a transcription and summarization pipeline that
transforms audio into knowledge. The output is meeting minutes and
topic summaries enabling topic-specific analyses stored in your
systems of record. This is accomplished on your infrastructure
without 3rd parties keeping your data private, secure, and
organized.
</p>
<About buttonText="Learn more" />
</div>
</section>
<section className="rounded-xl md:bg-blue-200 flex flex-col justify-start p-6">
<h2 className="text-2xl font-bold mt-4 mb-2"> Try Reflector</h2>
<label className="mb-3">
<p>What is this meeting about ?</p>
<input type="text" onChange={nameChange} />
</label>
<label className="mb-3">
<p>Do you need live translation ?</p>
<SelectSearch
search
options={supportedLatinLanguages}
value={targetLanguage}
onChange={onLanguageChange}
placeholder="Choose your language"
/>
</label>
{loading ? (
<p className="">Checking permission...</p>
) : permissionOk ? (
<> Microphone permission granted </>
) : (
<>
<p className="">
In order to use Reflector, we kindly request permission to
access your microphone during meetings and events.
<br />
<Privacy buttonText="Privacy policy" />
<br />
{permissionDenied &&
"Permission to use your microphone was denied, please change the permission setting in your browser and refresh this page."}
</p>
<button
className="mt-4 bg-blue-400 hover:bg-blue-500 focus-visible:bg-blue-500 text-white font-bold py-2 px-4 rounded m-auto"
onClick={requestPermission}
disabled={permissionDenied}
>
{permissionDenied ? "Access denied" : "Grant Permission"}
</button>
</>
)}
<button onClick={send} disabled={!permissionOk}>
{createTranscript.loading ? "loading" : "Send"}
</button>
</section>
</div>
</>
);

View File

@@ -5,6 +5,7 @@ import { useRouter } from "next/navigation";
type UseWebSockets = {
transcriptText: string;
translateText: string;
topics: Topic[];
finalSummary: FinalSummary;
status: Status;
@@ -12,7 +13,9 @@ type UseWebSockets = {
export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
const [transcriptText, setTranscriptText] = useState<string>("");
const [translateText, setTranslateText] = useState<string>("");
const [textQueue, setTextQueue] = useState<string[]>([]);
const [translationQueue, setTranslationQueue] = useState<string[]>([]);
const [isProcessing, setIsProcessing] = useState(false);
const [topics, setTopics] = useState<Topic[]>([]);
const [finalSummary, setFinalSummary] = useState<FinalSummary>({
@@ -30,6 +33,8 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
setIsProcessing(true);
const text = textQueue[0];
setTranscriptText(text);
setTranslateText(translationQueue[0]);
console.log("displaying " + translateText);
const WPM_READING = 200 + textQueue.length * 10; // words per minute to read
const wordCount = text.split(/\s+/).length;
@@ -38,6 +43,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
setTimeout(() => {
setIsProcessing(false);
setTextQueue((prevQueue) => prevQueue.slice(1));
setTranslationQueue((prevQueue) => prevQueue.slice(1));
}, delay);
}, [textQueue, isProcessing]);
@@ -158,11 +164,13 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
switch (message.event) {
case "TRANSCRIPT":
const newText = (message.data.text ?? "").trim();
const newTranslation = (message.data.translation ?? "").trim();
if (!newText) break;
console.debug("TRANSCRIPT event:", newText);
setTextQueue((prevQueue) => [...prevQueue, newText]);
setTranslationQueue((prevQueue) => [...prevQueue, newTranslation]);
break;
case "TOPIC":
@@ -233,5 +241,5 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
};
}, [transcriptId]);
return { transcriptText, topics, finalSummary, status };
return { transcriptText, translateText, topics, finalSummary, status };
};