Skip to content

Add vector embeddings for search queries#20

Merged
onmax merged 27 commits intomainfrom
jsdanielh/main
Oct 8, 2025
Merged

Add vector embeddings for search queries#20
onmax merged 27 commits intomainfrom
jsdanielh/main

Conversation

@jsdanielh
Copy link
Copy Markdown
Member

Add vector embedding for search queries.

This closes #11.

@nuxthub-admin
Copy link
Copy Markdown
Contributor

nuxthub-admin bot commented Oct 7, 2025

✅ Deployed crypto-map-next

Deployed crypto-map-next 6133dc7 to preview

🔗 crypto-map-next-preview.je-cf9.workers.dev
📌 57bec7b0-crypto-map-next-preview.je-cf9.workers.dev
📱
View QR Code QR code linking to deployment URL.

📋 View deployment logs

Use a bash script for generating embeddings since node is not
available in the database container image.
Comment on lines 56 to 57
export type Location = typeof locations.$inferSelect
export type LocationCategory = typeof locationCategories.$inferSelect
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This was my mistake. This kind of types are defined in ~/shared/types. defining the types here seems to no give us anything.

/docker-entrypoint-initdb.d/03-seed.sh || true

# Run the vector embeddings generation
echo "Running vector embeddings generation on startup..."
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This morning the whole docker/supabase thing was refactored completely. I think this might create a mergin issue. I will fix it in this PR :)

Copy link
Copy Markdown
Member

@onmax onmax left a comment

Choose a reason for hiding this comment

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

would you like to have a call?

Comment on lines +228 to +235
if (error instanceof Error && error.message.includes('OpenAI API key')) {
consola.warn('OpenAI API key not configured, falling back to keyword-only search')
}
else if (error instanceof Error && error.message.includes('OpenAI authentication')) {
consola.warn('OpenAI authentication failed, falling back to keyword-only search')
}
else if (error instanceof Error && error.message.includes('vector')) {
consola.warn('Vector database operations failed, falling back to keyword-only search')
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

i would remove this completely. Just use

throw createError(error)

createError is a function from h3.

if we needed it we can always add more details later, but let;s keep the code clean i would say

Comment on lines +84 to +117
private static validateVectorSearchConfig(
config: any,
errors: string[],
warnings: string[],
): void {
if (typeof config.keywordLimit !== 'number' || config.keywordLimit < 1 || config.keywordLimit > 100) {
errors.push('VECTOR_SEARCH_KEYWORD_LIMIT must be a number between 1 and 100')
}

if (typeof config.vectorLimit !== 'number' || config.vectorLimit < 1 || config.vectorLimit > 100) {
errors.push('VECTOR_SEARCH_VECTOR_LIMIT must be a number between 1 and 100')
}

if (typeof config.hybridThreshold !== 'number' || config.hybridThreshold < 1 || config.hybridThreshold > 50) {
errors.push('VECTOR_SEARCH_HYBRID_THRESHOLD must be a number between 1 and 50')
}

if (typeof config.similarityThreshold !== 'number' || config.similarityThreshold < 0 || config.similarityThreshold > 1) {
errors.push('VECTOR_SEARCH_SIMILARITY_THRESHOLD must be a number between 0 and 1')
}

// Logical validation
if (config.hybridThreshold > config.keywordLimit) {
warnings.push('VECTOR_SEARCH_HYBRID_THRESHOLD is greater than VECTOR_SEARCH_KEYWORD_LIMIT. Vector search may never be triggered.')
}

if (config.similarityThreshold > 0.9) {
warnings.push('VECTOR_SEARCH_SIMILARITY_THRESHOLD is very high (>0.9). This may result in very few vector search results.')
}

if (config.similarityThreshold < 0.3) {
warnings.push('VECTOR_SEARCH_SIMILARITY_THRESHOLD is very low (<0.3). This may result in many irrelevant vector search results.')
}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This kind of check adds complexity. we can always improve the safeRuntimeConfig to add these checks.

/**
* Nitro plugin to validate configuration during server startup
*/
export default defineNitroPlugin(async (_nitroApp) => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

since the validateVectorSearchConfig is unnecessary, this whole plugin is also unnecessary imo

/**
* Validate all required environment variables and configuration
*/
static validateConfiguration(): void {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

not needed this whole file

/**
* Service for generating embeddings using OpenAI API
*/
export class EmbeddingService {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this is way too much code.

we can use something like this https://ai-sdk.dev/docs/ai-sdk-core/embeddings#embedding-a-single-value

Then setup the OPENAI_API_KEY in .env and it should be more than enough.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

config such as maxRetries: 3,
baseDelay: 1000, // 1 second
maxDelay: 30000, // 30 seconds
batchSize: 100, // OpenAI batch limit

not necessaary in m opinion. the ai sdk provides that for us

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

also the "batch" optimization is also not ncessary.

I would suggest to run a embedding manually for the categories and put the result in the database/seed The scrit can be run with tsx and ai sdk. We should run it only once.

in the future if we update the categories, then we run it again.

onmax added 8 commits October 8, 2025 08:03
- Remove Location type from schema (use shared/types)
- Simplify error handling in search endpoint
- Remove config validation (use safeRuntimeConfig)
- Remove location embeddings (only category embeddings)
- Revert to named catalog structure in workspace
- Remove vector search dependencies and config
- Add full-text search on location name and address
- Add category similarity search using embeddings
- Cache query embeddings in NuxtHub KV (30 day TTL)
- Combine text and category results with deduplication
- Use AI SDK for embedding generation
- Support user-selected category filters
- Add /api/search/autocomplete for fast full-text search
- Add /api/search/embed for background embedding precompute
- Remove TTL from embedding cache (permanent storage)
- Min query length: 2 characters
- Add form-based autocomplete with search icon
- Show user's query as first result
- Display matching locations below with map pin icons
- Precompute embeddings while typing (background)
- Support UUID-based location fetching
- Extract locationSelect helper to reduce duplication
- Use semantic search when submitting user's query
- Use direct UUID fetch when selecting location
- Format template to one line per element
- Use @submit.prevent for form submission
- Remove icons from autocomplete locations
- Add PostgreSQL ts_headline for match highlighting
- Style <mark> tags as bold (no background)
- Move search.get.ts to search/index.get.ts
@onmax onmax merged commit 3c2fecd into main Oct 8, 2025
1 check passed
@jsdanielh jsdanielh deleted the jsdanielh/main branch October 8, 2025 22:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve Search: Multi-language, Synonyms, and Relevance

2 participants