progress in ai in person module

This commit is contained in:
Hesabix 2025-07-19 10:19:33 +00:00
parent fc6f286e0e
commit 3b617f9971
4 changed files with 1411 additions and 143 deletions

View file

@ -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()
]
]);
}
}
}

View file

@ -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;
}
}

View file

@ -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']}";

View file

@ -76,23 +76,6 @@
</template>
<span>مشاهده آرشیو گفتگوها</span>
</v-tooltip>
<!-- دکمه راهنمای عملیات -->
<v-tooltip location="bottom">
<template v-slot:activator="{ props }">
<v-btn
v-bind="props"
icon
@click="showOperationsGuide = true"
class="mr-2 guide-btn"
color="info"
variant="tonal"
>
<v-icon>mdi-help-circle</v-icon>
</v-btn>
</template>
<span>راهنمای عملیات مدیریت اشخاص</span>
</v-tooltip>
</v-toolbar>
<div class="page-container">
<!-- کارت اطلاعات قیمتگذاری و آمار استفاده -->
@ -202,6 +185,81 @@
}">
<div class="message-text" v-html="renderMarkdown(message.text)"></div>
<!-- Debug Info Section -->
<div class="debug-info" v-if="message.debug_info">
<div class="debug-header" @click="toggleDebugInfo(index)">
<span>اطلاعات دیباگ</span>
<span class="debug-toggle">{{ message.debug_info.expanded ? '▼' : '▶' }}</span>
</div>
<div class="debug-content" v-if="message.debug_info.expanded">
<div class="debug-section" v-if="message.debug_info.operation_type">
<h5>نوع عملیات:</h5>
<p>{{ message.debug_info.operation_type }}</p>
</div>
<div class="debug-section" v-if="message.debug_info.current_step">
<h5>مرحله فعلی:</h5>
<p>{{ message.debug_info.current_step }}</p>
</div>
<div class="debug-section" v-if="message.debug_info.attempt_count">
<h5>تعداد تلاش:</h5>
<p>{{ message.debug_info.attempt_count }} از {{ message.debug_info.max_attempts }}</p>
</div>
<div class="debug-section" v-if="message.debug_info.next_action">
<h5>مرحله بعدی:</h5>
<p>{{ message.debug_info.next_action }}</p>
</div>
<div class="debug-section" v-if="message.debug_info.final_result">
<h5>نتیجه نهایی:</h5>
<p>{{ message.debug_info.final_result }}</p>
</div>
<div class="debug-section" v-if="message.debug_info.final_data">
<h5>دادههای نهایی:</h5>
<pre>{{ JSON.stringify(message.debug_info.final_data, null, 2) }}</pre>
</div>
<div class="debug-section" v-if="message.debug_info.json_response">
<h5>پاسخ JSON:</h5>
<pre>{{ JSON.stringify(message.debug_info.json_response, null, 2) }}</pre>
</div>
<div class="debug-section" v-if="message.debug_info.tool_commands && message.debug_info.tool_commands.length > 0">
<h5>دستورات ابزار یافت شده:</h5>
<div v-for="(command, cmdIndex) in message.debug_info.tool_commands" :key="cmdIndex">
<strong>{{ command.tool }}</strong>
<pre>{{ JSON.stringify(command.params, null, 2) }}</pre>
</div>
</div>
<div class="debug-section" v-if="message.debug_info.execution_result">
<h5>نتیجه اجرا:</h5>
<pre>{{ JSON.stringify(message.debug_info.execution_result, null, 2) }}</pre>
</div>
<div class="debug-section" v-if="message.debug_info.execution_results">
<h5>نتایج اجرای چندمرحلهای:</h5>
<div v-for="(result, resultIndex) in message.debug_info.execution_results" :key="resultIndex">
<strong>مرحله {{ resultIndex + 1 }}:</strong>
<pre>{{ JSON.stringify(result, null, 2) }}</pre>
</div>
</div>
<div class="debug-section" v-if="message.debug_info.ai_response">
<h5>پاسخ هوش مصنوعی:</h5>
<pre>{{ message.debug_info.ai_response }}</pre>
</div>
<div class="debug-section" v-if="message.debug_info.error">
<h5>خطا:</h5>
<p class="error">{{ message.debug_info.error }}</p>
</div>
</div>
</div>
<!-- دکمه شارژ برای پیامهای خطای اعتبار -->
<div v-if="message.showChargeButton" class="charge-button-container mt-3">
<v-btn
@ -433,32 +491,6 @@
</v-card-text>
</v-card>
</v-dialog>
<!-- دیالوگ راهنمای عملیات -->
<v-dialog v-model="showOperationsGuide" max-width="800px">
<v-card>
<v-card-title class="d-flex align-center justify-space-between">
<span>راهنمای عملیات مدیریت اشخاص</span>
<v-btn icon @click="showOperationsGuide = false">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<v-card-text>
<div v-if="operationsGuide" v-html="renderMarkdown(operationsGuide)"></div>
<div v-else class="text-center pa-4">
<v-progress-circular indeterminate color="primary"></v-progress-circular>
</div>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="primary" @click="showOperationsGuide = false">
بستن
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
@ -522,9 +554,6 @@ export default {
selectedPerson: null,
personTransactions: [],
showPersonInfo: false,
// متغیرهای راهنمای عملیات
showOperationsGuide: false,
operationsGuide: null
};
},
computed: {
@ -564,7 +593,6 @@ export default {
await this.checkConnection();
await this.loadConversations();
await this.loadBalance();
await this.loadOperationsGuide(); // Add this line
this.setWelcomeMessage();
},
methods: {
@ -656,17 +684,6 @@ export default {
}
},
async loadOperationsGuide() {
try {
const response = await axios.get('/api/wizard/persons/guide');
if (response.data.success) {
this.operationsGuide = response.data.guide;
}
} catch (error) {
console.error('خطا در بارگذاری راهنما:', error);
}
},
formatBalance(balance) {
// تبدیل به عدد صحیح
const intBalance = Math.round(balance);
@ -853,39 +870,38 @@ export default {
});
if (response && response.data && response.data.success) {
console.log('AI Response Data:', response.data);
this.userMessages.push({
isAI: true,
text: response.data.response,
usage: response.data.usage,
cost: response.data.cost
cost: response.data.cost,
debug_info: response.data.debug_info ? {
...response.data.debug_info,
expanded: false
} : null
});
// بهروزرسانی اعتبار کاربر
await this.loadBalance();
// بهروزرسانی لیست گفتگوها
await this.loadConversations();
this.$emit('show-snackbar', {
text: 'پاسخ دریافت شد',
color: 'success'
});
} else if (response && response.data) {
// بررسی خطای اعتبار
if (response.data.error && response.data.error.includes('اعتبار')) {
this.userMessages.push({
isAI: true,
text: `خطا: ${response.data.error}`,
isError: true,
showChargeButton: response.data.showChargeButton || false
});
await this.loadBalance();
} else {
this.userMessages.push({
isAI: true,
text: `خطا: ${response.data.error}`,
isError: true
});
}
} else {
// اگر هیچ پاسخی از سرور دریافت نشد
console.log('AI Error Response:', response.data);
this.userMessages.push({
isAI: true,
text: 'خطا: خطا در ارتباط با سرور',
isError: true
text: `خطا: ${response.data.error}`,
isError: true,
debug_info: response.data.debug_info || null
});
} else {
console.log('No response data');
this.userMessages.push({
isAI: true,
text: 'خطا در ارتباط با سرور',
isError: true,
debug_info: null
});
}
} catch (error) {
@ -893,7 +909,8 @@ export default {
this.userMessages.push({
isAI: true,
text: 'خطا: خطا در ارتباط با سرور',
isError: true
isError: true,
debug_info: null
});
} finally {
this.isLoading = false;
@ -1029,6 +1046,12 @@ export default {
color: 'error'
});
}
},
toggleDebugInfo(index) {
if (this.userMessages[index] && this.userMessages[index].debug_info) {
this.userMessages[index].debug_info.expanded = !this.userMessages[index].debug_info.expanded;
}
}
}
};
@ -1303,4 +1326,78 @@ export default {
.send-icon-rotate {
transform: rotate(180deg);
}
/* استایل‌های Debug Info */
.debug-info-section {
border-top: 1px solid rgba(0, 0, 0, 0.1);
padding-top: 12px;
}
.debug-panel-title {
font-size: 0.875rem;
font-weight: 500;
color: #666;
}
.debug-content {
font-size: 0.875rem;
}
.debug-section h4 {
color: #333;
margin-bottom: 8px;
}
.debug-card {
background: #fafafa;
border: 1px solid #e0e0e0;
}
.debug-text {
font-family: 'Courier New', monospace;
font-size: 0.75rem;
line-height: 1.4;
color: #333;
background: #f5f5f5;
padding: 8px;
border-radius: 4px;
overflow-x: auto;
white-space: pre-wrap;
word-break: break-word;
}
.command-item {
border-left: 3px solid #1a237e;
padding-left: 12px;
background: #f8f9fa;
border-radius: 4px;
padding: 8px;
}
.command-header {
display: flex;
align-items: center;
margin-bottom: 4px;
}
.command-header .text-caption {
color: #666;
font-weight: 500;
}
/* استایل‌های Manual Commands */
.manual-commands-section {
border-top: 1px solid rgba(0, 0, 0, 0.1);
padding-top: 12px;
}
.manual-commands-section h4 {
color: #333;
margin-bottom: 8px;
}
.manual-commands-section .v-btn {
font-size: 0.75rem;
font-weight: 500;
}
</style>