# Implementing AI Semantic Search with OpenAI Embeddings in prompts.chat

> Learn how prompts.chat implements AI semantic search using OpenAI embeddings to find meaning-based results. Discover cosine similarity and custom thresholds for efficient search.

- Repository: [Fatih Kadir Akın/prompts.chat](https://github.com/f/prompts.chat)
- Tags: how-to-guide
- Published: 2026-04-02

---

**prompts.chat implements AI semantic search by generating OpenAI embeddings for prompts, computing cosine similarity against translated query vectors, and surfacing meaning-based results above a configurable 0.4 threshold.**

The `prompts.chat` repository adds a sophisticated semantic layer that enables users to discover prompts by conceptual meaning rather than exact keyword matches. This functionality relies on OpenAI's embedding models and is controlled through a centralized feature flag system. The implementation spans embedding generation, query preprocessing, similarity scoring, and hybrid search integration across the Next.js application.

## How Semantic Search Works in prompts.chat

The semantic search pipeline operates through a sequence of validation, translation, vectorization, and scoring steps. Every entry point first validates that the feature is enabled and that the required API credentials are present.

### Feature Flag Configuration

Before any AI processing occurs, the system checks `isAISearchEnabled()` in [`src/lib/ai/embeddings.ts`](https://github.com/f/prompts.chat/blob/main/src/lib/ai/embeddings.ts)【L93-L96】. This function verifies both the `features.aiSearch` flag defined in the platform configuration and the presence of `process.env.OPENAI_API_KEY`. If either check fails, the pipeline returns graceful fallbacks to traditional text search.

```typescript
// prompts.config.ts
export const config = {
  features: {
    aiSearch: true, // Enable AI-semantic search
  },
};

```

### Query Translation Pipeline

Non-English queries are automatically translated to maximize embedding accuracy. The `containsNonEnglish` utility detects non-ASCII characters, triggering `translateQueryToEnglish` to convert the input using `gpt-4o-mini`【L28-L68】. This ensures that the subsequent embedding generation operates on English keyword strings, matching the embedding space of the stored prompts.

```typescript
// src/lib/ai/embeddings.ts
async function translateQueryToEnglish(text: string): Promise<string> {
  // Uses gpt-4o-mini for cost-effective translation
  // Returns English keyword string for embedding
}

```

### Embedding Generation and Similarity Scoring

The (translated) query is vectorized using OpenAI's `text-embedding-3-small` model via `generateEmbedding`【L70-L78】. The system then retrieves all public prompts with pre-computed embeddings and calculates cosine similarity against the query vector. Only results exceeding the **0.4 similarity threshold** are retained【L121-L132】.

The `semanticSearch` function sorts matches by similarity score and returns the top *n* results (default 20)【L72-L89】. The public API endpoint at [`src/app/api/search/ai/route.ts`](https://github.com/f/prompts.chat/blob/main/src/app/api/search/ai/route.ts) packages these results with metadata including the original query and result count【L24-L32】.

## Core Implementation Files

### Embedding Utilities (embeddings.ts)

The [`src/lib/ai/embeddings.ts`](https://github.com/f/prompts.chat/blob/main/src/lib/ai/embeddings.ts) file serves as the central nervous system for all embedding operations. It exports `generatePromptEmbedding` for single prompt processing and `generateAllEmbeddings` for bulk operations【L81-L119】【L150-L170】. The file also implements vector math utilities including cosine similarity calculations essential for the ranking algorithm.

Key functions include:
- **`generateEmbedding`** - Creates 1536-dimensional vectors using OpenAI's API
- **`semanticSearch`** - Orchestrates the similarity computation and filtering
- **`findAndSaveRelatedPrompts`** - Discovers semantically related content for the "related prompts" feature【L298-L364】

### Search API Endpoint (route.ts)

The `/api/search/ai` route in [`src/app/api/search/ai/route.ts`](https://github.com/f/prompts.chat/blob/main/src/app/api/search/ai/route.ts) exposes semantic search to the frontend. It validates the feature flag, accepts query parameters for search terms and result limits, and returns a JSON response containing the ranked prompt objects.

### Hybrid Search Integration (prompt-builder-tools.ts)

The Prompt Builder UI leverages a hybrid approach through [`src/lib/ai/prompt-builder-tools.ts`](https://github.com/f/prompts.chat/blob/main/src/lib/ai/prompt-builder-tools.ts). The `executeToolCall` function with the `"search_prompts`" tool runs traditional full-text search in parallel with semantic search, merging and deduplicating results【L54-L108】. If neither search yields results, the system falls back to recent random prompts to provide stylistic examples.

## Database Schema and Maintenance

### Storing Embeddings in Prisma

The Prisma schema defines the `Prompt` model with an `embedding` column storing the vector representation. A separate `PromptConnection` table maintains "related" relationships between prompts of the same type, populated by the semantic similarity engine.

```typescript
// src/prisma/schema.prisma
model Prompt {
  id        String   @id @default(uuid())
  embedding Float[]? // Vector storage for semantic search
  // ... other fields
}

model PromptConnection {
  id       String @id @default(uuid())
  label    String // "related" for semantic matches
  // ... connection fields
}

```

### Bulk Regeneration Strategy

Administrators can trigger bulk embedding generation via the `/api/admin/embeddings` route. The `generateAllEmbeddings` function processes the entire catalog with progress callbacks, reporting success and error counts for monitoring【L150-L170】.

```typescript
// Triggered via /api/admin/embeddings?regenerate=true
await generateAllEmbeddings((current, total, ok, err) => {
  console.log(`Progress: ${current}/${total} – ✅ ${ok} ❌ ${err}`);
}, true);

```

## Related Prompt Discovery

Beyond search, the embedding system powers content recommendation through `findAndSaveRelatedPrompts`【L298-L364】. When a prompt's embedding is generated, this function identifies up to four nearest neighbors of the same type and persists them as `PromptConnection` records with the label `"related"`. This creates a semantic graph that suggests conceptually similar prompts in the UI.

## Practical Implementation Examples

### Enabling AI Search in Configuration

```typescript
// prompts.config.ts
export const config = {
  features: {
    aiSearch: true,
  },
};

```

### Generating Embeddings for New Prompts

```typescript
import { generatePromptEmbedding } from "@/lib/ai/embeddings";

export async function createPrompt(data: PromptCreateInput) {
  const prompt = await db.prompt.create({ data });
  // Store embedding for public prompts only
  await generatePromptEmbedding(prompt.id);
  return prompt;
}

```

### Client-Side Semantic Search

```typescript
async function semanticSearch(query: string, limit = 20) {
  const res = await fetch(
    `/api/search/ai?q=${encodeURIComponent(query)}&limit=${limit}`
  );
  if (!res.ok) throw new Error("Search failed");
  return res.json(); // { results, query, count }
}

```

### Using the Hybrid Search Tool

```typescript
import { executeToolCall } from "@/lib/ai/prompt-builder-tools";

const { result } = await executeToolCall(
  "search_prompts",
  { query: "image generation", limit: 5, promptType: "IMAGE" },
  currentState,
  availableTags,
  availableCategories
);

if (result.success) {
  console.log("Found prompts:", result.data.prompts);
}

```

## Summary

- **Feature gating**: All AI search functionality is controlled by `features.aiSearch` and validated through `isAISearchEnabled()` before processing.
- **Query preprocessing**: Non-English queries are translated using `gpt-4o-mini` to ensure optimal embedding quality with `text-embedding-3-small`.
- **Similarity threshold**: Results are filtered at **0.4 cosine similarity** and ranked before returning the top 20 matches.
- **Hybrid architecture**: The Prompt Builder combines traditional text search with semantic vectors for comprehensive result coverage.
- **Maintenance automation**: Bulk regeneration via `/api/admin/embeddings` and automatic related-prompt linking keep the semantic index current.

## Frequently Asked Questions

### What embedding model does prompts.chat use for semantic search?

The implementation uses OpenAI's `text-embedding-3-small` model as specified in [`src/lib/ai/embeddings.ts`](https://github.com/f/prompts.chat/blob/main/src/lib/ai/embeddings.ts)【L70-L78】. This model provides a balance between vector quality and API cost, generating 1536-dimensional embeddings that are stored directly in the PostgreSQL database via Prisma's Float array type.

### How does the system handle non-English search queries?

When `containsNonEnglish` detects non-ASCII characters in the query, the system invokes `translateQueryToEnglish` which utilizes `gpt-4o-mini` to produce an English keyword string【L28-L68】. This translation step ensures the query embedding aligns with the English-based prompt embeddings in the database, maintaining search accuracy across languages without requiring multilingual embedding models.

### What is the similarity threshold for returning semantic search results?

The system filters results using a **0.4 cosine similarity threshold** defined in the `semanticSearch` function【L121-L132】. Only prompts with similarity scores exceeding this value are included in the final result set, ensuring that returned items demonstrate genuine semantic relevance rather than weak statistical associations.

### How are related prompts discovered and stored?

The `findAndSaveRelatedPrompts` function in [`src/lib/ai/embeddings.ts`](https://github.com/f/prompts.chat/blob/main/src/lib/ai/embeddings.ts) computes vector similarity between a target prompt and all other prompts of the same type【L298-L364】. It selects up to four nearest neighbors and persists them in the `PromptConnection` table with the label `"related"`, creating a semantic recommendation graph that the UI can query to suggest related content.