From 3b617f997183597d2c61e005eb4cad0ea23db580 Mon Sep 17 00:00:00 2001 From: Babak Alizadeh Date: Sat, 19 Jul 2025 10:19:33 +0000 Subject: [PATCH] progress in ai in person module --- .../src/Controller/wizardController.php | 387 +++++++- hesabixCore/src/Service/AI/AIService.php | 891 ++++++++++++++++-- .../Service/AI/PersonManagementService.php | 15 +- webUI/src/views/wizard/home.vue | 261 +++-- 4 files changed, 1411 insertions(+), 143 deletions(-) diff --git a/hesabixCore/src/Controller/wizardController.php b/hesabixCore/src/Controller/wizardController.php index 7673611d..c0f8b3cc 100644 --- a/hesabixCore/src/Controller/wizardController.php +++ b/hesabixCore/src/Controller/wizardController.php @@ -176,7 +176,8 @@ class wizardController extends AbstractController 'response' => $responseContent, 'conversationId' => $conversation->getId(), 'model' => $result['model'] ?? null, - 'usage' => $result['usage'] ?? null + 'usage' => $result['usage'] ?? null, + 'debug_info' => $result['debug_info'] ?? null ]; // محاسبه هزینه در صورت وجود اطلاعات usage @@ -212,14 +213,21 @@ class wizardController extends AbstractController return $this->json([ 'success' => false, - 'error' => $result['error'] ?? 'خطای نامشخص در سرویس هوش مصنوعی' + 'error' => $result['error'] ?? 'خطای نامشخص در سرویس هوش مصنوعی', + 'debug_info' => $result['debug_info'] ?? null ]); } } catch (\Exception $e) { return $this->json([ 'success' => false, - 'error' => 'خطا در پردازش درخواست: ' . $e->getMessage() + 'error' => 'خطا در پردازش درخواست: ' . $e->getMessage(), + 'debug_info' => [ + 'ai_response' => null, + 'tool_commands' => [], + 'has_commands' => false, + 'error_details' => $e->getMessage() + ] ]); } } @@ -557,4 +565,377 @@ class wizardController extends AbstractController ]); } } + + #[Route('/api/wizard/execute-command', name: 'wizard_execute_command', methods: ['POST'])] + public function wizard_execute_command( + Request $request, + Access $access, + EntityManagerInterface $entityManager, + Log $log + ): JsonResponse + { + try { + $acc = $access->hasRole('join'); + if (!$acc) { + throw $this->createAccessDeniedException(); + } + + // بررسی دسترسی هوش مصنوعی + if (!$acc['ai']) { + return $this->json([ + 'success' => false, + 'error' => 'شما دسترسی استفاده از هوش مصنوعی را ندارید' + ]); + } + + $params = json_decode($request->getContent(), true) ?? []; + + if (!isset($params['tool']) || !isset($params['params'])) { + return $this->json([ + 'success' => false, + 'error' => 'ابزار و پارامترها الزامی هستند' + ]); + } + + $tool = $params['tool']; + $commandParams = $params['params']; + $business = $acc['bid']; + + // اجرای دستور + $result = null; + switch ($tool) { + case 'add_person': + $result = $this->aiService->getPersonManagementService()->addPerson($commandParams, $business, $acc['user']); + break; + case 'edit_person': + $result = $this->aiService->getPersonManagementService()->editPerson($commandParams, $business, $acc['user']); + break; + case 'delete_person': + $result = $this->aiService->getPersonManagementService()->deletePerson($commandParams, $business, $acc['user']); + break; + case 'show_person': + $result = $this->aiService->getPersonManagementService()->showPerson($commandParams, $business, $acc['user']); + break; + case 'search_persons': + $result = $this->aiService->getPersonManagementService()->searchPersons($commandParams, $business); + break; + default: + return $this->json([ + 'success' => false, + 'error' => "ابزار '{$tool}' شناخته نشد" + ]); + } + + if ($result && $result['success']) { + return $this->json([ + 'success' => true, + 'response' => $result['message'] ?? 'عملیات با موفقیت انجام شد', + 'debug_info' => [ + 'ai_response' => 'دستور اجرا شد', + 'tool_commands' => [ + [ + 'tool' => $tool, + 'params' => $commandParams + ] + ], + 'has_commands' => true, + 'execution_result' => $result + ] + ]); + } else { + return $this->json([ + 'success' => false, + 'error' => $result['error'] ?? 'خطا در اجرای دستور', + 'debug_info' => [ + 'ai_response' => 'خطا در اجرای دستور', + 'tool_commands' => [ + [ + 'tool' => $tool, + 'params' => $commandParams + ] + ], + 'has_commands' => true, + 'execution_result' => $result + ] + ]); + } + + } catch (\Exception $e) { + return $this->json([ + 'success' => false, + 'error' => 'خطا در اجرای دستور: ' . $e->getMessage(), + 'debug_info' => [ + 'ai_response' => null, + 'tool_commands' => [], + 'has_commands' => false, + 'error_details' => $e->getMessage() + ] + ]); + } + } + + #[Route('/api/wizard/test-debug-info', name: 'wizard_test_debug_info', methods: ['POST'])] + public function wizard_test_debug_info(Access $access): JsonResponse + { + try { + $acc = $access->hasRole('join'); + if (!$acc) { + throw $this->createAccessDeniedException(); + } + + // بررسی دسترسی هوش مصنوعی + if (!$acc['ai']) { + return $this->json([ + 'success' => false, + 'error' => 'شما دسترسی استفاده از هوش مصنوعی را ندارید', + 'debug_info' => [ + 'ai_response' => 'خطای دسترسی', + 'tool_commands' => [], + 'has_commands' => false, + 'error_details' => 'No AI access' + ] + ]); + } + + return $this->json([ + 'success' => true, + 'response' => 'تست Debug Info با موفقیت انجام شد', + 'debug_info' => [ + 'ai_response' => 'این یک تست برای Debug Info است', + 'tool_commands' => [ + [ + 'tool' => 'test_tool', + 'params' => ['test_param' => 'test_value'] + ] + ], + 'has_commands' => true, + 'test_data' => 'این داده تست است' + ] + ]); + + } catch (\Exception $e) { + return $this->json([ + 'success' => false, + 'error' => 'خطا در تست Debug Info: ' . $e->getMessage(), + 'debug_info' => [ + 'ai_response' => null, + 'tool_commands' => [], + 'has_commands' => false, + 'error_details' => $e->getMessage() + ] + ]); + } + } + + #[Route('/api/wizard/test-interactive', name: 'wizard_test_interactive', methods: ['POST'])] + public function wizard_test_interactive(Access $access): JsonResponse + { + try { + $acc = $access->hasRole('join'); + if (!$acc) { + throw $this->createAccessDeniedException(); + } + + // بررسی دسترسی هوش مصنوعی + if (!$acc['ai']) { + return $this->json([ + 'success' => false, + 'error' => 'شما دسترسی استفاده از هوش مصنوعی را ندارید', + 'debug_info' => [ + 'ai_response' => 'خطای دسترسی', + 'action_type' => 'error', + 'has_commands' => false, + 'error_details' => 'No AI access' + ] + ]); + } + + // تست سیستم تعاملی + $testMessage = "تلفن 09123456789 را برای محسن اضافه کن"; + $business = $acc['bid']; + + $result = $this->aiService->sendRequest($testMessage, $business, $acc['user']); + + return $this->json([ + 'success' => true, + 'response' => $result['response'] ?? 'تست سیستم تعاملی', + 'debug_info' => $result['debug_info'] ?? [ + 'ai_response' => 'تست سیستم تعاملی', + 'action_type' => 'test', + 'has_commands' => false + ] + ]); + + } catch (\Exception $e) { + return $this->json([ + 'success' => false, + 'error' => 'خطا در تست سیستم تعاملی: ' . $e->getMessage(), + 'debug_info' => [ + 'ai_response' => null, + 'action_type' => 'error', + 'has_commands' => false, + 'error_details' => $e->getMessage() + ] + ]); + } + } + + #[Route('/api/wizard/test-interactive-system', name: 'wizard_test_interactive_system', methods: ['POST'])] + public function wizard_test_interactive_system(Access $access): JsonResponse + { + try { + $acc = $access->hasRole('join'); + if (!$acc) { + throw $this->createAccessDeniedException(); + } + + // بررسی دسترسی هوش مصنوعی + if (!$acc['ai']) { + return $this->json([ + 'success' => false, + 'error' => 'شما دسترسی استفاده از هوش مصنوعی را ندارید', + 'debug_info' => [ + 'ai_response' => 'خطای دسترسی', + 'action_type' => 'error', + 'has_commands' => false, + 'error_details' => 'No AI access' + ] + ]); + } + + // تست سیستم تعاملی + $testMessage = "تلفن 09123456789 را برای محسن اضافه کن"; + $business = $acc['bid']; + + $result = $this->aiService->sendRequest($testMessage, $business, $acc['user']); + + return $this->json([ + 'success' => true, + 'response' => $result['response'] ?? 'تست سیستم تعاملی', + 'debug_info' => $result['debug_info'] ?? [ + 'ai_response' => 'تست سیستم تعاملی', + 'action_type' => 'test', + 'has_commands' => false + ] + ]); + + } catch (\Exception $e) { + return $this->json([ + 'success' => false, + 'error' => 'خطا در تست سیستم تعاملی: ' . $e->getMessage(), + 'debug_info' => [ + 'ai_response' => null, + 'action_type' => 'error', + 'has_commands' => false, + 'error_details' => $e->getMessage() + ] + ]); + } + } + + #[Route('/api/wizard/test-continuous-operation', name: 'wizard_test_continuous_operation', methods: ['POST'])] + public function wizard_test_continuous_operation(Access $access): JsonResponse + { + try { + $acc = $access->hasRole('join'); + if (!$acc) { + throw $this->createAccessDeniedException(); + } + + // بررسی دسترسی هوش مصنوعی + if (!$acc['ai']) { + return $this->json([ + 'success' => false, + 'error' => 'شما دسترسی استفاده از هوش مصنوعی را ندارید', + 'debug_info' => [ + 'ai_response' => 'خطای دسترسی', + 'action_type' => 'error', + 'has_commands' => false, + 'error_details' => 'No AI access' + ] + ]); + } + + // تست عملیات پیوسته + $testMessage = "برای احمد موبایل 09123456789 تنظیم کن"; + $business = $acc['bid']; + + $result = $this->aiService->sendRequest($testMessage, $business, $acc['user']); + + return $this->json([ + 'success' => true, + 'response' => $result['response'] ?? 'تست عملیات پیوسته', + 'debug_info' => $result['debug_info'] ?? [ + 'ai_response' => 'تست عملیات پیوسته', + 'action_type' => 'test', + 'has_commands' => false + ] + ]); + + } catch (\Exception $e) { + return $this->json([ + 'success' => false, + 'error' => 'خطا در تست عملیات پیوسته: ' . $e->getMessage(), + 'debug_info' => [ + 'ai_response' => null, + 'action_type' => 'error', + 'has_commands' => false, + 'error_details' => $e->getMessage() + ] + ]); + } + } + + #[Route('/api/wizard/test-smart-operation', name: 'wizard_test_smart_operation', methods: ['POST'])] + public function wizard_test_smart_operation(Access $access): JsonResponse + { + try { + $acc = $access->hasRole('join'); + if (!$acc) { + throw $this->createAccessDeniedException(); + } + + // بررسی دسترسی هوش مصنوعی + if (!$acc['ai']) { + return $this->json([ + 'success' => false, + 'error' => 'شما دسترسی استفاده از هوش مصنوعی را ندارید', + 'debug_info' => [ + 'ai_response' => 'خطای دسترسی', + 'action_type' => 'error', + 'has_commands' => false, + 'error_details' => 'No AI access' + ] + ]); + } + + // تست عملیات هوشمند + $testMessage = "تلفن 09123456789 را برای محسن اضافه کن"; + $business = $acc['bid']; + + $result = $this->aiService->sendRequest($testMessage, $business, $acc['user']); + + return $this->json([ + 'success' => true, + 'response' => $result['response'] ?? 'تست عملیات هوشمند', + 'debug_info' => $result['debug_info'] ?? [ + 'ai_response' => 'تست عملیات هوشمند', + 'action_type' => 'test', + 'has_commands' => false + ] + ]); + + } catch (\Exception $e) { + return $this->json([ + 'success' => false, + 'error' => 'خطا در تست عملیات هوشمند: ' . $e->getMessage(), + 'debug_info' => [ + 'ai_response' => null, + 'action_type' => 'error', + 'has_commands' => false, + 'error_details' => $e->getMessage() + ] + ]); + } + } } diff --git a/hesabixCore/src/Service/AI/AIService.php b/hesabixCore/src/Service/AI/AIService.php index 2de53f87..95a5f062 100644 --- a/hesabixCore/src/Service/AI/AIService.php +++ b/hesabixCore/src/Service/AI/AIService.php @@ -75,6 +75,10 @@ class AIService // پردازش پاسخ هوش مصنوعی برای تشخیص دستورات ابزار $processedResponse = $this->processAIResponse($aiResponse, $business, $user); + // اضافه کردن debug logging + error_log('AIService Debug - AI Response: ' . $aiResponse); + error_log('AIService Debug - Processed Response: ' . json_encode($processedResponse)); + return [ 'success' => true, 'response' => $processedResponse['response'], @@ -82,7 +86,8 @@ class AIService 'service' => $service, 'model' => $this->getAIModel(), 'requires_action' => $processedResponse['requires_action'] ?? false, - 'action_data' => $processedResponse['action_data'] ?? null + 'action_data' => $processedResponse['action_data'] ?? null, + 'debug_info' => $processedResponse['debug_info'] ?? null ]; } else { // اگر کلید data وجود ندارد، احتمالاً پاسخ از ابزار است @@ -143,62 +148,766 @@ class AIService */ private function getSystemPrompt(): string { - return "شما یک دستیار هوشمند برای سیستم حسابداری حسابیکس هستید. شما دسترسی به ابزارهای زیر دارید: - -🔧 ابزارهای موجود: - -1. **مدیریت اشخاص** (person_management): - - افزودن شخص جدید: add_person{name:نام مستعار} - - حذف شخص: delete_person{name:نام مستعار} - - ویرایش شخص: edit_person{name:نام مستعار, phone:موبایل, address:آدرس, email:ایمیل} - - نمایش مشخصات: show_person{name:نام مستعار} - - جستجوی اشخاص: search_persons{search:متن جستجو, limit:تعداد نتایج} - -📋 قوانین استفاده: -- اگر کاربر درخواست عملیات مدیریت اشخاص دارد، از دستورات بالا استفاده کنید -- نام شخص = نام مستعار (nikename) که در دیتابیس فیلد الزامی است -- نام مستعار معمولاً همان نامی است که کاربران استفاده می‌کنند -- برای عملیات پیچیده، اطلاعات را جمع‌آوری کنید -- همیشه پاسخ فارسی و واضح ارائه دهید -- حتماً دستور ابزار را در پاسخ خود قرار دهید - -🔄 حفظ context: -- همیشه تاریخچه گفتگو را در نظر بگیرید -- اگر کاربر به سوال قبلی اشاره می‌کند، آن را در نظر بگیرید -- اگر نام شخص در سوال قبلی ذکر شده، از آن استفاده کنید -- برای سوالات کوتاه، به context قبلی مراجعه کنید - -💡 مثال‌های استفاده: -- 'علی رو حذف کن' → ابتدا بگویید: 'برای حذف شخص علی، از دستور delete_person{name:علی} استفاده می‌کنم.' -- 'شخص جدید با نام احمد اضافه کن' → ابتدا بگویید: 'برای افزودن شخص جدید، از دستور add_person{name:احمد} استفاده می‌کنم.' -- 'مشخصات محسن رو نشون بده' → ابتدا بگویید: 'برای نمایش مشخصات محسن، از دستور show_person{name:محسن} استفاده می‌کنم.' -- 'اطلاعات رضا کمری رو بده' → ابتدا بگویید: 'برای نمایش مشخصات رضا کمری، از دستور show_person{name:رضا کمری} استفاده می‌کنم.' - -💬 مثال حفظ context: -- کاربر: 'اطلاعات رضا رو بهم بده' -- دستیار: 'کدام رضا؟ لطفاً نام کامل یا نام مستعار را مشخص کنید.' -- کاربر: 'کمری' -- دستیار: 'برای نمایش مشخصات رضا کمری، از دستور show_person{name:رضا کمری} استفاده می‌کنم.' - -⚠️ نکات مهم: -- نام شخص = نام مستعار (nikename) در دیتابیس -- حتماً دستور ابزار را در پاسخ خود قرار دهید -- فقط از ابزارهایی که معرفی شده‌اند استفاده کنید -- اگر ابزار مناسب وجود ندارد، به کاربر بگویید -- برای عملیات پیچیده، مرحله به مرحله پیش بروید -- همیشه context گفتگو را حفظ کنید - -لطفاً درخواست کاربر را بررسی کرده و در صورت نیاز از ابزارهای مناسب استفاده کنید. حتماً دستور ابزار را در پاسخ خود قرار دهید و context گفتگو را حفظ کنید."; + return "شما یک دستیار هوشمند برای سیستم حسابداری حسابیکس هستید.\n\n🔧 ابزارهای موجود:\n\n1. **مدیریت اشخاص**:\n - افزودن شخص جدید: add_person{name:نام مستعار, full_name:نام کامل}\n - حذف شخص: delete_person{name:نام مستعار}\n - ویرایش شخص: edit_person{name:نام مستعار, mobile:موبایل, address:آدرس, email:ایمیل}\n - نمایش مشخصات: show_person{name:نام مستعار}\n - جستجوی اشخاص: search_persons{search:متن جستجو, limit:تعداد نتایج}\n\n📋 قوانین مهم:\n- حتماً از دستورات بالا استفاده کنید\n- نام شخص = نام مستعار (nikename) - فیلد الزامی\n- نام کامل (full_name) = نام و نام خانوادگی - فیلد اختیاری\n\n🔄 سیستم تعاملی چندمرحله‌ای:\nبرای عملیات پیچیده که نیاز به چند مرحله دارند، از ساختار JSON استفاده کنید:\n\n```json\n{ + \"action\": \"tool_command\", + \"tool\": \"نام_ابزار\", + \"params\": { + \"param1\": \"value1\", + \"param2\": \"value2\" + }, + \"user_message\": \"پیام نمایشی برای کاربر\", + \"debug_info\": \"اطلاعات دیباگ\", + \"requires_followup\": true, + \"next_step\": \"توضیح مرحله بعدی\" +} +```\n\n🔄 سیستم عملیات پیوسته تا حصول نتیجه:\nبرای عملیات‌هایی که ممکن است نیاز به چندین تلاش داشته باشند، از متغیر `operation_complete` استفاده کنید:\n\n```json\n{ + \"action\": \"continuous_operation\", + \"operation_type\": \"نوع_عملیات\", + \"current_step\": \"مرحله_فعلی\", + \"steps\": [ + { + \"tool\": \"search_persons\", + \"params\": {\"search\": \"محسن\"}, + \"purpose\": \"جستجوی شخص محسن\" + } + ], + \"user_message\": \"در حال جستجوی شخص محسن...\", + \"debug_info\": \"عملیات پیوسته برای یافتن و ویرایش محسن\", + \"operation_complete\": false, + \"next_action\": \"اگر محسن پیدا نشد، شخص جدید بساز\", + \"max_attempts\": 3 +} +```\n\n🔄 سیستم عملیات هوشمند چندمرحله‌ای (جدید):\nبرای عملیات‌هایی که نیاز به تصمیم‌گیری هوشمند دارند، از ساختار زیر استفاده کنید:\n\n```json\n{ + \"action\": \"smart_operation\", + \"operation_type\": \"add_phone_to_person\", + \"target_person\": \"محسن\", + \"target_phone\": \"09123456789\", + \"steps\": [ + { + \"tool\": \"search_persons\", + \"params\": {\"search\": \"محسن\"}, + \"purpose\": \"جستجوی شخص محسن\", + \"on_success\": \"edit_person\", + \"on_failure\": \"add_person\" + } + ], + \"user_message\": \"در حال جستجوی شخص محسن...\", + \"debug_info\": \"عملیات هوشمند برای افزودن تلفن\", + \"operation_complete\": false, + \"next_action\": \"بر اساس نتیجه جستجو، شخص را ویرایش یا اضافه کن\" +} +```\n\n📝 انواع پاسخ‌ها:\n\n1. **پاسخ مستقیم** (برای عملیات ساده):\n```json\n{ + \"action\": \"direct_response\", + \"user_message\": \"پیام نمایشی برای کاربر\", + \"debug_info\": \"اطلاعات دیباگ\" +} +```\n\n2. **دستور ابزار** (برای عملیات تک مرحله‌ای):\n```json\n{ + \"action\": \"tool_command\", + \"tool\": \"edit_person\", + \"params\": { + \"name\": \"محسن\", + \"mobile\": \"09123456789\" + }, + \"user_message\": \"در حال ویرایش موبایل محسن...\", + \"debug_info\": \"اجرای دستور edit_person\" +} +```\n\n3. **عملیات چندمرحله‌ای** (برای عملیات پیچیده):\n```json\n{ + \"action\": \"multi_step\", + \"steps\": [ + { + \"tool\": \"search_persons\", + \"params\": {\"search\": \"محسن\"}, + \"purpose\": \"جستجوی شخص محسن\" + }, + { + \"tool\": \"edit_person\", + \"params\": {\"name\": \"محسن\", \"mobile\": \"09123456789\"}, + \"purpose\": \"ویرایش موبایل\" + } + ], + \"user_message\": \"در حال جستجو و ویرایش اطلاعات محسن...\", + \"debug_info\": \"عملیات چندمرحله‌ای\", + \"requires_followup\": true +} +```\n\n4. **عملیات هوشمند چندمرحله‌ای** (جدید):\n```json\n{ + \"action\": \"smart_operation\", + \"operation_type\": \"add_phone_to_person\", + \"target_person\": \"محسن\", + \"target_phone\": \"09123456789\", + \"steps\": [ + { + \"tool\": \"search_persons\", + \"params\": {\"search\": \"محسن\"}, + \"purpose\": \"جستجوی شخص محسن\", + \"on_success\": \"edit_person\", + \"on_failure\": \"add_person\" + } + ], + \"user_message\": \"در حال جستجوی شخص محسن...\", + \"debug_info\": \"عملیات هوشمند برای افزودن تلفن\", + \"operation_complete\": false, + \"next_action\": \"بر اساس نتیجه جستجو، شخص را ویرایش یا اضافه کن\" +} +```\n\n5. **نتیجه نهایی** (وقتی عملیات کامل شد):\n```json\n{ + \"action\": \"operation_complete\", + \"operation_type\": \"add_phone_to_person\", + \"final_result\": \"عملیات با موفقیت انجام شد\", + \"user_message\": \"موبایل 09123456789 برای محسن محمودی با موفقیت اضافه شد\", + \"debug_info\": \"عملیات پیوسته کامل شد\", + \"operation_complete\": true, + \"total_steps\": 2, + \"final_data\": { + \"person_id\": 139, + \"person_name\": \"محسن محمودی\", + \"new_mobile\": \"09123456789\" + } +} +```\n\n💡 مثال‌های استفاده:\n\n**مثال 1 - عملیات ساده:**\n- 'علی رو حذف کن' → دستور مستقیم delete_person\n\n**مثال 2 - عملیات با جستجو:**\n- 'تلفن 09123456789 را برای محسن اضافه کن' → ابتدا جستجو، سپس ویرایش\n\n**مثال 3 - عملیات هوشمند:**\n- 'شخصی با نام محسن پیدا کن و موبایلش رو 09123456789 کن' → جستجو + اگر پیدا شد ویرایش + اگر پیدا نشد بساز\n\n**مثال 4 - عملیات پیچیده:**\n- 'برای احمد موبایل 09123456789 تنظیم کن' → جستجو + اگر پیدا نشد بساز + ویرایش موبایل\n\n**مثال 5 - نمایش نتایج جستجو:**\n- '5 نفر اخیر را نشان بده' → جستجو + نمایش مستقیم نتایج بدون followup\n\n⚠️ نکات مهم:\n- حتماً از ساختار JSON استفاده کنید\n- برای عملیات پیچیده، ابتدا جستجو کنید\n- اگر شخصی پیدا نشد، شخص جدید بسازید\n- پیام‌های کاربر را واضح و مفید بنویسید\n- اطلاعات دیباگ را کامل ارائه دهید\n- برای عملیات‌هایی که فقط نیاز به نمایش نتایج دارند، requires_followup را false کنید\n- برای عملیات پیوسته، operation_complete را false نگه دارید تا به نتیجه برسید\n- وقتی عملیات کامل شد، operation_complete را true کنید و نتیجه نهایی را ارائه دهید\n- برای عملیات هوشمند، از on_success و on_failure استفاده کنید تا مرحله بعدی مشخص شود\n- برای جستجو و نمایش نتایج، مستقیماً نتایج را در user_message قرار دهید و requires_followup را false کنید\n\n🔄 منطق عملیات هوشمند:\n1. ابتدا جستجو کنید\n2. اگر پیدا شد، عملیات مورد نظر را انجام دهید\n3. اگر پیدا نشد، شخص جدید بسازید\n4. سپس عملیات مورد نظر را انجام دهید\n5. در نهایت operation_complete را true کنید\n\n🔄 منطق عملیات پیوسته:\n1. ابتدا جستجو کنید\n2. اگر پیدا شد، عملیات مورد نظر را انجام دهید\n3. اگر پیدا نشد، شخص جدید بسازید\n4. سپس عملیات مورد نظر را انجام دهید\n5. در نهایت operation_complete را true کنید\n\n🔄 منطق نمایش نتایج:\n1. جستجو را انجام دهید\n2. نتایج را مستقیماً در user_message قرار دهید\n3. requires_followup را false کنید\n4. اطلاعات کامل را در debug_info قرار دهید\n\n🔄 منطق پاسخ‌دهی عمومی:\n1. سوال را بررسی کنید\n2. اگر سوال عمومی است، پاسخ آموزشی ارائه دهید\n3. از direct_response استفاده کنید\n4. اطلاعات مفید و کامل ارائه دهید\n\nلطفاً درخواست کاربر را بررسی کرده و پاسخ مناسب را با ساختار JSON ارائه دهید."; } /** * پردازش پاسخ هوش مصنوعی و تشخیص دستورات ابزار */ private function processAIResponse(string $aiResponse, ?Business $business, $user): array + { + // ابتدا سعی کن JSON را از پاسخ استخراج کن + $jsonResponse = $this->extractJSONFromResponse($aiResponse); + + if ($jsonResponse) { + return $this->processJSONResponse($jsonResponse, $aiResponse, $business, $user); + } + + // اگر JSON یافت نشد، از روش قدیمی استفاده کن + return $this->processLegacyResponse($aiResponse, $business, $user); + } + + /** + * استخراج JSON از پاسخ AI + */ + private function extractJSONFromResponse(string $aiResponse): ?array + { + // جستجوی JSON در پاسخ + if (preg_match('/```json\s*(\{.*?\})\s*```/s', $aiResponse, $matches)) { + $jsonString = $matches[1]; + } elseif (preg_match('/(\{.*\})/s', $aiResponse, $matches)) { + $jsonString = $matches[1]; + } else { + return null; + } + + $decoded = json_decode($jsonString, true); + return $decoded ?: null; + } + + /** + * پردازش پاسخ JSON + */ + private function processJSONResponse(array $jsonResponse, string $originalResponse, ?Business $business, $user): array + { + $action = $jsonResponse['action'] ?? 'direct_response'; + + switch ($action) { + case 'direct_response': + return [ + 'response' => $jsonResponse['user_message'] ?? $originalResponse, + 'requires_action' => false, + 'action_data' => null, + 'debug_info' => [ + 'ai_response' => $originalResponse, + 'json_response' => $jsonResponse, + 'action_type' => 'direct_response', + 'has_commands' => false + ] + ]; + + case 'tool_command': + return $this->executeSingleToolCommand($jsonResponse, $originalResponse, $business, $user); + + case 'multi_step': + return $this->executeMultiStepCommand($jsonResponse, $originalResponse, $business, $user); + + case 'continuous_operation': + return $this->executeContinuousOperation($jsonResponse, $originalResponse, $business, $user); + + case 'smart_operation': + return $this->executeSmartOperation($jsonResponse, $originalResponse, $business, $user); + + case 'operation_complete': + return [ + 'response' => $jsonResponse['user_message'] ?? 'عملیات با موفقیت کامل شد', + 'requires_action' => false, + 'action_data' => null, + 'debug_info' => [ + 'ai_response' => $originalResponse, + 'json_response' => $jsonResponse, + 'action_type' => 'operation_complete', + 'has_commands' => false, + 'final_result' => $jsonResponse['final_result'] ?? null, + 'final_data' => $jsonResponse['final_data'] ?? null + ] + ]; + + default: + return [ + 'response' => $jsonResponse['user_message'] ?? $originalResponse, + 'requires_action' => false, + 'action_data' => null, + 'debug_info' => [ + 'ai_response' => $originalResponse, + 'json_response' => $jsonResponse, + 'action_type' => 'unknown', + 'has_commands' => false, + 'error' => 'نوع عملیات نامعتبر' + ] + ]; + } + } + + /** + * اجرای دستور ابزار تک مرحله‌ای + */ + private function executeSingleToolCommand(array $jsonResponse, string $originalResponse, ?Business $business, $user): array + { + $tool = $jsonResponse['tool'] ?? ''; + $params = $jsonResponse['params'] ?? []; + + if (empty($tool)) { + return [ + 'response' => $jsonResponse['user_message'] ?? 'خطا: ابزار مشخص نشده است', + 'requires_action' => false, + 'action_data' => null, + 'debug_info' => [ + 'ai_response' => $originalResponse, + 'json_response' => $jsonResponse, + 'action_type' => 'tool_command', + 'has_commands' => false, + 'error' => 'ابزار مشخص نشده است' + ] + ]; + } + + $result = $this->executeToolCommand(['tool' => $tool, 'params' => $params], $business, $user); + + $finalResponse = $jsonResponse['user_message'] ?? 'عملیات انجام شد'; + + // برای جستجو، نتایج را مستقیماً نمایش بده + if ($tool === 'search_persons' && $result['success'] && isset($result['persons'])) { + $persons = $result['persons']; + $count = count($persons); + + if ($count > 0) { + $finalResponse .= "\n\n"; + if (isset($params['search']) && !empty($params['search'])) { + $finalResponse .= "نتایج جستجو برای \"{$params['search']}\":\n"; + } else { + $finalResponse .= "لیست {$count} نفر اخیر:\n"; + } + + foreach ($persons as $index => $person) { + $finalResponse .= "\n" . ($index + 1) . ". "; + if (!empty($person['nikename'])) { + $finalResponse .= $person['nikename']; + } elseif (!empty($person['name'])) { + $finalResponse .= $person['name']; + } else { + $finalResponse .= "شخص " . $person['code']; + } + + if (!empty($person['mobile'])) { + $finalResponse .= " - موبایل: " . $person['mobile']; + } + + $finalResponse .= " (کد: " . $person['code'] . ")"; + } + } else { + $finalResponse .= "\n\nهیچ شخصی یافت نشد."; + } + + // برای جستجو، followup را غیرفعال کن + $requiresFollowup = false; + } elseif ($tool === 'show_person' && $result['success'] && isset($result['person'])) { + // برای نمایش اطلاعات شخص، نتایج را مستقیماً نمایش بده + $person = $result['person']; + + $finalResponse .= "\n\n"; + $finalResponse .= "📋 اطلاعات شخص:\n"; + $finalResponse .= "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"; + + // نمایش اطلاعات اصلی + if (isset($person['نام مستعار']) && !empty($person['نام مستعار'])) { + $finalResponse .= "👤 نام مستعار: " . $person['نام مستعار'] . "\n"; + } + if (isset($person['نام کامل']) && !empty($person['نام کامل'])) { + $finalResponse .= "📝 نام کامل: " . $person['نام کامل'] . "\n"; + } + if (isset($person['کد']) && !empty($person['کد'])) { + $finalResponse .= "🔢 کد: " . $person['کد'] . "\n"; + } + + // نمایش اطلاعات تماس + if (isset($person['موبایل']) && !empty($person['موبایل']) && $person['موبایل'] !== 'تعیین نشده') { + $finalResponse .= "📱 موبایل: " . $person['موبایل'] . "\n"; + } + if (isset($person['تلفن']) && !empty($person['تلفن']) && $person['تلفن'] !== 'تعیین نشده') { + $finalResponse .= "☎️ تلفن: " . $person['تلفن'] . "\n"; + } + if (isset($person['ایمیل']) && !empty($person['ایمیل']) && $person['ایمیل'] !== 'تعیین نشده') { + $finalResponse .= "📧 ایمیل: " . $person['ایمیل'] . "\n"; + } + + // نمایش اطلاعات آدرس + if (isset($person['آدرس']) && !empty($person['آدرس']) && $person['آدرس'] !== 'تعیین نشده') { + $finalResponse .= "📍 آدرس: " . $person['آدرس'] . "\n"; + } + + // نمایش اطلاعات شرکت + if (isset($person['شرکت']) && !empty($person['شرکت']) && $person['شرکت'] !== 'تعیین نشده') { + $finalResponse .= "🏢 شرکت: " . $person['شرکت'] . "\n"; + } + + // نمایش اطلاعات مالی + if (isset($person['تراز حساب']) && !empty($person['تراز حساب'])) { + $finalResponse .= "💰 تراز حساب: " . $person['تراز حساب'] . "\n"; + } + if (isset($person['وضعیت حساب']) && !empty($person['وضعیت حساب'])) { + $finalResponse .= "📊 وضعیت حساب: " . $person['وضعیت حساب'] . "\n"; + } + + // نمایش اطلاعات شناسایی + if (isset($person['شناسه ملی']) && !empty($person['شناسه ملی']) && $person['شناسه ملی'] !== 'تعیین نشده') { + $finalResponse .= "🆔 شناسه ملی: " . $person['شناسه ملی'] . "\n"; + } + if (isset($person['کد اقتصادی']) && !empty($person['کد اقتصادی']) && $person['کد اقتصادی'] !== 'تعیین نشده') { + $finalResponse .= "🏛️ کد اقتصادی: " . $person['کد اقتصادی'] . "\n"; + } + + // نمایش انواع + if (isset($person['انواع']) && !empty($person['انواع']) && $person['انواع'] !== 'تعیین نشده') { + $finalResponse .= "🏷️ انواع: " . $person['انواع'] . "\n"; + } + + $finalResponse .= "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"; + + // برای نمایش اطلاعات شخص، followup را غیرفعال کن + $requiresFollowup = false; + } else { + // برای سایر عملیات، از تنظیمات AI استفاده کن + if ($result['success']) { + $finalResponse .= "\n\n" . ($result['message'] ?? 'عملیات با موفقیت انجام شد'); + } else { + $finalResponse .= "\n\nخطا: " . ($result['error'] ?? 'خطای نامشخص'); + } + + $requiresFollowup = $jsonResponse['requires_followup'] ?? false; + } + + return [ + 'response' => $finalResponse, + 'requires_action' => $requiresFollowup, + 'action_data' => $jsonResponse['next_step'] ?? null, + 'debug_info' => [ + 'ai_response' => $originalResponse, + 'json_response' => $jsonResponse, + 'action_type' => 'tool_command', + 'tool_commands' => [['tool' => $tool, 'params' => $params]], + 'has_commands' => true, + 'execution_result' => $result + ] + ]; + } + + /** + * اجرای دستور چندمرحله‌ای + */ + private function executeMultiStepCommand(array $jsonResponse, string $originalResponse, ?Business $business, $user): array + { + $steps = $jsonResponse['steps'] ?? []; + $results = []; + $allCommands = []; + + foreach ($steps as $step) { + $tool = $step['tool'] ?? ''; + $params = $step['params'] ?? []; + + if (!empty($tool)) { + $allCommands[] = ['tool' => $tool, 'params' => $params]; + $result = $this->executeToolCommand(['tool' => $tool, 'params' => $params], $business, $user); + $results[] = $result; + } + } + + $finalResponse = $jsonResponse['user_message'] ?? 'عملیات چندمرحله‌ای انجام شد'; + + // اضافه کردن نتایج به پاسخ + foreach ($results as $index => $result) { + if ($result['success']) { + $finalResponse .= "\n\nمرحله " . ($index + 1) . ": " . ($result['message'] ?? 'موفق'); + } else { + $finalResponse .= "\n\nمرحله " . ($index + 1) . ": خطا - " . ($result['error'] ?? 'خطای نامشخص'); + } + } + + return [ + 'response' => $finalResponse, + 'requires_action' => $jsonResponse['requires_followup'] ?? false, + 'action_data' => $jsonResponse['next_step'] ?? null, + 'debug_info' => [ + 'ai_response' => $originalResponse, + 'json_response' => $jsonResponse, + 'action_type' => 'multi_step', + 'tool_commands' => $allCommands, + 'has_commands' => true, + 'execution_results' => $results + ] + ]; + } + + /** + * اجرای عملیات پیوسته تا حصول نتیجه + */ + private function executeContinuousOperation(array $jsonResponse, string $originalResponse, ?Business $business, $user): array + { + $operationType = $jsonResponse['operation_type'] ?? ''; + $currentStep = $jsonResponse['current_step'] ?? 1; + $steps = $jsonResponse['steps'] ?? []; + $maxAttempts = $jsonResponse['max_attempts'] ?? 3; + $attemptCount = $jsonResponse['attempt_count'] ?? 1; + $operationComplete = $jsonResponse['operation_complete'] ?? false; + + // اگر عملیات کامل شده، نتیجه نهایی را برگردان + if ($operationComplete) { + return [ + 'response' => $jsonResponse['user_message'] ?? 'عملیات با موفقیت کامل شد', + 'requires_action' => false, + 'action_data' => null, + 'debug_info' => [ + 'ai_response' => $originalResponse, + 'json_response' => $jsonResponse, + 'action_type' => 'operation_complete', + 'has_commands' => false, + 'final_result' => $jsonResponse['final_result'] ?? null, + 'final_data' => $jsonResponse['final_data'] ?? null + ] + ]; + } + + // اگر تعداد تلاش‌ها از حد مجاز بیشتر شد + if ($attemptCount > $maxAttempts) { + return [ + 'response' => 'تعداد تلاش‌ها از حد مجاز بیشتر شد. لطفاً درخواست خود را واضح‌تر بیان کنید.', + 'requires_action' => false, + 'action_data' => null, + 'debug_info' => [ + 'ai_response' => $originalResponse, + 'json_response' => $jsonResponse, + 'action_type' => 'continuous_operation', + 'has_commands' => false, + 'error' => 'تعداد تلاش‌ها از حد مجاز بیشتر شد', + 'attempt_count' => $attemptCount, + 'max_attempts' => $maxAttempts + ] + ]; + } + + // اجرای مراحل فعلی + $results = []; + $allCommands = []; + + foreach ($steps as $step) { + $tool = $step['tool'] ?? ''; + $params = $step['params'] ?? []; + + if (!empty($tool)) { + $allCommands[] = ['tool' => $tool, 'params' => $params]; + $result = $this->executeToolCommand(['tool' => $tool, 'params' => $params], $business, $user); + $results[] = $result; + } + } + + // بررسی نتایج و تصمیم‌گیری برای مرحله بعدی + $nextAction = $this->determineNextAction($operationType, $results, $jsonResponse); + + $finalResponse = $jsonResponse['user_message'] ?? 'عملیات پیوسته در حال اجرا...'; + + // اضافه کردن نتایج به پاسخ + foreach ($results as $index => $result) { + if ($result['success']) { + $finalResponse .= "\n\nمرحله " . ($index + 1) . ": " . ($result['message'] ?? 'موفق'); + } else { + $finalResponse .= "\n\nمرحله " . ($index + 1) . ": خطا - " . ($result['error'] ?? 'خطای نامشخص'); + } + } + + return [ + 'response' => $finalResponse, + 'requires_action' => true, + 'action_data' => [ + 'operation_type' => $operationType, + 'current_step' => $currentStep, + 'next_action' => $nextAction, + 'attempt_count' => $attemptCount, + 'max_attempts' => $maxAttempts, + 'results' => $results + ], + 'debug_info' => [ + 'ai_response' => $originalResponse, + 'json_response' => $jsonResponse, + 'action_type' => 'continuous_operation', + 'tool_commands' => $allCommands, + 'has_commands' => true, + 'execution_results' => $results, + 'operation_type' => $operationType, + 'current_step' => $currentStep, + 'attempt_count' => $attemptCount, + 'max_attempts' => $maxAttempts, + 'next_action' => $nextAction + ] + ]; + } + + /** + * اجرای عملیات هوشمند چندمرحله‌ای + */ + private function executeSmartOperation(array $jsonResponse, string $originalResponse, ?Business $business, $user): array + { + $operationType = $jsonResponse['operation_type'] ?? ''; + $targetPerson = $jsonResponse['target_person'] ?? ''; + $targetPhone = $jsonResponse['target_phone'] ?? ''; + $steps = $jsonResponse['steps'] ?? []; + + // اجرای مرحله اول (معمولاً جستجو) + $firstStep = $steps[0] ?? null; + if (!$firstStep) { + return [ + 'response' => 'خطا: مرحله اول تعریف نشده است', + 'requires_action' => false, + 'action_data' => null, + 'debug_info' => [ + 'ai_response' => $originalResponse, + 'json_response' => $jsonResponse, + 'action_type' => 'smart_operation', + 'has_commands' => false, + 'error' => 'مرحله اول تعریف نشده' + ] + ]; + } + + $tool = $firstStep['tool'] ?? ''; + $params = $firstStep['params'] ?? []; + $onSuccess = $firstStep['on_success'] ?? ''; + $onFailure = $firstStep['on_failure'] ?? ''; + + // اجرای مرحله اول + $result = $this->executeToolCommand(['tool' => $tool, 'params' => $params], $business, $user); + + if ($result['success']) { + // بررسی نتیجه جستجو + if (isset($result['persons'])) { + if (!empty($result['persons'])) { + // شخص پیدا شد، عملیات on_success را انجام بده + return $this->executeNextStep($onSuccess, $targetPerson, $targetPhone, $result, $business, $user, $originalResponse, $jsonResponse); + } else { + // شخص پیدا نشد، عملیات on_failure را انجام بده + return $this->executeNextStep($onFailure, $targetPerson, $targetPhone, $result, $business, $user, $originalResponse, $jsonResponse); + } + } + } + + // اگر نتیجه ناموفق بود + return [ + 'response' => 'خطا در اجرای عملیات: ' . ($result['error'] ?? 'خطای نامشخص'), + 'requires_action' => false, + 'action_data' => null, + 'debug_info' => [ + 'ai_response' => $originalResponse, + 'json_response' => $jsonResponse, + 'action_type' => 'smart_operation', + 'has_commands' => true, + 'execution_result' => $result, + 'error' => 'خطا در اجرای مرحله اول' + ] + ]; + } + + /** + * اجرای مرحله بعدی بر اساس نتیجه + */ + private function executeNextStep(string $action, string $targetPerson, string $targetPhone, array $searchResult, ?Business $business, $user, string $originalResponse, array $jsonResponse): array + { + switch ($action) { + case 'edit_person': + // ویرایش شخص موجود + $person = $searchResult['persons'][0] ?? null; + if ($person) { + $editParams = [ + 'name' => $person['nikename'], + 'mobile' => $targetPhone + ]; + + $editResult = $this->executeToolCommand(['tool' => 'edit_person', 'params' => $editParams], $business, $user); + + if ($editResult['success']) { + return [ + 'response' => "موبایل {$targetPhone} برای {$targetPerson} با موفقیت تنظیم شد", + 'requires_action' => false, + 'action_data' => null, + 'debug_info' => [ + 'ai_response' => $originalResponse, + 'json_response' => $jsonResponse, + 'action_type' => 'smart_operation_complete', + 'has_commands' => true, + 'search_result' => $searchResult, + 'edit_result' => $editResult, + 'final_result' => 'عملیات ویرایش با موفقیت انجام شد' + ] + ]; + } else { + return [ + 'response' => 'خطا در ویرایش موبایل: ' . ($editResult['error'] ?? 'خطای نامشخص'), + 'requires_action' => false, + 'action_data' => null, + 'debug_info' => [ + 'ai_response' => $originalResponse, + 'json_response' => $jsonResponse, + 'action_type' => 'smart_operation', + 'has_commands' => true, + 'search_result' => $searchResult, + 'edit_result' => $editResult, + 'error' => 'خطا در ویرایش' + ] + ]; + } + } + break; + + case 'add_person': + // افزودن شخص جدید + $addParams = [ + 'name' => $targetPerson, + 'mobile' => $targetPhone + ]; + + $addResult = $this->executeToolCommand(['tool' => 'add_person', 'params' => $addParams], $business, $user); + + if ($addResult['success']) { + return [ + 'response' => "شخص جدید {$targetPerson} با موبایل {$targetPhone} با موفقیت ایجاد شد", + 'requires_action' => false, + 'action_data' => null, + 'debug_info' => [ + 'ai_response' => $originalResponse, + 'json_response' => $jsonResponse, + 'action_type' => 'smart_operation_complete', + 'has_commands' => true, + 'search_result' => $searchResult, + 'add_result' => $addResult, + 'final_result' => 'عملیات افزودن با موفقیت انجام شد' + ] + ]; + } else { + return [ + 'response' => 'خطا در افزودن شخص: ' . ($addResult['error'] ?? 'خطای نامشخص'), + 'requires_action' => false, + 'action_data' => null, + 'debug_info' => [ + 'ai_response' => $originalResponse, + 'json_response' => $jsonResponse, + 'action_type' => 'smart_operation', + 'has_commands' => true, + 'search_result' => $searchResult, + 'add_result' => $addResult, + 'error' => 'خطا در افزودن' + ] + ]; + } + break; + } + + return [ + 'response' => 'عملیات نامشخص: ' . $action, + 'requires_action' => false, + 'action_data' => null, + 'debug_info' => [ + 'ai_response' => $originalResponse, + 'json_response' => $jsonResponse, + 'action_type' => 'smart_operation', + 'has_commands' => false, + 'error' => 'عملیات نامشخص: ' . $action + ] + ]; + } + + /** + * تعیین مرحله بعدی بر اساس نتایج + */ + private function determineNextAction(string $operationType, array $results, array $jsonResponse): string + { + switch ($operationType) { + case 'add_phone_to_person': + // بررسی نتایج جستجو + foreach ($results as $result) { + if (isset($result['persons']) && empty($result['persons'])) { + // شخص پیدا نشد، باید شخص جدید بسازیم + return "شخص پیدا نشد. در حال ساخت شخص جدید..."; + } elseif (isset($result['persons']) && !empty($result['persons'])) { + // شخص پیدا شد، موبایل را ویرایش کن + return "شخص پیدا شد. در حال ویرایش موبایل..."; + } + } + break; + + case 'edit_person_info': + // بررسی نتایج جستجو + foreach ($results as $result) { + if (isset($result['persons']) && empty($result['persons'])) { + return "شخص پیدا نشد. لطفاً نام صحیح را وارد کنید."; + } elseif (isset($result['persons']) && !empty($result['persons'])) { + return "شخص پیدا شد. در حال ویرایش اطلاعات..."; + } + } + break; + + case 'delete_person': + // بررسی نتایج جستجو + foreach ($results as $result) { + if (isset($result['persons']) && empty($result['persons'])) { + return "شخص پیدا نشد. لطفاً نام صحیح را وارد کنید."; + } elseif (isset($result['persons']) && !empty($result['persons'])) { + return "شخص پیدا شد. در حال حذف..."; + } + } + break; + } + + return $jsonResponse['next_action'] ?? "مرحله بعدی تعیین نشده"; + } + + /** + * پردازش پاسخ قدیمی (برای سازگاری) + */ + private function processLegacyResponse(string $aiResponse, ?Business $business, $user): array { // تشخیص دستورات ابزار در پاسخ $toolCommands = $this->extractToolCommands($aiResponse); + // اضافه کردن debug info + $debugInfo = [ + 'ai_response' => $aiResponse, + 'tool_commands' => $toolCommands, + 'has_commands' => !empty($toolCommands), + 'response_type' => 'legacy' + ]; + + // اگر دستور ابزاری یافت نشد، سعی کن دستورات را از متن استخراج کن + if (empty($toolCommands)) { + $extractedCommands = $this->extractCommandsFromText($aiResponse); + if (!empty($extractedCommands)) { + $toolCommands = $extractedCommands; + $debugInfo['extracted_commands'] = $extractedCommands; + $debugInfo['has_commands'] = true; + } + } + if (!empty($toolCommands)) { // اجرای دستورات ابزار $results = []; @@ -213,7 +922,8 @@ class AIService return [ 'response' => $finalResponse, 'requires_action' => false, - 'action_data' => null + 'action_data' => null, + 'debug_info' => $debugInfo ]; } @@ -221,7 +931,8 @@ class AIService return [ 'response' => $aiResponse, 'requires_action' => false, - 'action_data' => null + 'action_data' => null, + 'debug_info' => $debugInfo ]; } @@ -232,13 +943,13 @@ class AIService { $commands = []; - // الگوهای دستورات ابزار + // الگوهای دستورات ابزار - ساده شده $patterns = [ - 'add_person' => '/add_person\{name:([^}]+)\}/u', + 'add_person' => '/add_person\{([^}]+)\}/u', 'delete_person' => '/delete_person\{name:([^}]+)\}/u', - 'edit_person' => '/edit_person\{name:([^}]+)(?:,([^}]+))*\}/u', + 'edit_person' => '/edit_person\{([^}]+)\}/u', 'show_person' => '/show_person\{name:([^}]+)\}/u', - 'search_persons' => '/search_persons\{search:([^}]+)(?:,limit:([^}]+))*\}/u' + 'search_persons' => '/search_persons\{search:([^}]+)\}/u' ]; foreach ($patterns as $tool => $pattern) { @@ -256,6 +967,62 @@ class AIService return $commands; } + /** + * استخراج دستورات از متن پاسخ AI + */ + private function extractCommandsFromText(string $text): array + { + $commands = []; + $text = mb_strtolower($text, 'UTF-8'); + + // الگوهای تشخیص دستورات برای فارسی + $patterns = [ + 'add_person' => [ + '/(?:افزودن|اضافه|ایجاد|ساخت)\s+(?:شخص|مشتری|کارمند)\s+(?:جدید\s+)?(?:با\s+نام\s+)?([^\s،]+)/u', + '/(?:شخص|مشتری|کارمند)\s+(?:جدید\s+)?(?:با\s+نام\s+)?([^\s،]+)\s+(?:اضافه|افزودن|ایجاد|ساخت)/u', + '/([^\s،]+)\s+(?:اضافه|افزودن|ایجاد|ساخت)/u', + '/(?:برای|به)\s+([^\s،]+)\s+(?:اضافه|افزودن|ایجاد|ساخت)/u' + ], + 'edit_person' => [ + '/(?:ویرایش|تغییر|تنظیم)\s+(?:موبایل|شماره|تلفن)\s+(?:برای|به)\s+([^\s،]+)\s+(?:به\s+)?([0-9]+)/u', + '/([^\s،]+)\s+(?:موبایل|شماره|تلفن)\s+(?:به\s+)?([0-9]+)/u', + '/(?:موبایل|شماره|تلفن)\s+([0-9]+)\s+(?:را\s+)?(?:برای|به)\s+([^\s،]+)/u', + '/(?:برای|به)\s+([^\s،]+)\s+(?:موبایل|شماره|تلفن)\s+([0-9]+)/u' + ] + ]; + + foreach ($patterns as $tool => $toolPatterns) { + foreach ($toolPatterns as $pattern) { + if (preg_match($pattern, $text, $matches)) { + if ($tool === 'add_person') { + $commands[] = [ + 'tool' => $tool, + 'params' => ['name' => $matches[1]] + ]; + } elseif ($tool === 'edit_person') { + // تشخیص اینکه کدام پارامتر نام و کدام موبایل است + if (preg_match('/^[0-9]+$/', $matches[1])) { + // اگر اولین پارامتر عدد است، پس موبایل است + $commands[] = [ + 'tool' => $tool, + 'params' => ['name' => $matches[2], 'mobile' => $matches[1]] + ]; + } else { + // اگر اولین پارامتر عدد نیست، پس نام است + $commands[] = [ + 'tool' => $tool, + 'params' => ['name' => $matches[1], 'mobile' => $matches[2]] + ]; + } + } + break; + } + } + } + + return $commands; + } + /** * تجزیه پارامترهای دستور ابزار */ @@ -263,7 +1030,11 @@ class AIService { $params = []; - // استخراج پارامترها از فرمت {name:value,key:value} + // حذف نام ابزار از ابتدای دستور + $command = preg_replace('/^\w+\{/', '', $command); + $command = rtrim($command, '}'); + + // استخراج پارامترها از فرمت name:value,key:value if (preg_match_all('/([^:,}]+):([^,}]+)/u', $command, $matches, PREG_SET_ORDER)) { foreach ($matches as $match) { $key = trim($match[1]); @@ -272,6 +1043,18 @@ class AIService // حذف کاراکترهای اضافی $value = rtrim($value, ',}'); + // حذف فاصله‌های اضافی + $key = trim($key); + $value = trim($value); + + // اصلاح کلیدهای نامعتبر + if (strpos($key, '{') !== false) { + $key = str_replace('{', '', $key); + } + if (strpos($key, 'edit_person') !== false) { + $key = 'name'; + } + $params[$key] = $value; } } diff --git a/hesabixCore/src/Service/AI/PersonManagementService.php b/hesabixCore/src/Service/AI/PersonManagementService.php index b576e7ec..63dba871 100644 --- a/hesabixCore/src/Service/AI/PersonManagementService.php +++ b/hesabixCore/src/Service/AI/PersonManagementService.php @@ -31,6 +31,8 @@ class PersonTools public function addPerson(array $params, Business $business, $user): array { $name = $params['name'] ?? ''; + $fullName = $params['full_name'] ?? $name; // نام کامل (اختیاری) + if (empty($name)) { return [ 'success' => false, @@ -38,7 +40,7 @@ class PersonTools ]; } - // بررسی وجود شخص با همین نام + // بررسی وجود شخص با همین نام مستعار $existingPerson = $this->entityManager->getRepository(Person::class)->findOneBy([ 'nikename' => $name, 'bid' => $business @@ -47,14 +49,14 @@ class PersonTools if ($existingPerson) { return [ 'success' => false, - 'error' => "شخصی با نام '{$name}' قبلاً وجود دارد." + 'error' => "شخصی با نام مستعار '{$name}' قبلاً وجود دارد." ]; } // ایجاد شخص جدید $person = new Person(); - $person->setName($name); - $person->setNikename($name); + $person->setNikename($name); // نام مستعار (الزامی) + $person->setName($fullName); // نام کامل (اختیاری) $person->setBid($business); // تولید کد خودکار @@ -138,6 +140,11 @@ class PersonTools $changes[] = "موبایل: {$params['phone']}"; } + if (isset($params['mobile'])) { + $person->setMobile($params['mobile']); + $changes[] = "موبایل: {$params['mobile']}"; + } + if (isset($params['address'])) { $person->setAddress($params['address']); $changes[] = "آدرس: {$params['address']}"; diff --git a/webUI/src/views/wizard/home.vue b/webUI/src/views/wizard/home.vue index 065a527c..aba33206 100644 --- a/webUI/src/views/wizard/home.vue +++ b/webUI/src/views/wizard/home.vue @@ -76,23 +76,6 @@ مشاهده آرشیو گفتگوها - - - - - راهنمای عملیات مدیریت اشخاص -
@@ -202,6 +185,81 @@ }">
+ +
+
+ اطلاعات دیباگ + {{ message.debug_info.expanded ? '▼' : '▶' }} +
+
+
+
نوع عملیات:
+

{{ message.debug_info.operation_type }}

+
+ +
+
مرحله فعلی:
+

{{ message.debug_info.current_step }}

+
+ +
+
تعداد تلاش:
+

{{ message.debug_info.attempt_count }} از {{ message.debug_info.max_attempts }}

+
+ +
+
مرحله بعدی:
+

{{ message.debug_info.next_action }}

+
+ +
+
نتیجه نهایی:
+

{{ message.debug_info.final_result }}

+
+ +
+
داده‌های نهایی:
+
{{ JSON.stringify(message.debug_info.final_data, null, 2) }}
+
+ +
+
پاسخ JSON:
+
{{ JSON.stringify(message.debug_info.json_response, null, 2) }}
+
+ +
+
دستورات ابزار یافت شده:
+
+ {{ command.tool }} +
{{ JSON.stringify(command.params, null, 2) }}
+
+
+ +
+
نتیجه اجرا:
+
{{ JSON.stringify(message.debug_info.execution_result, null, 2) }}
+
+ +
+
نتایج اجرای چندمرحله‌ای:
+
+ مرحله {{ resultIndex + 1 }}: +
{{ JSON.stringify(result, null, 2) }}
+
+
+ +
+
پاسخ هوش مصنوعی:
+
{{ message.debug_info.ai_response }}
+
+ +
+
خطا:
+

{{ message.debug_info.error }}

+
+
+
+
- - - - - - راهنمای عملیات مدیریت اشخاص - - mdi-close - - - - -
-
- -
-
- - - - - بستن - - -
-