Skip to content

Conversation

@ParikhShreya
Copy link

@ParikhShreya ParikhShreya commented Nov 22, 2025

Overview

This PR implements a Smart Search Bar with a Voice Search button for PictoPy.
Previously, users had to manually browse the sidebar to access features like AI Tagging, Videos, or Albums.
With this enhancement, users can quickly search for pages, images, or tags using text or voice input.

Features Added

Smart Search Bar

  • Positioned in the top navigation bar.
  • Accepts text input to search:
    • Image names or tags.
    • Pages like AI Tagging, Videos, Albums, etc.
  • Displays a dropdown with matching suggestions.
  • Voice Search Button
    • Small microphone icon inside the search bar.
    • Activates browser's SpeechRecognition API on click.
    • Converts voice input into text in the search field.

Benefits

  • Simplifies navigation across different pages.
  • Allows quick access to images and tags.
  • Improves accessibility and user experience.
  • Provides a foundation for future voice-based or AI-enhanced search features.

Implementation Notes

  • Created a new SearchBar component.
  • Integrated Lucide Mic icon for voice search.
  • Used Web Speech API for real-time speech-to-text conversion.
  • Dropdown suggestions only include existing pages to prevent navigation errors.
  • Ensured full compatibility with dark/light mode themes.

Screenshots

LIGHT MODE

image image

DARK MODE

image image

###Video

22.11.2025_11.38.11_REC_PICTOPY.mp4

Issue

Closes #627

Summary by CodeRabbit

Release Notes

  • New Features
    • Voice-activated search and navigation capabilities using speech recognition.
    • Enhanced search bar with live filtering, dropdown suggestions, and keyboard navigation support.
    • Quick voice-driven shortcuts for immediate access to key sections like favorites.
    • Improved error handling for unsupported browsers and unmatched voice commands.
    • Redesigned navigation header with responsive layout and enhanced dark/light mode styling.

✏️ Tip: You can customize this high-level summary in your review settings.

Added error handling and voice search functionality to the Navbar component.
Added voice command functionality and improved error handling.
Refactor ErrorDialog and Navbar components for improved styling and functionality. Adjust voice search handling and cleanup code structure.
@github-actions github-actions bot added enhancement New feature or request frontend labels Nov 22, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 22, 2025

Walkthrough

This pull request adds voice-to-text functionality through a new VoiceCommand React component leveraging the Web Speech API, then integrates it into the Navbar component with interactive search, dropdown filtering, keyboard navigation, error handling, and route mapping for seamless navigation.

Changes

Cohort / File(s) Summary
Voice Input Component
frontend/src/components/Dialog/VoiceCommand.tsx
New component enabling speech-to-text via Web Speech API. Manages listening state, initializes browser SpeechRecognition on click, configures for en-US language, processes transcripts via onCommand callback, and displays Listening UI state with error alerts.
Navbar Rewrite
frontend/src/components/Navigation/Navbar/Navbar.tsx
Comprehensive rewrite introducing dynamic search with local state, dropdown filtering, keyboard navigation (ArrowUp/ArrowDown/Enter), voice command integration, ErrorDialog for user-facing messages, route mapping dispatcher, and responsive header layout with logo, search area, theme selector, and user avatar. Added default export alongside named export.

Sequence Diagrams

sequenceDiagram
    actor User
    participant Navbar
    participant VoiceCommand
    participant SpeechRecognition
    participant RouteMap
    
    User->>Navbar: Click microphone icon
    Navbar->>VoiceCommand: Mount VoiceCommand component
    VoiceCommand->>SpeechRecognition: Initialize & start listening
    Note over VoiceCommand: Display "Listening…" state
    User->>SpeechRecognition: Speak command (e.g., "favourites")
    SpeechRecognition->>VoiceCommand: Return transcript
    VoiceCommand->>VoiceCommand: Lowercase & trim transcript
    VoiceCommand->>Navbar: Invoke onCommand callback
    Navbar->>RouteMap: Match transcript to route
    alt Route found
        Navbar->>Navbar: Navigate via window.location.href
        Note over Navbar: Clear search, update UI
    else Route not found
        Navbar->>Navbar: Show ErrorDialog to user
    end
Loading
sequenceDiagram
    actor User
    participant Navbar
    
    User->>Navbar: Type in search input
    Navbar->>Navbar: Update query state
    Navbar->>Navbar: Filter suggestions based on query
    Navbar->>Navbar: Display dropdown results
    
    alt Keyboard navigation
        User->>Navbar: Press ArrowDown
        Navbar->>Navbar: Highlight next suggestion
        User->>Navbar: Press Enter
        Navbar->>Navbar: Navigate to selected page
    else Voice input
        User->>Navbar: Click microphone
        Note over Navbar: VoiceCommand flow initiated
    else Direct selection
        User->>Navbar: Click suggestion
        Navbar->>Navbar: Navigate to page
    end
    
    Navbar->>Navbar: Clear search state
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Navbar.tsx rewrite: Multiple new state variables, complex keyboard event handling, route mapping logic, error dialog integration, and voice command integration require thorough logic review
  • Voice integration: Verify Web Speech API usage, error handling for unsupported browsers, and transcript processing
  • Route mapping: Confirm route keys match application structure and error cases are properly handled
  • UI/UX consistency: Review responsive styling, light/dark mode support, and accessibility considerations (ARIA labels, keyboard navigation)
  • State management: Ensure search query state, listening state, and error state are properly managed and cleared

Suggested labels

UI

Suggested reviewers

  • rahulharpal1603

Poem

🐰 Whiskers twitching with delight,
A voice command brings new light,
Search bars dancing, mics so keen,
Navigation slick and clean!
From spoken word to mapped route—
PictoPy's interface is acute! 🎤✨

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately reflects the main objective of implementing a smart search bar with voice search functionality as described in the changes and linked issue #627.
Linked Issues check ✅ Passed The implementation successfully addresses all primary objectives from issue #627: creates a smart search bar component with voice search via Web Speech API, enables text/voice-based navigation to pages, and implements keyboard navigation with dropdown suggestions.
Out of Scope Changes check ✅ Passed Changes include a new VoiceCommand component and comprehensive Navbar rewrite with dynamic search and keyboard navigation, which are all within scope per issue #627 requirements for the smart search bar and voice functionality.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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: 0

🧹 Nitpick comments (7)
frontend/src/components/Dialog/VoiceCommand.tsx (2)

11-40: Avoid blocking alert for speech errors; surface via props or app‑level UI

alert calls for unsupported browsers and recognition errors break the app’s visual/UX flow and are harder to style or internationalize. Since you already have in‑app dialogs elsewhere, it would be cleaner to surface these via a callback or parent UI instead of hard‑coding alerts here.

Consider extending the props and delegating error display to the caller:

-interface Props {
-  onCommand: (cmd: string) => void;
-}
+interface Props {
+  onCommand: (cmd: string) => void;
+  onError?: (message: string) => void;
+}
...
-    if (!SpeechRecognition) {
-      alert("Speech recognition not supported in this browser.");
-      return;
-    }
+    if (!SpeechRecognition) {
+      onError?.("Speech recognition is not supported in this browser.");
+      return;
+    }
...
-    recognition.onerror = () => {
-      setListening(false);
-      alert("Try again...");
-    };
+    recognition.onerror = () => {
+      setListening(false);
+      onError?.("There was an error with speech recognition. Please try again.");
+    };

This keeps the component reusable and lets Navbar (or others) decide how to present errors.


43-55: Unify voice handling with Navbar to avoid duplicated Web Speech logic

Navbar currently imports VoiceCommand but reimplements its own SpeechRecognition wiring and mic button. That gives you two separate code paths to maintain for essentially the same concern.

Either:

  • Replace the inline mic button in Navbar with <VoiceCommand onCommand={...} /> wired to your goToPage logic (and optional onError as above), or
  • If Navbar’s overlay‑style UX is preferred and VoiceCommand won’t be reused, drop the import/this component to avoid dead/duplicate behavior.

Reusing VoiceCommand in Navbar keeps speech configuration, language, and error behavior in one place.

frontend/src/components/Navigation/Navbar/Navbar.tsx (5)

14-21: Reuse shared dialog components instead of a bespoke ErrorDialog overlay

You define a custom ErrorDialog here while other flows (e.g., FaceSearchDialog) already rely on shared Dialog / showInfoDialog patterns. For consistency in styling, accessibility, and focus management, consider reusing those existing primitives instead of maintaining a separate modal implementation just for navbar errors.


28-35: Avoid subscribing to state.search if navbar doesn’t use it

searchState, isSearchActive, and queryImage are derived but not used later, which means Navbar will still re‑render on every search state change without benefiting from the data.

If this subscription is no longer needed, you can remove the selector and derived locals to reduce unnecessary renders:

-  const searchState = useSelector((state: any) => state.search);
-  const dispatch = useDispatch();
-
-  const isSearchActive = searchState.active;
-  const queryImage = searchState.queryImage;
+  const dispatch = useDispatch();

You still call dispatch(clearSearch()) in goToPage, so the slice remains in use without coupling Navbar’s render cycle to it.


63-72: Prefer router navigation (useNavigate / Link) over window.location and raw anchors

goToPage uses window.location.href, and the logo/settings use <a href> links. In a React SPA (and given FaceSearchDialog uses useNavigate), this forces full page reloads and bypasses client‑side routing.

Consider switching to router navigation, for example:

-import React, { useState, useEffect, useRef } from "react";
+import React, { useState, useEffect, useRef } from "react";
+import { useNavigate, Link } from "react-router-dom";
...
 export function Navbar() {
+  const navigate = useNavigate();
...
   const goToPage = (label: string) => {
     dispatch(clearSearch());
     const key = label.trim().toLowerCase().replace(/\s+/g, "-");

-    if (routeMap[key]) {
-      window.location.href = routeMap[key];
-    } else {
+    if (routeMap[key]) {
+      navigate(routeMap[key]);
+    } else {
       setError(`The page "${label}" does not exist.`);
     }
   };
...
-      <a href="/" className="flex items-center gap-2">
+      <Link to="/" className="flex items-center gap-2">
...
-        <a href="/settings">
+        <Link to="/settings">
...
-        </a>
+        </Link>

This keeps navigation within the SPA and plays nicely with history, guards, and Tauri’s routing integration.

Also applies to: 144-147, 196-201


74-87: Improve Enter‑key behavior when no suggestion is highlighted

handleKeyDown only reacts to Enter when activeIndex >= 0, so typing a query and pressing Enter without using the arrow keys is a no‑op even when filtered has matches.

Consider treating Enter with no active item as “go to the first suggestion” (or directly attempt goToPage(query)):

-    } else if (e.key === "Enter" && activeIndex >= 0) {
-      goToPage(filtered[activeIndex]);
-      setActiveIndex(-1);
-    }
+    } else if (e.key === "Enter") {
+      if (activeIndex >= 0) {
+        goToPage(filtered[activeIndex]);
+      } else if (filtered.length > 0) {
+        goToPage(filtered[0]);
+      }
+      setActiveIndex(-1);
+    }

This aligns with typical search‑box UX where Enter triggers navigation based on the current query.


91-140: Stop SpeechRecognition when closing the voice dialog and reuse the existing ref

The voice flow starts a SpeechRecognition instance and stores it in recognitionRef, but closing the voice overlay (✕ button) only toggles voiceOpen and never calls stop(). That can leave recognition running briefly in the background after the UI disappears, and the ref is otherwise unused.

You can centralize cleanup and make use of recognitionRef:

   const recognitionRef = useRef<any>(null);
...
-  const startListening = () => {
+  const stopListening = () => {
+    if (recognitionRef.current) {
+      recognitionRef.current.stop();
+      recognitionRef.current = null;
+    }
+    setVoiceOpen(false);
+  };
+
+  const startListening = () => {
     setVoiceOpen(true);
...
-    const recog = new SR();
-    recognitionRef.current = recog;
+    const recog = new SR();
+    recognitionRef.current = recog;
...
-    recog.onerror = () => {
-      setVoiceText("Try again");
-      setTimeout(() => setVoiceOpen(false), 800);
-    };
+    recog.onerror = () => {
+      setVoiceText("Try again");
+      setTimeout(() => stopListening(), 800);
+    };
...
-    recog.start();
+    recog.start();
   };
...
-      {voiceOpen && (
+      {voiceOpen && (
         <div className="fixed top-28 left-0 right-0 flex justify-center z-[2000]">
           <div className="relative max-w-sm w-full rounded-3xl p-6 bg-white border shadow-xl dark:bg-neutral-900">
-            <button className="absolute top-3 right-4 text-xl font-bold" onClick={() => setVoiceOpen(false)}>
+            <button
+              className="absolute top-3 right-4 text-xl font-bold"
+              onClick={stopListening}
+            >
               ✕
             </button>

Also, since you already have a dedicated VoiceCommand component encapsulating Web Speech behavior, consider delegating recognition there and using its callback to route, to avoid diverging behavior/config between two separate implementations.

Also applies to: 206-215

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8dbc960 and 7bc639d.

📒 Files selected for processing (2)
  • frontend/src/components/Dialog/VoiceCommand.tsx (1 hunks)
  • frontend/src/components/Navigation/Navbar/Navbar.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/components/Navigation/Navbar/Navbar.tsx (4)
frontend/src/features/onboardingSelectors.ts (2)
  • selectName (15-15)
  • selectAvatar (13-13)
frontend/src/features/searchSlice.ts (1)
  • clearSearch (21-24)
frontend/src/components/Dialog/FaceSearchDialog.tsx (1)
  • FaceSearchDialog (25-153)
frontend/src/components/ThemeToggle.tsx (1)
  • ThemeSelector (12-52)

@ParikhShreya
Copy link
Author

Hi Sir @rahulharpal1603 ,
I hope you’re doing well. I wanted to inform you that I accidentally closed the previous Pull Request (#646) while trying to reset my local branch, which caused me to lose some commits.
To correct this, I’ve created a new PR with the complete changes, referencing Issue #627 and the previous PR I closed . and I created a new PR #657

I kindly request you to please review this PR and share your valuable feedback whenever you get time.
Thank you for your guidance and support.

@Vaibhavi-14shetty
Copy link

Is this issue assigned?

@ParikhShreya
Copy link
Author

Yes @Vaibhavi-14shetty ,
This issue is assigned to me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request frontend

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feat: Add Smart Search Bar with Voice Search Button for Quick Navigation

2 participants