Laravel · Gender prediction
Queue gender enrichment jobs in Laravel
EnrichCustomerGender is a queued job that takes up to 50 customer ids, loads the models, and sends them to /v1/gender/batch as name items with an optional country_code hint. array_filter removes the country key when a customer has none, keeping each item valid. Results come back in order with each item's id, so the job updates the matching Customer through the keyed collection without another query.
The job saves result_status for every prediction, including unknown ones, where gender is null and no further lookups are needed. Item errors are skipped so a later run can try them again. On a 429 rate_limited response the job releases itself for the Retry-After period. Every other failure calls fail, because a batch that fails validation, lacks credits or hits a server error should not be resent automatically.
Steps
- 1
Add gender_status, predicted_gender and gender_confidence columns with a migration and make them fillable.
- 2
Create the job with php artisan make:job EnrichCustomerGender and paste in the example.
- 3
Dispatch it in chunks of 50 from a scheduled Artisan command, as shown at the bottom.
- 4
Run a queue worker and inspect a few rows, including ones that came back unknown.
- 5
Use the stored values only in aggregate reports or as profile suggestions customers can edit.
php artisan make:rule NotBreachedPassword
php artisan make:listener CheckEmailBreaches --event="Illuminate\Auth\Events\Registered"
php artisan make:job EnrichCustomerGender<?php
// app/Jobs/EnrichCustomerGender.php
namespace App\Jobs;
use App\Exceptions\FinowlException;
use App\Models\Customer;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Http;
class EnrichCustomerGender implements ShouldQueue
{
use Queueable;
/** @param array<int, int> $customerIds at most 50, one batch request per job */
public function __construct(public array $customerIds) {}
public function handle(): void
{
$customers = Customer::whereKey($this->customerIds)->get()->keyBy('id');
$items = $customers->map(fn (Customer $c) => array_filter([
'id' => (string) $c->id,
'type' => 'name',
'value' => $c->first_name,
'country' => $c->country_code, // optional ISO 3166-1 alpha-2 hint
]))->values()->all();
$response = Http::finowl()->timeout(30)->post('/v1/gender/batch', ['items' => $items]);
if ($response->failed()) {
$error = FinowlException::fromResponse($response);
if ($error->status === 429 && $error->errorCode === 'rate_limited') {
$this->release($error->retryAfter ?? 60); // nothing ran, safe to try again
return;
}
$this->fail($error); // 400, 401, quota_exceeded or 5xx: never resend blindly
return;
}
foreach ($response->json('data') as $row) {
if (isset($row['error'])) {
continue; // item-level failure; it stays null and a later run picks it up
}
$prediction = $row['data'];
$customers[(int) $row['id']]->update([
'gender_status' => $prediction['result_status'], // identified or unknown
'predicted_gender' => $prediction['gender'], // null when unknown
'gender_confidence' => $prediction['confidence'],
]);
}
}
}
// Dispatch in chunks of 50, e.g. from a scheduled command:
// Customer::whereNull('gender_status')->where('first_name', '!=', '')
// ->chunkById(50, fn ($chunk) => EnrichCustomerGender::dispatch($chunk->modelKeys()));IN PRODUCTION
Production tips
Filter out customers with empty first names before dispatching. Batch validation is all or nothing, so one invalid item makes the request return 400 and none of the names are processed.
Add the RateLimited job middleware with a shared limiter slightly under 60 per minute, so several queue workers together stay inside your account's request limit.
Keep predicted_gender separate from any gender column customers fill in themselves. Predictions estimate typical name usage and can be wrong for individuals, so the customer's own answer always wins.
Each lookup costs 1 credit (3 when it requests AI), with 100 free credits every month. See pricing and error codes.
A FEW GOOD QUESTIONS
Common questions
Related guides
- Check email breaches in Laravel with a queued listener
- Validate breached passwords with a Laravel rule
- Predict gender from names in Python
- Predict gender from a name in Node.js
- Batch gender prediction in TypeScript
- Predict gender from names in Go with net/http
- Gender analytics from names for fintech audiences
- Gender insights from names for e-commerce analytics
- Gender estimates for SaaS user research and analytics
Queue gender enrichment jobs in Laravel
Grab an API key, paste the example and run it. 100 free credits every month.