🚀 مُصادَق: الإطلاق الأولي للنظام المتكامل
This commit is contained in:
31
app/Services/AI/Contracts/AIProviderInterface.php
Normal file
31
app/Services/AI/Contracts/AIProviderInterface.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services\AI\Contracts;
|
||||
|
||||
final class ExtractionResultDTO
|
||||
{
|
||||
public function __construct(
|
||||
public string $invoiceNumber,
|
||||
public string $invoiceDate,
|
||||
public string $supplierName,
|
||||
public ?string $supplierTin,
|
||||
public string $supplierAddress,
|
||||
public ?string $buyerName,
|
||||
public ?string $buyerTin,
|
||||
public array $lines,
|
||||
public float $subtotal,
|
||||
public float $taxAmount,
|
||||
public float $grand_total,
|
||||
public string $currency,
|
||||
public float $confidence,
|
||||
public array $usage
|
||||
) {}
|
||||
}
|
||||
|
||||
interface AIProviderInterface
|
||||
{
|
||||
public function extractFromFile(string $filePath, string $mimeType): ExtractionResultDTO;
|
||||
public function getProviderName(): string;
|
||||
}
|
||||
77
app/Services/AI/GeminiProvider.php
Normal file
77
app/Services/AI/GeminiProvider.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services\AI;
|
||||
|
||||
use App\Services\AI\Contracts\{AIProviderInterface, ExtractionResultDTO};
|
||||
use GuzzleHttp\Client;
|
||||
use Exception;
|
||||
|
||||
final class GeminiProvider implements AIProviderInterface
|
||||
{
|
||||
private Client $client;
|
||||
private string $apiKey;
|
||||
private string $model;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->client = new Client();
|
||||
$this->apiKey = $_ENV['GEMINI_API_KEY'] ?? '';
|
||||
$this->model = $_ENV['GEMINI_MODEL'] ?? 'gemini-2.0-flash';
|
||||
}
|
||||
|
||||
public function extractFromFile(string $filePath, string $mimeType): ExtractionResultDTO
|
||||
{
|
||||
$fileData = base64_encode(file_get_contents($filePath));
|
||||
|
||||
$prompt = "Extract invoice data from this file. Return ONLY valid JSON (no markdown). " .
|
||||
"Fields: invoice_number, invoice_date (YYYY-MM-DD), supplier_name, supplier_tin, supplier_address, " .
|
||||
"buyer_name, buyer_tin, lines (description, quantity, unit_price, line_total, tax_rate), " .
|
||||
"subtotal, tax_amount, grand_total, currency (JOD), confidence (0-1).";
|
||||
|
||||
$response = $this->client->post("https://generativelanguage.googleapis.com/v1beta/models/{$this->model}:generateContent?key={$this->apiKey}", [
|
||||
'json' => [
|
||||
'contents' => [
|
||||
[
|
||||
'parts' => [
|
||||
['text' => $prompt],
|
||||
[
|
||||
'inline_data' => [
|
||||
'mime_type' => $mimeType,
|
||||
'data' => $fileData
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
'generationConfig' => [
|
||||
'response_mime_type' => 'application/json'
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$data = json_decode($response->getBody()->getContents(), true);
|
||||
$jsonStr = $data['candidates'][0]['content']['parts'][0]['text'] ?? '{}';
|
||||
$result = json_decode($jsonStr, true);
|
||||
|
||||
return new ExtractionResultDTO(
|
||||
$result['invoice_number'] ?? '',
|
||||
$result['invoice_date'] ?? '',
|
||||
$result['supplier_name'] ?? '',
|
||||
$result['supplier_tin'] ?? null,
|
||||
$result['supplier_address'] ?? '',
|
||||
$result['buyer_name'] ?? null,
|
||||
$result['buyer_tin'] ?? null,
|
||||
$result['lines'] ?? [],
|
||||
(float)($result['subtotal'] ?? 0),
|
||||
(float)($result['tax_amount'] ?? 0),
|
||||
(float)($result['grand_total'] ?? 0),
|
||||
$result['currency'] ?? 'JOD',
|
||||
(float)($result['confidence'] ?? 0),
|
||||
$data['usageMetadata'] ?? []
|
||||
);
|
||||
}
|
||||
|
||||
public function getProviderName(): string { return 'gemini'; }
|
||||
}
|
||||
Reference in New Issue
Block a user