PHPackages                             timm49/similar-content-laravel - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. timm49/similar-content-laravel

ActiveLibrary[API Development](/categories/api)

timm49/similar-content-laravel
==============================

A Laravel package to get similar content for recommendations, semantic search and more powered by AI

1.0.0(11mo ago)015MITPHPPHP ^8.2

Since Jun 9Pushed 9mo agoCompare

[ Source](https://github.com/Timm49/similar-content-laravel)[ Packagist](https://packagist.org/packages/timm49/similar-content-laravel)[ RSS](/packages/timm49-similar-content-laravel/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (6)Versions (4)Used By (0)

Similar Content Laravel
=======================

[](#similar-content-laravel)

Add content recommendations (e.g. “Related articles” or “You might also like”) and semantic search to your Laravel applications in a breeze with the power of AI.

What this package does
----------------------

[](#what-this-package-does)

This package simplifies adding content recommendations and semantic search to your Laravel application. You don't need any prior knowledge of AI, vectors, or embeddings—this package handles the complexity for you.

**Generate embeddings of your databases content**

Use the built-in Artisan command to generate embeddings for all existing records for all defined models. Once that's done you'll probably want to add a couple of lines your application code to handle it automatically when new records are created or updated. The embeddings are stored in your database. Optionally, you can enable auto\_generation, which generates embeddings automatically using model events (saved).

**Get similar content**

Retrieve similar content for a specific record and use it for a recommendation section, semantic searching or any other embedding related feature.

### See it in action

[](#see-it-in-action)

A simple example application using this package can be found here: [timm49/example-app-similar-content](https://github.com/Timm49/example-app-similar-content)

Installation
------------

[](#installation)

Install via Composer:

```
composer require timm49/similar-content-laravel
```

Run the installation command:

```
php artisan similar-content:install
```

Then run migrations:

```
php artisan migrate
```

Configuration
-------------

[](#configuration)

### OpenAI API Key

[](#openai-api-key)

config/similar\_content.php

```
return [
    'openai_api_key' => env('SIMILAR_CONTENT_OPENAI_API_KEY'), // OpenAI API Key
    'limit_similar_results' => 10, // how many items will be fetched for similar results
    'limit_search_results' => 10, // how many items will be fetched for search results
    'auto_generate' => false, // auto generate embeddings when a model is created/updated
    'cache_enabled' => false, // cache the similar content results
    'cache_ttl' => 3600,   // default ttl in seconds
];
```

Add the SIMILAR\_CONTENT\_OPENAI\_API\_KEY to your .env file

```
SIMILAR_CONTENT_OPENAI_API_KEY=some-key
```

### Auto Generate

[](#auto-generate)

If you want the package to automatically create/update embeddings using model events, you can do so by setting 'auto\_generate' in the config to true.

> Use carefully as this will call the API on every "saved" hook!

### Mark the models you want to retrieve similar content for

[](#mark-the-models-you-want-to-retrieve-similar-content-for)

Add the #\[HasEmbeddings\] attribute to the models you want to store embeddings for. Embeddings are necessary to find and compare similar items.

```
use Timm49\SimilarContentLaravel\Attributes\HasEmbeddings;

#[HasEmbeddings]
class Article extends Model
{
    use HasSimilarContent;
}
```

### Generating embeddings for existing records

[](#generating-embeddings-for-existing-records)

Run the artisan command to generate and store embeddings for the marked models:

```
php artisan similar-content:generate-embeddings
```

To generate embeddings for all records, including existing items, use the --force flag:

```
php artisan similar-content:generate-embeddings --force
```

To generate and store embeddings for a record from within your application code, use this:

```
SimilarContent::createEmbedding($article);
```

Retrieving similar content
--------------------------

[](#retrieving-similar-content)

Retrieving similar items for a record is as simple as:

```
$results = SimilarContent::getSimilarContent($article);
foreach ($results as $result) {
    echo "Found similar content (score: {$result->similarityScore}) with ID {$result->targetId}";
}
```

This will return an **array of `SimilarContentResult` objects**, each representing a similar record and its similarity score.

```
readonly class SimilarContentResult
{
    public function __construct(
        public string $sourceType,      // Class name of the original model
        public string $sourceId,        // ID of the original model
        public string $targetType,      // Class name of the similar model
        public string $targetId,        // ID of the similar model
        public float $similarityScore,  // Value between 0 and 1 (1 = identical)
    ) {
    }
}
```

Semantic search
---------------

[](#semantic-search)

You can also use this package to find records similar to a search query string, enabling semantic search in your application. Unlike traditional search, which matches exact words or phrases, semantic search understands the meaning behind the query — allowing users to find relevant results even if the wording doesn't exactly match.

Behind the scenes, the package sends the query (e.g. 'Donald Trump') to the OpenAI API to generate an embedding and compares it to your stored model embeddings.

Retrieving content similar to a query is as simple as:

```
SimilarContent::search('Donald Trump');
```

> This will search for similar content for ALL target types (models)

This will return an **array of `SearchResult` objects**, each representing a similar record and its similarity score.

```
readonly class SearchResult
{
    public function __construct(
        public string $id,             // ID of the similar model
        public string $type,           // Class name of the similar model
        public float $similarityScore, // Value between 0 and 1 (1 = identical)
    ) {
    }
}
```

To search only in "articles" and "pages", you can pass an array of models:

```
SimilarContent::search('Donald Trump', [
    Article::class,
    Page::class,
]);
```

Customizing Embedding Data
--------------------------

[](#customizing-embedding-data)

The package ships with a `HasSimilarContent` trait which you can use in your models. You can customize the default behavior by overriding the `getEmbeddingData()` method:

```
use Timm49\SimilarContentLaravel\Traits\HasSimilarContent;

class Article extends Model
{
    use HasSimilarContent;

    public function getEmbeddingData(): string
    {
        return $this->title . "\n" . $this->content;
    }
}
```

This gives you full control over:

- Which fields are included in the embedding
    - How the data is formatted
    - What text is used for similarity matching

> 📘 It's very important to include the right data for the right embedding purposes. I've added some links at the bottom of this README which should be helpful to get familiar with vector databases, embedding, etc.

How similarity is calculated
----------------------------

[](#how-similarity-is-calculated)

This package uses cosine similarity to compare content embeddings. After generating an embedding (a high-dimensional vector) for each model, it calculates the similarity between two records by measuring the cosine of the angle between their vectors.

- A cosine similarity of 1 means the embeddings are identical (perfect match)
    - A score of 0 means they are completely unrelated (orthogonal vectors)
    - The result is a value between 0 and 1, where higher values indicate stronger similarity

All similarity comparisons are done in PHP by loading and comparing vectors in memory.

⚠️ Database &amp; Performance Notes
-----------------------------------

[](#️-database--performance-notes)

This package **does not require a dedicated vector database** but now also supports pgvector for PostgreSQL users, in addition to working with standard SQL databases like MySQL and SQLite.

#### ✅ Benefits

[](#-benefits)

- Works out-of-the-box with your existing Laravel database setup — embeddings are stored in your current database, not a separate one.
- No need to maintain a separate vector store unless needed.
- With pgvector, similarity scoring can be offloaded to the database, improving performance for larger datasets.

#### ⚠️ Considerations

[](#️-considerations)

There are two different ways similarity is calculated, depending on your database setup:

#### PostgreSQL with pgvector support:

[](#postgresql-with-pgvector-support)

- If you're using the pgvector extension, the package leverages native vector operations.
- This allows similarity scores to be calculated directly in the database via SQL (e.g., 1 - (data &lt;#&gt; '...')), making queries significantly faster and scalable.
- **Note:** Due to differences in data types and precision handling, slight variations in similarity scores may occur compared to standard SQL databases.

#### Standard SQL databases (MySQL, SQLite, non-pgvector PostgreSQL, etc.):

[](#standard-sql-databases-mysql-sqlite-non-pgvector-postgresql-etc)

- The package loads all embeddings for the relevant model into memory and performs cosine similarity comparisons in PHP.
- This can lead to performance issues with a large number of records.
- Suitable for smaller or medium-sized datasets, but may not scale well with millions of embeddings.

> ℹ️ If you're running PostgreSQL and expect to work with a high volume of embeddings, enabling pgvector is highly recommended for better performance and scalability.

Useful resources
----------------

[](#useful-resources)

Here's some good resources to get you started:

- [Example Application](https://github.com/Timm49/example-app-similar-content) A Laravel application showcasing this package on dummy content. You can see the similarity results in action on both News Articles content, as well as ecommerce products.
- [Beginner Friendly Deep Dive On Vector Databases](https://www.dailydoseofds.com/a-beginner-friendly-and-comprehensive-deep-dive-on-vector-databases) Good to get you started
- [Evaluating Vector Databases 101](https://medium.com/tr-labs-ml-engineering-blog/evaluating-vector-databases-101-5f87a2366bb1) – A comprehensive guide to understanding vector DB architecture, indexing, filtering, ANN algorithms, and how to evaluate different options for production use.
- [OpenAI Embeddings Documentation](https://platform.openai.com/docs/guides/embeddings) Official OpenAI docs

Alternatives
------------

[](#alternatives)

Similar packages with a slightly different approach:

- [5am-code/ada-laravel](https://github.com/5am-code/ada-laravel) Uses vector database

Contributing
------------

[](#contributing)

Contributions are welcome! Please submit issues and pull requests.

License
-------

[](#license)

MIT © Timm49

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance54

Moderate activity, may be stable

Popularity6

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 85.7% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

3

Last Release

335d ago

Major Versions

0.0.2 → 1.0.02025-06-12

### Community

Maintainers

![](https://www.gravatar.com/avatar/6c246d1354ca721211d96c0f238148c7abc3b6326b690708945ace6b6ead1417?d=identicon)[Timm49](/maintainers/Timm49)

---

Top Contributors

[![Timm49](https://avatars.githubusercontent.com/u/1558967?v=4)](https://github.com/Timm49 "Timm49 (6 commits)")[![raregastjoh](https://avatars.githubusercontent.com/u/219139295?v=4)](https://github.com/raregastjoh "raregastjoh (1 commits)")

---

Tags

phplaravelaiopenaiembeddingsrecommendationvector-searchsemantic-searchsimilar contentcontent similarity

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/timm49-similar-content-laravel/health.svg)

```
[![Health](https://phpackages.com/badges/timm49-similar-content-laravel/health.svg)](https://phpackages.com/packages/timm49-similar-content-laravel)
```

###  Alternatives

[openai-php/laravel

OpenAI PHP for Laravel is a supercharged PHP API client that allows you to interact with the Open AI API

3.7k7.6M74](/packages/openai-php-laravel)[resend/resend-laravel

Resend for Laravel

1191.4M6](/packages/resend-resend-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
