Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,8 @@
"rust-analyzer.cargo.targetDir": "target/analyzer",
"rust-analyzer.cargo.extraEnv": {
"MACOSX_DEPLOYMENT_TARGET": "14.2"
},
"[typescriptreact]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
}
}
21 changes: 21 additions & 0 deletions apps/desktop/src/components/editor-area/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,30 @@ import { toast } from "@hypr/ui/components/ui/toast";
import { cn } from "@hypr/ui/lib/utils";
import { generateText, localProviderName, modelProvider, smoothStream, streamText, tool } from "@hypr/utils/ai";
import { useOngoingSession, useSession, useSessions } from "@hypr/utils/contexts";
import { load } from "@tauri-apps/plugin-store";
import { enhanceFailedToast } from "../toast/shared";
import { AnnotationBox } from "./annotation-box";
import { FloatingButton } from "./floating-button";
import { NoteHeader } from "./note-header";
import { TextSelectionPopover } from "./text-selection-popover";

const getUserContext = async (): Promise<string | null> => {
try {
const store = await load("store.json", { autoSave: false });
const val = await store.get("user_context");
if (val && typeof val === "object" && "value" in val && typeof (val as any).value === "string") {
return (val as { value: string }).value;
}
return null;
} catch (error) {
console.error("Failed to fetch user context", error);
return null;
}
}




async function generateTitleDirect(
enhancedContent: string,
targetSessionId: string,
Expand Down Expand Up @@ -448,11 +466,14 @@ export function useEnhanceMutation({

let customInstruction = selectedTemplate?.description;

const userContext = (await getUserContext()) ?? "";

const systemMessage = await templateCommands.render(
"enhance.system",
{
config,
type,
userContext,
// Pass userHeaders when using H1 headers, templateInfo otherwise
...(shouldUseH1Headers
? { userHeaders: h1Headers }
Expand Down
3 changes: 3 additions & 0 deletions apps/desktop/src/components/settings/components/tab-icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
MessageSquareIcon,
SettingsIcon,
SparklesIcon,
UserIcon,
} from "lucide-react";

import { type Tab } from "./types";
Expand Down Expand Up @@ -56,6 +57,8 @@ export function TabIcon({ tab }: { tab: Tab }) {
return <CreditCardIcon className="h-4 w-4" />;
case "mcp":
return <McpIcon className="h-4 w-4" />;
case "user-context":
return <UserIcon className="h-4 w-4" />;
default:
return null;
}
Expand Down
5 changes: 4 additions & 1 deletion apps/desktop/src/components/settings/components/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
NetworkIcon,
Settings,
Sparkles,
User,
Volume2,
} from "lucide-react";

Expand All @@ -23,7 +24,8 @@ export type Tab =
| "feedback"
| "integrations"
| "mcp"
| "billing";
| "billing"
| "user-context";

export const TABS: { name: Tab; icon: LucideIcon }[] = [
{ name: "general", icon: Settings },
Expand All @@ -37,4 +39,5 @@ export const TABS: { name: Tab; icon: LucideIcon }[] = [
{ name: "mcp", icon: NetworkIcon },
{ name: "billing", icon: CreditCard },
{ name: "feedback", icon: BlocksIcon },
{ name: "user-context", icon: User },
];
93 changes: 93 additions & 0 deletions apps/desktop/src/components/settings/views/user-context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { Button } from "@hypr/ui/components/ui/button";
import { Textarea } from "@hypr/ui/components/ui/textarea";
import { toast } from "@hypr/ui/components/ui/toast";
import { load } from "@tauri-apps/plugin-store";
import React, { useEffect, useRef, useState } from "react";

export default function UserContext() {
const [isLoading, setIsLoading] = useState(false);
const textAreaRef = useRef<HTMLTextAreaElement>(null);
const [userContext, setUserContext] = useState<{ value: string } | null>(null);

const showUserContextToast = (content: string) => {
toast({
id: "user-context",
title: "User Context",
content: content,
dismissible: true,
});
};

const getStore = async () => {
return await load("store.json", { autoSave: false });
};

const getUserContext = async (): Promise<{ value: string } | null> => {
let store = await getStore();
let userContext = await store.get("user_context");

return userContext as { value: string } | null;
};

const handleSave = async () => {
try {
setIsLoading(true);
let store = await getStore();

const value = textAreaRef.current?.value?.trim();

if (!store) {
showUserContextToast("Failed to retrieve user store");
setIsLoading(false);
return;
}

if (!value) {
showUserContextToast("Please enter some content before saving.");
setIsLoading(false);
return;
}

store.set("user_context", { value });
await store.save();
showUserContextToast("User context saved successfully");
setIsLoading(false);
} catch (error) {
setIsLoading(false);
console.log("Failed to save user context with error ", error);
}
};

useEffect(() => {
getUserContext().then((val) => {
setUserContext(val);
}).catch((e) => {
console.log(e);
});
}, []);

return (
<div className="flex-1 ">
<div className="mb-2">
<p className="text-black ">User Context</p>
</div>
<Textarea
className="h-full"
ref={textAreaRef}
placeholder="Enter details about yourself"
defaultValue={userContext?.value ?? ""}
>
</Textarea>

<div className="mt-2 flex flex-row w-full justify-center">
<Button
isLoading={isLoading}
className="w-3/4"
onClick={handleSave}
>
<span className="text-white">Save</span>
</Button>
</div>
</div>
);
}
4 changes: 4 additions & 0 deletions apps/desktop/src/routes/app.settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
Sound,
TemplatesView,
} from "@/components/settings/views";
import UserContext from "@/components/settings/views/user-context";
import { cn } from "@hypr/ui/lib/utils";

const schema = z.object({
Expand Down Expand Up @@ -71,6 +72,8 @@ function Component() {
return t`License`;
case "mcp":
return t`MCP`;
case "user-context":
return t`User Context`;
default:
return tab;
}
Expand Down Expand Up @@ -140,6 +143,7 @@ function Component() {
{search.tab === "integrations" && <Integrations />}
{search.tab === "mcp" && <MCP />}
{search.tab === "billing" && <Billing />}
{search.tab === "user-context" && <UserContext />}
</div>
</div>
</div>
Expand Down
9 changes: 9 additions & 0 deletions crates/template/assets/enhance.system.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ You will be given multiple inputs from the user. Below are useful information th
- Meeting Information (txt)
- Raw Note (txt)
- Meeting Transcript (txt)
- User Context (txt)

-The User Context contains important background details about the user, such as their role, company, ongoing projects, style/tone preferences, and domain terminology.
-You must always take this into account when generating enhanced notes to make them more relevant and personalized.

{% if userContext %}
Here is the User Context:
{{ userContext | trim }}
{% endif %}

# About Raw Notes

Expand Down