🤖 Shop Product AI Content Generator

📋 Implementation Prompt | 🎯 Yedek Parça Otomatik İçerik Üretimi

SİSTEM KONTEKST

🏢 Multi-Tenant Laravel Sistemi

Parametre Değer
Tenant ID 2
Domain ixtif.com
Database tenant_ixtif
Sektör Endüstriyel Ekipman (Forklift, Transpalet)
Laravel Versiyonu 11.x
PHP Versiyonu 8.3

📊 Database Tables

shop_products → Ana ürün tablosu (PK: product_id) shop_categories → Kategori tablosu (PK: category_id) shop_brands → Marka tablosu (PK: brand_id) shop_product_variants → Variant ürünler media_library_items → Görsel yönetimi (Leonardo AI outputs)

🗄️ ShopProduct Model

Namespace: Modules\Shop\App\Models\ShopProduct Table: shop_products Primary Key: product_id (integer) Translatable Fields (Spatie/HasTranslations): - title (array: tr/en) - slug (array: tr/en) - body (array: tr/en) - short_description (array: tr/en) JSON Fields: - primary_specs (array) - faq_data (array) - tags (array) - technical_specs (array) - highlighted_features (array) Relations: - category (BelongsTo ShopCategory) - brand (BelongsTo ShopBrand) - variants (HasMany ShopProductVariant) - parent (BelongsTo ShopProduct, foreign: parent_product_id)

🗄️ ShopCategory Model

Namespace: Modules\Shop\App\Models\ShopCategory Table: shop_categories Primary Key: category_id (integer) Important Fields: - parent_id (integer, nullable) → Alt kategori ise parent category ID - title (array: tr/en) - slug (array: tr/en) Yedek Parça Kategorisi: category_id = 7 (parent_id IS NULL) Alt kategoriler: parent_id = 7

🧠 AI Services

Service Namespace Kullanım
OpenAI GPT-4 App\Services\OpenAI\OpenAIService İçerik üretimi (TR + EN bilingual)
Leonardo AI App\Services\Media\LeonardoAIService Görsel üretimi (1024x1024 square)

GÖREV TANIMI

🎯 Ne Yapacaksın?

Shop modülü için yedek parça ürünlerine otomatik AI içerik üretimi sistemi oluşturacaksın.

✅ Hangi Ürünler İşlenecek?

  • Kategori: Sadece "Yedek Parça" (category_id = 7 VEYA parent category = 7)
  • Variant Durumu: Sadece ana ürünler (parent_product_id IS NULL veya 0)
  • Variant ürünler SKIP: Eğer parent_product_id > 0 ise işleme

🚫 Hangi Ürünler İŞLENMEZ?

  • ❌ Forklift kategorisi ürünleri
  • ❌ Transpalet kategorisi ürünleri
  • ❌ Variant ürünler (child products)
  • ❌ Diğer kategoriler

⚡ İki Farklı Strateji

Ürün içeriği mevcut durumuna göre iki farklı akışa girecek:

Durum Strateji Ne Yapılacak?
Branch A
Mevcut içerik VAR
EXPAND (Genişlet) • Mevcut teknik detayları koru
• İçeriği genişlet
• SEO ekle
Branch B
Mevcut içerik YOK
CREATE (Genel Oluştur) • Genel tanıtım yap
• Teknik detay VERME
• Güvenli içerik

AKIŞ DİYAGRAMI

BAŞLANGIÇ: Admin "Generate AI Content" butonuna tıklar
1. ÜRÜN FİLTRELEME
$product = ShopProduct::find($productId); // Kontrol 1: Yedek parça mı? if ($product->category_id != 7 && $product->category->parent_id != 7) { throw new Exception('Bu ürün yedek parça kategorisinde değil'); } // Kontrol 2: Variant ürün mü? if ($product->parent_product_id && $product->parent_product_id > 0) { throw new Exception('Variant ürünler işlenmez, sadece ana ürünler'); }
2. MEVCUT İÇERİK KONTROLÜ (KRİTİK!)
$existingBody = $product->body['tr'] ?? ''; $hasContent = strlen($existingBody) > 100; if ($hasContent) { // BRANCH A → Genişlet $strategy = 'expand'; } else { // BRANCH B → Yeni oluştur $strategy = 'create'; }

🟢 BRANCH A - Mevcut İçerik Varsa

A1. Mevcut veriyi parse et
$existingData = [ 'body' => $product->body, 'primary_specs' => $product->primary_specs, 'faq_data' => $product->faq_data, ]; // Teknik detayları çıkar (regex ile) // "150mm", "2.5 kg", "220V", "Döküm Çelik" gibi
A2. GPT-4 Prompt (Genişletme)
$prompt = "IMPROVE and EXPAND this existing product content for a forklift spare part. PRODUCT: {$product->title['tr']} CATEGORY: Yedek Parça EXISTING CONTENT: {$existingBody} EXISTING SPECS: {$extractedSpecs} RULES: ✅ KEEP all technical details (dimensions, materials, compatibility) ✅ EXPAND descriptions with more context ✅ ADD SEO keywords (forklift, yedek parça, onarım, servis, montaj) ✅ Use Pattern v4 HTML structure ❌ NEVER mention price ✅ Bilingual output: TR + EN OUTPUT FORMAT (JSON): { \"title\": {\"tr\": \"...\", \"en\": \"...\"}, \"short_description\": {\"tr\": \"...\", \"en\": \"...\"}, \"primary_specs\": [ {\"label\": \"Malzeme\", \"value\": \"Döküm Çelik\"}, {\"label\": \"Uyumluluk\", \"value\": \"Forklift Arka Dingil\"} ], \"body\": { \"tr\": \"
...
\", \"en\": \"
...
\" }, \"faq_data\": [ {\"question\": \"...\", \"answer\": \"...\"} ], \"tags\": [\"forklift\", \"yedek parça\", \"akson kapağı\"] }"
A3. Leonardo AI Görseller (2 adet)
// Foto 1: Kullanım ortamı $prompt1 = "Industrial workshop scene, forklift spare part installation, mechanic hands assembling parts, professional lighting, realistic photo"; // Foto 2: Teknik çizim (blueprint) $prompt2 = "Technical blueprint drawing, forklift axle component diagram, engineering schematic, white background, clean lines"; // Her ikisi de: 1024x1024, cinematic style

🔴 BRANCH B - Mevcut İçerik Yoksa

B1. Sadece başlık + kategori al
$basicInfo = [ 'title' => $product->title, 'category' => $product->category->title, ]; // Başka BİLGİ YOK! Teknik detay yok!
B2. GPT-4 Prompt (Güvenli Mod)
$prompt = "CREATE GENERAL product description for a forklift spare part. PRODUCT: {$product->title['tr']} CATEGORY: Yedek Parça ⚠️ CRITICAL RULES: ❌ NO specific dimensions/weight/voltage ❌ NO price information ❌ NO exact technical specifications ✅ Use general phrases: 'Detaylar için arayın', 'Forklift modelinize uyumlu', 'Profesyonel montaj önerilir' ✅ Focus on: quality, reliability, OEM standards ✅ SEO keywords (forklift, yedek parça, onarım) ✅ Pattern v4 HTML structure ✅ Bilingual: TR + EN OUTPUT FORMAT (same JSON as Branch A, but with general content)"
B3. Leonardo AI Görseller (2 adet)
// Aynı strateji (context görseller, exact product değil)
3. VALIDATION (Her iki branch için)
// Fiyat kontrolü if (preg_match('/\d+\s*(TL|USD|\$|€|lira|dolar)/i', $content)) { throw new Exception('Content contains price!'); } // Branch B için teknik detay kontrolü if ($strategy === 'create') { if (preg_match('/\d+\s*(mm|cm|kg|volt|V|A)/i', $content)) { throw new Exception('New content should not have technical specs!'); } }
4. GÖRSELLER EMBED + SEO
// Görselleri body içine embed et $imageTag = "<a href='{$imageUrl}' class='glightbox'> <img src='{$imageUrl}' alt='Forklift {$product->title['tr']} Yedek Parça Montaj Görseli' title='{$product->title['tr']} - OEM Kalite Forklift Yedek Parça' loading='lazy' class='w-full aspect-square rounded-xl object-cover'> </a>";
5. DATABASE SAVE
$product->update([ 'title' => $aiContent['title'], 'short_description' => $aiContent['short_description'], 'body' => $aiContent['body'], 'primary_specs' => $aiContent['primary_specs'], 'faq_data' => $aiContent['faq_data'], 'tags' => $aiContent['tags'], ]); // Cache clear Artisan::call('view:clear'); Artisan::call('responsecache:clear');

KRİTİK KURALLAR

🚨 KURAL 1: FİYAT BİLGİSİ ASLA

Hiçbir durumda fiyat bilgisi verilmeyecek:

  • ❌ "500 TL", "1000 $", "100-500 TL arası"
  • ❌ "Ucuz", "Uygun fiyat", "Ekonomik"
  • ✅ "Fiyat için arayın"
  • ✅ "Güncel fiyat bilgisi için iletişime geçin"

🚨 KURAL 2: TEKNİK DETAY (Koşullu)

Durum Teknik Detay
Branch A (Mevcut VAR) ✅ KULLAN - Mevcut teknik detayları koruyup genişlet
Branch B (Mevcut YOK) ❌ VERME - Spesifik boyut/ağırlık/voltaj belirtme

🚨 KURAL 3: GOOGLE SEO ÖNCELİKLİ

  • ✅ Long-tail keywords: "forklift arka dingil yedek parça"
  • ✅ LSI keywords: bakım, onarım, servis, montaj, değişim
  • ✅ FAQ = Google arama sorguları formatında
  • ✅ Alt/title tags görsellerde

🚨 KURAL 4: GÖRSEL STRATEJİSİ

  • ❌ Ürünü birebir oluşturma (AI hallucination riski!)
  • ✅ Foto 1: Kullanım ortamı (atölye, montaj sahnesi)
  • ✅ Foto 2: Sallantılı teknik çizim (blueprint style)
  • ✅ 1024x1024 square format
  • ✅ Cinematic veya realistic style

IMPLEMENTASYON DETAYLARI

📁 Dosya Yapısı

Modules/Shop/app/Services/ ├── ProductFilterService.php → Ürün filtreleme ├── ContentStrategyRouter.php → Branch A/B yönlendirme ├── ShopProductAIContentService.php → Ana AI service (updated) ├── ContentValidator.php → Validation (updated) └── ShopProductImageGenerator.php → Leonardo AI görseller Modules/Shop/app/Jobs/ └── GenerateProductImagesJob.php → Queue job (görseller) Modules/Shop/app/Livewire/Admin/ └── ProductAIContentGenerator.php → Admin UI component

🔧 ProductFilterService.php

namespace Modules\Shop\App\Services; class ProductFilterService { public function isEligible(ShopProduct $product): bool { // Yedek parça kontrolü $isSparePartCategory = $product->category_id === 7 || $product->category->parent_id === 7; if (!$isSparePartCategory) { return false; } // Variant kontrolü if ($product->parent_product_id && $product->parent_product_id > 0) { return false; } return true; } public function getEligibleProducts(): Collection { return ShopProduct::where(function($q) { $q->where('category_id', 7) ->orWhereHas('category', fn($q2) => $q2->where('parent_id', 7)); }) ->where(function($q) { $q->whereNull('parent_product_id') ->orWhere('parent_product_id', 0); }) ->get(); } }

🔧 ContentStrategyRouter.php

namespace Modules\Shop\App\Services; class ContentStrategyRouter { public function route(ShopProduct $product): string { $existingBody = $product->body['tr'] ?? ''; $hasContent = strlen($existingBody) > 100; return $hasContent ? 'expand' : 'create'; } public function extractExistingData(ShopProduct $product): array { $body = $product->body['tr'] ?? ''; return [ 'body' => $product->body, 'specs' => $this->extractTechnicalSpecs($body), 'primary_specs' => $product->primary_specs, 'faq_data' => $product->faq_data, ]; } protected function extractTechnicalSpecs(string $body): array { // Regex patterns for: // - Dimensions: "150mm", "2.5 cm" // - Weight: "3 kg", "500g" // - Voltage: "220V", "24V" // - Material: "Döküm Çelik", "Alüminyum" preg_match_all('/\d+\s*(mm|cm|kg|g|V|volt)/i', $body, $matches); return $matches[0] ?? []; } }

🔧 ContentValidator.php

namespace Modules\Shop\App\Services; class ContentValidator { public function validate(array $content, string $strategy): array { $errors = []; // Fiyat kontrolü (HER ZAMAN) if ($this->containsPrice($content)) { $errors[] = 'Content contains price information'; } // Teknik detay kontrolü (SADECE Branch B) if ($strategy === 'create' && $this->containsTechnicalSpecs($content)) { $errors[] = 'New content should not contain specific technical specifications'; } return $errors; } protected function containsPrice($content): bool { $text = json_encode($content); return preg_match('/\d+\s*(TL|USD|\$|€|lira|dolar|euro)/i', $text) || preg_match('/(ucuz|pahalı|uygun fiyat|ekonomik)/i', $text); } protected function containsTechnicalSpecs($content): bool { $text = json_encode($content); return preg_match('/\d+\s*(mm|cm|kg|g|volt|V|A|amper)/i', $text); } }

🎨 HTML Pattern v4 (Output Format)

<!-- İçerik Yapısı --> <section class='mb-20'> <div class='grid md:grid-cols-2 gap-8 mb-12'> <!-- Sol: Açıklama --> <div> <p class='text-gray-700 dark:text-gray-300'>...</p> </div> <!-- Sağ: Görsel --> <a href='{imageUrl}' class='glightbox'> <img src='{imageUrl}' alt='...' loading='lazy'> </a> </div> </section> <section class='mb-20'> <h2 class='text-3xl font-bold mb-12 text-gray-900 dark:text-white'> Neden Bu Yedek Parçayı Tercih Etmelisiniz? </h2> <div class='grid md:grid-cols-3 gap-8'> <!-- Kartlar --> </div> </section>

TEST SENARYOLARI

✅ Test 1: Ürün Filtreleme

  • Forklift ürünü seç → Hata: "Sadece yedek parça kategorisi"
  • Variant ürün seç → Hata: "Variant ürünler işlenmez"
  • Yedek parça ana ürün → ✅ Devam

✅ Test 2: Branch A (Mevcut İçerik VAR)

  • Ürün: Body dolu (>100 char)
  • Kontrol: Teknik detaylar korundu mu?
  • Kontrol: İçerik genişledi mi?
  • Kontrol: Fiyat YOK mu?

✅ Test 3: Branch B (Mevcut İçerik YOK)

  • Ürün: Body boş veya <100 char
  • Kontrol: Genel tanıtım yapıldı mı?
  • Kontrol: Teknik detay YOK mu?
  • Kontrol: Fiyat YOK mu?

SQL SORGULARI

Yedek Parça Ana Ürünlerini Bul

-- Tenant database seç USE tenant_ixtif; -- Yedek parça kategorisindeki ana ürünler SELECT p.product_id, p.title, p.category_id, c.title AS category_title, LENGTH(JSON_EXTRACT(p.body, '$.tr')) AS content_length FROM shop_products p JOIN shop_categories c ON p.category_id = c.category_id WHERE (p.category_id = 7 OR c.parent_id = 7) AND (p.parent_product_id IS NULL OR p.parent_product_id = 0);

Mevcut İçerik İstatistikleri

-- Branch A: Mevcut içeriği olanlar SELECT COUNT(*) AS has_content FROM shop_products p WHERE (p.category_id = 7 OR EXISTS( SELECT 1 FROM shop_categories c WHERE c.category_id = p.category_id AND c.parent_id = 7 )) AND (p.parent_product_id IS NULL OR p.parent_product_id = 0) AND LENGTH(JSON_EXTRACT(p.body, '$.tr')) > 100; -- Branch B: Mevcut içeriği olmayanlar SELECT COUNT(*) AS no_content FROM shop_products p WHERE (p.category_id = 7 OR EXISTS( SELECT 1 FROM shop_categories c WHERE c.category_id = p.category_id AND c.parent_id = 7 )) AND (p.parent_product_id IS NULL OR p.parent_product_id = 0) AND (p.body IS NULL OR LENGTH(JSON_EXTRACT(p.body, '$.tr')) <= 100);

BAŞARI KRİTERLERİ

✅ Sistem Başarılı Sayılır Eğer:

  1. Sadece yedek parça kategorisi işleniyor
  2. Variant ürünler otomatik skip ediliyor
  3. Mevcut içerik varsa (Branch A) teknik detaylar KORUNUYOR
  4. Mevcut içerik yoksa (Branch B) genel tanıtım yapılıyor
  5. HİÇBİR ÜRÜNDE fiyat bilgisi YOK
  6. Branch B ürünlerinde spesifik teknik detay YOK
  7. SEO keywords her üründe mevcut
  8. Görseller context sağlıyor (exact product değil)
  9. GLightbox + SEO tags çalışıyor
  10. Validation tüm kurallara uyuyor