231 lines
8.8 KiB
PHP
231 lines
8.8 KiB
PHP
<?php
|
|
|
|
namespace Database\Seeders;
|
|
|
|
use App\Helpers\FirstParty\AI\CloudflareAI;
|
|
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
|
use Illuminate\Database\Seeder;
|
|
use App\Models\Category;
|
|
use Illuminate\Support\Facades\File;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class CategorySeeder extends Seeder
|
|
{
|
|
/**
|
|
* Run the database seeds.
|
|
*/
|
|
public function run(): void
|
|
{
|
|
// Path to the JSON files
|
|
$jsonPath = database_path('seeders/data/json/category');
|
|
|
|
// Check if directory exists
|
|
if (!File::exists($jsonPath)) {
|
|
$this->command->error("JSON directory not found: {$jsonPath}");
|
|
return;
|
|
}
|
|
|
|
// Get all JSON files except the schema file
|
|
$jsonFiles = File::glob($jsonPath . '/*.json');
|
|
$jsonFiles = array_filter($jsonFiles, function ($file) {
|
|
return !str_contains(basename($file), 'schema');
|
|
});
|
|
|
|
$this->command->info('Starting to seed categories from JSON files...');
|
|
$this->command->info('Found ' . count($jsonFiles) . ' JSON files to process.');
|
|
|
|
foreach ($jsonFiles as $jsonFile) {
|
|
$this->processJsonFile($jsonFile);
|
|
}
|
|
|
|
$this->command->info('Category seeding completed successfully!');
|
|
}
|
|
|
|
/**
|
|
* Process a single JSON file
|
|
*/
|
|
private function processJsonFile(string $filePath): void
|
|
{
|
|
$fileName = basename($filePath);
|
|
$this->command->info("Processing: {$fileName}");
|
|
|
|
try {
|
|
// Read and decode JSON content
|
|
$jsonContent = File::get($filePath);
|
|
$data = json_decode($jsonContent, true);
|
|
|
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
|
$this->command->error("Invalid JSON in file: {$fileName} - " . json_last_error_msg());
|
|
return;
|
|
}
|
|
|
|
// Validate JSON structure
|
|
if (!isset($data['category'])) {
|
|
$this->command->error("Missing 'category' key in file: {$fileName}");
|
|
return;
|
|
}
|
|
|
|
$categoryData = $data['category'];
|
|
|
|
// Validate required fields
|
|
if (!isset($categoryData['name']) || !isset($categoryData['description'])) {
|
|
$this->command->error("Missing required fields (name/description) in file: {$fileName}");
|
|
return;
|
|
}
|
|
|
|
// Create main category
|
|
$mainCategory = $this->createMainCategory($categoryData, $data);
|
|
|
|
if (!$mainCategory) {
|
|
$this->command->error("Failed to create main category for file: {$fileName}");
|
|
return;
|
|
}
|
|
|
|
// Create subcategories
|
|
if (isset($categoryData['subcategories']) && is_array($categoryData['subcategories'])) {
|
|
foreach ($categoryData['subcategories'] as $index => $subcategoryData) {
|
|
if (!$this->createSubcategory($subcategoryData, $mainCategory, $data, $index)) {
|
|
$this->command->warn("Failed to create subcategory at index {$index} for file: {$fileName}");
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->command->info("✓ Successfully processed: {$fileName}");
|
|
} catch (\Exception $e) {
|
|
$this->command->error("Error processing {$fileName}: " . $e->getMessage());
|
|
Log::error("CategorySeeder error for {$fileName}", [
|
|
'error' => $e->getMessage(),
|
|
'trace' => $e->getTraceAsString()
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a main category
|
|
*/
|
|
private function createMainCategory(array $categoryData, array $originalData): ?Category
|
|
{
|
|
try {
|
|
// Check if category already exists
|
|
$existingCategory = Category::where('name', $categoryData['name'])
|
|
->whereNull('parent_id')
|
|
->first();
|
|
|
|
if ($existingCategory) {
|
|
$this->command->warn("Main category '{$categoryData['name']}' already exists. Skipping...");
|
|
return $existingCategory;
|
|
}
|
|
|
|
// Create the main category
|
|
$category = Category::create([
|
|
'is_enabled' => true,
|
|
'name' => $categoryData['name'],
|
|
'description' => $categoryData['description'],
|
|
'subcategories' => $categoryData['subcategories'] ?? null,
|
|
'keywords' => $categoryData['keywords'] ?? null,
|
|
'meme_angles' => null, // Main categories don't have meme_angles
|
|
'sample_captions' => null, // Main categories don't have sample_captions
|
|
'payload' => $originalData,
|
|
'embedding' => CloudflareAI::getVectorEmbeddingBgeSmall($categoryData['name'] . " " . $categoryData['description']),
|
|
]);
|
|
|
|
// Add keywords as tags
|
|
if (isset($categoryData['keywords']) && is_array($categoryData['keywords'])) {
|
|
$this->attachKeywordsAsTags($category, $categoryData['keywords']);
|
|
}
|
|
|
|
$this->command->line(" ✓ Created main category: {$category->name}");
|
|
|
|
return $category;
|
|
} catch (\Exception $e) {
|
|
$this->command->error("Error creating main category: " . $e->getMessage());
|
|
Log::error("Error creating main category", [
|
|
'category_data' => $categoryData,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a subcategory
|
|
*/
|
|
private function createSubcategory(array $subcategoryData, Category $parentCategory, array $originalData, int $index): ?Category
|
|
{
|
|
try {
|
|
// Validate required subcategory fields
|
|
if (!isset($subcategoryData['name']) || !isset($subcategoryData['description'])) {
|
|
$this->command->warn("Subcategory at index {$index} missing required fields (name/description). Skipping...");
|
|
return null;
|
|
}
|
|
|
|
// Check if subcategory already exists
|
|
$existingSubcategory = Category::where('name', $subcategoryData['name'])
|
|
->where('parent_id', $parentCategory->id)
|
|
->first();
|
|
|
|
if ($existingSubcategory) {
|
|
$this->command->warn(" Subcategory '{$subcategoryData['name']}' already exists. Skipping...");
|
|
return $existingSubcategory;
|
|
}
|
|
|
|
// Create subcategory payload
|
|
$subcategoryPayload = [
|
|
'subcategory' => $subcategoryData,
|
|
'parent_category' => [
|
|
'name' => $parentCategory->name,
|
|
'description' => $parentCategory->description
|
|
]
|
|
];
|
|
|
|
// Create the subcategory using the correct nested set method
|
|
$subcategory = Category::create([
|
|
'is_enabled' => false,
|
|
'name' => $subcategoryData['name'],
|
|
'description' => $subcategoryData['description'],
|
|
'meme_angles' => $subcategoryData['meme_angles'] ?? null,
|
|
'sample_captions' => $subcategoryData['sample_captions'] ?? null,
|
|
'keywords' => $subcategoryData['keywords'] ?? null,
|
|
'subcategories' => null, // Subcategories don't have subcategories
|
|
'payload' => $subcategoryPayload,
|
|
'parent_id' => $parentCategory->id, // Set parent_id directly
|
|
'embedding' => CloudflareAI::getVectorEmbeddingBgeSmall($subcategoryData['name'] . " " . $subcategoryData['description']),
|
|
]);
|
|
|
|
// Add keywords as tags
|
|
if (isset($subcategoryData['keywords']) && is_array($subcategoryData['keywords'])) {
|
|
$this->attachKeywordsAsTags($subcategory, $subcategoryData['keywords']);
|
|
}
|
|
|
|
$this->command->line(" ✓ Created subcategory: {$subcategory->name}");
|
|
|
|
return $subcategory;
|
|
} catch (\Exception $e) {
|
|
$this->command->error("Error creating subcategory at index {$index}: " . $e->getMessage());
|
|
Log::error("Error creating subcategory", [
|
|
'subcategory_data' => $subcategoryData,
|
|
'parent_id' => $parentCategory->id,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Attach keywords as tags to a category
|
|
*/
|
|
private function attachKeywordsAsTags(Category $category, array $keywords): void
|
|
{
|
|
try {
|
|
$category->attachTags($keywords, 'category');
|
|
} catch (\Exception $e) {
|
|
$this->command->warn("Failed to attach tags to category '{$category->name}': " . $e->getMessage());
|
|
Log::warning("Failed to attach tags", [
|
|
'category_id' => $category->id,
|
|
'keywords' => $keywords,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
}
|