Update: 2026-05-04 01:33:55
This commit is contained in:
103
app/core/AI.php
Normal file
103
app/core/AI.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace App\Core;
|
||||
|
||||
/**
|
||||
* Gemini AI Integration for Invoice Extraction
|
||||
*/
|
||||
class AI
|
||||
{
|
||||
private static string $baseUrl = "https://generativelanguage.googleapis.com/v1beta/models/gemini-flash-lite-latest:generateContent";
|
||||
|
||||
/**
|
||||
* Extract Data from Invoice Image or PDF (Base64)
|
||||
*/
|
||||
public static function extractInvoiceData(string $base64Data, string $mimeType): ?array
|
||||
{
|
||||
$apiKey = env('GEMINI_API_KEY');
|
||||
if (!$apiKey) {
|
||||
error_log('AI Error: GEMINI_API_KEY is missing');
|
||||
return null;
|
||||
}
|
||||
|
||||
$prompt = "You are an expert in Jordanian E-Invoicing (UBL 2.1).
|
||||
Extract all data from this invoice image/document into a JSON format.
|
||||
|
||||
Strict Rules:
|
||||
1. Ensure numeric values are numbers, not strings.
|
||||
2. Identify the Supplier TIN (Tax Identification Number) and Buyer TIN (if present).
|
||||
3. Identify if the invoice is 'Cash' or 'Credit'.
|
||||
4. Identify if it is 'Simplified' (B2C) or 'Standard' (B2B).
|
||||
5. Extract line items precisely.
|
||||
6. Return ONLY valid JSON, no markdown formatting.
|
||||
|
||||
Required JSON Structure:
|
||||
{
|
||||
\"invoice_number\": \"\",
|
||||
\"invoice_date\": \"YYYY-MM-DD\",
|
||||
\"invoice_type\": \"cash|credit\",
|
||||
\"invoice_category\": \"simplified|standard\",
|
||||
\"supplier_tin\": \"\",
|
||||
\"supplier_name\": \"\",
|
||||
\"supplier_address\": \"\",
|
||||
\"buyer_tin\": \"\",
|
||||
\"buyer_name\": \"\",
|
||||
\"buyer_national_id\": \"\",
|
||||
\"subtotal\": 0.000,
|
||||
\"tax_amount\": 0.000,
|
||||
\"discount_total\": 0.000,
|
||||
\"grand_total\": 0.000,
|
||||
\"currency\": \"JOD\",
|
||||
\"items\": [
|
||||
{
|
||||
\"description\": \"\",
|
||||
\"quantity\": 0,
|
||||
\"unit_price\": 0.000,
|
||||
\"tax_amount\": 0.000,
|
||||
\"total\": 0.000
|
||||
}
|
||||
]
|
||||
}";
|
||||
|
||||
$payload = [
|
||||
"contents" => [
|
||||
[
|
||||
"parts" => [
|
||||
["text" => $prompt],
|
||||
[
|
||||
"inline_data" => [
|
||||
"mime_type" => $mimeType,
|
||||
"data" => $base64Data
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
"generationConfig" => [
|
||||
"response_mime_type" => "application/json"
|
||||
]
|
||||
];
|
||||
|
||||
$ch = curl_init(self::$baseUrl . "?key=" . $apiKey);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
if ($httpCode !== 200) {
|
||||
error_log("AI Error: Gemini API returned code $httpCode. Response: " . $response);
|
||||
return null;
|
||||
}
|
||||
|
||||
$result = json_decode($response, true);
|
||||
$textResponse = $result['candidates'][0]['content']['parts'][0]['text'] ?? null;
|
||||
|
||||
if (!$textResponse) return null;
|
||||
|
||||
return json_decode($textResponse, true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user