diff --git a/client/app/components/SearchMovieModal/SearchMovieModal.tsx b/client/app/components/SearchMovieModal/SearchMovieModal.tsx index 0466819..45bfcb4 100644 --- a/client/app/components/SearchMovieModal/SearchMovieModal.tsx +++ b/client/app/components/SearchMovieModal/SearchMovieModal.tsx @@ -16,7 +16,11 @@ interface SearchMovieModalProps { isLoading?: boolean; } +export type SearchType = 'mongodb-search' | 'vector-search'; + export interface SearchParams { + searchType: SearchType; + // MongoDB Search fields plot?: string; fullplot?: string; directors?: string; @@ -25,9 +29,13 @@ export interface SearchParams { limit?: number; skip?: number; search_operator?: 'must' | 'should' | 'mustNot' | 'filter'; + // Vector Search fields + q?: string; } interface SearchFormData { + searchType: SearchType; + // MongoDB Search fields plot: string; fullplot: string; directors: string; @@ -35,9 +43,13 @@ interface SearchFormData { cast: string; limit: string; search_operator: 'must' | 'should' | 'mustNot' | 'filter'; + // Vector Search fields + q: string; } const getInitialFormData = (): SearchFormData => ({ + searchType: 'mongodb-search', + // MongoDB Search fields plot: '', fullplot: '', directors: '', @@ -45,6 +57,8 @@ const getInitialFormData = (): SearchFormData => ({ cast: '', limit: '20', search_operator: 'must', + // Vector Search fields + q: '', }); export default function SearchMovieModal({ @@ -58,15 +72,22 @@ export default function SearchMovieModal({ const validateForm = () => { const newErrors: Record = {}; - // Check if at least one search field has a value - const hasSearchInput = formData.plot.trim() || - formData.fullplot.trim() || - formData.directors.trim() || - formData.writers.trim() || - formData.cast.trim(); + if (formData.searchType === 'mongodb-search') { + // Check if at least one search field has a value for MongoDB Search + const hasSearchInput = formData.plot.trim() || + formData.fullplot.trim() || + formData.directors.trim() || + formData.writers.trim() || + formData.cast.trim(); - if (!hasSearchInput) { - newErrors.general = 'Please enter search terms in at least one field'; + if (!hasSearchInput) { + newErrors.general = 'Please enter search terms in at least one field'; + } + } else if (formData.searchType === 'vector-search') { + // Check if query field has a value for Vector Search + if (!formData.q.trim()) { + newErrors.q = 'Please enter a search query.'; + } } // Validate limit @@ -86,27 +107,35 @@ export default function SearchMovieModal({ return; } - // Build search parameters, only including non-empty fields + // Build search parameters based on search type const searchParams: SearchParams = { - search_operator: formData.search_operator, + searchType: formData.searchType, limit: parseInt(formData.limit), - skip: 0, // Always start from beginning for new search }; - if (formData.plot.trim()) { - searchParams.plot = formData.plot.trim(); - } - if (formData.fullplot.trim()) { - searchParams.fullplot = formData.fullplot.trim(); - } - if (formData.directors.trim()) { - searchParams.directors = formData.directors.trim(); - } - if (formData.writers.trim()) { - searchParams.writers = formData.writers.trim(); - } - if (formData.cast.trim()) { - searchParams.cast = formData.cast.trim(); + if (formData.searchType === 'mongodb-search') { + // Add MongoDB Search specific parameters + searchParams.search_operator = formData.search_operator; + searchParams.skip = 0; // Always start from beginning for new search + + if (formData.plot.trim()) { + searchParams.plot = formData.plot.trim(); + } + if (formData.fullplot.trim()) { + searchParams.fullplot = formData.fullplot.trim(); + } + if (formData.directors.trim()) { + searchParams.directors = formData.directors.trim(); + } + if (formData.writers.trim()) { + searchParams.writers = formData.writers.trim(); + } + if (formData.cast.trim()) { + searchParams.cast = formData.cast.trim(); + } + } else if (formData.searchType === 'vector-search') { + // Add Vector Search specific parameters + searchParams.q = formData.q.trim(); } onSearch(searchParams); @@ -140,7 +169,10 @@ export default function SearchMovieModal({

Search Movies

- Search across movie plots, directors, writers, and cast. + {formData.searchType === 'mongodb-search' + ? 'Search across movie plots, directors, writers, and cast.' + : 'Find movies with similar plots using semantic search.' + }

{errors.general && ( @@ -150,135 +182,206 @@ export default function SearchMovieModal({ )}
- {/* Search Fields */} -
- {/* Plot Search */} -
- - handleInputChange('plot', e.target.value)} - className={`${styles.input} ${errors.plot ? styles.inputError : ''}`} - disabled={isLoading} - placeholder="Exact phrase search in plot summaries" - /> - {errors.plot && {errors.plot}} -
- - {/* Full Plot Search */} -
- - handleInputChange('fullplot', e.target.value)} - className={`${styles.input} ${errors.fullplot ? styles.inputError : ''}`} - disabled={isLoading} - placeholder="Search in full plot descriptions" - /> - {errors.fullplot && {errors.fullplot}} -
- - {/* Directors Search */} -
- - handleInputChange('directors', e.target.value)} - className={`${styles.input} ${errors.directors ? styles.inputError : ''}`} - disabled={isLoading} - placeholder="Director names" - /> - {errors.directors && {errors.directors}} -
- - {/* Writers Search */} -
- - handleInputChange('writers', e.target.value)} - className={`${styles.input} ${errors.writers ? styles.inputError : ''}`} - disabled={isLoading} - placeholder="Writer names" - /> - {errors.writers && {errors.writers}} -
- - {/* Cast Search */} -
- - handleInputChange('cast', e.target.value)} - className={`${styles.input} ${errors.cast ? styles.inputError : ''}`} - disabled={isLoading} - placeholder="Actor names" - /> - {errors.cast && {errors.cast}} -
- - {/* Limit */} -
- - handleInputChange('limit', e.target.value)} - className={`${styles.input} ${errors.limit ? styles.inputError : ''}`} - disabled={isLoading} - min="1" - max="100" - /> - {errors.limit && {errors.limit}} -
-
- - {/* Search Operator */} + {/* Search Type Selector */}
-
+ {/* Conditional Form Fields */} + {formData.searchType === 'mongodb-search' ? ( + <> + {/* MongoDB Search Fields */} +
+ {/* Plot Search */} +
+ + handleInputChange('plot', e.target.value)} + className={`${styles.input} ${errors.plot ? styles.inputError : ''}`} + disabled={isLoading} + placeholder="Exact phrase search in plot summaries" + /> + {errors.plot && {errors.plot}} +
+ + {/* Full Plot Search */} +
+ + handleInputChange('fullplot', e.target.value)} + className={`${styles.input} ${errors.fullplot ? styles.inputError : ''}`} + disabled={isLoading} + placeholder="Search in full plot descriptions" + /> + {errors.fullplot && {errors.fullplot}} +
+ + {/* Directors Search */} +
+ + handleInputChange('directors', e.target.value)} + className={`${styles.input} ${errors.directors ? styles.inputError : ''}`} + disabled={isLoading} + placeholder="Director names" + /> + {errors.directors && {errors.directors}} +
+ + {/* Writers Search */} +
+ + handleInputChange('writers', e.target.value)} + className={`${styles.input} ${errors.writers ? styles.inputError : ''}`} + disabled={isLoading} + placeholder="Writer names" + /> + {errors.writers && {errors.writers}} +
+ + {/* Cast Search */} +
+ + handleInputChange('cast', e.target.value)} + className={`${styles.input} ${errors.cast ? styles.inputError : ''}`} + disabled={isLoading} + placeholder="Actor names" + /> + {errors.cast && {errors.cast}} +
+ + {/* Limit */} +
+ + handleInputChange('limit', e.target.value)} + className={`${styles.input} ${errors.limit ? styles.inputError : ''}`} + disabled={isLoading} + min="1" + max="100" + /> + {errors.limit && {errors.limit}} +
+
+ + {/* Search Operator */} +
+ + + + {searchOperatorOptions.find(opt => opt.value === formData.search_operator)?.description} + +
+ + ) : ( + <> + {/* Vector Search Fields */} +
+ +