memperbaiki cost/benefit

This commit is contained in:
iFannJR 2026-06-02 21:58:50 +07:00
parent 4b2a9130cd
commit e68e59a169
3 changed files with 72 additions and 16 deletions

View File

@ -29,7 +29,7 @@ public function getRecommendations(array $input): Collection
$criterias = Criteria::orderBy('weight_order')->get(); $criterias = Criteria::orderBy('weight_order')->get();
if ($criterias->isEmpty()) { if ($criterias->isEmpty()) {
return $products->take(5)->map(fn ($p, $i) => [ return $products->take(5)->map(fn($p, $i) => [
'rank' => $i + 1, 'rank' => $i + 1,
'product' => $p, 'product' => $p,
'score' => 0.0, 'score' => 0.0,
@ -47,7 +47,7 @@ public function getRecommendations(array $input): Collection
return $ranked->map(function ($item, $index) use ($products, $criteriaNames, $priorities) { return $ranked->map(function ($item, $index) use ($products, $criteriaNames, $priorities) {
$product = $products->firstWhere('id', $item['product_id']); $product = $products->firstWhere('id', $item['product_id']);
if (! $product) { if (!$product) {
return null; return null;
} }
$explanation = $this->buildExplanation($product, $item['score'], $priorities, $criteriaNames); $explanation = $this->buildExplanation($product, $item['score'], $priorities, $criteriaNames);
@ -87,7 +87,7 @@ public function getRecommendationsWithMatrix(array $input): array
$criterias = Criteria::orderBy('weight_order')->get(); $criterias = Criteria::orderBy('weight_order')->get();
if ($criterias->isEmpty()) { if ($criterias->isEmpty()) {
$recommendations = $products->take(5)->map(fn ($p, $i) => [ $recommendations = $products->take(5)->map(fn($p, $i) => [
'rank' => $i + 1, 'rank' => $i + 1,
'product' => $p, 'product' => $p,
'score' => 0.0, 'score' => 0.0,
@ -110,7 +110,7 @@ public function getRecommendationsWithMatrix(array $input): array
$ranked = $scores->sortByDesc('score')->take(5)->values(); $ranked = $scores->sortByDesc('score')->take(5)->values();
$topProductIds = $ranked->pluck('product_id')->all(); $topProductIds = $ranked->pluck('product_id')->all();
$rankedScoresByProductId = $ranked $rankedScoresByProductId = $ranked
->mapWithKeys(fn ($item) => [$item['product_id'] => round($item['score'], 4)]) ->mapWithKeys(fn($item) => [$item['product_id'] => round($item['score'], 4)])
->all(); ->all();
$criteriasWithWeight = []; $criteriasWithWeight = [];
@ -125,7 +125,7 @@ public function getRecommendationsWithMatrix(array $input): array
$decisionMatrix = []; $decisionMatrix = [];
foreach ($topProductIds as $productId) { foreach ($topProductIds as $productId) {
$row = $matrix[$productId] ?? null; $row = $matrix[$productId] ?? null;
if (! $row) { if (!$row) {
continue; continue;
} }
$product = $products->firstWhere('id', $productId); $product = $products->firstWhere('id', $productId);
@ -139,7 +139,7 @@ public function getRecommendationsWithMatrix(array $input): array
$normalizedMatrix = []; $normalizedMatrix = [];
foreach ($topProductIds as $productId) { foreach ($topProductIds as $productId) {
$row = $normalized[$productId] ?? null; $row = $normalized[$productId] ?? null;
if (! $row) { if (!$row) {
continue; continue;
} }
$product = $products->firstWhere('id', $productId); $product = $products->firstWhere('id', $productId);
@ -156,7 +156,7 @@ public function getRecommendationsWithMatrix(array $input): array
$criteriaNames = $criterias->keyBy('id')->map->name; $criteriaNames = $criterias->keyBy('id')->map->name;
$recommendations = $ranked->map(function ($item, $index) use ($products, $criteriaNames, $priorities) { $recommendations = $ranked->map(function ($item, $index) use ($products, $criteriaNames, $priorities) {
$product = $products->firstWhere('id', $item['product_id']); $product = $products->firstWhere('id', $item['product_id']);
if (! $product) { if (!$product) {
return null; return null;
} }
$explanation = $this->buildExplanation($product, $item['score'], $priorities, $criteriaNames); $explanation = $this->buildExplanation($product, $item['score'], $priorities, $criteriaNames);
@ -205,23 +205,33 @@ protected function ageRangeOverlaps(string $ageRange, int $childMin, int $childM
protected function buildWeightsFromPriorities(array $priorities, Collection $criterias): array protected function buildWeightsFromPriorities(array $priorities, Collection $criterias): array
{ {
// priorities: [criteria_id => 1..5]
// return weights by criteria name: ['Harga' => 0.2, 'Kualitas' => 0.2, ...]
$raw = []; $raw = [];
$sum = 0.0; $sum = 0.0;
foreach ($criterias as $c) { foreach ($criterias as $c) {
$w = (float) ($priorities[(string) $c->id] ?? $priorities[$c->id] ?? 1);
if ($w < 1) $w = 1; $input = (int) ($priorities[(string) $c->id] ?? $priorities[$c->id] ?? 3);
if ($w > 5) $w = 5;
if ($input < 1)
$input = 1;
if ($input > 5)
$input = 5;
// Jika Cost, dibalik
if ($c->type === 'cost') {
$w = 6 - $input;
} else {
$w = $input;
}
$raw[$c->name] = $w; $raw[$c->name] = $w;
$sum += $w; $sum += $w;
} }
$count = max(1, $criterias->count());
$weights = []; $weights = [];
foreach ($raw as $name => $v) {
$weights[$name] = $sum > 0 ? $v / $sum : 1 / $count; foreach ($raw as $name => $value) {
$weights[$name] = $value / $sum;
} }
return $weights; return $weights;
@ -240,7 +250,7 @@ protected function buildMatrix(Collection $products, Collection $criterias): arr
} }
} }
foreach ($criterias as $c) { foreach ($criterias as $c) {
if (! isset($row[$c->name])) { if (!isset($row[$c->name])) {
$row[$c->name] = $c->name === 'Harga' ? (float) $product->price : 0; $row[$c->name] = $c->name === 'Harga' ? (float) $product->price : 0;
} }
} }

View File

@ -0,0 +1,25 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('products', function (Blueprint $table) {
$table->longBlob('image_blob')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
//
}
};

View File

@ -0,0 +1,21 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
public function up(): void
{
Schema::table('products', function (Blueprint $table) {
$table->binary('image_blob')->nullable()->after('image');
});
}
public function down(): void
{
Schema::table('products', function (Blueprint $table) {
$table->dropColumn('image_blob');
});
}
};