diff --git a/composer.json b/composer.json index 77f398141..aa0b9442d 100644 --- a/composer.json +++ b/composer.json @@ -22,6 +22,7 @@ "maatwebsite/excel": "^3.1", "mpdf/mpdf": "^8.2", "prettus/l5-repository": "^2.7.9", + "smalot/pdfparser": "^2.11", "webklex/laravel-imap": "^5.3" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 3b62d79e6..d1ec7d977 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ae0cc17dca0430364a53a5cfb74af712", + "content-hash": "d2180cfea5efd3787ff96f24c0185624", "packages": [ { "name": "barryvdh/laravel-dompdf", @@ -5354,6 +5354,57 @@ ], "time": "2024-12-10T13:12:19+00:00" }, + { + "name": "smalot/pdfparser", + "version": "v2.11.0", + "source": { + "type": "git", + "url": "https://github.com/smalot/pdfparser.git", + "reference": "ac8e6678b0940e4b2ccd5caadd3fb18e68093be6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/smalot/pdfparser/zipball/ac8e6678b0940e4b2ccd5caadd3fb18e68093be6", + "reference": "ac8e6678b0940e4b2ccd5caadd3fb18e68093be6", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "ext-zlib": "*", + "php": ">=7.1", + "symfony/polyfill-mbstring": "^1.18" + }, + "type": "library", + "autoload": { + "psr-0": { + "Smalot\\PdfParser\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0" + ], + "authors": [ + { + "name": "Sebastien MALOT", + "email": "sebastien@malot.fr" + } + ], + "description": "Pdf parser library. Can read and extract information from pdf file.", + "homepage": "https://www.pdfparser.org", + "keywords": [ + "extract", + "parse", + "parser", + "pdf", + "text" + ], + "support": { + "issues": "https://github.com/smalot/pdfparser/issues", + "source": "https://github.com/smalot/pdfparser/tree/v2.11.0" + }, + "time": "2024-08-16T06:48:03+00:00" + }, { "name": "symfony/console", "version": "v6.4.17", @@ -11422,6 +11473,6 @@ "platform": { "php": "^8.2" }, - "platform-dev": [], - "plugin-api-version": "2.3.0" + "platform-dev": {}, + "plugin-api-version": "2.6.0" } diff --git a/packages/Webkul/Admin/src/Config/core_config.php b/packages/Webkul/Admin/src/Config/core_config.php index de3e3fef1..dac06fde6 100644 --- a/packages/Webkul/Admin/src/Config/core_config.php +++ b/packages/Webkul/Admin/src/Config/core_config.php @@ -29,6 +29,77 @@ 'options' => 'Webkul\Core\Core@locales', ], ], + ], [ + 'key' => 'general.magic_ai', + 'name' => 'admin::app.configuration.index.magic-ai.title', + 'info' => 'admin::app.configuration.index.magic-ai.info', + 'icon' => 'icon-setting', + 'sort' => 3, + ], [ + 'key' => 'general.magic_ai.settings', + 'name' => 'admin::app.configuration.index.magic-ai.settings.title', + 'info' => 'admin::app.configuration.index.magic-ai.settings.info', + 'sort' => 1, + 'fields' => [ + [ + 'name' => 'enable', + 'title' => 'admin::app.configuration.index.magic-ai.settings.enable', + 'type' => 'boolean', + 'channel_based' => true, + ], [ + 'name' => 'model', + 'title' => 'admin::app.configuration.index.magic-ai.settings.models.title', + 'type' => 'select', + 'channel_based' => true, + 'depends' => 'enable:1', + 'options' => [ + [ + 'title' => 'admin::app.configuration.index.magic-ai.settings.models.gpt-4o', + 'value' => 'gpt-4o', + ], [ + 'title' => 'admin::app.configuration.index.magic-ai.settings.models.gpt-4o-mini', + 'value' => 'gpt-4o-mini', + ], [ + 'title' => 'admin::app.configuration.index.magic-ai.settings.models.gemini-flash', + 'value' => 'gemini-1.5-flash', + ], [ + 'title' => 'admin::app.configuration.index.magic-ai.settings.models.deepseek-r1', + 'value' => 'deepseek-r1:8b', + ], [ + 'title' => 'admin::app.configuration.index.magic-ai.settings.models.ollama', + 'value' => 'llama3.2:latest', + ], [ + 'title' => 'admin::app.configuration.index.magic-ai.settings.models.llama', + 'value' => 'llama-3.3-70b-versatile', + ], + ], + ], [ + 'name' => 'api_key', + 'title' => 'admin::app.configuration.index.magic-ai.settings.api-key', + 'type' => 'password', + 'depends' => 'enable:1,model:gpt-4o,model:gpt-4o-mini,model:gemini-1.5-flash,model:llama-3.3-70b-versatile', + 'validation' => 'required_if:enable,1', + 'info' => 'admin::app.configuration.index.magic-ai.settings.api-key-info', + ], [ + 'name' => 'api_domain', + 'title' => 'admin::app.configuration.index.magic-ai.settings.api-domain', + 'type' => 'text', + 'info' => 'admin::app.configuration.index.magic-ai.settings.api-domain-info', + 'depends' => 'enable:1', + ], + ], + ], [ + 'key' => 'general.magic_ai.pdf_generation', + 'name' => 'admin::app.configuration.index.magic-ai.settings.pdf-generation', + 'info' => 'admin::app.configuration.index.magic-ai.settings.pdf-generation-info', + 'sort' => 1, + 'fields' => [ + [ + 'name' => 'enabled', + 'title' => 'admin::app.configuration.index.magic-ai.settings.enable', + 'type' => 'boolean', + ], + ], ], /** diff --git a/packages/Webkul/Admin/src/Http/Controllers/Lead/LeadController.php b/packages/Webkul/Admin/src/Http/Controllers/Lead/LeadController.php index 5d1e2dc24..c15d5f773 100755 --- a/packages/Webkul/Admin/src/Http/Controllers/Lead/LeadController.php +++ b/packages/Webkul/Admin/src/Http/Controllers/Lead/LeadController.php @@ -19,12 +19,14 @@ use Webkul\Attribute\Repositories\AttributeRepository; use Webkul\Contact\Repositories\PersonRepository; use Webkul\DataGrid\Enums\DateRangeOptionEnum; +use Webkul\Lead\Helpers\Lead; use Webkul\Lead\Repositories\LeadRepository; use Webkul\Lead\Repositories\PipelineRepository; use Webkul\Lead\Repositories\ProductRepository; use Webkul\Lead\Repositories\SourceRepository; use Webkul\Lead\Repositories\StageRepository; use Webkul\Lead\Repositories\TypeRepository; +use Webkul\Lead\Services\LeadService; use Webkul\Tag\Repositories\TagRepository; use Webkul\User\Repositories\UserRepository; @@ -44,6 +46,7 @@ public function __construct( protected StageRepository $stageRepository, protected LeadRepository $leadRepository, protected ProductRepository $productRepository, + protected PersonRepository $personRepository ) { request()->request->add(['entity_type' => 'leads']); } @@ -625,4 +628,70 @@ private function getKanbanColumns(): array ], ]; } + + /** + * Create Lead with specified AI. + */ + public function createByAI(LeadForm $request) + { + if (! $pdfFile = $request->file('file')) { + return response()->json([ + 'status' => 'error', + 'message' => trans('admin::app.leads.file.not-found'), + ], 400); + } + + $extractedData = LeadService::extractDataFromPdf($pdfFile->getPathName()); + + if (! empty($extractedData['error'])) { + return response()->json([ + 'status' => 'error', + 'message' => $extractedData['error'], + ], 400); + } + + $leadData = Lead::mapAIDataToLead($extractedData); + + if ( + ! empty($leadData['status']) + && $leadData['status'] === 'error' + ) { + return response()->json([ + 'status' => 'error', + 'message' => $leadData['message'], + ], 400); + } + + return self::leadCreate($leadData); + } + + /** + * Create lead independent entity. + */ + private function leadCreate($data) + { + $person = $this->personRepository->create($data['person']); + + $pipeline = $this->pipelineRepository->getDefaultPipeline(); + + $stage = $pipeline->stages()->first(); + + $data = array_merge($data, [ + 'lead_pipeline_id' => $pipeline->id, + 'lead_pipeline_stage_id' => $stage->id, + 'expected_close_date' => Carbon::now()->addDays(7), + 'person' => [ + 'id' => $person->id, + 'organization_id' => $data['person']['organization_id'] ?? null, + ], + ]); + + $lead = $this->leadRepository->create($data); + + Event::dispatch('lead.create.after', $lead); + + return response()->json([ + 'message' => trans('admin::app.leads.create-success'), + ], 200); + } } diff --git a/packages/Webkul/Admin/src/Resources/lang/ar/app.php b/packages/Webkul/Admin/src/Resources/lang/ar/app.php index 5e77682cf..34eff8d36 100644 --- a/packages/Webkul/Admin/src/Resources/lang/ar/app.php +++ b/packages/Webkul/Admin/src/Resources/lang/ar/app.php @@ -1872,6 +1872,12 @@ 'destroy-success' => 'تم حذف العميل المحتمل بنجاح.', 'destroy-failed' => 'لا يمكن حذف العميل المحتمل.', + 'file' => [ + 'invalid-format' => 'تنسيق JSON غير صالح.', + 'invalid-response' => 'تنسيق استجابة الذكاء الاصطناعي غير صالح.', + 'not-found' => 'الملف غير موجود.', + ], + 'index' => [ 'title' => 'العملاء المحتملون', 'create-btn' => 'إنشاء عميل محتمل', @@ -1936,6 +1942,15 @@ 'all-pipelines' => 'كل المسارات', 'create-new-pipeline' => 'إنشاء مسار جديد', ], + + 'upload' => [ + 'create-lead' => 'إنشاء عميل محتمل باستخدام الذكاء الاصطناعي', + 'file' => 'تحميل ملف', + 'file-info' => 'يتم قبول ملفات بصيغة PDF فقط.', + 'save-btn' => 'حفظ', + 'sample-pdf' => 'نموذج PDF', + 'upload-pdf' => 'تحميل PDF', + ], ], 'create' => [ @@ -2069,22 +2084,49 @@ ], 'email' => [ - 'title' => 'Email Settings', - 'info' => 'Email configuration for the application.', + 'title' => 'إعدادات البريد الإلكتروني', + 'info' => 'تكوين البريد الإلكتروني للتطبيق.', 'imap' => [ - 'title' => 'IMAP Settings', - 'info' => 'IMAP email configuration for receiving emails.', + 'title' => 'إعدادات IMAP', + 'info' => 'تكوين البريد الإلكتروني IMAP لتلقي الرسائل.', 'account' => [ - 'title' => 'IMAP Account', - 'title-info' => 'Configure your IMAP account settings here.', - 'host' => 'Host', - 'port' => 'Port', - 'encryption' => 'Encryption Type', - 'validate-cert' => 'Validate SSL Certificate', - 'username' => 'IMAP Username', - 'password' => 'IMAP Password', + 'title' => 'حساب IMAP', + 'title-info' => 'قم بتكوين إعدادات حساب IMAP هنا.', + 'host' => 'المضيف', + 'port' => 'المنفذ', + 'encryption' => 'نوع التشفير', + 'validate-cert' => 'التحقق من شهادة SSL', + 'username' => 'اسم مستخدم IMAP', + 'password' => 'كلمة مرور IMAP', + ], + ], + ], + + 'magic-ai' => [ + 'title' => 'الذكاء الاصطناعي السحري', + 'info' => 'تكوين الذكاء الاصطناعي السحري للتطبيق.', + + 'settings' => [ + 'api-domain' => 'نطاق API لـ LLM', + 'api-domain-info' => 'لـ Olama و Grow فقط، مثال: http://localhost:11434', + 'api-key' => 'مفتاح API', + 'api-key-info' => 'يرجى التأكد من استخدام مفتاح API فريد لكل نوع نموذج للحفاظ على الأداء الأمثل والأمان.', + 'enable' => 'تمكين', + 'info' => 'عزز تجربتك مع ميزة الذكاء الاصطناعي السحري عن طريق إدخال مفتاح API الحصري الخاص بك وتوضيح التكامل السهل. استحوذ على التحكم في بيانات اعتماد OpenAI الخاصة بك وقم بتخصيص الإعدادات وفقًا لاحتياجاتك الخاصة.', + 'pdf-generation' => 'توليد PDF', + 'pdf-generation-info' => 'قم بتمكين ميزة توليد PDF لاستخراج البيانات تلقائيًا من ملفات PDF وتحويلها إلى تنسيق نصي. عزز إنتاجيتك وكفاءتك بتمكين هذه الميزة لتبسيط سير العمل الخاص بك.', + 'title' => 'الإعدادات العامة', + + 'models' => [ + 'deepseek-r1' => 'DeepSeek-R1 8db', + 'gemini-flash' => 'Gemini-1.5 Flash', + 'gpt-4o' => 'GPT-4.0', + 'gpt-4o-mini' => 'GPT-4.0 mini', + 'llama' => 'Llama 3.3 (Groq)', + 'ollama' => 'Ollama (llama3.2:latest)', + 'title' => 'النماذج', ], ], ], diff --git a/packages/Webkul/Admin/src/Resources/lang/en/app.php b/packages/Webkul/Admin/src/Resources/lang/en/app.php index a18a80b7f..e69249b29 100644 --- a/packages/Webkul/Admin/src/Resources/lang/en/app.php +++ b/packages/Webkul/Admin/src/Resources/lang/en/app.php @@ -1874,6 +1874,12 @@ 'destroy-success' => 'Lead deleted successfully.', 'destroy-failed' => 'Lead can not be deleted.', + 'file' => [ + 'invalid-format' => 'Invalid JSON format.', + 'invalid-response' => 'Invalid AI response format.', + 'not-found' => 'File not found.', + ], + 'index' => [ 'title' => 'Leads', 'create-btn' => 'Create Lead', @@ -1938,6 +1944,15 @@ 'all-pipelines' => 'All Pipelines', 'create-new-pipeline' => 'Create New Pipeline', ], + + 'upload' => [ + 'create-lead' => 'Create Lead Using AI', + 'file' => 'File Upload', + 'file-info' => 'Only PDF format files are accepted.', + 'save-btn' => 'Save', + 'sample-pdf' => 'Sample PDF', + 'upload-pdf' => 'Upload PDF', + ], ], 'create' => [ @@ -2090,6 +2105,33 @@ ], ], ], + + 'magic-ai' => [ + 'title' => 'Magic AI', + 'info' => 'Magic AI configuration for the application.', + + 'settings' => [ + 'api-domain' => 'LLM API Domain', + 'api-domain-info' => ' For Olama And Grow only, Exp:- http://localhost:11434', + 'api-key' => 'API Key', + 'api-key-info' => 'Please ensure that you use a unique API key for each model type to maintain optimal performance and security.', + 'enable' => 'Enable', + 'info' => 'Enhance your experience with the Magic AI feature by entering your exclusive API Key and indicating the effortless integration. Seize command over your OpenAI credentials and customize the settings according to your specific needs.', + 'pdf-generation' => 'PDF Generation', + 'pdf-generation-info' => 'Enable the PDF Generation feature to automatically extract data from PDF files and convert them into text format. Enhance your productivity and efficiency by enabling this feature to streamline your workflow.', + 'title' => 'General Settings', + + 'models' => [ + 'deepseek-r1' => 'DeepSeek-R1 8db', + 'gemini-flash' => 'Gemini-1.5 Flash', + 'gpt-4o' => 'GPT-4.0', + 'gpt-4o-mini' => 'GPT-4.0 mini', + 'llama' => 'Llama 3.3 (Groq)', + 'ollama' => 'Ollama (llama3.2:latest)', + 'title' => 'Models', + ], + ], + ], ], ], diff --git a/packages/Webkul/Admin/src/Resources/lang/es/app.php b/packages/Webkul/Admin/src/Resources/lang/es/app.php index 464b93773..dee9358a4 100644 --- a/packages/Webkul/Admin/src/Resources/lang/es/app.php +++ b/packages/Webkul/Admin/src/Resources/lang/es/app.php @@ -1875,6 +1875,12 @@ 'destroy-success' => 'Lead eliminado exitosamente.', 'destroy-failed' => 'No se puede eliminar el lead.', + 'file' => [ + 'invalid-format' => 'Formato JSON inválido.', + 'invalid-response' => 'Formato de respuesta de IA inválido.', + 'not-found' => 'Archivo no encontrado.', + ], + 'index' => [ 'title' => 'Leads', 'create-btn' => 'Crear Lead', @@ -1939,6 +1945,15 @@ 'all-pipelines' => 'Todos los Canales', 'create-new-pipeline' => 'Crear Nuevo Canal', ], + + 'upload' => [ + 'create-lead' => 'Crear Lead Usando IA', + 'file' => 'Subir Archivo', + 'file-info' => 'Solo se aceptan archivos en formato PDF.', + 'save-btn' => 'Guardar', + 'sample-pdf' => 'PDF de Muestra', + 'upload-pdf' => 'Subir PDF', + ], ], 'create' => [ @@ -2072,22 +2087,49 @@ ], 'email' => [ - 'title' => 'Email Settings', - 'info' => 'Email configuration for the application.', + 'title' => 'Configuración de Correo Electrónico', + 'info' => 'Configuración de correo electrónico para la aplicación.', 'imap' => [ - 'title' => 'IMAP Settings', - 'info' => 'IMAP email configuration for receiving emails.', + 'title' => 'Configuración IMAP', + 'info' => 'Configuración de correo electrónico IMAP para recibir correos electrónicos.', 'account' => [ - 'title' => 'IMAP Account', - 'title-info' => 'Configure your IMAP account settings here.', + 'title' => 'Cuenta IMAP', + 'title-info' => 'Configura los ajustes de tu cuenta IMAP aquí.', 'host' => 'Host', - 'port' => 'Port', - 'encryption' => 'Encryption Type', - 'validate-cert' => 'Validate SSL Certificate', - 'username' => 'IMAP Username', - 'password' => 'IMAP Password', + 'port' => 'Puerto', + 'encryption' => 'Tipo de Cifrado', + 'validate-cert' => 'Validar Certificado SSL', + 'username' => 'Nombre de Usuario IMAP', + 'password' => 'Contraseña IMAP', + ], + ], + ], + + 'magic-ai' => [ + 'title' => 'Magic AI', + 'info' => 'Configuración de Magic AI para la aplicación.', + + 'settings' => [ + 'api-domain' => 'Dominio de la API de LLM', + 'api-domain-info' => 'Solo para Olama y Grow, Ejemplo: http://localhost:11434', + 'api-key' => 'Clave API', + 'api-key-info' => 'Asegúrese de usar una clave API única para cada tipo de modelo para mantener un rendimiento y seguridad óptimos.', + 'enable' => 'Habilitar', + 'info' => 'Mejore su experiencia con la función Magic AI ingresando su clave API exclusiva e indicando la integración sin esfuerzo. Tome el control de sus credenciales de OpenAI y personalice la configuración según sus necesidades específicas.', + 'pdf-generation' => 'Generación de PDF', + 'pdf-generation-info' => 'Habilite la función de Generación de PDF para extraer automáticamente datos de archivos PDF y convertirlos en formato de texto. Mejore su productividad y eficiencia habilitando esta función para optimizar su flujo de trabajo.', + 'title' => 'Configuraciones Generales', + + 'models' => [ + 'deepseek-r1' => 'DeepSeek-R1 8db', + 'gemini-flash' => 'Gemini-1.5 Flash', + 'gpt-4o' => 'GPT-4.0', + 'gpt-4o-mini' => 'GPT-4.0 mini', + 'llama' => 'Llama 3.3 (Groq)', + 'ollama' => 'Ollama (llama3.2:latest)', + 'title' => 'Modelos', ], ], ], diff --git a/packages/Webkul/Admin/src/Resources/lang/fa/app.php b/packages/Webkul/Admin/src/Resources/lang/fa/app.php index 99916848c..3ed056eb9 100644 --- a/packages/Webkul/Admin/src/Resources/lang/fa/app.php +++ b/packages/Webkul/Admin/src/Resources/lang/fa/app.php @@ -1876,6 +1876,12 @@ 'destroy-success' => 'سرنخ با موفقیت حذف شد.', 'destroy-failed' => 'سرنخ قابل حذف نیست.', + 'file' => [ + 'invalid-format' => 'فرمت JSON نامعتبر است.', + 'invalid-response' => 'فرمت پاسخ AI نامعتبر است.', + 'not-found' => 'فایل یافت نشد.', + ], + 'index' => [ 'title' => 'سرنخ‌ها', 'create-btn' => 'ایجاد سرنخ', @@ -1940,6 +1946,15 @@ 'all-pipelines' => 'تمام خطوط تولید', 'create-new-pipeline' => 'ایجاد خط تولید جدید', ], + + 'upload' => [ + 'create-lead' => 'ایجاد سرنخ با استفاده از هوش مصنوعی', + 'file' => 'بارگذاری فایل', + 'file-info' => 'فقط فایل‌های با فرمت PDF پذیرفته می‌شوند.', + 'save-btn' => 'ذخیره', + 'sample-pdf' => 'نمونه PDF', + 'upload-pdf' => 'بارگذاری PDF', + ], ], 'create' => [ @@ -2073,22 +2088,49 @@ ], 'email' => [ - 'title' => 'Email Settings', - 'info' => 'Email configuration for the application.', + 'title' => 'تنظیمات ایمیل', + 'info' => 'پیکربندی ایمیل برای برنامه.', 'imap' => [ - 'title' => 'IMAP Settings', - 'info' => 'IMAP email configuration for receiving emails.', + 'title' => 'تنظیمات IMAP', + 'info' => 'پیکربندی ایمیل IMAP برای دریافت ایمیل‌ها.', 'account' => [ - 'title' => 'IMAP Account', - 'title-info' => 'Configure your IMAP account settings here.', - 'host' => 'Host', - 'port' => 'Port', - 'encryption' => 'Encryption Type', - 'validate-cert' => 'Validate SSL Certificate', - 'username' => 'IMAP Username', - 'password' => 'IMAP Password', + 'title' => 'حساب IMAP', + 'title-info' => 'تنظیمات حساب IMAP خود را اینجا پیکربندی کنید.', + 'host' => 'میزبان', + 'port' => 'پورت', + 'encryption' => 'نوع رمزگذاری', + 'validate-cert' => 'اعتبارسنجی گواهی SSL', + 'username' => 'نام کاربری IMAP', + 'password' => 'رمز عبور IMAP', + ], + ], + ], + + 'magic-ai' => [ + 'title' => 'هوش مصنوعی جادویی', + 'info' => 'پیکربندی هوش مصنوعی جادویی برای برنامه.', + + 'settings' => [ + 'api-domain' => 'دامنه API LLM', + 'api-domain-info' => 'فقط برای Olama و Grow، مثال: http://localhost:11434', + 'api-key' => 'کلید API', + 'api-key-info' => 'لطفاً اطمینان حاصل کنید که از یک کلید API منحصر به فرد برای هر نوع مدل استفاده کنید تا عملکرد و امنیت بهینه حفظ شود.', + 'enable' => 'فعال کردن', + 'info' => 'تجربه خود را با ویژگی هوش مصنوعی جادویی با وارد کردن کلید API منحصر به فرد خود و نشان دادن یکپارچه‌سازی آسان بهبود بخشید. کنترل بر روی اعتبارنامه‌های OpenAI خود را به دست آورید و تنظیمات را بر اساس نیازهای خاص خود سفارشی کنید.', + 'pdf-generation' => 'تولید PDF', + 'pdf-generation-info' => 'ویژگی تولید PDF را فعال کنید تا به طور خودکار داده‌ها را از فایل‌های PDF استخراج کرده و به فرمت متنی تبدیل کنید. با فعال کردن این ویژگی، بهره‌وری و کارایی خود را افزایش دهید تا جریان کاری خود را ساده کنید.', + 'title' => 'تنظیمات عمومی', + + 'models' => [ + 'deepseek-r1' => 'DeepSeek-R1 8db', + 'gemini-flash' => 'Gemini-1.5 Flash', + 'gpt-4o' => 'GPT-4.0', + 'gpt-4o-mini' => 'GPT-4.0 mini', + 'llama' => 'Llama 3.3 (Groq)', + 'ollama' => 'Ollama (llama3.2:latest)', + 'title' => 'مدل‌ها', ], ], ], diff --git a/packages/Webkul/Admin/src/Resources/lang/pt_BR/app.php b/packages/Webkul/Admin/src/Resources/lang/pt_BR/app.php index 7b7dac348..b01af48c8 100644 --- a/packages/Webkul/Admin/src/Resources/lang/pt_BR/app.php +++ b/packages/Webkul/Admin/src/Resources/lang/pt_BR/app.php @@ -1690,6 +1690,12 @@ 'destroy-success' => 'Lead excluído com sucesso.', 'destroy-failed' => 'Lead não pode ser excluído.', + 'file' => [ + 'invalid-format' => 'Formato JSON inválido.', + 'invalid-response' => 'Formato de resposta AI inválido.', + 'not-found' => 'Arquivo não encontrado.', + ], + 'index' => [ 'title' => 'Leads', 'create-btn' => 'Criar Lead', @@ -1754,6 +1760,15 @@ 'all-pipelines' => 'Todos os Pipelines', 'create-new-pipeline' => 'Criar Novo Pipeline', ], + + 'upload' => [ + 'create-lead' => 'Criar Lead Usando AI', + 'file' => 'Upload de Arquivo', + 'file-info' => 'Apenas arquivos em formato PDF são aceitos.', + 'save-btn' => 'Salvar', + 'sample-pdf' => 'PDF de Exemplo', + 'upload-pdf' => 'Carregar PDF', + ], ], 'create' => [ @@ -1868,8 +1883,8 @@ 'index' => [ 'back' => 'Voltar', 'save-btn' => 'Salvar Configuração', - 'save-success' => 'Configuração salva com sucesso.', - 'search' => 'Buscar', + 'save-success' => 'Configuração Salva com Sucesso.', + 'search' => 'Pesquisar', 'title' => 'Configuração', 'general' => [ @@ -1880,8 +1895,56 @@ 'title' => 'Geral', 'info' => 'Atualize suas configurações gerais aqui.', 'locale-settings' => [ - 'title' => 'Configurações de Localização', - 'title-info' => 'Define o idioma usado na interface do usuário, como Inglês (en), Francês (fr) ou Japonês (ja).', + 'title' => 'Configurações de Localidade', + 'title-info' => 'Define o idioma usado na interface do usuário, como Árabe (ar), Inglês (en), Espanhol (es), Persa (fa) e Turco (tr).', + ], + ], + ], + + 'email' => [ + 'title' => 'Configurações de Email', + 'info' => 'Configuração de email para a aplicação.', + + 'imap' => [ + 'title' => 'Configurações IMAP', + 'info' => 'Configuração de email IMAP para receber emails.', + + 'account' => [ + 'title' => 'Conta IMAP', + 'title-info' => 'Configure as configurações da sua conta IMAP aqui.', + 'host' => 'Host', + 'port' => 'Porta', + 'encryption' => 'Tipo de Criptografia', + 'validate-cert' => 'Validar Certificado SSL', + 'username' => 'Nome de Usuário IMAP', + 'password' => 'Senha IMAP', + ], + ], + ], + + 'magic-ai' => [ + 'title' => 'Magic AI', + 'info' => 'Configuração do Magic AI para a aplicação.', + + 'settings' => [ + 'api-domain' => 'Domínio da API LLM', + 'api-domain-info' => 'Para Olama e Grow apenas, Ex: http://localhost:11434', + 'api-key' => 'Chave API', + 'api-key-info' => 'Certifique-se de usar uma chave API exclusiva para cada tipo de modelo para manter o desempenho e a segurança ideais.', + 'enable' => 'Habilitar', + 'info' => 'Melhore sua experiência com o recurso Magic AI inserindo sua Chave API exclusiva e indicando a integração sem esforço. Assuma o controle sobre suas credenciais OpenAI e personalize as configurações de acordo com suas necessidades específicas.', + 'pdf-generation' => 'Geração de PDF', + 'pdf-generation-info' => 'Habilite o recurso de Geração de PDF para extrair automaticamente dados de arquivos PDF e convertê-los em formato de texto. Aumente sua produtividade e eficiência habilitando este recurso para simplificar seu fluxo de trabalho.', + 'title' => 'Configurações Gerais', + + 'models' => [ + 'deepseek-r1' => 'DeepSeek-R1 8db', + 'gemini-flash' => 'Gemini-1.5 Flash', + 'gpt-4o' => 'GPT-4.0', + 'gpt-4o-mini' => 'GPT-4.0 mini', + 'llama' => 'Llama 3.3 (Groq)', + 'ollama' => 'Ollama (llama3.2:latest)', + 'title' => 'Modelos', ], ], ], diff --git a/packages/Webkul/Admin/src/Resources/lang/tr/app.php b/packages/Webkul/Admin/src/Resources/lang/tr/app.php index 9ba75dd05..5969885b2 100644 --- a/packages/Webkul/Admin/src/Resources/lang/tr/app.php +++ b/packages/Webkul/Admin/src/Resources/lang/tr/app.php @@ -1876,6 +1876,12 @@ 'destroy-success' => 'Lead başarıyla silindi.', 'destroy-failed' => 'Lead silinemedi.', + 'file' => [ + 'invalid-format' => 'Geçersiz JSON formatı.', + 'invalid-response' => 'Geçersiz AI yanıt formatı.', + 'not-found' => 'Dosya bulunamadı.', + ], + 'index' => [ 'title' => 'Leads', 'create-btn' => 'Lead Oluştur', @@ -1940,6 +1946,15 @@ 'all-pipelines' => 'Tüm Boru Hatları', 'create-new-pipeline' => 'Yeni Boru Hattı Oluştur', ], + + 'upload' => [ + 'create-lead' => 'AI Kullanarak Lead Oluştur', + 'file' => 'Dosya Yükle', + 'file-info' => 'Sadece PDF formatındaki dosyalar kabul edilir.', + 'save-btn' => 'Kaydet', + 'sample-pdf' => 'Örnek PDF', + 'upload-pdf' => 'PDF Yükle', + ], ], 'create' => [ @@ -2092,6 +2107,33 @@ ], ], ], + + 'magic-ai' => [ + 'title' => 'Sihirli AI', + 'info' => 'Uygulama için Sihirli AI yapılandırması.', + + 'settings' => [ + 'api-domain' => 'LLM API Alanı', + 'api-domain-info' => 'Sadece Olama ve Grow için, Ör: http://localhost:11434', + 'api-key' => 'API Anahtarı', + 'api-key-info' => 'Optimum performans ve güvenliği sağlamak için her model türü için benzersiz bir API anahtarı kullanmayı unutmayın.', + 'enable' => 'Etkinleştir', + 'info' => 'Benzersiz API Anahtarınızı girerek ve sorunsuz entegrasyonu belirterek Sihirli AI özelliği ile deneyiminizi geliştirin. OpenAI kimlik bilgilerinizi kontrol altına alın ve özel ihtiyaçlarınıza göre ayarları özelleştirin.', + 'pdf-generation' => 'PDF Oluşturma', + 'pdf-generation-info' => 'PDF dosyalarından otomatik olarak veri çıkarmak ve bunları metin formatına dönüştürmek için PDF Oluşturma özelliğini etkinleştirin. Bu özelliği etkinleştirerek iş akışınızı basitleştirin ve verimliliğinizi artırın.', + 'title' => 'Genel Ayarlar', + + 'models' => [ + 'deepseek-r1' => 'DeepSeek-R1 8db', + 'gemini-flash' => 'Gemini-1.5 Flash', + 'gpt-4o' => 'GPT-4.0', + 'gpt-4o-mini' => 'GPT-4.0 mini', + 'llama' => 'Llama 3.3 (Groq)', + 'ollama' => 'Ollama (llama3.2:latest)', + 'title' => 'Modeller', + ], + ], + ], ], ], diff --git a/packages/Webkul/Admin/src/Resources/lang/vi/app.php b/packages/Webkul/Admin/src/Resources/lang/vi/app.php index ad692ce2d..fbcf78b78 100644 --- a/packages/Webkul/Admin/src/Resources/lang/vi/app.php +++ b/packages/Webkul/Admin/src/Resources/lang/vi/app.php @@ -1769,6 +1769,12 @@ 'destroy-success' => 'Xóa khách hàng tiềm năng thành công.', 'destroy-failed' => 'Không thể xóa khách hàng tiềm năng.', + 'file' => [ + 'invalid-format' => 'Định dạng JSON không hợp lệ.', + 'invalid-response' => 'Định dạng phản hồi AI không hợp lệ.', + 'not-found' => 'Không tìm thấy tệp.', + ], + 'index' => [ 'title' => 'Khách Hàng Tiềm Năng', 'create-btn' => 'Tạo Khách Hàng Tiềm Năng', @@ -1833,6 +1839,15 @@ 'all-pipelines' => 'Tất Cả Các Quy Trình', 'create-new-pipeline' => 'Tạo Quy Trình Mới', ], + + 'upload' => [ + 'create-lead' => 'Tạo Khách Hàng Tiềm Năng Bằng AI', + 'file' => 'Tải Lên Tệp', + 'file-info' => 'Chỉ chấp nhận các tệp định dạng PDF.', + 'save-btn' => 'Lưu', + 'sample-pdf' => 'PDF Mẫu', + 'upload-pdf' => 'Tải Lên PDF', + ], ], 'create' => [ @@ -1945,22 +1960,70 @@ 'configuration' => [ 'index' => [ - 'back' => 'Quay Lại', - 'save-btn' => 'Lưu Cấu Hình', - 'save-success' => 'Lưu Cấu Hình Thành Công.', - 'search' => 'Tìm Kiếm', - 'title' => 'Cấu Hình', + 'back' => 'Quay lại', + 'save-btn' => 'Lưu Cấu hình', + 'save-success' => 'Cấu hình đã được lưu thành công.', + 'search' => 'Tìm kiếm', + 'title' => 'Cấu hình', 'general' => [ 'title' => 'Chung', - 'info' => 'Cấu Hình Chung', + 'info' => 'Cấu hình chung', 'general' => [ 'title' => 'Chung', 'info' => 'Cập nhật cài đặt chung của bạn tại đây.', 'locale-settings' => [ - 'title' => 'Cài Đặt Ngôn Ngữ', - 'title-info' => 'Định nghĩa ngôn ngữ sử dụng trong giao diện người dùng, chẳng hạn như tiếng Anh (en), tiếng Pháp (fr) hoặc tiếng Nhật (ja).', + 'title' => 'Cài đặt ngôn ngữ', + 'title-info' => 'Định nghĩa ngôn ngữ được sử dụng trong giao diện người dùng, như tiếng Ả Rập (ar), tiếng Anh (en), tiếng Tây Ban Nha (es), tiếng Ba Tư (fa) và tiếng Thổ Nhĩ Kỳ (tr).', + ], + ], + ], + + 'email' => [ + 'title' => 'Cài đặt Email', + 'info' => 'Cấu hình email cho ứng dụng.', + + 'imap' => [ + 'title' => 'Cài đặt IMAP', + 'info' => 'Cấu hình email IMAP để nhận email.', + + 'account' => [ + 'title' => 'Tài khoản IMAP', + 'title-info' => 'Cấu hình cài đặt tài khoản IMAP của bạn tại đây.', + 'host' => 'Máy chủ', + 'port' => 'Cổng', + 'encryption' => 'Loại mã hóa', + 'validate-cert' => 'Xác thực chứng chỉ SSL', + 'username' => 'Tên người dùng IMAP', + 'password' => 'Mật khẩu IMAP', + ], + ], + ], + + 'magic-ai' => [ + 'title' => 'Magic AI', + 'info' => 'Cấu hình Magic AI cho ứng dụng.', + + 'settings' => [ + 'api-domain' => 'Tên miền API LLM', + 'api-domain-info' => 'Dành cho Olama và Grow, Ví dụ: http://localhost:11434', + 'api-key' => 'Khóa API', + 'api-key-info' => 'Hãy đảm bảo rằng bạn sử dụng một khóa API duy nhất cho mỗi loại mô hình để duy trì hiệu suất và bảo mật tối ưu.', + 'enable' => 'Kích hoạt', + 'info' => 'Nâng cao trải nghiệm của bạn với tính năng Magic AI bằng cách nhập Khóa API độc quyền của bạn và chỉ định tích hợp dễ dàng. Nắm quyền kiểm soát thông tin đăng nhập OpenAI của bạn và tùy chỉnh cài đặt theo nhu cầu cụ thể của bạn.', + 'pdf-generation' => 'Tạo PDF', + 'pdf-generation-info' => 'Kích hoạt tính năng Tạo PDF để tự động trích xuất dữ liệu từ các tệp PDF và chuyển đổi chúng thành định dạng văn bản. Nâng cao năng suất và hiệu quả của bạn bằng cách kích hoạt tính năng này để tối ưu hóa quy trình làm việc của bạn.', + 'title' => 'Cài đặt chung', + + 'models' => [ + 'deepseek-r1' => 'DeepSeek-R1 8db', + 'gemini-flash' => 'Gemini-1.5 Flash', + 'gpt-4o' => 'GPT-4.0', + 'gpt-4o-mini' => 'GPT-4.0 mini', + 'llama' => 'Llama 3.3 (Groq)', + 'ollama' => 'Ollama (llama3.2:latest)', + 'title' => 'Mô hình', ], ], ], diff --git a/packages/Webkul/Admin/src/Resources/views/components/button/index.blade.php b/packages/Webkul/Admin/src/Resources/views/components/button/index.blade.php index 25c00fd10..e4bc772fe 100644 --- a/packages/Webkul/Admin/src/Resources/views/components/button/index.blade.php +++ b/packages/Webkul/Admin/src/Resources/views/components/button/index.blade.php @@ -19,7 +19,7 @@ - + @{{ title }} diff --git a/packages/Webkul/Admin/src/Resources/views/leads/index.blade.php b/packages/Webkul/Admin/src/Resources/views/leads/index.blade.php index d19c1d472..0795dc369 100644 --- a/packages/Webkul/Admin/src/Resources/views/leads/index.blade.php +++ b/packages/Webkul/Admin/src/Resources/views/leads/index.blade.php @@ -25,6 +25,11 @@ {!! view_render_event('admin.leads.index.header.right.before') !!}
+ + @if(core()->getConfigData('general.magic_ai.pdf_generation.enabled')) + @include('admin::leads.index.upload') + @endif + @if ((request()->view_type ?? "kanban") == "table") diff --git a/packages/Webkul/Admin/src/Resources/views/leads/index/upload.blade.php b/packages/Webkul/Admin/src/Resources/views/leads/index/upload.blade.php new file mode 100644 index 000000000..81b274ac8 --- /dev/null +++ b/packages/Webkul/Admin/src/Resources/views/leads/index/upload.blade.php @@ -0,0 +1,134 @@ + + + + +@pushOnce('scripts') + + + +@endPushOnce diff --git a/packages/Webkul/Admin/src/Routes/Admin/leads-routes.php b/packages/Webkul/Admin/src/Routes/Admin/leads-routes.php index c94940f4d..43a0be06f 100644 --- a/packages/Webkul/Admin/src/Routes/Admin/leads-routes.php +++ b/packages/Webkul/Admin/src/Routes/Admin/leads-routes.php @@ -14,6 +14,8 @@ Route::post('create', 'store')->name('admin.leads.store'); + Route::post('create-by-ai', 'createByAI')->name('admin.leads.create_by_ai'); + Route::get('view/{id}', 'view')->name('admin.leads.view'); Route::get('edit/{id}', 'edit')->name('admin.leads.edit'); diff --git a/packages/Webkul/Core/src/Vite.php b/packages/Webkul/Core/src/Vite.php index 633093869..9df887a2c 100644 --- a/packages/Webkul/Core/src/Vite.php +++ b/packages/Webkul/Core/src/Vite.php @@ -30,7 +30,7 @@ public function asset(string $filename, string $namespace = 'admin') } /** - * Set bagisto vite. + * Set krayin vite. * * @return mixed */ diff --git a/packages/Webkul/Lead/src/Helpers/Lead.php b/packages/Webkul/Lead/src/Helpers/Lead.php new file mode 100644 index 000000000..a2c936a3f --- /dev/null +++ b/packages/Webkul/Lead/src/Helpers/Lead.php @@ -0,0 +1,126 @@ +getConfigData('general.magic_ai.settings.model'), self::GEMINI_MODEL); + + $content = $isGeminiModel ? $aiData['candidates'][0]['content']['parts'][0]['text'] : $aiData['choices'][0]['message']['content']; + + $content = strip_tags($content); + + preg_match('/\{.*\}/s', $content, $matches); + + if (! $jsonString = $matches[0] ?? null) { + return [ + 'status' => 'error', + 'message' => trans('admin::app.leads.file.invalid-response'), + ]; + } + + $finalData = json_decode($jsonString); + + if (json_last_error() !== JSON_ERROR_NONE) { + return [ + 'status' => 'error', + 'message' => trans('admin::app.leads.file.invalid-format'), + ]; + } + + try { + self::validateLeadData($finalData); + + $validatedData = app(LeadForm::class)->validated(); + + return array_merge($validatedData, self::prepareLeadData($finalData)); + } catch (\Exception $e) { + return [ + 'status' => 'error', + 'message' => $e->getMessage(), + ]; + } + } + + /** + * Validate the lead data. + */ + private static function validateLeadData($data) + { + $dataArray = json_decode(json_encode($data), true); + + $validator = Validator::make($dataArray, [ + 'title' => 'required|string|max:255', + 'lead_value' => 'required|numeric|min:0', + 'person.name' => 'required|string|max:255', + 'person.emails.value' => 'required|email', + 'person.contact_numbers.value' => 'required|string|max:20', + ]); + + if ($validator->fails()) { + throw new \Illuminate\Validation\ValidationException( + $validator, + response()->json([ + 'status' => 'error', + 'message' => $validator->errors()->getMessages(), + ], 400) + ); + } + + return $data; + } + + private static function prepareLeadData($finalData) + { + return [ + 'status' => 1, + 'title' => $finalData->title ?? 'N/A', + 'description' => $finalData->description ?? null, + 'lead_source_id' => 1, + 'lead_type_id' => 1, + 'lead_value' => $finalData->lead_value ?? 0, + 'person' => [ + 'name' => $finalData->person->name ?? 'Unknown', + 'emails' => [ + [ + 'value' => $finalData->person->emails->value ?? null, + 'label' => $finalData->person->emails->label ?? 'work', + ], + ], + 'contact_numbers' => [ + [ + 'value' => $finalData->person->contact_numbers->value ?? null, + 'label' => $finalData->person->contact_numbers->label ?? 'work', + ], + ], + 'entity_type' => self::PERSON_ENTITY, + ], + 'entity_type' => self::LEAD_ENTITY, + ]; + } +} diff --git a/packages/Webkul/Lead/src/Services/GeminiService.php b/packages/Webkul/Lead/src/Services/GeminiService.php new file mode 100644 index 000000000..8ba62f4ae --- /dev/null +++ b/packages/Webkul/Lead/src/Services/GeminiService.php @@ -0,0 +1,88 @@ + 'application/json', + ])->post($url, $data); + + if ($response->failed()) { + throw new Exception($response->json('error.message')); + } + + return $response->json(); + } catch (Exception $e) { + return ['error' => $e->getMessage()]; + } + } + + /** + * Prepare request data for AI. + */ + private static function prepareLeadExtractionRequestData($prompt) + { + return [ + 'contents' => [ + [ + 'parts' => [ + [ + 'text' => "You are an AI assistant. Extract data from the provided PDF text. + + Example Output: + { + \"status\": 1, + \"title\": \"Untitled Lead\", + \"person\": { + \"name\": \"Unknown\", + \"emails\": { + \"value\": null, + \"label\": null + }, + \"contact_numbers\": { + \"value\": null, + \"label\": null + } + }, + \"lead_pipeline_stage_id\": null, + \"lead_value\": 0, + \"source\": \"AI Extracted\" + } + + Note: Only return the output. Do not return or add any comments. + + PDF Content: + $prompt", + ], + ], + 'role' => 'user', + ], + ], + 'generationConfig' => [ + 'temperature' => 0.2, + 'topK' => 30, + 'topP' => 0.8, + 'maxOutputTokens' => 512, + ], + ]; + } +} diff --git a/packages/Webkul/Lead/src/Services/LeadService.php b/packages/Webkul/Lead/src/Services/LeadService.php new file mode 100644 index 000000000..5c14072d6 --- /dev/null +++ b/packages/Webkul/Lead/src/Services/LeadService.php @@ -0,0 +1,52 @@ +parseFile($pdfPath)->getText()))) { + throw new Exception('PDF content is empty or could not be extracted.'); + } + + return self::processPromptWithAI($pdfText); + } catch (Exception $e) { + return ['error' => $e->getMessage()]; + } + } + + /** + * Send a request to the LLM API. + */ + private static function processPromptWithAI($prompt) + { + $model = core()->getConfigData('general.magic_ai.settings.model'); + $apiKey = core()->getConfigData('general.magic_ai.settings.api_key'); + + if (! $apiKey || ! $model) { + return ['error' => 'Missing API key or model configuration.']; + } + + if (str_contains($model, Lead::GEMINI_MODEL)) { + return GeminiService::ask($prompt, $model, $apiKey); + } else { + return OpenAIService::ask($prompt, $model); + } + } +} diff --git a/packages/Webkul/Lead/src/Services/OpenAIService.php b/packages/Webkul/Lead/src/Services/OpenAIService.php new file mode 100644 index 000000000..9c015e452 --- /dev/null +++ b/packages/Webkul/Lead/src/Services/OpenAIService.php @@ -0,0 +1,94 @@ + 'application/json', + 'Authorization' => 'Bearer '.core()->getConfigData('general.magic_ai.settings.api_key'), + ])->post($url, $data); + + if ($response->failed()) { + throw new Exception($response->json('error.message')); + } + + return $response->json(); + } catch (Exception $e) { + return ['error' => $e->getMessage()]; + } + } + + /** + * Prepare request data for AI. + */ + private static function prepareLeadExtractionRequestData($model, $prompt) + { + return [ + 'model' => $model, + 'messages' => [ + [ + 'role' => 'system', + 'content' => 'You are an AI assistant. You have to extract the data from the PDF file. + Example Output: + { + "status": 1, + "title": "Untitled Lead", + "person": { + "name": "Unknown", + "emails": { + "value": null, + "label": null + }, + "contact_numbers": { + "value": null, + "label": null + } + }, + "lead_pipeline_stage_id": null, + "lead_value": 0, + "source": "AI Extracted" + } + Note: Only return the output, Do not return or add any comments.', + ], + ['role' => 'user', 'content' => "PDF:\n$prompt"], + ], + ]; + } + + /** + * Get API Url for the model. + */ + private static function getApiUrlForModel($model) + { + $apiDomain = core()->getConfigData('general.magic_ai.settings.api_domain'); + + $apiUrlMap = [ + 'gpt-4o' => Lead::OPEN_AI_MODEL_URL, + 'gpt-4o-mini' => Lead::OPEN_AI_MODEL_URL, + 'llama3.2:latest' => "$apiDomain/v1/chat/completions", + 'deepseek-r1:8b' => "$apiDomain/v1/chat/completions", + ]; + + return $apiUrlMap[$model] ?? 'https://api.groq.com/openai/v1/chat/completions'; + } +} diff --git a/storage/app/public/.gitignore b/storage/app/public/.gitignore index abdee4c37..0efcfa459 100644 --- a/storage/app/public/.gitignore +++ b/storage/app/public/.gitignore @@ -1,3 +1,5 @@ * !data-transfer +!lead-samples/ +!lead-samples/* !.gitignore diff --git a/storage/app/public/lead-samples/sample.pdf b/storage/app/public/lead-samples/sample.pdf new file mode 100644 index 000000000..078a5df76 Binary files /dev/null and b/storage/app/public/lead-samples/sample.pdf differ