107 lines
3.2 KiB
PHP
107 lines
3.2 KiB
PHP
<?php
|
|
/**
|
|
* Voice Parse Intent Proxy Endpoint (Grok Variant - xAI)
|
|
* POST /v1/voice/parse-intent-grok
|
|
*
|
|
* Proxies transcribed text to Grok (xAI) to extract intent and parameters.
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Middleware\AuthMiddleware;
|
|
use App\Middleware\RateLimitMiddleware;
|
|
use App\Core\Security;
|
|
use App\Core\Validator;
|
|
|
|
// Rate limit: 20 per minute
|
|
RateLimitMiddleware::check(20, 60);
|
|
|
|
$decoded = AuthMiddleware::check();
|
|
$data = Security::sanitize(input());
|
|
|
|
$errors = Validator::validate($data, ['text' => 'required']);
|
|
if ($errors) {
|
|
json_error('النص مطلوب', 422);
|
|
}
|
|
|
|
$apiKey = env('XAI_API_KEY'); // Ensure this is set in .env
|
|
if (!$apiKey) {
|
|
json_error('xAI API Key غير متوفر', 500);
|
|
}
|
|
|
|
$text = $data['text'];
|
|
|
|
$systemPrompt = <<<PROMPT
|
|
أنت محلل أوامر لنظام مُصادَق للفوترة الأردني.
|
|
استخرج النية والمعاملات من النص وأرجع JSON فقط.
|
|
|
|
الأوامر المتاحة:
|
|
- list_invoices: { company?: string, from?: date, to?: date, status?: string }
|
|
- check_quota: {}
|
|
- open_scanner: { company?: string }
|
|
- search_invoice: { amount?: number, company?: string, number?: string }
|
|
- get_report: { type: "tax"|"monthly", period?: string }
|
|
- check_status: { invoice_id?: string, company?: string }
|
|
- export_pdf: { invoice_id?: string, company?: string }
|
|
- navigate: { screen: string }
|
|
|
|
أرجع JSON بهذا التنسيق:
|
|
{
|
|
"action": "...",
|
|
"params": {...},
|
|
"confirmation": "نص قصير تأكيد بالعامية الأردنية أو الفصحى المبسطة"
|
|
}
|
|
PROMPT;
|
|
|
|
$payload = [
|
|
'model' => 'grok-beta', // Update to current xAI model name
|
|
'messages' => [
|
|
['role' => 'system', 'content' => $systemPrompt],
|
|
['role' => 'user', 'content' => $text]
|
|
],
|
|
'response_format' => ['type' => 'json_object'],
|
|
'temperature' => 0.2
|
|
];
|
|
|
|
$url = "https://api.x.ai/v1/chat/completions";
|
|
|
|
try {
|
|
$ch = curl_init($url);
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_POST => true,
|
|
CURLOPT_POSTFIELDS => json_encode($payload),
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_HTTPHEADER => [
|
|
'Content-Type: application/json',
|
|
'Authorization: Bearer ' . $apiKey
|
|
]
|
|
]);
|
|
|
|
$response = curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
$error = curl_error($ch);
|
|
curl_close($ch);
|
|
|
|
if ($httpCode !== 200) {
|
|
error_log("Grok Error: $response | $error");
|
|
json_error('فشل في تحليل الأمر بواسطة Grok. تأكد من صحة مفتاح API وصلاحية الحساب.', 500);
|
|
}
|
|
|
|
$respData = json_decode($response, true);
|
|
if (!isset($respData['choices'][0]['message']['content'])) {
|
|
json_error('رد غير متوقع من Grok AI', 500);
|
|
}
|
|
|
|
$jsonText = $respData['choices'][0]['message']['content'];
|
|
$parsed = json_decode($jsonText, true);
|
|
|
|
if (!$parsed) {
|
|
json_error('فشل في تحليل الرد كـ JSON', 500);
|
|
}
|
|
|
|
json_success($parsed, 'تم تحليل الأمر بواسطة Grok');
|
|
} catch (\Throwable $e) {
|
|
error_log("Voice Intent Error: " . $e->getMessage());
|
|
json_error('حدث خطأ فني أثناء تحليل الأمر صوتياً.', 500);
|
|
}
|