Skip to content
Closed
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
81 changes: 45 additions & 36 deletions apps/desktop/src/components/editor-area/floating-button.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useQueryClient } from "@tanstack/react-query";
import { PlusIcon, RefreshCwIcon, TypeOutlineIcon, XIcon, ZapIcon } from "lucide-react";
import { useEffect, useRef, useState } from "react";

Expand Down Expand Up @@ -70,6 +71,7 @@ export function FloatingButton({
const [showRefreshIcon, setShowRefreshIcon] = useState(true);
const [showTemplatePopover, setShowTemplatePopover] = useState(false);
const hideTimeoutRef = useRef<NodeJS.Timeout | null>(null);
const queryClient = useQueryClient();

// Clear timeout on cleanup
useEffect(() => {
Expand Down Expand Up @@ -111,6 +113,7 @@ export function FloatingButton({
hideTimeoutRef.current = null;
}
if (!showRaw && !isEnhancePending && showRefreshIcon) {
queryClient.invalidateQueries({ queryKey: ["templates"] });
setShowTemplatePopover(true);
}
};
Expand All @@ -121,11 +124,9 @@ export function FloatingButton({
}, 100);
};

// Simple template selection - just call parent function
const handleTemplateSelect = (templateId: string) => {
setShowTemplatePopover(false);

// Send analytics event for custom template usage (not for "auto")
if (templateId !== "auto") {
analyticsCommands.event({
event: "custom_template_enhancement_started",
Expand All @@ -136,45 +137,21 @@ export function FloatingButton({
handleEnhanceWithTemplate(templateId);
};

// Helper function to extract emoji and clean name
const extractEmojiAndName = (title: string) => {
const emojiMatch = title.match(/^(\p{Emoji})\s*/u);
if (emojiMatch) {
return {
emoji: emojiMatch[1],
name: title.replace(/^(\p{Emoji})\s*/u, "").trim(),
};
}

// Fallback emoji based on keywords if no emoji in title
const lowercaseTitle = title.toLowerCase();
let fallbackEmoji = "📄";
if (lowercaseTitle.includes("meeting")) {
fallbackEmoji = "💼";
}
if (lowercaseTitle.includes("interview")) {
fallbackEmoji = "👔";
}
if (lowercaseTitle.includes("standup")) {
fallbackEmoji = "☀️";
}
if (lowercaseTitle.includes("review")) {
fallbackEmoji = "📝";
}

return {
emoji: fallbackEmoji,
name: title,
};
};

const handleAddTemplate = async () => {
setShowTemplatePopover(false);
try {
// Open settings window
queryClient.invalidateQueries({ queryKey: ["templates"] });

await windowsCommands.windowShow({ type: "settings" });
// Navigate to templates tab
await windowsCommands.windowNavigate({ type: "settings" }, "/app/settings?tab=templates");

const handleWindowFocus = () => {
queryClient.invalidateQueries({ queryKey: ["templates"] });
queryClient.invalidateQueries({ queryKey: ["llm-connection"] });
window.removeEventListener("focus", handleWindowFocus);
};

window.addEventListener("focus", handleWindowFocus);
} catch (error) {
console.error("Failed to open settings/templates:", error);
}
Expand Down Expand Up @@ -356,3 +333,35 @@ function RunOrRerun({ showRefresh }: { showRefresh: boolean }) {
</div>
);
}

// Helper function to extract emoji and clean name
const extractEmojiAndName = (title: string) => {
const emojiMatch = title.match(/^(\p{Emoji})\s*/u);
if (emojiMatch) {
return {
emoji: emojiMatch[1],
name: title.replace(/^(\p{Emoji})\s*/u, "").trim(),
};
}

// Fallback emoji based on keywords if no emoji in title
const lowercaseTitle = title.toLowerCase();
let fallbackEmoji = "📄";
if (lowercaseTitle.includes("meeting")) {
fallbackEmoji = "💼";
}
if (lowercaseTitle.includes("interview")) {
fallbackEmoji = "👔";
}
if (lowercaseTitle.includes("standup")) {
fallbackEmoji = "☀️";
}
if (lowercaseTitle.includes("review")) {
fallbackEmoji = "📝";
}

return {
emoji: fallbackEmoji,
name: title,
};
};
33 changes: 21 additions & 12 deletions apps/desktop/src/components/editor-area/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,8 @@ export function useEnhanceMutation({
}) {
const { userId, onboardingSessionId } = useHypr();
const [progress, setProgress] = useState(0);
const [actualIsLocalLlm, setActualIsLocalLlm] = useState(isLocalLlm);
const queryClient = useQueryClient();

const preMeetingText = extractTextFromHtml(preMeetingNote);
const rawText = extractTextFromHtml(rawContent);
Expand All @@ -316,7 +318,15 @@ export function useEnhanceMutation({
const enhance = useMutation({
mutationKey: ["enhance", sessionId],
mutationFn: async () => {
if (isLocalLlm) {
await queryClient.invalidateQueries({ queryKey: ["llm-connection"] });
await new Promise(resolve => setTimeout(resolve, 100));

const { type } = await connectorCommands.getLlmConnection();
const freshIsLocalLlm = type === "HyprLocal";

setActualIsLocalLlm(freshIsLocalLlm);

if (freshIsLocalLlm) {
setProgress(0);
}

Expand All @@ -334,12 +344,9 @@ export function useEnhanceMutation({
dismissible: true,
duration: 5000,
});

return;
}

const { type } = await connectorCommands.getLlmConnection();

const config = await dbCommands.getConfig();

let templateInfo = "";
Expand Down Expand Up @@ -399,8 +406,6 @@ Sections:`;
: provider.languageModel("defaultModel");

if (sessionId !== onboardingSessionId) {
const { type } = await connectorCommands.getLlmConnection();

analyticsCommands.event({
event: "normal_enhance_start",
distinct_id: userId,
Expand All @@ -412,7 +417,8 @@ Sections:`;
const { text, fullStream } = streamText({
abortSignal,
model,
...(isLocalLlm && {
// Use fresh value for tools
...(freshIsLocalLlm && {
tools: {
update_progress: tool({ parameters: z.any() }),
},
Expand All @@ -425,7 +431,8 @@ Sections:`;
markdownTransform(),
smoothStream({ delayInMs: 80, chunking: "line" }),
],
...(isLocalLlm && {
// Use fresh value for provider options
...(freshIsLocalLlm && {
providerOptions: {
[localProviderName]: {
metadata: customGrammar
Expand All @@ -446,7 +453,8 @@ Sections:`;
if (chunk.type === "text-delta") {
acc += chunk.textDelta;
}
if (chunk.type === "tool-call" && isLocalLlm) {
// Use fresh value for progress updates
if (chunk.type === "tool-call" && freshIsLocalLlm) {
const chunkProgress = chunk.args?.progress ?? 0;
setProgress(chunkProgress);
}
Expand All @@ -469,12 +477,13 @@ Sections:`;
});

persistSession();
if (isLocalLlm) {

if (actualIsLocalLlm) {
setProgress(0);
}
},
onError: (error) => {
if (isLocalLlm) {
if (actualIsLocalLlm) {
setProgress(0);
}
console.error(error);
Expand All @@ -485,7 +494,7 @@ Sections:`;
},
});

return { enhance, progress: isLocalLlm ? progress : undefined };
return { enhance, progress: actualIsLocalLlm ? progress : undefined };
}

function useGenerateTitleMutation({ sessionId }: { sessionId: string }) {
Expand Down