Skip to content

Download speech-to-text model while onboarding#2468

Merged
ComputelessComputer merged 3 commits intomainfrom
feat/local-stt-model-selection
Dec 30, 2025
Merged

Download speech-to-text model while onboarding#2468
ComputelessComputer merged 3 commits intomainfrom
feat/local-stt-model-selection

Conversation

@ComputelessComputer
Copy link
Collaborator

@ComputelessComputer ComputelessComputer commented Dec 22, 2025

to download speech-to-text models in onboarding

onboarding.mp4

as you can see in the video, #2470 is needed as well


This is part 1 of 2 in a stack made with GitButler:

@netlify
Copy link

netlify bot commented Dec 22, 2025

Deploy Preview for hyprnote-storybook canceled.

Name Link
🔨 Latest commit 6aa819e
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/6953b12a13d58500084a5777

@netlify
Copy link

netlify bot commented Dec 22, 2025

Deploy Preview for hyprnote canceled.

Name Link
🔨 Latest commit 6aa819e
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/6953b12a440e5c000812ca62

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 22, 2025

📝 Walkthrough

Walkthrough

This PR refactors local STT model download logic from an embedded component implementation into a reusable hook, and adds support for local STT configuration in the onboarding flow. A new useLocalModelDownload hook centralizes download lifecycle management, while conditional rendering enables local STT setup during onboarding when a URL parameter is present.

Changes

Cohort / File(s) Summary
Onboarding local STT flow
apps/desktop/src/components/onboarding/configure-notice.tsx
Conditionally renders LocalConfigureNotice component when search parameter includes local. Introduces LocalModelRow for rendering model options with download status. Exposes STEP_ID_CONFIGURE_NOTICE constant. Persists model selection via settings callbacks and triggers download commands.
Settings STT configure refactoring
apps/desktop/src/components/settings/ai/stt/configure.tsx
Removes local state management (useState, useEffect) and inline useLocalModelDownload implementation. Now imports external useLocalModelDownload hook from shared hooks module. Updates imports to remove sttModelQueries dependency.
Shared STT exports
apps/desktop/src/components/settings/ai/stt/shared.tsx
Replaces in-file sttModelQueries object with export alias to localSttQueries. Removes previous query definitions and adjusts imports accordingly.
Local STT model hook
apps/desktop/src/hooks/useLocalSttModel.ts
New file introducing useLocalModelDownload hook for managing download lifecycle, state tracking, and event subscriptions. Exports localSttKeys (query key definitions), localSttQueries (isDownloaded/isDownloading queries), and hook with progress, error state, and download/cancel controls.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • New hook implementation requires careful review of event subscription logic, state management patterns, and query configuration
  • Import/export changes across shared modules must be verified for consistency
  • Integration points between onboarding component and centralized hook logic should be validated
  • File: apps/desktop/src/hooks/useLocalSttModel.ts may warrant extra attention due to event handling and progress tracking logic

Possibly related PRs

Suggested reviewers

  • yujonglee

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding local STT model selection for Hyprnote, which is clearly supported by the detailed changes across multiple files.
Description check ✅ Passed The description is well-detailed and directly related to the changeset, covering the feature implementation, refactoring work, and providing testing guidance for the PR.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/local-stt-model-selection

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
apps/desktop/src/components/onboarding/configure-notice.tsx (1)

181-181: Redundant query per row when parent already fetches download status.

LocalModelRow calls useQuery(localSttQueries.isDownloaded(model)) for each model, but the parent LocalConfigureNotice already queries the same data (p2Downloaded, p3Downloaded). Consider passing the downloaded status as a prop to avoid duplicate queries.

🔎 Proposed refactor to pass downloaded status as prop
 function LocalModelRow({
   model,
   displayName,
   description,
   isSelected,
   onSelect,
+  isDownloaded,
 }: {
   model: SupportedSttModel;
   displayName: string;
   description: string;
   isSelected: boolean;
   onSelect: () => void;
+  isDownloaded: boolean;
 }) {
-  const isDownloaded = useQuery(localSttQueries.isDownloaded(model));
 
   return (
     // ... use isDownloaded directly instead of isDownloaded.data
apps/desktop/src/hooks/useLocalSttModel.ts (2)

1-2: Consolidate duplicate imports.

useQuery and queryOptions can be imported from @tanstack/react-query in a single import statement.

🔎 Proposed fix
-import { queryOptions } from "@tanstack/react-query";
-import { useQuery } from "@tanstack/react-query";
+import { queryOptions, useQuery } from "@tanstack/react-query";

22-47: Consider the polling frequency impact.

Both isDownloaded and isDownloading queries use refetchInterval: 1000 (1 second). When multiple models are displayed (e.g., in the settings page with 5+ model rows), this creates frequent backend calls. Consider whether a longer interval (e.g., 2-3 seconds) would suffice, or use event-driven updates instead of polling for download status.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6cf957d and 82d3ed7.

📒 Files selected for processing (4)
  • apps/desktop/src/components/onboarding/configure-notice.tsx
  • apps/desktop/src/components/settings/ai/stt/configure.tsx
  • apps/desktop/src/components/settings/ai/stt/shared.tsx
  • apps/desktop/src/hooks/useLocalSttModel.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*

📄 CodeRabbit inference engine (AGENTS.md)

Format using dprint fmt from the root. Do not use cargo fmt.

Files:

  • apps/desktop/src/components/settings/ai/stt/shared.tsx
  • apps/desktop/src/components/onboarding/configure-notice.tsx
  • apps/desktop/src/hooks/useLocalSttModel.ts
  • apps/desktop/src/components/settings/ai/stt/configure.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props. Just inline them.
Never do manual state management for form/mutation. Use useForm from tanstack-form and useQuery/useMutation from tanstack-query for 99% cases.

Files:

  • apps/desktop/src/components/settings/ai/stt/shared.tsx
  • apps/desktop/src/components/onboarding/configure-notice.tsx
  • apps/desktop/src/hooks/useLocalSttModel.ts
  • apps/desktop/src/components/settings/ai/stt/configure.tsx
**/*.{ts,tsx,rs,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

By default, avoid writing comments at all. If you write one, it should be about 'Why', not 'What'.

Files:

  • apps/desktop/src/components/settings/ai/stt/shared.tsx
  • apps/desktop/src/components/onboarding/configure-notice.tsx
  • apps/desktop/src/hooks/useLocalSttModel.ts
  • apps/desktop/src/components/settings/ai/stt/configure.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: If there are many classNames with conditional logic, use cn (import from @hypr/utils). Always pass an array and split by logical grouping.
Use motion/react instead of framer-motion.

Files:

  • apps/desktop/src/components/settings/ai/stt/shared.tsx
  • apps/desktop/src/components/onboarding/configure-notice.tsx
  • apps/desktop/src/hooks/useLocalSttModel.ts
  • apps/desktop/src/components/settings/ai/stt/configure.tsx
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Agent implementations should use TypeScript and follow the established architectural patterns defined in the agent framework
Agent communication should use defined message protocols and interfaces

Files:

  • apps/desktop/src/hooks/useLocalSttModel.ts
🧠 Learnings (1)
📚 Learning: 2025-12-16T07:24:36.000Z
Learnt from: CR
Repo: fastrepl/hyprnote PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-16T07:24:36.000Z
Learning: Applies to **/*.{ts,tsx} : Never do manual state management for form/mutation. Use `useForm` from tanstack-form and `useQuery`/`useMutation` from tanstack-query for 99% cases.

Applied to files:

  • apps/desktop/src/components/onboarding/configure-notice.tsx
🧬 Code graph analysis (1)
apps/desktop/src/components/onboarding/configure-notice.tsx (4)
apps/desktop/src/components/onboarding/config.tsx (1)
  • getNext (17-30)
apps/desktop/src/hooks/useLocalSttModel.ts (1)
  • localSttQueries (22-47)
apps/desktop/src/components/onboarding/shared.tsx (1)
  • OnboardingContainer (6-41)
packages/utils/src/cn.ts (1)
  • cn (20-22)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-22.04-8)
  • GitHub Check: fmt
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
🔇 Additional comments (9)
apps/desktop/src/components/onboarding/configure-notice.tsx (2)

93-97: Auto-navigation effect may cause unexpected behavior.

The useEffect navigates away immediately if either model is already downloaded. This could be surprising UX if a user wants to download a different model than the one they already have. Consider whether this is the intended behavior, or if users should be allowed to choose even when they have a model downloaded.

Additionally, onNavigate is a callback prop that likely changes on each render. If onNavigate is not memoized by the parent, this effect could trigger unexpectedly.


184-199: Good accessibility implementation.

The interactive div correctly implements role="button", tabIndex={0}, and keyboard event handling for Enter and Space keys. The cn utility is used properly with array grouping for conditional classes.

apps/desktop/src/components/settings/ai/stt/shared.tsx (1)

12-19: Clean re-export pattern for backward compatibility.

The alias export localSttQueries as sttModelQueries maintains backward compatibility for existing consumers while centralizing the query logic in the new hook file. This follows good module organization practices.

apps/desktop/src/components/settings/ai/stt/configure.tsx (2)

5-5: Clean refactor to use shared hook.

The imports are streamlined appropriately - removed useState and useEffect that were previously used for local download state management, and now imports the centralized useLocalModelDownload hook. This follows the DRY principle and aligns with the PR's goal of extracting shared logic.

Also applies to: 22-22, 25-25


307-317: Hook integration looks correct.

The useLocalModelDownload hook is properly integrated, with the useSafeSelectModel callback passed for onDownloadComplete. This ensures the model selection only happens when the listener is inactive, preventing issues during active transcription sessions.

apps/desktop/src/hooks/useLocalSttModel.ts (4)

11-20: Well-structured query key factory.

The localSttKeys factory follows the recommended React Query key-factory pattern, providing consistent and hierarchical cache keys. This enables effective cache invalidation and query deduplication.


96-109: Good guard against duplicate downloads.

The handleDownload function correctly guards against initiating a download when one is already in progress (isDownloaded.data || isDownloading.data || isStarting). The error handling for the download command result is also properly implemented.


69-87: Event listener cleanup pattern is correct.

The effect properly returns a cleanup function that awaits the unlisten promise and calls the returned function. This ensures the listener is removed when the component unmounts or the model changes.


89-94: No action needed. The onDownloadComplete callback passed to this hook is memoized by the caller via useCallback in useSafeSelectModel(), so including it in the dependency array is appropriate and won't cause excessive re-runs.

@github-project-automation github-project-automation bot moved this to Backlog in Product Dec 27, 2025
@ComputelessComputer ComputelessComputer moved this from Backlog to In review in Product Dec 27, 2025
@ComputelessComputer ComputelessComputer changed the title Add local STT model selection for Hyprnote Download speech-to-text model while onboarding Dec 27, 2025
@netlify
Copy link

netlify bot commented Dec 30, 2025

Deploy Preview for howto-fix-macos-audio-selection canceled.

Name Link
🔨 Latest commit 6aa819e
🔍 Latest deploy log https://app.netlify.com/projects/howto-fix-macos-audio-selection/deploys/6953b12a4e7a9300081812f4

@ComputelessComputer ComputelessComputer force-pushed the feat/local-stt-model-selection branch from 4a1ba02 to ca01aac Compare December 30, 2025 10:21
@ComputelessComputer ComputelessComputer force-pushed the feat/local-stt-model-selection branch from ca01aac to d23c718 Compare December 30, 2025 10:53
Add error state and loading indicator for model download process
to provide better user feedback and prevent multiple download attempts.
@ComputelessComputer ComputelessComputer merged commit b7e650a into main Dec 30, 2025
22 checks passed
@github-project-automation github-project-automation bot moved this from In review to Done in Product Dec 30, 2025
@ComputelessComputer ComputelessComputer deleted the feat/local-stt-model-selection branch December 30, 2025 11:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant