@@ -361,7 +361,10 @@ var options = new ODataOptions
361361| ` AdditionalFilter ` | ` string? ` | ` null ` | Static filter ANDed with search |
362362| ` CaseInsensitive ` | ` bool ` | ` true ` | Use tolower() wrapper |
363363| ` MinSearchLength ` | ` int ` | ` 1 ` | Min chars before API call |
364+ | ` TimeoutSeconds ` | ` int ` | ` 30 ` | HTTP request timeout |
364365| ` CustomHeaders ` | ` Dictionary<string,string>? ` | ` null ` | HTTP headers (e.g., Authorization) |
366+ | ` ResultsPropertyName ` | ` string ` | ` "value" ` | JSON property containing results |
367+ | ` IncludeCount ` | ` bool ` | ` false ` | Include $count in response |
365368
366369### Fluent Builder
367370
@@ -444,17 +447,143 @@ Configuration in `appsettings.json`:
444447
445448### AI Parameters
446449
447- | Parameter | Default | Description |
448- | -----------| ---------| -------------|
449- | ` SimilarityThreshold ` | ` 0.15 ` | Minimum cosine similarity (0-1) for results |
450- | ` MinSearchLength ` | ` 3 ` | Characters before semantic search triggers |
451- | ` DebounceMs ` | ` 500 ` | Delay before API call |
452- | ` ItemCacheDuration ` | ` 1 hour ` | Embedding cache TTL for items |
453- | ` QueryCacheDuration ` | ` 15 min ` | Embedding cache TTL for queries |
454- | ` MaxItemCacheSize ` | ` 10,000 ` | Maximum cached item embeddings |
455- | ` MaxQueryCacheSize ` | ` 1,000 ` | Maximum cached query embeddings |
456- | ` PreWarmCache ` | ` false ` | Generate all embeddings on init |
457- | ` ShowCacheStatus ` | ` true ` | Display cache statistics |
450+ | Parameter | Type | Default | Description |
451+ | -----------| ------| ---------| -------------|
452+ | ` SimilarityThreshold ` | ` float ` | ` 0.15 ` | Minimum cosine similarity (0-1) for results |
453+ | ` MinSearchLength ` | ` int ` | ` 3 ` | Characters before semantic search triggers |
454+ | ` DebounceMs ` | ` int ` | ` 500 ` | Delay before API call |
455+ | ` MaxResults ` | ` int? ` | ` null ` | Maximum results (null = all matching) |
456+ | ` ItemCacheDuration ` | ` TimeSpan ` | ` 1 hour ` | Embedding cache TTL for items |
457+ | ` QueryCacheDuration ` | ` TimeSpan ` | ` 15 min ` | Embedding cache TTL for queries |
458+ | ` MaxItemCacheSize ` | ` int ` | ` 10,000 ` | Maximum cached item embeddings |
459+ | ` MaxQueryCacheSize ` | ` int ` | ` 1,000 ` | Maximum cached query embeddings |
460+ | ` PreWarmCache ` | ` bool ` | ` false ` | Generate all embeddings on init |
461+ | ` ShowCacheStatus ` | ` bool ` | ` true ` | Display cache statistics |
462+
463+ ## Vector Database Providers
464+
465+ For production deployments with persistent storage and scalable semantic search, use external vector database providers. These eliminate the need to regenerate embeddings on restart and support millions of items.
466+
467+ ### Supported Providers
468+
469+ | Provider | Package | Features |
470+ | ----------| ---------| ----------|
471+ | PostgreSQL (pgvector) | ` EasyAppDev.Blazor.AutoComplete.AI.PostgreSql ` | Self-hosted, 6 distance functions (Cosine, L2, DotProduct, Manhattan, Hamming, Jaccard), HNSW index |
472+ | Azure AI Search | ` EasyAppDev.Blazor.AutoComplete.AI.AzureSearch ` | Hybrid search (vector + keyword), semantic ranking, managed service |
473+ | Pinecone | ` EasyAppDev.Blazor.AutoComplete.AI.Pinecone ` | Serverless, namespaces, automatic scaling |
474+ | Qdrant | ` EasyAppDev.Blazor.AutoComplete.AI.Qdrant ` | Open-source, self-hosted, advanced filtering |
475+ | Azure CosmosDB | ` EasyAppDev.Blazor.AutoComplete.AI.CosmosDb ` | Multi-model, global distribution, integrated NoSQL |
476+
477+ ### Quick Start (PostgreSQL)
478+
479+ ``` bash
480+ dotnet add package EasyAppDev.Blazor.AutoComplete.AI.PostgreSql
481+ ```
482+
483+ ``` csharp
484+ using EasyAppDev .Blazor .AutoComplete .AI .PostgreSql .Extensions ;
485+
486+ // Configure services
487+ builder .Services .AddAutoCompletePostgres <Product >(
488+ configureOptions : options =>
489+ {
490+ options .ConnectionString = " Host=localhost;Database=myapp;Username=user;Password=pass" ;
491+ options .CollectionName = " products" ;
492+ options .EmbeddingDimensions = 1536 ; // text-embedding-3-small
493+ },
494+ textSelector : p => $" {p .Name } {p .Description } {p .Category }" ,
495+ idSelector : p => p .Id .ToString ());
496+
497+ // Add OpenAI embeddings and vector search data source
498+ builder .Services .AddAutoCompleteVectorSearch <Product >(
499+ openAiApiKey : " sk-..." ,
500+ configureOptions : options =>
501+ {
502+ options .MaxResults = 20 ;
503+ options .MinSimilarityScore = 0 . 15 f ;
504+ });
505+ ```
506+
507+ Component usage is unchanged:
508+
509+ ``` razor
510+ <SemanticAutoComplete TItem="Product"
511+ TextField="@(p => p.Name)"
512+ @bind-Value="selectedProduct" />
513+ ```
514+
515+ ### Quick Start (Azure AI Search)
516+
517+ ``` bash
518+ dotnet add package EasyAppDev.Blazor.AutoComplete.AI.AzureSearch
519+ ```
520+
521+ ``` csharp
522+ using EasyAppDev .Blazor .AutoComplete .AI .AzureSearch .Extensions ;
523+
524+ builder .Services .AddAutoCompleteAzureSearch <Product >(
525+ configureOptions : options =>
526+ {
527+ options .Endpoint = " https://my-search.search.windows.net" ;
528+ options .ApiKey = " your-api-key" ;
529+ options .IndexName = " products" ;
530+ options .EnableHybridSearch = true ; // Vector + keyword search
531+ },
532+ textSelector : p => $" {p .Name } {p .Description }" ,
533+ idSelector : p => p .Id .ToString ());
534+
535+ builder .Services .AddAutoCompleteVectorSearchWithAzure <Product >(
536+ endpoint : " https://my-openai.openai.azure.com/" ,
537+ apiKey : " your-openai-key" ,
538+ deploymentName : " text-embedding-ada-002" ,
539+ configureOptions : options =>
540+ {
541+ options .EnableHybridSearch = true ;
542+ });
543+ ```
544+
545+ ### When to Use Vector Providers
546+
547+ | Scenario | Recommendation |
548+ | ----------| ----------------|
549+ | Development/Prototyping | Use in-memory ` SemanticSearchDataSource ` |
550+ | Small datasets (< 10K items) | Either approach works |
551+ | Production (> 10K items) | Use vector provider |
552+ | Need persistence across restarts | Use vector provider |
553+ | Multi-instance deployment | Use vector provider (shared database) |
554+ | Need hybrid search (vector + keyword) | Azure AI Search or CosmosDB |
555+
556+ ### Indexing Data
557+
558+ Before searching, index your data:
559+
560+ ``` csharp
561+ // Inject the indexer
562+ public class ProductService
563+ {
564+ private readonly IVectorIndexer <Product > _indexer ;
565+
566+ public async Task IndexProductsAsync (IEnumerable <Product > products )
567+ {
568+ // Ensure collection/index exists
569+ await _indexer .EnsureCollectionExistsAsync ();
570+
571+ // Index all items (with progress reporting)
572+ _indexer .ProgressChanged += (s , e ) =>
573+ Console .WriteLine ($" Indexed {e .ProcessedItems }/{e .TotalItems }" );
574+
575+ await _indexer .IndexAsync (products );
576+ }
577+
578+ public async Task IndexSingleProductAsync (Product product )
579+ {
580+ // Upsert single item
581+ await _indexer .IndexAsync (product );
582+ }
583+ }
584+ ```
585+
586+ See the [ Migration Guide] ( docs/migration-guide.md ) for detailed instructions on migrating from in-memory search to vector providers.
458587
459588## API Reference
460589
@@ -463,16 +592,16 @@ Configuration in `appsettings.json`:
463592| Parameter | Type | Default | Description |
464593| -----------| ------| ---------| -------------|
465594| ` Items ` | ` IEnumerable<TItem>? ` | ` null ` | Collection of items |
466- | ` DataSource ` | ` IAutoCompleteDataSource<TItem>? ` | ` null ` | Async data source |
595+ | ` DataSource ` | ` IAutoCompleteDataSource<TItem>? ` | ` null ` | Async data source (takes precedence over Items) |
467596| ` Value ` | ` TItem? ` | ` null ` | Selected value (two-way) |
468597| ` ValueChanged ` | ` EventCallback<TItem?> ` | | Selection change event |
469598| ` TextField ` | ` Expression<Func<TItem, string>>? ` | ` null ` | Display text property |
470599| ` SearchFields ` | ` Expression<Func<TItem, string[]>>? ` | ` null ` | Multi-field search |
471600| ` Placeholder ` | ` string? ` | ` null ` | Input placeholder |
472601| ` MinSearchLength ` | ` int ` | ` 1 ` | Min chars before search |
602+ | ` MaxSearchLength ` | ` int ` | ` 500 ` | Max input length (security, max 2000) |
473603| ` MaxDisplayedItems ` | ` int ` | ` 100 ` | Max items shown |
474604| ` DebounceMs ` | ` int ` | ` 300 ` | Debounce delay (ms) |
475- | ` MaxSearchLength ` | ` int ` | ` 500 ` | Max input length (security) |
476605| ` AllowClear ` | ` bool ` | ` true ` | Show clear button |
477606| ` Disabled ` | ` bool ` | ` false ` | Disable component |
478607| ` CloseOnSelect ` | ` bool ` | ` true ` | Close on selection |
@@ -500,9 +629,9 @@ Configuration in `appsettings.json`:
500629| Parameter | Type | Default | Description |
501630| -----------| ------| ---------| -------------|
502631| ` Theme ` | ` Theme ` | ` Auto ` | Light/Dark/Auto |
503- | ` ThemePreset ` | ` ThemePreset ` | ` None ` | Design system |
632+ | ` ThemePreset ` | ` ThemePreset ` | ` None ` | Design system (Material, Fluent, Modern, Bootstrap) |
504633| ` BootstrapTheme ` | ` BootstrapTheme ` | ` Default ` | Bootstrap color variant |
505- | ` Size ` | ` ComponentSize ` | ` Default ` | Component size |
634+ | ` Size ` | ` ComponentSize ` | ` Default ` | Component size (Compact, Default, Large) |
506635| ` EnableThemeTransitions ` | ` bool ` | ` true ` | Smooth transitions |
507636| ` RightToLeft ` | ` bool ` | ` false ` | RTL text direction |
508637| ` ThemeOverrides ` | ` ThemeOptions? ` | ` null ` | Structured overrides |
0 commit comments