progress in AGI

This commit is contained in:
Hesabix 2025-07-24 12:55:44 +00:00
parent 3047c62f5d
commit a095dd530f
7 changed files with 155 additions and 101 deletions

View file

@ -0,0 +1,44 @@
<?php
namespace App\AiTool;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\Person;
use App\Service\Explore;
class PersonService
{
private EntityManagerInterface $em;
private \App\Cog\PersonService $cogPersonService;
public function __construct(EntityManagerInterface $em, \App\Cog\PersonService $cogPersonService)
{
$this->em = $em;
$this->cogPersonService = $cogPersonService;
}
/**
* دریافت اطلاعات یک شخص بر اساس کد و اطلاعات دسترسی
*/
public function getPersonInfoByCode($code, $acc): array
{
if (!$code) {
return [
'error' => 'کد شخص الزامی است'
];
}
if (!$acc) {
return [
'error' => 'اطلاعات دسترسی (acc) الزامی است'
];
}
try {
return $this->cogPersonService->getPersonInfo($code, $acc);
} catch (\Exception $e) {
return [
'error' => 'خطا در دریافت اطلاعات شخص: ' . $e->getMessage()
];
}
}
}

View file

@ -7,7 +7,6 @@ use App\Entity\Person;
use App\Entity\PersonType;
use App\Entity\HesabdariRow;
use App\Service\Explore;
use App\Service\Access;
/**
* سرویس مدیریت اشخاص
@ -17,12 +16,12 @@ use App\Service\Access;
class PersonService
{
private EntityManagerInterface $entityManager;
private Access $access;
private array $access;
/**
* سازنده سرویس
*/
public function __construct(EntityManagerInterface $entityManager, Access $access)
public function __construct(EntityManagerInterface $entityManager, array $access)
{
$this->entityManager = $entityManager;
$this->access = $access;

View file

@ -32,7 +32,8 @@ class wizardController extends AbstractController
Log $log
): JsonResponse
{
try {
$acc = $access->hasRole('join');
if (!$acc) {
return $this->json([
@ -45,7 +46,8 @@ class wizardController extends AbstractController
}
// بررسی دسترسی هوش مصنوعی
if (!$acc['ai']) {
$acc = $access->hasRole('ai');
if (!$acc) {
return $this->json([
'success' => false,
'error' => 'شما دسترسی استفاده از هوش مصنوعی را ندارید',
@ -96,7 +98,11 @@ class wizardController extends AbstractController
'showChargeButton' => true,
'debug_info' => [
'balance' => $currentBalance,
'required' => $estimatedCost
'required' => $estimatedCost,
'business' => [
'id' => $business->getId(),
'name' => $business->getName(),
]
]
]);
}
@ -142,15 +148,27 @@ class wizardController extends AbstractController
}
}
// پاک‌سازی خروجی از اشیای Doctrine (Business, User و ...)
array_walk_recursive($response, function (&$item) {
if (is_object($item) && method_exists($item, 'getId')) {
$item = $item->getId();
}
});
return $this->json($response);
} else {
return $this->json([
$errorResponse = [
'success' => false,
'error' => $result['error'] ?? 'خطای نامشخص در سرویس هوش مصنوعی',
'debug_info' => $result['debug_info'] ?? ['fallback' => 'no debug info from service', 'result' => $result]
]);
];
array_walk_recursive($errorResponse, function (&$item) {
if (is_object($item) && method_exists($item, 'getId')) {
$item = $item->getId();
}
});
return $this->json($errorResponse);
}
try {
} catch (\Exception $e) {
return $this->json([
'success' => false,

View file

@ -64,15 +64,13 @@ class AGIService
'service_status' => $status,
'inputs' => [
'message' => $message,
'business' => $business,
'user' => $user,
'conversationId' => $conversationId
]
]
];
}
try {
// مدیریت گفتگو و تاریخچه
$conversation = $this->manageConversation($conversationId, $business, $user, $message);
$conversationHistory = $this->getConversationHistory($conversation);
@ -80,8 +78,8 @@ class AGIService
// ذخیره پیام کاربر
$this->saveUserMessage($conversation, $message);
// ساخت پرامپ هوشمند
$prompt = $this->buildSmartPrompt($message, $business, $conversationHistory);
// فقط سوال کاربر به عنوان prompt
$userPrompt = $message;
$service = $this->getAIAgentSource();
$apiKey = $this->getAIApiKey($service);
@ -94,16 +92,14 @@ class AGIService
'service' => $service,
'inputs' => [
'message' => $message,
'business' => $business,
'user' => $user,
'conversationId' => $conversationId
]
]
];
}
// ارسال درخواست با function calling
$result = $this->sendToAIServiceWithFunctionCalling($prompt, $apiKey, $service, $conversationHistory, $acc);
// ارسال درخواست با function calling (فقط سوال کاربر)
$result = $this->sendToAIServiceWithFunctionCalling($userPrompt, $apiKey, $service, $conversationHistory, $acc);
if (!$result['success']) {
return $result;
@ -129,18 +125,8 @@ class AGIService
'tool_results' => $result['tool_results'] ?? []
]
];
try {
} catch (\Exception $e) {
$this->log->error('خطا در ارسال درخواست به هوش مصنوعی: ' . $e->getMessage(), [
'context' => 'AGIService::sendRequest',
'message' => $message,
'business' => $business,
'user' => $user,
'conversationId' => $conversationId,
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
return [
'success' => false,
'error' => 'خطا در پردازش درخواست: ' . $e->getMessage(),
@ -149,8 +135,6 @@ class AGIService
'exception' => $e->getMessage(),
'inputs' => [
'message' => $message,
'business' => $business,
'user' => $user,
'conversationId' => $conversationId
]
]
@ -166,33 +150,36 @@ class AGIService
$urls = $this->getServiceUrls($service);
$model = $this->getAIModel();
// ساخت messages با تاریخچه
$messages = [];
// اضافه کردن تاریخچه گفتگو
// پیام system شامل قوانین خروجی و مثال دقیق
$systemPrompt = "شما دستیار هوشمند حسابیکس هستید. فقط پاسخ را به صورت JSON مطابق مثال خروجی بده. اگر نیاز به ابزار داشتی، از function calling استفاده کن."
. $this->promptService->getOutputFormatPrompt();
$messages = [
[
'role' => 'system',
'content' => $systemPrompt
]
];
// تاریخچه گفتگو
foreach ($conversationHistory as $historyItem) {
$messages[] = [
'role' => $historyItem['role'],
'content' => $historyItem['content']
];
}
// اضافه کردن پیام فعلی
// پیام user فقط سوال فعلی
$messages[] = [
'role' => 'user',
'content' => $prompt
];
// تعریف ابزارهای موجود
$tools = $this->buildToolsFromPromptServices();
$data = [
'model' => $model,
'messages' => $messages,
'tools' => $tools,
'tool_choice' => 'auto', // اجازه انتخاب ابزار به مدل
'tool_choice' => 'auto',
'max_tokens' => 12000,
'temperature' => 0.1
'temperature' => 0.9
];
$maxIterations = 5; // حداکثر تعداد تکرار برای جلوگیری از حلقه بی‌نهایت
@ -220,7 +207,12 @@ class AGIService
'context' => 'sendToAIServiceWithFunctionCalling',
'url_list' => $urls,
'data' => $data,
'iteration' => $iteration
'iteration' => $iteration,
'result' => $result,
'apiKey' => $apiKey,
'service' => $service,
'conversationHistory' => $conversationHistory,
]
];
}
@ -313,63 +305,22 @@ class AGIService
try {
switch ($tool) {
case 'getPersonInfo':
// استفاده مستقیم از سرویس Cog\PersonService
return $this->callGetPersonInfoFromCog($params);
// استفاده مستقیم از سرویس جدید
$cogPersonService = new \App\Cog\PersonService($this->em, $params['acc'] ?? null);
$personService = new \App\AiTool\PersonService($this->em, $cogPersonService);
return $personService->getPersonInfoByCode($params['code'] ?? null, $params['acc'] ?? null);
default:
return [
'error' => 'ابزار ناشناخته: ' . $tool
];
}
} catch (\Exception $e) {
$this->log->error('خطا در اجرای ابزار: ' . $e->getMessage(), [
'context' => 'AGIService::callTool',
'tool' => $tool,
'params' => $params,
'exception' => $e->getMessage()
]);
return [
'error' => 'خطا در اجرای ابزار: ' . $e->getMessage()
];
}
}
/**
* اجرای ابزار getPersonInfo با استفاده از سرویس Cog\PersonService
*/
private function callGetPersonInfoFromCog(array $params)
{
$code = $params['code'] ?? null;
if (!$code) {
return [
'error' => 'کد شخص الزامی است'
];
}
try {
// دریافت اطلاعات دسترسی (acc) از context یا پارامترها
$acc = $params['acc'] ?? null;
if (!$acc) {
return [
'error' => 'اطلاعات دسترسی (acc) الزامی است'
];
}
// استفاده از سرویس Cog\PersonService
$personService = new \App\Cog\PersonService($this->em, $this->provider->getAccessService());
$result = $personService->getPersonInfo($code, $acc);
return $result;
} catch (\Exception $e) {
$this->log->error('خطا در دریافت اطلاعات شخص از Cog: ' . $e->getMessage(), [
'context' => 'AGIService::callGetPersonInfoFromCog',
'code' => $code,
'exception' => $e->getMessage()
]);
return [
'error' => 'خطا در دریافت اطلاعات شخص: ' . $e->getMessage()
];
}
}
/**
* ساخت پرامپ هوشمند
*/
@ -420,9 +371,19 @@ class AGIService
*/
private function makeHttpRequest(string $url, array $data, string $apiKey): array
{
$requestJson = json_encode($data, JSON_UNESCAPED_UNICODE);
$debugInfo = [
'request_url' => $url,
'request_data' => $data,
'request_headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $apiKey,
],
'api_key' => $apiKey,
'model' => $data['model'] ?? null,
'request_json' => $requestJson,
'request_time' => date('Y-m-d H:i:s'),
'request_size_bytes' => strlen($requestJson),
];
try {
@ -440,6 +401,10 @@ class AGIService
$content = $response->getContent(false); // false: throw exception on 4xx/5xx نمی‌دهد
$debugInfo['http_code'] = $statusCode;
$debugInfo['raw_response'] = $content;
$debugInfo['response_headers'] = $response->getHeaders(false);
$debugInfo['response_time'] = date('Y-m-d H:i:s');
$debugInfo['response_size_bytes'] = strlen($content);
$debugInfo['response_sample'] = mb_substr($content, 0, 500, 'UTF-8');
if ($statusCode !== 200) {
$debugInfo['http_error_message'] = $this->getHttpErrorMessage($statusCode);
@ -461,6 +426,7 @@ class AGIService
];
}
$debugInfo['response_data'] = $responseData;
return [
'success' => true,
'data' => $responseData,
@ -629,13 +595,6 @@ class AGIService
return (bool) ($this->registryMGR->get('system', 'aiEnabled') ?? false);
}
/**
* دریافت پرامپ هوش مصنوعی
*/
public function getAIPrompt(): string
{
return $this->registryMGR->get('system', 'aiPrompt') ?? 'شما یک دستیار هوشمند برای سیستم حسابداری هستید.';
}
/**
* مدیریت گفتگو - ایجاد یا بازیابی گفتگوی موجود
@ -833,6 +792,19 @@ class AGIService
*/
private function buildToolsFromPromptServices(): array
{
return $this->promptService->getAllTools();
// بر اساس آخرین مستندات OpenAI و OpenRouter، باید هر ابزار به صورت زیر باشد:
// [
// 'type' => 'function',
// 'function' => [
// 'name' => ..., 'description' => ..., 'parameters' => [...]
// ]
// ]
// این ساختار در PromptService رعایت شده اما اینجا یکبار دیگر چک و لاگ می‌کنیم
$tools = $this->promptService->getAllTools();
// ابزارها را در لاگ دیباگ ذخیره کن
if (method_exists($this->log, 'debug')) {
$this->log->debug('AIService tools', ['tools' => $tools]);
}
return $tools;
}
}

View file

@ -26,6 +26,13 @@ class BankPromptService
$bankAccountInfoData = json_decode($bankAccountInfoPrompt, true);
if ($bankAccountInfoData) {
// اصلاح ساختار properties
$properties = [
'code' => [
'type' => 'string',
'description' => 'Bank account code (e.g., 1001, 1002)'
]
];
$tools[] = [
'type' => 'function',
'function' => [
@ -33,8 +40,8 @@ class BankPromptService
'description' => $bankAccountInfoData['description'],
'parameters' => [
'type' => 'object',
'properties' => $bankAccountInfoData['input'],
'required' => array_keys($bankAccountInfoData['input'])
'properties' => $properties,
'required' => ['code']
]
]
];

View file

@ -26,6 +26,13 @@ class InventoryPromptService
$itemInfoData = json_decode($itemInfoPrompt, true);
if ($itemInfoData) {
// اصلاح ساختار properties
$properties = [
'code' => [
'type' => 'string',
'description' => 'Item code (e.g., 1001, 1002)'
]
];
$tools[] = [
'type' => 'function',
'function' => [
@ -33,8 +40,8 @@ class InventoryPromptService
'description' => $itemInfoData['description'],
'parameters' => [
'type' => 'object',
'properties' => $itemInfoData['input'],
'required' => array_keys($itemInfoData['input'])
'properties' => $properties,
'required' => ['code']
]
]
];

View file

@ -26,6 +26,13 @@ class PersonPromptService
$personInfoData = json_decode($personInfoPrompt, true);
if ($personInfoData) {
// اصلاح ساختار properties
$properties = [
'code' => [
'type' => 'string',
'description' => 'Person code (e.g., 1001, 1002)'
]
];
$tools[] = [
'type' => 'function',
'function' => [
@ -33,8 +40,8 @@ class PersonPromptService
'description' => $personInfoData['description'],
'parameters' => [
'type' => 'object',
'properties' => $personInfoData['input'],
'required' => array_keys($personInfoData['input'])
'properties' => $properties,
'required' => ['code']
]
]
];