diff --git a/apps/desktop/src/components/editor-area/note-header/listen-button.tsx b/apps/desktop/src/components/editor-area/note-header/listen-button.tsx index 889e5d3ba3..805ace81e7 100644 --- a/apps/desktop/src/components/editor-area/note-header/listen-button.tsx +++ b/apps/desktop/src/components/editor-area/note-header/listen-button.tsx @@ -62,6 +62,19 @@ export default function ListenButton({ sessionId }: { sessionId: string }) { }, }); + const anySttModelExists = useQuery({ + queryKey: ["check-any-stt-model-downloaded"], + refetchInterval: 3000, + queryFn: async () => { + const supportedModels = await localSttCommands.listSupportedModels(); + const sttDownloadStatuses = await Promise.all( + supportedModels.map((model) => localSttCommands.isModelDownloaded(model)), + ); + return sttDownloadStatuses.some(Boolean); + }, + enabled: isOnboarding, + }); + const ongoingSessionStatus = useOngoingSession((s) => s.status); const ongoingSessionId = useOngoingSession((s) => s.sessionId); const ongoingSessionStore = useOngoingSession((s) => ({ @@ -88,6 +101,11 @@ export default function ListenButton({ sessionId }: { sessionId: string }) { const handleStartSession = () => { if (ongoingSessionStatus === "inactive") { ongoingSessionStore.start(sessionId); + + // Set mic muted after starting if it's onboarding + if (isOnboarding) { + listenerCommands.setMicMuted(true); + } } }; @@ -121,7 +139,9 @@ export default function ListenButton({ sessionId }: { sessionId: string }) { if (ongoingSessionStatus === "inactive") { const buttonProps = { - disabled: !modelDownloaded.data || (meetingEnded && isEnhancePending), + disabled: isOnboarding + ? !anySttModelExists.data || (meetingEnded && isEnhancePending) + : !modelDownloaded.data || (meetingEnded && isEnhancePending), onClick: handleStartSession, }; @@ -199,13 +219,16 @@ function WhenInactiveAndMeetingNotEndedOnboarding({ disabled, onClick }: { disab className={cn([ "w-24 h-9 rounded-full border-2 transition-all cursor-pointer outline-none p-0 flex items-center justify-center gap-1", "bg-neutral-800 border-neutral-700 text-white text-xs font-medium", + !disabled + ? "hover:scale-95" + : "opacity-50 cursor-progress", ])} style={{ boxShadow: "0 0 0 2px rgba(255, 255, 255, 0.8) inset", }} > - Play video + {disabled ? "Wait..." : "Play video"} ); } @@ -326,12 +349,6 @@ function RecordingControls({ } }, [configQuery.data]); - useEffect(() => { - if (sessionId === onboardingSessionId) { - listenerCommands.setMicMuted(true); - } - }, [ongoingSessionMuted.micMuted]); - const handleStopWithTemplate = () => { const actualTemplateId = selectedTemplate === "auto" ? null : selectedTemplate; onStop(actualTemplateId); diff --git a/apps/desktop/src/components/settings/components/ai/stt-view.tsx b/apps/desktop/src/components/settings/components/ai/stt-view.tsx index d165401a30..471e9794de 100644 --- a/apps/desktop/src/components/settings/components/ai/stt-view.tsx +++ b/apps/desktop/src/components/settings/components/ai/stt-view.tsx @@ -70,7 +70,7 @@ export const sttModelMetadata: Record void; + showSystemSettings?: boolean; +} + +function PermissionItem({ + icon, + title, + description, + done, + isPending, + onRequest, + showSystemSettings = false, +}: PermissionItemProps) { + return ( +
+
+
+
{icon}
+
+
+
{title}
+
+ {done + ? ( + + + Access Granted + + ) + : {description}} +
+
+
+
+ {!done && ( + <> + + + )} + {done && ( +
+ +
+ )} +
+
+ ); +} + +interface AudioPermissionsViewProps { + onContinue: () => void; +} + +export function AudioPermissionsView({ onContinue }: AudioPermissionsViewProps) { + const { t } = useLingui(); + + const micPermissionStatus = useQuery({ + queryKey: ["micPermission"], + queryFn: () => listenerCommands.checkMicrophoneAccess(), + refetchInterval: 3000, + }); + + const systemAudioPermissionStatus = useQuery({ + queryKey: ["systemAudioPermission"], + queryFn: () => listenerCommands.checkSystemAudioAccess(), + refetchInterval: 3000, + }); + + const micPermission = useMutation({ + mutationFn: () => listenerCommands.requestMicrophoneAccess(), + onSuccess: () => micPermissionStatus.refetch(), + onError: console.error, + }); + + const capturePermission = useMutation({ + mutationFn: () => listenerCommands.requestSystemAudioAccess(), + onSuccess: () => systemAudioPermissionStatus.refetch(), + onError: console.error, + }); + + const allPermissionsGranted = micPermissionStatus.data && systemAudioPermissionStatus.data; + + return ( +
+

+ Audio Permissions +

+ +

+ Grant access to audio so Hyprnote can transcribe your meetings +

+ +
+ } + title={t`Microphone Access`} + description={t`Required for meeting transcription`} + done={micPermissionStatus.data} + isPending={micPermission.isPending} + onRequest={() => micPermission.mutate({})} + /> + + } + title={t`System Audio Access`} + description={t`Required for meeting transcription`} + done={systemAudioPermissionStatus.data} + isPending={capturePermission.isPending} + onRequest={() => capturePermission.mutate({})} + /> +
+ + + Continue + + + {!allPermissionsGranted && ( +

+ Grant both permissions to continue +

+ )} +
+ ); +} diff --git a/apps/desktop/src/components/welcome-modal/calendar-permissions-view.tsx b/apps/desktop/src/components/welcome-modal/calendar-permissions-view.tsx new file mode 100644 index 0000000000..a9388fbe20 --- /dev/null +++ b/apps/desktop/src/components/welcome-modal/calendar-permissions-view.tsx @@ -0,0 +1,161 @@ +import { Trans } from "@lingui/react/macro"; +import { useQuery } from "@tanstack/react-query"; +import { type as getOsType } from "@tauri-apps/plugin-os"; +import { CalendarIcon, CheckCircle2Icon, UserIcon } from "lucide-react"; +import { useCallback } from "react"; + +import { commands as appleCalendarCommands } from "@hypr/plugin-apple-calendar"; +import { Button } from "@hypr/ui/components/ui/button"; +import PushableButton from "@hypr/ui/components/ui/pushable-button"; +import { cn } from "@hypr/ui/lib/utils"; + +interface PermissionItemProps { + icon: React.ReactNode; + title: string; + description: string; + done: boolean | undefined; + onRequest: () => void; +} + +function PermissionItem({ + icon, + title, + description, + done, + onRequest, +}: PermissionItemProps) { + return ( +
+
+
+
{icon}
+
+
+
{title}
+
+ {done + ? ( + + + Access Granted + + ) + : {description}} +
+
+
+
+ {!done && ( + + )} + {done && ( +
+ +
+ )} +
+
+ ); +} + +interface CalendarPermissionsViewProps { + onContinue: () => void; +} + +export function CalendarPermissionsView({ onContinue }: CalendarPermissionsViewProps) { + const calendarAccess = useQuery({ + queryKey: ["settings", "calendarAccess"], + queryFn: () => appleCalendarCommands.calendarAccessStatus(), + refetchInterval: 500, + }); + + const contactsAccess = useQuery({ + queryKey: ["settings", "contactsAccess"], + queryFn: () => appleCalendarCommands.contactsAccessStatus(), + refetchInterval: 500, + }); + + const handleRequestCalendarAccess = useCallback(() => { + if (getOsType() === "macos") { + appleCalendarCommands + .requestCalendarAccess() + .then(() => { + calendarAccess.refetch(); + }) + .catch((error) => { + console.error(error); + }); + } + }, [calendarAccess]); + + const handleRequestContactsAccess = useCallback(() => { + if (getOsType() === "macos") { + appleCalendarCommands + .requestContactsAccess() + .then(() => { + contactsAccess.refetch(); + }) + .catch((error) => { + console.error(error); + }); + } + }, [contactsAccess]); + + return ( +
+

+ Calendar & Contacts +

+ +

+ Connect your calendar and contacts for a better experience +

+ +
+ } + title="Calendar Access" + description="Track events & meetings" + done={calendarAccess.data} + onRequest={handleRequestCalendarAccess} + /> + + } + title="Contacts Access" + description="Import meeting participants" + done={contactsAccess.data} + onRequest={handleRequestContactsAccess} + /> +
+ + + Continue + + +

+ These permissions are optional but recommended +

+
+ ); +} diff --git a/apps/desktop/src/components/welcome-modal/download-progress-view.tsx b/apps/desktop/src/components/welcome-modal/download-progress-view.tsx new file mode 100644 index 0000000000..6859f05233 --- /dev/null +++ b/apps/desktop/src/components/welcome-modal/download-progress-view.tsx @@ -0,0 +1,256 @@ +import { Trans } from "@lingui/react/macro"; +import { Channel } from "@tauri-apps/api/core"; +import { BrainIcon, CheckCircle2Icon, MicIcon } from "lucide-react"; +import { useEffect, useState } from "react"; + +import { commands as localLlmCommands } from "@hypr/plugin-local-llm"; +import { commands as localSttCommands, SupportedModel } from "@hypr/plugin-local-stt"; +import { Progress } from "@hypr/ui/components/ui/progress"; +import PushableButton from "@hypr/ui/components/ui/pushable-button"; +import { cn } from "@hypr/ui/lib/utils"; +import { sttModelMetadata } from "../settings/components/ai/stt-view"; + +interface ModelDownloadProgress { + channel: Channel; + progress: number; + error: boolean; + completed: boolean; +} + +interface DownloadProgressViewProps { + selectedSttModel: SupportedModel; + onContinue: () => void; +} + +const ModelProgressCard = ({ + title, + icon: Icon, + download, + size, +}: { + title: string; + icon: React.ElementType; + download: ModelDownloadProgress; + size: string; +}) => { + return ( +
+
+
+ +
+
+
{title}
+
+ {download.error + ? Download failed + : download.completed + ? ( + + + Ready + + ) + : ( +
+ Size: {size} • {Math.round(download.progress)}% + +
+ )} +
+
+
+ {download.completed && ( +
+ +
+ )} +
+ ); +}; + +export const DownloadProgressView = ({ + selectedSttModel, + onContinue, +}: DownloadProgressViewProps) => { + const [sttDownload, setSttDownload] = useState({ + channel: new Channel(), + progress: 0, + error: false, + completed: false, + }); + + const [llmDownload, setLlmDownload] = useState({ + channel: new Channel(), + progress: 0, + error: false, + completed: false, + }); + + const [currentMessageIndex, setCurrentMessageIndex] = useState(0); + + useEffect(() => { + localSttCommands.downloadModel(selectedSttModel, sttDownload.channel); + + localLlmCommands.downloadModel("HyprLLM", llmDownload.channel); + + sttDownload.channel.onmessage = (progress) => { + if (progress < 0) { + setSttDownload(prev => ({ ...prev, error: true })); + return; + } + + setSttDownload(prev => ({ + ...prev, + progress: Math.max(prev.progress, progress), + completed: progress >= 100, + })); + }; + + llmDownload.channel.onmessage = (progress) => { + if (progress < 0) { + setLlmDownload(prev => ({ ...prev, error: true })); + return; + } + + setLlmDownload(prev => ({ + ...prev, + progress: Math.max(prev.progress, progress), + completed: progress >= 100, + })); + }; + }, [selectedSttModel, sttDownload.channel, llmDownload.channel]); + + const bothCompleted = sttDownload.completed && llmDownload.completed; + const hasErrors = sttDownload.error || llmDownload.error; + + useEffect(() => { + if (!bothCompleted && !hasErrors) { + const interval = setInterval(() => { + setCurrentMessageIndex((prev) => (prev + 1) % WAITING_MESSAGES.length); + }, 4000); + return () => clearInterval(interval); + } + }, [bothCompleted, hasErrors]); + + const WAITING_MESSAGES = [ + "Downloading models may take a few minutes...", + "You are free to continue your setup...", + "Teaching your AI not to snitch...", + "Running vibe_check.sh...", + "Munching granola for breakfast...", + "Securing your data from enemies...", + "Building your AI fortress...", + "Hunting down infected otters...", + "Wiping fingerprints off the algorithm...", + "Installing integrity.dmg (beta)...", + ]; + + useEffect(() => { + const handleSttCompletion = async () => { + if (sttDownload.completed) { + try { + await localSttCommands.setCurrentModel(selectedSttModel); + await localSttCommands.startServer(); + } catch (error) { + console.error("Error setting up STT:", error); + } + } + }; + + const handleLlmCompletion = async () => { + if (llmDownload.completed) { + try { + await localLlmCommands.setCurrentModel("HyprLLM"); + await localLlmCommands.startServer(); + } catch (error) { + console.error("Error setting up LLM:", error); + } + } + }; + + handleSttCompletion(); + handleLlmCompletion(); + }, [sttDownload.completed, llmDownload.completed, selectedSttModel]); + + const sttMetadata = sttModelMetadata[selectedSttModel]; + + return ( +
+

+ Downloading AI Models +

+ + {/* Replace static text with animated messages */} +
+

+ {!bothCompleted && !hasErrors && ( + + {WAITING_MESSAGES[currentMessageIndex]} + + )} + + {bothCompleted && ( + + All models ready! + + )} + + {hasErrors && ( + + Some downloads failed, but you can continue + + )} +

+
+ +
+ + + +
+ + + Continue + + +

+ It's ok to move on, downloads will continue in the background +

+
+ ); +}; diff --git a/apps/desktop/src/components/welcome-modal/index.tsx b/apps/desktop/src/components/welcome-modal/index.tsx index 0388da8d75..18a32fae15 100644 --- a/apps/desktop/src/components/welcome-modal/index.tsx +++ b/apps/desktop/src/components/welcome-modal/index.tsx @@ -1,8 +1,9 @@ -import { useMutation } from "@tanstack/react-query"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; import { useNavigate } from "@tanstack/react-router"; import { message } from "@tauri-apps/plugin-dialog"; import { useEffect, useState } from "react"; +import { showLlmModelDownloadToast, showSttModelDownloadToast } from "@/components/toast/shared"; import { commands } from "@/types"; import { commands as authCommands, events } from "@hypr/plugin-auth"; import { commands as localSttCommands, SupportedModel } from "@hypr/plugin-local-stt"; @@ -10,6 +11,12 @@ import { commands as sfxCommands } from "@hypr/plugin-sfx"; import { Modal, ModalBody } from "@hypr/ui/components/ui/modal"; import { Particles } from "@hypr/ui/components/ui/particles"; +import { commands as dbCommands } from "@hypr/plugin-db"; +import { commands as localLlmCommands } from "@hypr/plugin-local-llm"; +import { AudioPermissionsView } from "./audio-permissions-view"; +import { CalendarPermissionsView } from "./calendar-permissions-view"; +import { DownloadProgressView } from "./download-progress-view"; +import { LanguageSelectionView } from "./language-selection-view"; import { ModelSelectionView } from "./model-selection-view"; import { WelcomeView } from "./welcome-view"; @@ -20,8 +27,18 @@ interface WelcomeModalProps { export function WelcomeModal({ isOpen, onClose }: WelcomeModalProps) { const navigate = useNavigate(); + const queryClient = useQueryClient(); const [port, setPort] = useState(null); - const [showModelSelection, setShowModelSelection] = useState(false); + const [currentStep, setCurrentStep] = useState< + | "welcome" + | "model-selection" + | "download-progress" + | "audio-permissions" + | "language-selection" + | "calendar-permissions" + >("welcome"); + const [selectedSttModel, setSelectedSttModel] = useState("QuantizedSmall"); + const [wentThroughDownloads, setWentThroughDownloads] = useState(false); const selectSTTModel = useMutation({ mutationFn: (model: SupportedModel) => localSttCommands.setCurrentModel(model), @@ -73,17 +90,74 @@ export function WelcomeModal({ isOpen, onClose }: WelcomeModalProps) { }, [isOpen]); const handleStartLocal = () => { - setShowModelSelection(true); + setCurrentStep("model-selection"); }; const handleModelSelected = (model: SupportedModel) => { selectSTTModel.mutate(model); - + setSelectedSttModel(model); sessionStorage.setItem("model-download-toast-dismissed", "true"); + setCurrentStep("download-progress"); + }; + + const handleDownloadProgressContinue = () => { + setWentThroughDownloads(true); + setCurrentStep("audio-permissions"); + }; + + const handleAudioPermissionsContinue = () => { + setCurrentStep("language-selection"); + }; + + const handleLanguageSelectionContinue = async (languages: string[]) => { + // Save the selected languages to the database + try { + const config = await dbCommands.getConfig(); + await dbCommands.setConfig({ + ...config, + general: { + ...config.general, + spoken_languages: languages, + }, + }); + } catch (error) { + console.error("Failed to save language preferences:", error); + } + + setCurrentStep("calendar-permissions"); + }; + const handleCalendarPermissionsContinue = () => { onClose(); }; + useEffect(() => { + if (!isOpen && wentThroughDownloads) { + // start servers for mockup & tutorial + localSttCommands.startServer(); + localLlmCommands.startServer(); + + const checkAndShowToasts = async () => { + try { + const sttModelExists = await localSttCommands.isModelDownloaded(selectedSttModel as SupportedModel); + const llmModelExists = await localLlmCommands.isModelDownloaded("HyprLLM"); + + if (!sttModelExists) { + showSttModelDownloadToast(selectedSttModel, undefined, queryClient); + } + + if (!llmModelExists) { + showLlmModelDownloadToast("HyprLLM", undefined, queryClient); + } + } catch (error) { + console.error("Error checking model download status:", error); + } + }; + + checkAndShowToasts(); + } + }, [isOpen, wentThroughDownloads, selectedSttModel, queryClient]); + return (
- {!showModelSelection - ? ( - - ) - : ( - - )} + {currentStep === "welcome" && ( + + )} + {currentStep === "model-selection" && ( + + )} + {currentStep === "download-progress" && ( + + )} + {currentStep === "audio-permissions" && ( + + )} + {currentStep === "language-selection" && ( + + )} + {currentStep === "calendar-permissions" && ( + + )}
void; +} + +export function LanguageSelectionView({ onContinue }: LanguageSelectionViewProps) { + const [selectedLanguages, setSelectedLanguages] = useState(["en"]); + const [open, setOpen] = useState(false); + + const handleAddLanguage = (langCode: string) => { + if (!selectedLanguages.includes(langCode)) { + setSelectedLanguages([...selectedLanguages, langCode]); + } + setOpen(false); + }; + + const handleRemoveLanguage = (langCode: string) => { + // Don't allow removing English or if it would leave us with no languages + if (langCode === "en" || selectedLanguages.length <= 1) { + return; + } + setSelectedLanguages(selectedLanguages.filter(l => l !== langCode)); + }; + + const handleContinue = () => { + onContinue(selectedLanguages); + }; + + return ( +
+

+ Select Your Languages +

+ +

+ Choose the languages you speak for better transcription accuracy +

+ +
+
+
+
+
+ {selectedLanguages.map((langCode) => ( + + {LANGUAGES_ISO_639_1[langCode as ISO_639_1_CODE]?.name || langCode} + {selectedLanguages.length > 1 && langCode !== "en" && ( + + )} + + ))} +
+ {selectedLanguages.length === 0 && ( +

+ Select at least one language +

+ )} +
+ + + + + + + + + No language found. + + + {SUPPORTED_LANGUAGES.filter( + (lang) => !selectedLanguages.includes(lang), + ).map((lang) => { + const language = LANGUAGES_ISO_639_1[lang]; + return ( + handleAddLanguage(lang)} + className="flex items-center justify-between py-2" + > +
+
{language.name}
+
+ {language.nativeName} +
+
+
+ ); + })} +
+
+
+
+
+
+

+ Add languages you use during meetings to improve transcription accuracy +

+
+ + + Continue + +
+ ); +} diff --git a/apps/desktop/src/components/welcome-modal/model-selection-view.tsx b/apps/desktop/src/components/welcome-modal/model-selection-view.tsx index 785b925efc..8e60ced466 100644 --- a/apps/desktop/src/components/welcome-modal/model-selection-view.tsx +++ b/apps/desktop/src/components/welcome-modal/model-selection-view.tsx @@ -1,18 +1,10 @@ import { Trans } from "@lingui/react/macro"; -import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { useQuery } from "@tanstack/react-query"; import { BrainIcon, Zap as SpeedIcon } from "lucide-react"; import React, { useState } from "react"; import { Card, CardContent } from "@hypr/ui/components/ui/card"; -import { - Carousel, - CarouselContent, - CarouselItem, - CarouselNext, - CarouselPrevious, -} from "@hypr/ui/components/ui/carousel"; -import { showLlmModelDownloadToast, showSttModelDownloadToast } from "@/components/toast/shared"; import { SupportedModel } from "@hypr/plugin-local-stt"; import { commands as localSttCommands } from "@hypr/plugin-local-stt"; import PushableButton from "@hypr/ui/components/ui/pushable-button"; @@ -32,14 +24,16 @@ const RatingDisplay = ( icon: React.ElementType; }, ) => ( -
- {label} -
+
+ + {label} + +
{[...Array(maxRating)].map((_, i) => ( @@ -53,7 +47,6 @@ export const ModelSelectionView = ({ }: { onContinue: (model: SupportedModel) => void; }) => { - const queryClient = useQueryClient(); const [selectedModel, setSelectedModel] = useState("QuantizedSmall"); const supportedSTTModels = useQuery({ @@ -71,8 +64,6 @@ export const ModelSelectionView = ({ }); const handleContinue = () => { - showSttModelDownloadToast(selectedModel, undefined, queryClient); - showLlmModelDownloadToast(undefined, undefined, queryClient); onContinue(selectedModel); }; @@ -82,15 +73,14 @@ export const ModelSelectionView = ({ Select a transcribing model -
- - - {supportedSTTModels.data?.map(modelInfo => { +
+
+ {supportedSTTModels.data + ?.filter(modelInfo => { + const model = modelInfo.model; + return ["QuantizedTiny", "QuantizedSmall", "QuantizedLargeTurbo"].includes(model); + }) + ?.map(modelInfo => { const model = modelInfo.model; const metadata = sttModelMetadata[model as SupportedModel]; if (!metadata) { @@ -100,8 +90,8 @@ export const ModelSelectionView = ({ const isSelected = selectedModel === model; return ( - -
+
+
setSelectedModel(model as SupportedModel)} > - +
-
{metadata.name}
+
{metadata.name}
{metadata.description}
@@ -133,15 +123,10 @@ export const ModelSelectionView = ({
- +
); })} - -
- - -
- +
( -
- {label} -
+
+ + {label} + +
{[...Array(maxRating)].map((_, i) => ( diff --git a/apps/desktop/src/components/welcome-modal/welcome-view.tsx b/apps/desktop/src/components/welcome-modal/welcome-view.tsx index 9076745186..9301eb4542 100644 --- a/apps/desktop/src/components/welcome-modal/welcome-view.tsx +++ b/apps/desktop/src/components/welcome-modal/welcome-view.tsx @@ -25,7 +25,7 @@ export const WelcomeView: React.FC = ({ portReady, onGetStarte once className="mb-20 text-center text-2xl font-medium text-neutral-600" > - {t`The AI Meeting Notepad`} + {t`Where Conversations Stay Yours`} Create Note" msgid "Access granted" msgstr "Access granted" +#: src/components/welcome-modal/calendar-permissions-view.tsx:50 +#: src/components/welcome-modal/audio-permissions-view.tsx:53 #: src/components/settings/views/sound.tsx:39 msgid "Access Granted" msgstr "Access Granted" @@ -312,6 +315,14 @@ msgstr "Access Granted" msgid "Add a description..." msgstr "Add a description..." +#: src/components/welcome-modal/language-selection-view.tsx:171 +#~ msgid "Add languages you speak to improve transcription accuracy" +#~ msgstr "Add languages you speak to improve transcription accuracy" + +#: src/components/welcome-modal/language-selection-view.tsx:171 +msgid "Add languages you use during meetings to improve transcription accuracy" +msgstr "Add languages you use during meetings to improve transcription accuracy" + #: src/components/settings/views/team.tsx:94 msgid "Add members" msgstr "Add members" @@ -337,6 +348,10 @@ msgstr "AI" #~ msgid "AI notepad for meetings" #~ msgstr "AI notepad for meetings" +#: src/components/welcome-modal/download-progress-view.tsx:216 +msgid "All models ready!" +msgstr "All models ready!" + #: src/components/share-and-permission/participants-selector.tsx:31 msgid "All Participants" msgstr "All Participants" @@ -380,6 +395,10 @@ msgstr "Ask questions about past meetings" #~ msgid "Assistant:" #~ msgstr "Assistant:" +#: src/components/welcome-modal/audio-permissions-view.tsx:127 +msgid "Audio Permissions" +msgstr "Audio Permissions" + #: src/components/editor-area/note-header/listen-button.tsx:341 #~ msgid "Auto (Default)" #~ msgstr "Auto (Default)" @@ -413,6 +432,10 @@ msgstr "Built-in Templates" msgid "Calendar" msgstr "Calendar" +#: src/components/welcome-modal/calendar-permissions-view.tsx:124 +msgid "Calendar & Contacts" +msgstr "Calendar & Contacts" + #: src/components/settings/components/calendar/apple-calendar-integration-details.tsx:67 msgid "Calendar Access" msgstr "Calendar Access" @@ -453,6 +476,10 @@ msgstr "Chat with this meeting" #~ msgid "Choose the language you want to use for the speech-to-text model and language model" #~ msgstr "Choose the language you want to use for the speech-to-text model and language model" +#: src/components/welcome-modal/language-selection-view.tsx:93 +msgid "Choose the languages you speak for better transcription accuracy" +msgstr "Choose the languages you speak for better transcription accuracy" + #: src/components/settings/views/general.tsx:186 msgid "Choose whether to save your recordings locally." msgstr "Choose whether to save your recordings locally." @@ -499,6 +526,10 @@ msgstr "Connect with external tools and services to enhance your workflow" #~ msgid "Connect your {0} calendar to track upcoming events" #~ msgstr "Connect your {0} calendar to track upcoming events" +#: src/components/welcome-modal/calendar-permissions-view.tsx:128 +msgid "Connect your calendar and contacts for a better experience" +msgstr "Connect your calendar and contacts for a better experience" + #: src/components/settings/components/calendar/apple-calendar-integration-details.tsx:72 msgid "Connect your calendar and track events" msgstr "Connect your calendar and track events" @@ -515,10 +546,18 @@ msgstr "Connect your Obsidian vault to export notes" msgid "Contacts Access" msgstr "Contacts Access" -#: src/components/welcome-modal/model-selection-view.tsx:152 +#: src/components/welcome-modal/model-selection-view.tsx:137 +#: src/components/welcome-modal/language-selection-view.tsx:180 +#: src/components/welcome-modal/download-progress-view.tsx:248 +#: src/components/welcome-modal/calendar-permissions-view.tsx:153 +#: src/components/welcome-modal/audio-permissions-view.tsx:159 msgid "Continue" msgstr "Continue" +#: src/components/welcome-modal/download-progress-view.tsx:248 +#~ msgid "Continue Setup" +#~ msgstr "Continue Setup" + #: src/components/settings/views/ai.tsx:882 msgid "Control how autonomous the AI enhancement should be" msgstr "Control how autonomous the AI enhancement should be" @@ -603,6 +642,14 @@ msgstr "Display language" msgid "Download {0}" msgstr "Download {0}" +#: src/components/welcome-modal/download-progress-view.tsx:196 +msgid "Downloading AI Models" +msgstr "Downloading AI Models" + +#: src/components/welcome-modal/download-progress-view.tsx:252 +#~ msgid "Downloads will continue in the background" +#~ msgstr "Downloads will continue in the background" + #: src/components/settings/views/template.tsx:203 msgid "Duplicate" msgstr "Duplicate" @@ -623,6 +670,8 @@ msgstr "Email separated by commas" msgid "Emoji" msgstr "Emoji" +#: src/components/welcome-modal/calendar-permissions-view.tsx:65 +#: src/components/welcome-modal/audio-permissions-view.tsx:77 #: src/components/settings/views/sound.tsx:59 msgid "Enable" msgstr "Enable" @@ -725,6 +774,14 @@ msgstr "Get Started" msgid "Grant Access" msgstr "Grant Access" +#: src/components/welcome-modal/audio-permissions-view.tsx:131 +msgid "Grant access to audio so Hyprnote can transcribe your meetings" +msgstr "Grant access to audio so Hyprnote can transcribe your meetings" + +#: src/components/welcome-modal/audio-permissions-view.tsx:164 +msgid "Grant both permissions to continue" +msgstr "Grant both permissions to continue" + #: src/components/settings/views/general.tsx:212 msgid "Help us improve Hyprnote by sharing anonymous usage data" msgstr "Help us improve Hyprnote by sharing anonymous usage data" @@ -773,6 +830,10 @@ msgstr "Invite" msgid "Invite members" msgstr "Invite members" +#: src/components/welcome-modal/download-progress-view.tsx:252 +msgid "It's ok to move on, downloads will continue in the background" +msgstr "It's ok to move on, downloads will continue in the background" + #: src/components/settings/views/general.tsx:263 #~ msgid "Jargons" #~ msgstr "Jargons" @@ -850,6 +911,7 @@ msgstr "Member" msgid "Members" msgstr "Members" +#: src/components/welcome-modal/audio-permissions-view.tsx:137 #: src/components/settings/views/sound.tsx:97 msgid "Microphone Access" msgstr "Microphone Access" @@ -891,6 +953,10 @@ msgstr "New window" msgid "No calendars found" msgstr "No calendars found" +#: src/components/welcome-modal/language-selection-view.tsx:142 +msgid "No language found." +msgstr "No language found." + #: src/components/settings/views/team.tsx:175 msgid "No members found" msgstr "No members found" @@ -919,7 +985,7 @@ msgstr "No speech-to-text models available or failed to load." #~ msgid "No Template" #~ msgstr "No Template" -#: src/components/editor-area/note-header/listen-button.tsx:361 +#: src/components/editor-area/note-header/listen-button.tsx:378 msgid "No Template (Default)" msgstr "No Template (Default)" @@ -987,7 +1053,7 @@ msgstr "Optional for participant suggestions" msgid "Owner" msgstr "Owner" -#: src/components/editor-area/note-header/listen-button.tsx:384 +#: src/components/editor-area/note-header/listen-button.tsx:401 msgid "Pause" msgstr "Pause" @@ -1000,8 +1066,8 @@ msgid "Performance difference between languages" msgstr "Performance difference between languages" #: src/components/editor-area/note-header/listen-button.tsx:208 -msgid "Play video" -msgstr "Play video" +#~ msgid "Play video" +#~ msgstr "Play video" #: src/components/settings/views/general.tsx:239 msgid "Primary language for the interface" @@ -1019,6 +1085,10 @@ msgstr "Pro" msgid "Publish your note" msgstr "Publish your note" +#: src/components/welcome-modal/download-progress-view.tsx:66 +msgid "Ready" +msgstr "Ready" + #: src/components/organization-profile/recent-notes.tsx:42 msgid "Recent Notes" msgstr "Recent Notes" @@ -1035,10 +1105,16 @@ msgstr "Recent Notes" #~ msgid "Remove {0} from list" #~ msgstr "Remove {0} from list" +#: src/components/welcome-modal/audio-permissions-view.tsx:74 #: src/components/settings/views/sound.tsx:56 msgid "Requesting..." msgstr "Requesting..." +#: src/components/welcome-modal/audio-permissions-view.tsx:138 +#: src/components/welcome-modal/audio-permissions-view.tsx:147 +msgid "Required for meeting transcription" +msgstr "Required for meeting transcription" + #: src/components/settings/views/sound.tsx:107 msgid "Required to transcribe other people's voice during meetings" msgstr "Required to transcribe other people's voice during meetings" @@ -1047,7 +1123,7 @@ msgstr "Required to transcribe other people's voice during meetings" msgid "Required to transcribe your voice during meetings" msgstr "Required to transcribe your voice during meetings" -#: src/components/editor-area/note-header/listen-button.tsx:117 +#: src/components/editor-area/note-header/listen-button.tsx:135 msgid "Resume" msgstr "Resume" @@ -1097,10 +1173,14 @@ msgstr "Select a model from the dropdown (if available) or manually enter the mo msgid "Select a template to enhance your meeting notes" msgstr "Select a template to enhance your meeting notes" -#: src/components/welcome-modal/model-selection-view.tsx:82 +#: src/components/welcome-modal/model-selection-view.tsx:73 msgid "Select a transcribing model" msgstr "Select a transcribing model" +#: src/components/welcome-modal/language-selection-view.tsx:124 +msgid "Select at least one language" +msgstr "Select at least one language" + #: src/components/settings/components/calendar/calendar-selector.tsx:69 msgid "Select Calendars" msgstr "Select Calendars" @@ -1113,6 +1193,10 @@ msgstr "Select languages you speak for better transcription" #~ msgid "Select or enter the model name required by your endpoint." #~ msgstr "Select or enter the model name required by your endpoint." +#: src/components/welcome-modal/language-selection-view.tsx:89 +msgid "Select Your Languages" +msgstr "Select Your Languages" + #: src/components/settings/views/team.tsx:240 msgid "Send invite" msgstr "Send invite" @@ -1137,6 +1221,10 @@ msgstr "Show notifications when you join a meeting." msgid "Single sign-on for all users" msgstr "Single sign-on for all users" +#: src/components/welcome-modal/download-progress-view.tsx:222 +msgid "Some downloads failed, but you can continue" +msgstr "Some downloads failed, but you can continue" + #: src/routes/app.settings.tsx:116 #~ msgid "Sound" #~ msgstr "Sound" @@ -1153,11 +1241,11 @@ msgstr "Start Annual Plan" msgid "Start Monthly Plan" msgstr "Start Monthly Plan" -#: src/components/editor-area/note-header/listen-button.tsx:164 +#: src/components/editor-area/note-header/listen-button.tsx:184 msgid "Start recording" msgstr "Start recording" -#: src/components/editor-area/note-header/listen-button.tsx:392 +#: src/components/editor-area/note-header/listen-button.tsx:409 msgid "Stop" msgstr "Stop" @@ -1173,6 +1261,7 @@ msgstr "Summarize meeting" msgid "Synchronization across multiple devices" msgstr "Synchronization across multiple devices" +#: src/components/welcome-modal/audio-permissions-view.tsx:146 #: src/components/settings/views/sound.tsx:106 msgid "System Audio Access" msgstr "System Audio Access" @@ -1198,8 +1287,8 @@ msgid "Templates" msgstr "Templates" #: src/components/welcome-modal/welcome-view.tsx:28 -msgid "The AI Meeting Notepad" -msgstr "The AI Meeting Notepad" +#~ msgid "The AI Meeting Notepad" +#~ msgstr "The AI Meeting Notepad" #: src/components/settings/views/integrations.tsx:182 msgid "The base URL of your Obsidian server. This is typically http://127.0.0.1:27123." @@ -1213,6 +1302,10 @@ msgstr "The name of your Obsidian vault." msgid "There's a plan for everyone" msgstr "There's a plan for everyone" +#: src/components/welcome-modal/calendar-permissions-view.tsx:157 +msgid "These permissions are optional but recommended" +msgstr "These permissions are optional but recommended" + #: src/components/settings/views/profile.tsx:188 msgid "This is a short description of your company." msgstr "This is a short description of your company." @@ -1334,6 +1427,10 @@ msgstr "What's your organization size?" msgid "What's your role?" msgstr "What's your role?" +#: src/components/welcome-modal/welcome-view.tsx:28 +msgid "Where Conversations Stay Yours" +msgstr "Where Conversations Stay Yours" + #: src/components/settings/components/wer-modal.tsx:69 msgid "Whisper Model Language Performance (WER)" msgstr "Whisper Model Language Performance (WER)" diff --git a/apps/desktop/src/locales/ko/messages.po b/apps/desktop/src/locales/ko/messages.po index a5dba2ba93..8f38c0a034 100644 --- a/apps/desktop/src/locales/ko/messages.po +++ b/apps/desktop/src/locales/ko/messages.po @@ -261,8 +261,9 @@ msgstr "" #. placeholder {0}: disabled ? "Wait..." : isHovered ? "Resume" : "Ended" #: src/components/settings/views/templates.tsx:194 #: src/components/settings/components/wer-modal.tsx:116 -#: src/components/editor-area/note-header/listen-button.tsx:189 -#: src/components/editor-area/note-header/listen-button.tsx:228 +#: src/components/editor-area/note-header/listen-button.tsx:209 +#: src/components/editor-area/note-header/listen-button.tsx:231 +#: src/components/editor-area/note-header/listen-button.tsx:251 msgid "{0}" msgstr "" @@ -304,6 +305,8 @@ msgstr "" msgid "Access granted" msgstr "" +#: src/components/welcome-modal/calendar-permissions-view.tsx:50 +#: src/components/welcome-modal/audio-permissions-view.tsx:53 #: src/components/settings/views/sound.tsx:39 msgid "Access Granted" msgstr "" @@ -312,6 +315,14 @@ msgstr "" msgid "Add a description..." msgstr "" +#: src/components/welcome-modal/language-selection-view.tsx:171 +#~ msgid "Add languages you speak to improve transcription accuracy" +#~ msgstr "" + +#: src/components/welcome-modal/language-selection-view.tsx:171 +msgid "Add languages you use during meetings to improve transcription accuracy" +msgstr "" + #: src/components/settings/views/team.tsx:94 msgid "Add members" msgstr "" @@ -337,6 +348,10 @@ msgstr "" #~ msgid "AI notepad for meetings" #~ msgstr "" +#: src/components/welcome-modal/download-progress-view.tsx:216 +msgid "All models ready!" +msgstr "" + #: src/components/share-and-permission/participants-selector.tsx:31 msgid "All Participants" msgstr "" @@ -380,6 +395,10 @@ msgstr "" #~ msgid "Assistant:" #~ msgstr "" +#: src/components/welcome-modal/audio-permissions-view.tsx:127 +msgid "Audio Permissions" +msgstr "" + #: src/components/editor-area/note-header/listen-button.tsx:341 #~ msgid "Auto (Default)" #~ msgstr "" @@ -413,6 +432,10 @@ msgstr "" msgid "Calendar" msgstr "" +#: src/components/welcome-modal/calendar-permissions-view.tsx:124 +msgid "Calendar & Contacts" +msgstr "" + #: src/components/settings/components/calendar/apple-calendar-integration-details.tsx:67 msgid "Calendar Access" msgstr "" @@ -453,6 +476,10 @@ msgstr "" #~ msgid "Choose the language you want to use for the speech-to-text model and language model" #~ msgstr "" +#: src/components/welcome-modal/language-selection-view.tsx:93 +msgid "Choose the languages you speak for better transcription accuracy" +msgstr "" + #: src/components/settings/views/general.tsx:186 msgid "Choose whether to save your recordings locally." msgstr "" @@ -499,6 +526,10 @@ msgstr "" #~ msgid "Connect your {0} calendar to track upcoming events" #~ msgstr "" +#: src/components/welcome-modal/calendar-permissions-view.tsx:128 +msgid "Connect your calendar and contacts for a better experience" +msgstr "" + #: src/components/settings/components/calendar/apple-calendar-integration-details.tsx:72 msgid "Connect your calendar and track events" msgstr "" @@ -515,10 +546,18 @@ msgstr "" msgid "Contacts Access" msgstr "" -#: src/components/welcome-modal/model-selection-view.tsx:152 +#: src/components/welcome-modal/model-selection-view.tsx:137 +#: src/components/welcome-modal/language-selection-view.tsx:180 +#: src/components/welcome-modal/download-progress-view.tsx:248 +#: src/components/welcome-modal/calendar-permissions-view.tsx:153 +#: src/components/welcome-modal/audio-permissions-view.tsx:159 msgid "Continue" msgstr "" +#: src/components/welcome-modal/download-progress-view.tsx:248 +#~ msgid "Continue Setup" +#~ msgstr "" + #: src/components/settings/views/ai.tsx:882 msgid "Control how autonomous the AI enhancement should be" msgstr "" @@ -603,6 +642,14 @@ msgstr "" msgid "Download {0}" msgstr "" +#: src/components/welcome-modal/download-progress-view.tsx:196 +msgid "Downloading AI Models" +msgstr "" + +#: src/components/welcome-modal/download-progress-view.tsx:252 +#~ msgid "Downloads will continue in the background" +#~ msgstr "" + #: src/components/settings/views/template.tsx:203 msgid "Duplicate" msgstr "" @@ -623,6 +670,8 @@ msgstr "" msgid "Emoji" msgstr "" +#: src/components/welcome-modal/calendar-permissions-view.tsx:65 +#: src/components/welcome-modal/audio-permissions-view.tsx:77 #: src/components/settings/views/sound.tsx:59 msgid "Enable" msgstr "" @@ -725,6 +774,14 @@ msgstr "" msgid "Grant Access" msgstr "" +#: src/components/welcome-modal/audio-permissions-view.tsx:131 +msgid "Grant access to audio so Hyprnote can transcribe your meetings" +msgstr "" + +#: src/components/welcome-modal/audio-permissions-view.tsx:164 +msgid "Grant both permissions to continue" +msgstr "" + #: src/components/settings/views/general.tsx:212 msgid "Help us improve Hyprnote by sharing anonymous usage data" msgstr "" @@ -773,6 +830,10 @@ msgstr "" msgid "Invite members" msgstr "" +#: src/components/welcome-modal/download-progress-view.tsx:252 +msgid "It's ok to move on, downloads will continue in the background" +msgstr "" + #: src/components/settings/views/general.tsx:263 #~ msgid "Jargons" #~ msgstr "" @@ -850,6 +911,7 @@ msgstr "" msgid "Members" msgstr "" +#: src/components/welcome-modal/audio-permissions-view.tsx:137 #: src/components/settings/views/sound.tsx:97 msgid "Microphone Access" msgstr "" @@ -891,6 +953,10 @@ msgstr "" msgid "No calendars found" msgstr "" +#: src/components/welcome-modal/language-selection-view.tsx:142 +msgid "No language found." +msgstr "" + #: src/components/settings/views/team.tsx:175 msgid "No members found" msgstr "" @@ -919,7 +985,7 @@ msgstr "" #~ msgid "No Template" #~ msgstr "" -#: src/components/editor-area/note-header/listen-button.tsx:361 +#: src/components/editor-area/note-header/listen-button.tsx:378 msgid "No Template (Default)" msgstr "" @@ -987,7 +1053,7 @@ msgstr "" msgid "Owner" msgstr "" -#: src/components/editor-area/note-header/listen-button.tsx:384 +#: src/components/editor-area/note-header/listen-button.tsx:401 msgid "Pause" msgstr "" @@ -1000,8 +1066,8 @@ msgid "Performance difference between languages" msgstr "" #: src/components/editor-area/note-header/listen-button.tsx:208 -msgid "Play video" -msgstr "" +#~ msgid "Play video" +#~ msgstr "" #: src/components/settings/views/general.tsx:239 msgid "Primary language for the interface" @@ -1019,6 +1085,10 @@ msgstr "" msgid "Publish your note" msgstr "" +#: src/components/welcome-modal/download-progress-view.tsx:66 +msgid "Ready" +msgstr "" + #: src/components/organization-profile/recent-notes.tsx:42 msgid "Recent Notes" msgstr "" @@ -1035,10 +1105,16 @@ msgstr "" #~ msgid "Remove {0} from list" #~ msgstr "" +#: src/components/welcome-modal/audio-permissions-view.tsx:74 #: src/components/settings/views/sound.tsx:56 msgid "Requesting..." msgstr "" +#: src/components/welcome-modal/audio-permissions-view.tsx:138 +#: src/components/welcome-modal/audio-permissions-view.tsx:147 +msgid "Required for meeting transcription" +msgstr "" + #: src/components/settings/views/sound.tsx:107 msgid "Required to transcribe other people's voice during meetings" msgstr "" @@ -1047,7 +1123,7 @@ msgstr "" msgid "Required to transcribe your voice during meetings" msgstr "" -#: src/components/editor-area/note-header/listen-button.tsx:117 +#: src/components/editor-area/note-header/listen-button.tsx:135 msgid "Resume" msgstr "" @@ -1097,10 +1173,14 @@ msgstr "" msgid "Select a template to enhance your meeting notes" msgstr "" -#: src/components/welcome-modal/model-selection-view.tsx:82 +#: src/components/welcome-modal/model-selection-view.tsx:73 msgid "Select a transcribing model" msgstr "" +#: src/components/welcome-modal/language-selection-view.tsx:124 +msgid "Select at least one language" +msgstr "" + #: src/components/settings/components/calendar/calendar-selector.tsx:69 msgid "Select Calendars" msgstr "" @@ -1113,6 +1193,10 @@ msgstr "" #~ msgid "Select or enter the model name required by your endpoint." #~ msgstr "" +#: src/components/welcome-modal/language-selection-view.tsx:89 +msgid "Select Your Languages" +msgstr "" + #: src/components/settings/views/team.tsx:240 msgid "Send invite" msgstr "" @@ -1137,6 +1221,10 @@ msgstr "" msgid "Single sign-on for all users" msgstr "" +#: src/components/welcome-modal/download-progress-view.tsx:222 +msgid "Some downloads failed, but you can continue" +msgstr "" + #: src/routes/app.settings.tsx:116 #~ msgid "Sound" #~ msgstr "" @@ -1153,11 +1241,11 @@ msgstr "" msgid "Start Monthly Plan" msgstr "" -#: src/components/editor-area/note-header/listen-button.tsx:164 +#: src/components/editor-area/note-header/listen-button.tsx:184 msgid "Start recording" msgstr "" -#: src/components/editor-area/note-header/listen-button.tsx:392 +#: src/components/editor-area/note-header/listen-button.tsx:409 msgid "Stop" msgstr "" @@ -1173,6 +1261,7 @@ msgstr "" msgid "Synchronization across multiple devices" msgstr "" +#: src/components/welcome-modal/audio-permissions-view.tsx:146 #: src/components/settings/views/sound.tsx:106 msgid "System Audio Access" msgstr "" @@ -1198,8 +1287,8 @@ msgid "Templates" msgstr "" #: src/components/welcome-modal/welcome-view.tsx:28 -msgid "The AI Meeting Notepad" -msgstr "" +#~ msgid "The AI Meeting Notepad" +#~ msgstr "" #: src/components/settings/views/integrations.tsx:182 msgid "The base URL of your Obsidian server. This is typically http://127.0.0.1:27123." @@ -1213,6 +1302,10 @@ msgstr "" msgid "There's a plan for everyone" msgstr "" +#: src/components/welcome-modal/calendar-permissions-view.tsx:157 +msgid "These permissions are optional but recommended" +msgstr "" + #: src/components/settings/views/profile.tsx:188 msgid "This is a short description of your company." msgstr "" @@ -1334,6 +1427,10 @@ msgstr "" msgid "What's your role?" msgstr "" +#: src/components/welcome-modal/welcome-view.tsx:28 +msgid "Where Conversations Stay Yours" +msgstr "" + #: src/components/settings/components/wer-modal.tsx:69 msgid "Whisper Model Language Performance (WER)" msgstr "" diff --git a/apps/desktop/src/routes/app.tsx b/apps/desktop/src/routes/app.tsx index 4efad68f4e..28d3864a72 100644 --- a/apps/desktop/src/routes/app.tsx +++ b/apps/desktop/src/routes/app.tsx @@ -18,6 +18,7 @@ import { RightPanelProvider, SearchProvider, SettingsProvider, + useHypr, useLeftSidebar, useRightPanel, } from "@/contexts"; @@ -38,6 +39,7 @@ export const Route = createFileRoute("/app")({ function Component() { const router = useRouter(); + const { onboardingSessionId } = useHypr(); const { sessionsStore, ongoingSessionStore, isOnboardingNeeded, isIndividualizationNeeded } = Route.useLoaderData(); const [onboardingCompletedThisSession, setOnboardingCompletedThisSession] = useState(false); @@ -87,6 +89,12 @@ function Component() { onClose={() => { commands.setOnboardingNeeded(false); setOnboardingCompletedThisSession(true); + + // Navigate to thank you session if it exists + if (onboardingSessionId) { + router.navigate({ to: `/app/note/${onboardingSessionId}` }); + } + router.invalidate(); }} /> diff --git a/apps/desktop/src/styles/globals.css b/apps/desktop/src/styles/globals.css index f070d58c7b..e2d66dfd13 100644 --- a/apps/desktop/src/styles/globals.css +++ b/apps/desktop/src/styles/globals.css @@ -113,3 +113,23 @@ body { @apply select-text; } } + +/* Animations */ +@keyframes fadeInOut { + 0% { + opacity: 0; + transform: translateY(10px); + } + 20% { + opacity: 1; + transform: translateY(0); + } + 80% { + opacity: 1; + transform: translateY(0); + } + 100% { + opacity: 0; + transform: translateY(-10px); + } +} diff --git a/crates/db-user/assets/onboarding-raw.html b/crates/db-user/assets/onboarding-raw.html index fb3d8e2fdc..c67fa436ff 100644 --- a/crates/db-user/assets/onboarding-raw.html +++ b/crates/db-user/assets/onboarding-raw.html @@ -1,20 +1,26 @@ -
This is an example of your notes
You'll typically be jotting down really brief notes here
+
⚠️ Wait until the video is ready to play!
+
+
    +
  • This tutorial only requires STT. No LLM needed.
  • +
  • However, to use Hyprnote effectively for your meetings, you'll need both STT and LLM. Please wait for the download to finish.
  • +
+

+

new meeting -> new note and record

enhanced note = my note + transcript + magic

local = privacy + offline

-

extensions => realtime transcript, CRM integrations

-

CUSTOMIZATION!

+

chat, templates

Links

\ No newline at end of file diff --git a/crates/db-user/assets/thank-you.md b/crates/db-user/assets/thank-you.md index c82e3eef76..f1d1f2541f 100644 --- a/crates/db-user/assets/thank-you.md +++ b/crates/db-user/assets/thank-you.md @@ -1,7 +1,10 @@ -We appreciate your patience while you wait for your STT&LLM models to be downloaded. +We appreciate your patience while you wait for your **STT&LLM models** to be downloaded. +
-**In the meantime...** why don't you check out [our blog](https://hyprnote.com/blog) or [changelog](https://hyprnote.canny.io/changelog) for a better understanding of the service. We also have @[Onboarding Video](note:df1d8c52-6d9d-4471-aff1-5dbd35899cbe) for you to get started. +You will be able to try out Meeting Transcription after STT download is complete (the recording button will **turn RED** when it's ready!), and Meeting Summarization after LLM download is complete. +
+**In the meantime...** why don't you check out [docs](https://docs.hyprnote.com/using-hyprnote/getting-started) or [blog](https://hyprnote.com/blog) for a better understanding of the service. We also have @[Onboarding Video](note:df1d8c52-6d9d-4471-aff1-5dbd35899cbe) for you to get started.
Also, please [join our Discord](https://hyprnote.com/discord)! We really want to hear from you. diff --git a/crates/file/src/lib.rs b/crates/file/src/lib.rs index 2dcb12f1a9..6f41439a3a 100644 --- a/crates/file/src/lib.rs +++ b/crates/file/src/lib.rs @@ -345,7 +345,7 @@ mod tests { let temp_path = temp_file.path(); let s3_url = - "https://storage.hyprnote.com/v0/ggerganov/whisper.cpp/main/ggml-tiny-q8_0.bin"; + "https://storage2.hyprnote.com/v0/ggerganov/whisper.cpp/main/ggml-tiny-q8_0.bin"; let partial_content = b"PARTIAL_CONTENT".repeat(100); std::fs::write(temp_path, &partial_content).unwrap(); diff --git a/plugins/local-llm/assets/onboarding-enhanced.md b/plugins/local-llm/assets/onboarding-enhanced.md index f8c44d0913..1a2c5a37b7 100644 --- a/plugins/local-llm/assets/onboarding-enhanced.md +++ b/plugins/local-llm/assets/onboarding-enhanced.md @@ -1,16 +1,20 @@ -# Objective +# What is Hyprnote? +- AI notepad for private meetings +- Runs fully offline using on-device STT and LLM models. +- No internet or third-party servers involved. +- All data is stored locally to ensure user privacy. -- Onboard new users to Hyprnote quickly and efficiently. -- Demonstrate core functionality within the first 5 minutes of use. -- Guide users through setting up their first meeting note. -- Help users understand the value of automated transcription and summary features. +# How to use Hyprnote +- Create a new note and press the red record button to begin recording. +- Live transcription appears in the side panel as participants speak. +- Users jot down only key points during the meeting. +- After stopping the recording, Hyprnote generates an enhanced note by combining user notes and the transcript. -# Privacy and Performance - -- Built local-first: works offline and stores data on your device. -- Prioritizes user privacy and seamless experience. +# Features +- AI-enhanced summaries based on your notes and the full transcript. +- Built-in AI chat for follow-up questions. +- Customizable templates for different meeting types. # Stay Connected - -- Follow updates on [X](https://hyprnote.com/x). -- Join the community and chat on [Discord](https://hyprnote.com/discord). +- Join the community on [Discord](https://hyprnote.com/discord). +- Learn more in the [Official Docs](https://docs.hyprnote.com). \ No newline at end of file diff --git a/plugins/local-llm/src/model.rs b/plugins/local-llm/src/model.rs index 7579e685a4..0c1d132bad 100644 --- a/plugins/local-llm/src/model.rs +++ b/plugins/local-llm/src/model.rs @@ -17,8 +17,8 @@ impl SupportedModel { pub fn model_url(&self) -> &str { match self { - SupportedModel::Llama3p2_3bQ4 => "https://storage.hyprnote.com/v0/lmstudio-community/Llama-3.2-3B-Instruct-GGUF/main/Llama-3.2-3B-Instruct-Q4_K_M.gguf", - SupportedModel::HyprLLM => "https://storage.hyprnote.com/v0/yujonglee/hypr-llm-sm/model_q4_k_m.gguf" + SupportedModel::Llama3p2_3bQ4 => "https://storage2.hyprnote.com/v0/lmstudio-community/Llama-3.2-3B-Instruct-GGUF/main/Llama-3.2-3B-Instruct-Q4_K_M.gguf", + SupportedModel::HyprLLM => "https://storage2.hyprnote.com/v0/yujonglee/hypr-llm-sm/model_q4_k_m.gguf" } } diff --git a/plugins/local-stt/src/model.rs b/plugins/local-stt/src/model.rs index a5062ba364..cbd44725df 100644 --- a/plugins/local-stt/src/model.rs +++ b/plugins/local-stt/src/model.rs @@ -34,13 +34,13 @@ impl SupportedModel { pub fn model_url(&self) -> &str { match self { - SupportedModel::QuantizedTiny => "https://storage.hyprnote.com/v0/ggerganov/whisper.cpp/main/ggml-tiny-q8_0.bin", - SupportedModel::QuantizedTinyEn => "https://storage.hyprnote.com/v0/ggerganov/whisper.cpp/main/ggml-tiny.en-q8_0.bin", - SupportedModel::QuantizedBase => "https://storage.hyprnote.com/v0/ggerganov/whisper.cpp/main/ggml-base-q8_0.bin", - SupportedModel::QuantizedBaseEn => "https://storage.hyprnote.com/v0/ggerganov/whisper.cpp/main/ggml-base.en-q8_0.bin", - SupportedModel::QuantizedSmall => "https://storage.hyprnote.com/v0/ggerganov/whisper.cpp/main/ggml-small-q8_0.bin", - SupportedModel::QuantizedSmallEn => "https://storage.hyprnote.com/v0/ggerganov/whisper.cpp/main/ggml-small.en-q8_0.bin", - SupportedModel::QuantizedLargeTurbo => "https://storage.hyprnote.com/v0/ggerganov/whisper.cpp/main/ggml-large-v3-turbo-q8_0.bin", + SupportedModel::QuantizedTiny => "https://storage2.hyprnote.com/v0/ggerganov/whisper.cpp/main/ggml-tiny-q8_0.bin", + SupportedModel::QuantizedTinyEn => "https://storage2.hyprnote.com/v0/ggerganov/whisper.cpp/main/ggml-tiny.en-q8_0.bin", + SupportedModel::QuantizedBase => "https://storage2.hyprnote.com/v0/ggerganov/whisper.cpp/main/ggml-base-q8_0.bin", + SupportedModel::QuantizedBaseEn => "https://storage2.hyprnote.com/v0/ggerganov/whisper.cpp/main/ggml-base.en-q8_0.bin", + SupportedModel::QuantizedSmall => "https://storage2.hyprnote.com/v0/ggerganov/whisper.cpp/main/ggml-small-q8_0.bin", + SupportedModel::QuantizedSmallEn => "https://storage2.hyprnote.com/v0/ggerganov/whisper.cpp/main/ggml-small.en-q8_0.bin", + SupportedModel::QuantizedLargeTurbo => "https://storage2.hyprnote.com/v0/ggerganov/whisper.cpp/main/ggml-large-v3-turbo-q8_0.bin", } }