ixtif.com'daki AI Blog Draft üretim sistemini diğer tenant'lara nasıl uygulayacağınızı adım adım öğrenin
AI Blog Creator, iki aşamalı bir blog üretim sistemidir:
Her tenant için özel prompt dosyası oluşturulabilir. Bu sayede AI, o tenant'ın sektörüne, ürünlerine ve tonuna uygun içerik üretir.
┌─────────────────────────────────────────────────────────────┐
│ Admin Panel: /admin/blog/ai-drafts │
└─────────────────┬───────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ [Taslak Üret] → Livewire → GenerateDraftsJob (Queue) │
│ │
│ CategoryBasedDraftGenerator: │
│ ├── buildCategoryGroups() → 5 grup oluştur │
│ ├── Her grup için OpenAI API call │
│ ├── JSON parse │
│ └── blog_ai_drafts tablosuna kaydet │
└─────────────────┬───────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Admin taslakları görür ve seçim yapar (checkbox) │
└─────────────────┬───────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ [Seçili Blogları Yaz] → BlogAIBatchProcessor │
│ │
│ Her seçili taslak için GenerateBlogFromDraftJob: │
│ ├── BlogAIContentWriter.generateBlogFromDraft() │
│ │ ├── H2 outline üret (4-5 başlık) │
│ │ ├── Her H2 için içerik yaz (500-600 kelime) │
│ │ ├── FAQ üret (10 soru) │
│ │ ├── HowTo üret (7 adım) │
│ │ └── Leonardo AI görsel üret │
│ └── blogs tablosuna kaydet │
└─────────────────────────────────────────────────────────────┘
CategoryBasedDraftGenerator - Taslak üretimiBlogAIContentWriter - Blog yazımıBlogAIBatchProcessor - Toplu işlemTenantPromptLoader - Prompt yönetimiblog_ai_drafts - Taslaklarblogs - Blog yazılarıblog_categories - Kategorilertenant/ klasöründeModules/Blog/ ├── App/ │ ├── Models/ │ │ ├── Blog.php │ │ ├── BlogCategory.php │ │ └── BlogAIDraft.php ← AI taslak modeli │ │ │ ├── Services/ │ │ ├── BlogAIDraftGenerator.php ← Eski taslak üretici │ │ ├── CategoryBasedDraftGenerator.php ← YENİ! Kategori bazlı │ │ ├── BlogAIContentWriter.php ← Blog yazma servisi │ │ ├── BlogAIBatchProcessor.php ← Toplu işlem │ │ └── TenantPrompts/ │ │ ├── TenantPromptLoader.php ← Prompt yükleyici │ │ ├── DefaultPrompts.php ← Varsayılan prompt'lar │ │ └── Tenants/ │ │ ├── Tenant2Prompts.php ← iXtif (örnek) │ │ ├── Tenant4Prompts.php ← Başka tenant │ │ └── TenantXPrompts.php ← YENİ TENANT BURAYA! │ │ │ ├── Http/Livewire/Admin/ │ │ ├── BlogAiDraftComponent.php ← Admin UI │ │ └── BlogAiGuideComponent.php │ │ │ └── Jobs/ │ ├── GenerateDraftsJob.php ← Queue job (taslak) │ └── GenerateBlogFromDraftJob.php ← Queue job (blog) │ ├── database/migrations/tenant/ │ └── 2025_11_14_050744_create_blog_ai_drafts_table.php │ ├── resources/views/admin/livewire/ │ └── blog-ai-draft-component.blade.php │ └── routes/ └── admin.php ← /admin/blog/ai-drafts
Önemli: Yeni tenant eklerken sadece TenantPrompts/Tenants/ klasörüne
TenantXPrompts.php dosyası eklemeniz yeterli. Sistem otomatik algılar!
Yeni bir tenant'a AI Blog Creator eklemek için 3 ana adım var:
blog_ai_drafts tablosunu oluştur
blog_ai_drafts tablosu tenant database'inde oluşturulmalı:
# Tüm tenant'lar için migration çalıştır php artisan tenants:migrate --force # Veya belirli tenant için php artisan tenants:migrate --tenants=X --force
Migration dosyası: Modules/Blog/database/migrations/tenant/2025_11_14_050744_create_blog_ai_drafts_table.php
Tenant'a özel prompt dosyası oluşturmazsan DefaultPrompts.php kullanılır.
Özel içerik istiyorsan:
# Dosya konumu: Modules/Blog/App/Services/TenantPrompts/Tenants/Tenant{ID}Prompts.php # Örnek: Tenant 5 için Modules/Blog/App/Services/TenantPrompts/Tenants/Tenant5Prompts.php
Şablon dosya için Bölüm 6'ya bak
Admin panelden AI Provider tanımla veya mevcut olanı kullan:
# Admin Panel: /admin/ai/providers # Gerekli alanlar: - Provider: OpenAI - API Key: sk-... - Base URL: https://api.openai.com - Model: gpt-4o veya gpt-4o-mini - is_default: true - is_active: true
// TenantPromptLoader.php - loadTenantPrompts() $tenantId = tenant('id'); // Örn: 5 // Tenant-specific dosya var mı kontrol et $tenantClass = "Modules\\Blog\\...\\Tenants\\Tenant{$tenantId}Prompts"; $tenantFile = __DIR__ . "/Tenants/Tenant{$tenantId}Prompts.php"; if (File::exists($tenantFile) && class_exists($tenantClass)) { // ✅ Tenant özel prompt kullan $this->promptProvider = new $tenantClass(); } else { // ⚠️ DefaultPrompts fallback $this->promptProvider = new DefaultPrompts(); }
getDraftPrompt(): string
Taslak üretimi için AI'a verilen talimatlar
getBlogContentPrompt(): string
Blog yazımı için AI'a verilen talimatlar
getContext(): array
Tenant bilgileri (firma, iletişim, sektör)
return [
'company_info' => [
'name' => 'Firma Adı',
'title' => 'Site Başlığı',
'slogan' => 'Slogan',
'website' => 'https://...',
],
'contact_info' => [
'email' => 'info@...',
'phone' => '+90...',
'address' => '...',
],
'focus' => 'sektör_adı', // industrial_equipment, music, etc.
'industry' => 'Sektör Açıklaması',
'target_audience' => 'Hedef kitle',
];
getFallbackOutline(string $topicKeyword): array
OpenAI başarısız olursa kullanılacak varsayılan H2 başlıkları
return [
$topicKeyword . ' Nedir?',
'Özellikler ve Avantajlar',
'Kullanım Alanları',
'Seçim Kriterleri',
'Bakım ve Güvenlik',
'İletişim ve Destek',
];
buildImagePromptForBlog(string $blogTitle): string
(Opsiyonel)
Leonardo AI görsel üretimi için prompt (varsa)
DefaultPrompts'u kullanır, sadece firma bilgilerini override eder:
<?php namespace Modules\Blog\App\Services\TenantPrompts\Tenants; use Modules\Blog\App\Services\TenantPrompts\DefaultPrompts; /** * Tenant X için Blog AI Prompts * Dosya: Modules/Blog/App/Services/TenantPrompts/Tenants/TenantXPrompts.php */ class TenantXPrompts extends DefaultPrompts { /** * Tenant context override */ public function getContext(): array { $context = parent::getContext(); // Tenant-specific ek bilgiler $context['focus'] = 'your_industry'; // Sektör kodu $context['industry'] = 'Sektör Açıklaması'; $context['target_audience'] = 'Hedef kitle açıklaması'; return $context; } /** * Tenant için fallback outline */ public function getFallbackOutline(string $topicKeyword): array { return [ $topicKeyword . ' Nedir?', 'Özellikler ve Avantajlar', 'Kullanım Alanları', 'Seçim Kriterleri', 'İletişim ve Destek', ]; } }
Tüm metodları override eder, tam kontrol sağlar:
<?php namespace Modules\Blog\App\Services\TenantPrompts\Tenants; use Illuminate\Support\Facades\File; use Modules\Blog\App\Services\TenantPrompts\DefaultPrompts; /** * Tenant X için Blog AI Prompts (Tam Şablon) * * Bu dosyayı kopyalayıp tenant ID'ye göre düzenleyin: * - Class adını TenantXPrompts yapın (X = tenant ID) * - Dosya adını TenantXPrompts.php yapın */ class TenantXPrompts extends DefaultPrompts { protected string $promptPath; public function __construct() { // Opsiyonel: Markdown prompt dosyaları için path $this->promptPath = base_path('readme/tenant-x-prompts'); } /** * Draft (taslak) üretimi için AI prompt */ public function getDraftPrompt(): string { // Harici dosyadan yükle (varsa) $promptFile = $this->promptPath . '/draft-prompt.md'; if (File::exists($promptFile)) { return File::get($promptFile); } // Inline prompt return <<<'PROMPT' Sen profesyonel bir blog içerik stratejistisin. **FİRMA:** [Firma Adı] **SEKTÖR:** [Sektör] Görevin: [Sektör] konularında SEO uyumlu blog taslakları oluşturmak. **JSON FORMAT:** [ { "topic_keyword": "Blog başlığı", "meta_description": "150 karakterlik açıklama", "seo_keywords": ["kelime1", "kelime2"], "outline": ["H2 Başlık 1", "H2 Başlık 2", "H2 Başlık 3"] } ] **KURALLAR:** - SEO odaklı başlıklar - Türkçe karakter kullan - Teknik ve bilgilendirici içerik PROMPT; } /** * Blog içeriği yazımı için AI prompt */ public function getBlogContentPrompt(): string { return <<<'PROMPT' Sen profesyonel bir [sektör] içerik yazarısın. **FİRMA:** {company_info.name} **WEB:** {company_info.website} **ZORUNLU KURALLAR:** 1. **Kelime Sayısı:** 1500-2000 kelime 2. **HTML Format:** <h2>, <h3>, <p>, <ul>, <strong> kullan 3. **Firma Adı:** En az 3 kez kullan 4. **İletişim:** Sonuç bölümünde telefon ve email ver 5. **Fiyat YASAK:** Rakam verme, "iletişime geçin" yönlendir 6. **Yıl YASAK:** 2023, 2024 gibi yıllar kullanma **JSON FORMAT:** { "title": "Blog başlığı", "content": "Tam HTML içerik", "excerpt": "Kısa özet (180 karakter)" } PROMPT; } /** * Tenant context override */ public function getContext(): array { $context = parent::getContext(); // Kısa firma adı kullan (site_title) if (!empty($context['company_info']['title'])) { $context['company_info']['name'] = $context['company_info']['title']; } // Tenant-specific ek bilgiler $context['focus'] = 'your_industry_code'; $context['industry'] = 'B2B/B2C Sektör Açıklaması'; $context['target_audience'] = 'Hedef kitle açıklaması'; return $context; } /** * Tenant için fallback outline */ public function getFallbackOutline(string $topicKeyword): array { return [ $topicKeyword . ' Nedir?', 'Özellikler ve Avantajlar', 'Kullanım Alanları', 'Seçim Kriterleri', 'Sık Sorulan Sorular', 'İletişim ve Destek', ]; } }
focus: 'ecommerce'industry: 'B2C Online Satış'target_audience: 'Online alışveriş yapan tüketiciler'focus: 'tourism'industry: 'Turizm ve Seyahat'target_audience: 'Tatilciler, iş seyahati yapanlar'focus: 'legal'industry: 'Hukuki Danışmanlık'target_audience: 'Bireysel ve kurumsal müvekkiller'focus: 'healthcare'industry: 'Sağlık Hizmetleri'target_audience: 'Hastalar, sağlık arayan bireyler'# Migration çalıştır (tüm tenant'lar) php artisan tenants:migrate --force # Belirli tenant için migration php artisan tenants:migrate --tenants=5 --force # Cache temizle php artisan cache:clear && php artisan config:clear # Queue worker başlat (blog-ai queue'su için) php artisan queue:work --queue=blog-ai # Horizon (tüm queue'lar) php artisan horizon # Prompt loader debug (tinker) php artisan tinker >>> tenancy()->initialize(5); >>> app(\Modules\Blog\App\Services\TenantPrompts\TenantPromptLoader::class)->getProviderClass();