It is tedious, inconsistent, and frequently incorrect to manually tag blog posts. With AI embeddings, Laravel can automatically determine the topic of a blog post and assign the appropriate tags without the need for human intervention.
This guide demonstrates how to create a complete Laravel AI auto-tagging system using:
- The OpenAI Embeddings API
- Laravel Jobs & Queues
- Cron Scheduler
- Tag → Vector Matching
- Automatic Tag Assignment
This is one of the most useful AI enhancements for any Laravel-based CMS or blog system.
What We're Constructing
You'll construct:
- Table of Tag Vector - The meaning of each tag (such as "PHP", "Laravel", "Security", and "AI") will be represented by an embedding vector created by AI.
- A Generator for Post Embedding - We generate an embedding for the post content whenever a new post is saved.
- A Matching Algorithm - The system determines which post embeddings are closest by comparing them with tag embeddings.
- A Cron Job -The system automatically assigns AI-recommended tags every hour (or on any schedule).
This is ideal for:
- Custom blogs made with Laravel
- Headless CMS configurations
- Tagging categories in e-commerce
- Auto-classification of knowledge bases
- Websites for documentation
Now let's get started.
Step 1: Create Migration for Tag Embeddings
Run:
php artisan make:migration create_tag_embeddings_table
Migration:
public function up()
{
Schema::create('tag_embeddings', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tag_id')->unique();
$table->json('embedding'); // store vector
$table->timestamps();
});
}
Run:
php artisan migrate
Step 2: Generate Embeddings for Tags
Create a command:
php artisan make:command GenerateTagEmbeddings
Add logic:
public function handle()
{
$tags = Tag::all();
foreach ($tags as $tag) {
$vector = $this->embed($tag->name);
TagEmbedding::updateOrCreate(
['tag_id' => $tag->id],
['embedding' => json_encode($vector)]
);
$this->info("Embedding created for tag: {$tag->name}");
}
}
private function embed($text)
{
$client = new \GuzzleHttp\Client();
$response = $client->post("https://api.openai.com/v1/embeddings", [
"headers" => [
"Authorization" => "Bearer " . env('OPENAI_API_KEY'),
"Content-Type" => "application/json",
],
"json" => [
"model" => "text-embedding-3-large",
"input" => $text
]
]);
$data = json_decode($response->getBody(), true);
return $data['data'][0]['embedding'] ?? [];
}
Run once:
php artisan generate:tag-embeddings
Now all tags have AI meaning vectors.
Step 3: Save Embeddings for Each Post
Add to your Post model observer or event.
$post->embedding = $this->embed($post->content);
$post->save();
Migration for posts:
$table->json('embedding')->nullable();
Step 4: Matching Algorithm (Post → Tags)
Create a helper class:
class EmbeddingHelper
{
public static function cosineSimilarity($a, $b)
{
$dot = array_sum(array_map(fn($i, $j) => $i * $j, $a, $b));
$magnitudeA = sqrt(array_sum(array_map(fn($i) => $i * $i, $a)));
$magnitudeB = sqrt(array_sum(array_map(fn($i) => $i * $i, $b)));
return $dot / ($magnitudeA * $magnitudeB);
}
}
Step 5: Assign Tags Automatically (Queue Job)
Create job:
php artisan make:job AutoTagPost
Job logic:
public function handle()
{
$postEmbedding = json_decode($this->post->embedding, true);
$tags = TagEmbedding::with('tag')->get();
$scores = [];
foreach ($tags as $te) {
$sim = EmbeddingHelper::cosineSimilarity(
$postEmbedding,
json_decode($te->embedding, true)
);
$scores[$te->tag->id] = $sim;
}
arsort($scores); // highest similarity first
$best = array_slice($scores, 0, 5, true); // top 5 matches
$this->post->tags()->sync(array_keys($best));
}
Step 6: Cron Job to Process New Posts
Add to app/Console/Kernel.php:
protected function schedule(Schedule $schedule)
{
$schedule->command('ai:autotag-posts')->hourly();
}
Create command:
php artisan make:command AutoTagPosts
Command logic:
public function handle()
{
$posts = Post::whereNull('tags_assigned_at')->get();
foreach ($posts as $post) {
AutoTagPost::dispatch($post);
$post->update(['tags_assigned_at' => now()]);
}
}
Now, every hour, Laravel processes all new posts and assigns AI-selected tags.
Step 7: Test the Full Flow
- Create tags in admin
- Run: php artisan generate:tag-embeddings
- Create a new blog post
- Cron or queue runs
- Post automatically gets AI-selected tags
Useful enhancements
- Weight tags by frequency
- Use title + excerpt, not full content
- Add confidence scores to DB
- Auto-create new tags using AI
- Add a manual override UI
- Cache embeddings for performance
- Batch process 1,000+ posts
Next up, we’ll build a AI Category Recommendation for Drupal 11
0 comments:
Post a Comment