Skip to content

Commit bacdcf0

Browse files
Replace jargons setting with instruction in listen button (#677)
1 parent 522a255 commit bacdcf0

File tree

11 files changed

+234
-121
lines changed

11 files changed

+234
-121
lines changed

apps/desktop/src/components/editor-area/note-header/chips/index.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@ import { ParticipantsChip } from "./participants-chip";
33
import { PastNotesChip } from "./past-notes-chip";
44
import { TagChip } from "./tag-chip";
55

6-
interface ChipsProps {
6+
export default function NoteHeaderChips({ sessionId, hashtags = [] }: {
77
sessionId: string;
88
hashtags?: string[];
9-
}
10-
11-
export default function Chips({ sessionId, hashtags = [] }: ChipsProps) {
9+
}) {
1210
return (
1311
<div className="-mx-1.5 flex flex-row items-center overflow-x-auto scrollbar-none whitespace-nowrap">
1412
<EventChip sessionId={sessionId} />

apps/desktop/src/components/editor-area/note-header/listen-button.tsx

Lines changed: 94 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ import SoundIndicator from "@/components/sound-indicator";
88
import { useHypr } from "@/contexts";
99
import { useEnhancePendingState } from "@/hooks/enhance-pending";
1010
import { commands as analyticsCommands } from "@hypr/plugin-analytics";
11+
import { commands as dbCommands } from "@hypr/plugin-db";
1112
import { commands as listenerCommands } from "@hypr/plugin-listener";
1213
import { commands as localSttCommands } from "@hypr/plugin-local-stt";
1314
import { Button } from "@hypr/ui/components/ui/button";
1415
import { Popover, PopoverContent, PopoverTrigger } from "@hypr/ui/components/ui/popover";
1516
import { Spinner } from "@hypr/ui/components/ui/spinner";
17+
import { Textarea } from "@hypr/ui/components/ui/textarea";
1618
import { toast } from "@hypr/ui/components/ui/toast";
17-
import { Tooltip, TooltipContent, TooltipTrigger } from "@hypr/ui/components/ui/tooltip";
1819
import { cn } from "@hypr/ui/lib/utils";
1920
import { useOngoingSession, useSession } from "@hypr/utils/contexts";
2021
import ShinyButton from "./shiny-button";
@@ -150,25 +151,106 @@ export default function ListenButton({ sessionId }: { sessionId: string }) {
150151
}
151152

152153
function WhenInactiveAndMeetingNotEnded({ disabled, onClick }: { disabled: boolean; onClick: () => void }) {
154+
const [open, setOpen] = useState(false);
155+
const [instructionText, setInstructionText] = useState("");
156+
157+
const configQuery = useQuery({
158+
queryKey: ["config", "general"],
159+
queryFn: async () => await dbCommands.getConfig(),
160+
});
161+
162+
useEffect(() => {
163+
if (configQuery.data?.general?.jargons) {
164+
setInstructionText((configQuery.data.general.jargons ?? []).join(", "));
165+
}
166+
}, [configQuery.data]);
167+
168+
const mutation = useMutation({
169+
mutationFn: async (jargons: string) => {
170+
if (!configQuery.data) {
171+
return;
172+
}
173+
174+
const nextGeneral = {
175+
...(configQuery.data.general ?? {}),
176+
jargons: [jargons],
177+
};
178+
await dbCommands.setConfig({
179+
...configQuery.data,
180+
general: nextGeneral,
181+
});
182+
},
183+
onSuccess: () => {
184+
configQuery.refetch();
185+
},
186+
onError: console.error,
187+
});
188+
189+
const handleSaveJargons = () => {
190+
const currentConfigJargons = (configQuery.data?.general?.jargons ?? []).join(", ");
191+
if (instructionText !== currentConfigJargons) {
192+
mutation.mutate(instructionText);
193+
}
194+
};
195+
153196
return (
154-
<Tooltip>
155-
<TooltipTrigger asChild>
197+
<Popover
198+
open={open}
199+
onOpenChange={(newOpen) => {
200+
setOpen(newOpen);
201+
if (!newOpen) {
202+
handleSaveJargons();
203+
}
204+
}}
205+
>
206+
<PopoverTrigger asChild>
156207
<button
157208
disabled={disabled}
158-
onClick={onClick}
159209
className={cn([
160-
"w-9 h-9 rounded-full border-2 transition-all hover:scale-95 cursor-pointer outline-none p-0 flex items-center justify-center shadow-[inset_0_0_0_2px_rgba(255,255,255,0.8)]",
210+
"w-9 h-9 rounded-full border-2 transition-all hover:scale-95 cursor-pointer outline-none p-0 flex items-center justify-center",
161211
disabled ? "bg-neutral-200 border-neutral-400" : "bg-red-500 border-neutral-400",
212+
"shadow-[inset_0_0_0_2px_rgba(255,255,255,0.8)]",
162213
])}
163214
>
164215
</button>
165-
</TooltipTrigger>
166-
<TooltipContent side="bottom" align="end">
167-
<p>
168-
<Trans>Start recording</Trans>
169-
</p>
170-
</TooltipContent>
171-
</Tooltip>
216+
</PopoverTrigger>
217+
<PopoverContent className="w-80" align="end">
218+
<div className="flex flex-col gap-3">
219+
<div className="flex flex-col gap-2">
220+
<div className="text-sm font-medium text-neutral-700">
221+
<Trans>Custom instruction</Trans>
222+
</div>
223+
<Textarea
224+
value={instructionText}
225+
onChange={(e) => setInstructionText(e.target.value)}
226+
placeholder="ex) Hyprnote, JDCE, Fastrepl, John, Yujong"
227+
className="min-h-[80px] resize-none border-neutral-300 text-sm focus-visible:ring-0 focus-visible:ring-offset-0"
228+
/>
229+
<p className="text-xs text-neutral-400">
230+
<Trans>
231+
Provide descriptions about the meeting. Company specific terms, acronyms, jargons... any thing!
232+
</Trans>
233+
</p>
234+
</div>
235+
236+
<Button
237+
onClick={() => {
238+
handleSaveJargons();
239+
onClick();
240+
setOpen(false);
241+
}}
242+
disabled={disabled}
243+
className="w-full flex items-center gap-2"
244+
>
245+
<div className="relative flex-shrink-0">
246+
<div className="w-3 h-3 rounded-full bg-red-500"></div>
247+
<div className="absolute top-0 left-0 w-3 h-3 rounded-full bg-red-500 animate-ping opacity-75"></div>
248+
</div>
249+
<Trans>Start Meeting</Trans>
250+
</Button>
251+
</div>
252+
</PopoverContent>
253+
</Popover>
172254
);
173255
}
174256

apps/desktop/src/components/settings/views/general.tsx

Lines changed: 2 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import { zodResolver } from "@hookform/resolvers/zod";
22
import { LANGUAGES_ISO_639_1 } from "@huggingface/languages";
3-
import { Trans, useLingui } from "@lingui/react/macro";
3+
import { Trans } from "@lingui/react/macro";
44
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
55
import { useEffect } from "react";
66
import { useForm } from "react-hook-form";
77
import { z } from "zod";
88

9-
import { showModelSelectToast } from "@/components/toast/model-select";
10-
import { commands } from "@/types";
119
import { commands as dbCommands, type ConfigGeneral } from "@hypr/plugin-db";
1210
import {
1311
Form,
@@ -18,7 +16,6 @@ import {
1816
FormLabel,
1917
FormMessage,
2018
} from "@hypr/ui/components/ui/form";
21-
import { Input } from "@hypr/ui/components/ui/input";
2219
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@hypr/ui/components/ui/select";
2320
import { Switch } from "@hypr/ui/components/ui/switch";
2421

@@ -29,13 +26,11 @@ const schema = z.object({
2926
autostart: z.boolean().optional(),
3027
displayLanguage: z.enum(SUPPORTED_LANGUAGES as [string, ...string[]]),
3128
telemetryConsent: z.boolean().optional(),
32-
jargons: z.string(),
3329
});
3430

3531
type Schema = z.infer<typeof schema>;
3632

3733
export default function General() {
38-
const { t } = useLingui();
3934
const queryClient = useQueryClient();
4035

4136
const config = useQuery({
@@ -52,7 +47,6 @@ export default function General() {
5247
autostart: false,
5348
displayLanguage: "en",
5449
telemetryConsent: true,
55-
jargons: "",
5650
},
5751
});
5852

@@ -62,7 +56,6 @@ export default function General() {
6256
autostart: config.data.general.autostart ?? false,
6357
displayLanguage: config.data.general.display_language ?? "en",
6458
telemetryConsent: config.data.general.telemetry_consent ?? true,
65-
jargons: (config.data.general.jargons ?? []).join(", "),
6659
});
6760
}
6861
}, [config.data, form]);
@@ -78,7 +71,7 @@ export default function General() {
7871
autostart: v.autostart ?? false,
7972
display_language: v.displayLanguage,
8073
telemetry_consent: v.telemetryConsent ?? true,
81-
jargons: v.jargons.split(",").map((jargon) => jargon.trim()).filter(Boolean),
74+
jargons: config.data.general.jargons ?? [],
8275
};
8376

8477
await dbCommands.setConfig({
@@ -94,21 +87,8 @@ export default function General() {
9487

9588
useEffect(() => {
9689
const subscription = form.watch((value, { name }) => {
97-
if (name === "jargons") {
98-
return;
99-
}
100-
10190
mutation.mutate(form.getValues());
102-
103-
if (name === "autostart") {
104-
commands.setAutostart(!!value.autostart);
105-
}
106-
107-
if (name === "displayLanguage" && value.displayLanguage) {
108-
showModelSelectToast(value.displayLanguage);
109-
}
11091
});
111-
11292
return () => subscription.unsubscribe();
11393
}, [form, mutation]);
11494

@@ -175,36 +155,6 @@ export default function General() {
175155
</FormItem>
176156
)}
177157
/>
178-
179-
<FormField
180-
control={form.control}
181-
name="jargons"
182-
render={({ field }) => (
183-
<FormItem>
184-
<div>
185-
<FormLabel>
186-
<Trans>Jargons</Trans>
187-
</FormLabel>
188-
<FormDescription>
189-
<Trans>
190-
You can make Hyprnote takes these words into account when transcribing
191-
</Trans>
192-
</FormDescription>
193-
</div>
194-
<FormControl>
195-
<Input
196-
{...field}
197-
onBlur={() => mutation.mutate(form.getValues())}
198-
placeholder={t({
199-
id: "Type jargons (e.g., Blitz Meeting, PaC Squad)",
200-
})}
201-
className="focus-visible:ring-0 focus-visible:ring-offset-0"
202-
/>
203-
</FormControl>
204-
<FormMessage />
205-
</FormItem>
206-
)}
207-
/>
208158
</form>
209159
</Form>
210160
</div>

0 commit comments

Comments
 (0)