Files
reflector/www/app/(app)/transcripts/new/page.tsx
Sergey Mankovsky 0931095f49 fix: remaining dependabot security issues (#890)
* Upgrade docs deps

* Upgrade frontend to latest deps

* Update package overrides

* Remove redundant deps

* Add tailwind postcss plugin

* Replace language select with chakra

* Fix main nav

* Patch gray matter

* Fix webpack override

* Replace python-jose with pyjwt

* Override kv url for frontend in compose

* Upgrade hatchet sdk

* Update docs

* Supress pydantic warnings
2026-03-02 17:17:40 +01:00

221 lines
7.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import React, { useEffect, useState } from "react";
import useAudioDevice from "../useAudioDevice";
import "../../../styles/form.scss";
import About from "../../../(aboutAndPrivacy)/about";
import Privacy from "../../../(aboutAndPrivacy)/privacy";
import { useRouter } from "next/navigation";
import useCreateTranscript from "../createTranscript";
import { supportedLanguages } from "../../../supportedLanguages";
import {
Flex,
Box,
Spinner,
Heading,
Button,
Center,
Text,
Spacer,
} from "@chakra-ui/react";
import { useAuth } from "../../../lib/AuthProvider";
import { featureEnabled } from "../../../lib/features";
import { SearchableLanguageSelect } from "../../../components/SearchableLanguageSelect";
const TranscriptCreate = () => {
const router = useRouter();
const auth = useAuth();
const isAuthenticated = auth.status === "authenticated";
const isAuthRefreshing = auth.status === "refreshing";
const isLoading = auth.status === "loading";
const requireLogin = featureEnabled("requireLogin");
const [name, setName] = useState<string>("");
const nameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setName(event.target.value);
};
const [targetLanguage, setTargetLanguage] = useState<string>("NOTRANSLATION");
const onLanguageChange = (newval) => {
(!newval || typeof newval === "string") && setTargetLanguage(newval);
};
const createTranscript = useCreateTranscript();
const [loadingRecord, setLoadingRecord] = useState(false);
const [loadingUpload, setLoadingUpload] = useState(false);
const getTargetLanguage = () => {
if (targetLanguage === "NOTRANSLATION") return undefined;
return targetLanguage;
};
const send = () => {
if (loadingRecord || createTranscript.loading || permissionDenied) return;
setLoadingRecord(true);
const targetLang = getTargetLanguage();
createTranscript.create({
name,
source_language: "en",
target_language: targetLang || "en",
source_kind: "live",
});
};
const uploadFile = () => {
if (loadingUpload || createTranscript.loading || permissionDenied) return;
setLoadingUpload(true);
const targetLang = getTargetLanguage();
createTranscript.create({
name,
source_language: "en",
target_language: targetLang || "en",
source_kind: "file",
});
};
useEffect(() => {
let action = "record";
if (loadingUpload) action = "upload";
createTranscript.transcript &&
router.push(`/transcripts/${createTranscript.transcript.id}/${action}`);
}, [createTranscript.transcript]);
useEffect(() => {
if (createTranscript.error) setLoadingRecord(false);
}, [createTranscript.error]);
const { loading, permissionOk, permissionDenied, requestPermission } =
useAudioDevice();
return (
<Flex
maxW="container.xl"
flexDir="column"
margin="auto"
gap={2}
maxH="100%"
px={{ base: 5, md: 10 }}
py={5}
>
<Flex
flexDir={{ base: "column", md: "row" }}
justifyContent="space-between"
alignItems="center"
gap={8}
>
<Flex
flexDir="column"
h="full"
justifyContent="evenly"
flexBasis="1"
flexGrow={1}
>
<Heading size="2xl" textAlign={{ base: "center", md: "left" }}>
Welcome to Reflector
</Heading>
<Text mt={6}>
Reflector is a transcription and summarization pipeline that
transforms audio into knowledge.
<span className="hidden md:block">
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.
</span>
</Text>
<About buttonText="Learn more" />
<Text mt={6}>
In order to use Reflector, we kindly request permission to access
your microphone during meetings and events.
</Text>
{featureEnabled("privacy") && <Privacy buttonText="Privacy policy" />}
</Flex>
<Flex flexDir="column" h="full" flexBasis="1" flexGrow={1}>
<Center>
{isLoading ? (
<Spinner />
) : requireLogin && !isAuthenticated && !isAuthRefreshing ? (
<Button onClick={() => auth.signIn("authentik")}>Log in</Button>
) : (
<Flex
rounded="xl"
bg="blue.primary"
color="white"
maxW="96"
p={8}
flexDir="column"
my={4}
className="form-on-primary"
>
<Heading size="xl" mb={4}>
Try Reflector
</Heading>
<Box mb={4}>
<Text mb={1}>Recording name</Text>
<input
className="form-field-input"
type="text"
onChange={nameChange}
placeholder="Optional"
/>
</Box>
<Box mb={4}>
<Text mb={1}>Do you want to enable live translation?</Text>
<SearchableLanguageSelect
options={supportedLanguages}
value={targetLanguage}
onChange={onLanguageChange}
placeholder="No translation"
/>
</Box>
{!loading ? (
permissionOk ? (
<Spacer />
) : permissionDenied ? (
<Text className="">
Permission to use your microphone was denied, please
change the permission setting in your browser and refresh
this page.
</Text>
) : (
<Button
colorPalette="whiteAlpha"
onClick={requestPermission}
disabled={permissionDenied}
>
Request Microphone Permission
</Button>
)
) : (
<Text className="">Checking permissions...</Text>
)}
<Button
colorPalette="whiteAlpha"
onClick={send}
disabled={!permissionOk || loadingRecord || loadingUpload}
mt={2}
>
{loadingRecord ? "Loading..." : "Record Meeting"}
</Button>
<Text textAlign="center" m="2">
OR
</Text>
<Button
colorPalette="whiteAlpha"
onClick={uploadFile}
disabled={loadingRecord || loadingUpload}
>
{loadingUpload ? "Loading..." : "Upload File"}
</Button>
</Flex>
)}
</Center>
</Flex>
</Flex>
</Flex>
);
};
export default TranscriptCreate;