Add License Plate Recognizer integration and vehicle product suggestion route
- Implemented `licensePlateRecognizer` module with configuration classes (`enabled`, `api_key`) and API handling. - Introduced `moduleConfigRoute` endpoints for fetching and updating `licensePlateRecognizer` configurations. - Added `vehicleProductSuggestionRoute` with logic to fetch product suggestions based on vehicle plates. - Extended `moduleScannerRoute` with license plate recognition test and exception handling. - Updated `index.php` to include `licensePlateRecognizer` class.
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace classes;
|
||||
require_once WD . '/modules/licenseplaterecognizer/licenseplaterecognizer_c.php';
|
||||
|
||||
use Exception;
|
||||
use interfaces\licenseplaterecognizer_i;
|
||||
use licenseplaterecognizer\licenseplaterecognizer_c;
|
||||
|
||||
class licenseplaterecognizer implements licenseplaterecognizer_i
|
||||
{
|
||||
/**
|
||||
* The configuration of the module
|
||||
* @var licenseplaterecognizer_c
|
||||
*/
|
||||
public licenseplaterecognizer_c $config;
|
||||
/**
|
||||
* API URL
|
||||
* @var string
|
||||
*/
|
||||
private string $api_url = 'https://api.platerecognizer.com/v1/plate-reader/';
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->config = new licenseplaterecognizer_c();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function requireModuleEnabled(): void
|
||||
{
|
||||
if (!(bool)$this->config->enabled->getVariableValue()) {
|
||||
throw new Exception('licenseplaterecognizer module is not enabled.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws Exception If the module is not enabled or if there is an error in the API request
|
||||
* @throws Exception If the API response cannot be parsed
|
||||
*/
|
||||
public function licenseplaterecognizer(string $base64_image): array
|
||||
{
|
||||
$image_processor = new image_processor();
|
||||
|
||||
//ADD PARAMETER IN REQUEST LIKE regions
|
||||
$data = array(
|
||||
'upload' => $base64_image,
|
||||
'regions' => 'us-ca' // Optional
|
||||
);
|
||||
|
||||
// Prepare new cURL resource
|
||||
$ch = curl_init('https://api.platerecognizer.com/v1/plate-reader/');
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
|
||||
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
|
||||
|
||||
// Set HTTP Header for POST request
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
|
||||
"Authorization: Token " . $this->config->api_key->getVariableValue()
|
||||
)
|
||||
);
|
||||
|
||||
// Submit the POST request and close cURL session handle
|
||||
$result = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
$response_data = json_decode($result, true);
|
||||
if (isset($response_data['results']) && count($response_data['results']) > 0) {
|
||||
return [
|
||||
'success' => true,
|
||||
'license_plate_number' => $response_data['results'][0]['plate'] ?? null,
|
||||
'confidence' => $response_data['results'][0]['score'] ?? null,
|
||||
'raw_response' => $response_data,
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'No license plate detected.',
|
||||
'raw_response' => $response_data,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,7 @@ require_once 'classes/entra.php';
|
||||
require_once 'classes/limble.php';
|
||||
require_once 'classes/ocr_space.php';
|
||||
require_once 'classes/openai.php';
|
||||
require_once 'classes/licenseplaterecognizer.php';
|
||||
require_once 'classes/image_processor.php';
|
||||
require_once 'classes/upload_store.php';
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
namespace interfaces;
|
||||
require_once WD . '/interfaces/universal_module_i.php';
|
||||
interface licenseplaterecognizer_i extends universal_module_i
|
||||
{
|
||||
/**
|
||||
* licenseplaterecognizer - Get the plate number from the image.
|
||||
* @param string $base64_image The base64 encoded image to be processed.
|
||||
* @return array An array containing the plate number and other relevant information.
|
||||
*/
|
||||
public function licenseplaterecognizer(string $base64_image): array;
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace licenseplaterecognizer\config;
|
||||
|
||||
use Exception;
|
||||
use traits\module_config_variable;
|
||||
|
||||
class licenseplaterecognizer_api_key_c
|
||||
{
|
||||
use module_config_variable;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::setupConfigVariable(
|
||||
'licenseplaterecognizer',
|
||||
'api_key',
|
||||
'string',
|
||||
false,
|
||||
null,
|
||||
'The secret key for licenseplaterecognizer API',
|
||||
'1',
|
||||
true,
|
||||
''
|
||||
);
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace licenseplaterecognizer\config;
|
||||
|
||||
use Exception;
|
||||
use traits\module_config_variable;
|
||||
|
||||
class licenseplaterecognizer_enabled_c
|
||||
{
|
||||
use module_config_variable;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::setupConfigVariable(
|
||||
'licenseplaterecognizer',
|
||||
'enabled',
|
||||
'bool',
|
||||
true,
|
||||
null,
|
||||
'Whether licenseplaterecognizer is enabled',
|
||||
'1',
|
||||
false,
|
||||
'false'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace licenseplaterecognizer;
|
||||
require_once WD . '/modules/licenseplaterecognizer/config/licenseplaterecognizer_enabled_c.php';
|
||||
require_once WD . '/modules/licenseplaterecognizer/config/licenseplaterecognizer_api_key_c.php';
|
||||
|
||||
use licenseplaterecognizer\config\licenseplaterecognizer_enabled_c;
|
||||
use licenseplaterecognizer\config\licenseplaterecognizer_api_key_c;
|
||||
use traits\module_config_t;
|
||||
|
||||
class licenseplaterecognizer_c
|
||||
{
|
||||
use module_config_t;
|
||||
|
||||
/**
|
||||
* The status of licenseplaterecognizer, whether it is enabled or not
|
||||
* @var licenseplaterecognizer_enabled_c
|
||||
*/
|
||||
public licenseplaterecognizer_enabled_c $enabled;
|
||||
/**
|
||||
* The API key for licenseplaterecognizer
|
||||
* @var licenseplaterecognizer_api_key_c
|
||||
*/
|
||||
public licenseplaterecognizer_api_key_c $api_key;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->setupConfig('licenseplaterecognizer');
|
||||
$this->allowUpdate([
|
||||
licenseplaterecognizer_enabled_c::class,
|
||||
licenseplaterecognizer_api_key_c::class,
|
||||
]);
|
||||
$this->enabled = new licenseplaterecognizer_enabled_c();
|
||||
$this->api_key = new licenseplaterecognizer_api_key_c();
|
||||
}
|
||||
}
|
||||
@@ -563,5 +563,43 @@ class moduleConfigRoute
|
||||
'modules_openai_config' => 'Update openai config'
|
||||
]
|
||||
);
|
||||
/** LicensePlateRecognizer config > GET */
|
||||
$this->get('/licenseplaterecognizer/config', function () {
|
||||
global $response;
|
||||
$this->requirePermission('modules_licenseplaterecognizer_config');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
(new logs_o())->add('licenseplaterecognizer_config', 'global', 1, $user->id, 'LICENSEPLATERECOGNIZER_CONFIG', 'Successfully fetched licenseplaterecognizer config');
|
||||
$response->success(
|
||||
(new \classes\licenseplaterecognizer())->config->getConfigRequest()
|
||||
);
|
||||
} else {
|
||||
(new logs_o())->add('licenseplaterecognizer_config', 'global', 1, 0, 'LICENSEPLATERECOGNIZER_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'modules_licenseplaterecognizer_config' => 'Get licenseplaterecognizer config'
|
||||
]
|
||||
);
|
||||
/** LicensePlateRecognizer config > POST */
|
||||
$this->post('/licenseplaterecognizer/config', function () {
|
||||
global $response;
|
||||
$this->requirePermission('modules_licenseplaterecognizer_config');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
(new logs_o())->add('licenseplaterecognizer_config', 'global', 1, $user->id, 'LICENSEPLATERECOGNIZER_CONFIG', 'Successfully updated licenseplaterecognizer config');
|
||||
$response->success(
|
||||
(new \classes\licenseplaterecognizer())->config->postConfigRequest()
|
||||
);
|
||||
} else {
|
||||
(new logs_o())->add('licenseplaterecognizer_config', 'global', 1, 0, 'LICENSEPLATERECOGNIZER_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'modules_licenseplaterecognizer_config' => 'Update licenseplaterecognizer config'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,12 @@ namespace routes;
|
||||
|
||||
use classes\authentication;
|
||||
use classes\image_processor;
|
||||
use classes\licenseplaterecognizer;
|
||||
use classes\openai;
|
||||
use classes\response;
|
||||
use classes\router;
|
||||
use classes\upload_store;
|
||||
use Exception;
|
||||
use objects\logs_o;
|
||||
use traits\route_t;
|
||||
|
||||
@@ -23,8 +25,38 @@ class moduleScannerRoute
|
||||
$this->get('/modules/scanner/test', function () {
|
||||
global $response;
|
||||
$base64_image = '';
|
||||
//self::requirePermission('modules_scanner_test');
|
||||
$image_processor = new image_processor();
|
||||
// CREATE FILE READY TO UPLOAD WITH CURL
|
||||
$file = realpath('example.jpg');
|
||||
if (function_exists('curl_file_create')) { // php 5.5+
|
||||
$cFile = curl_file_create($file);
|
||||
} else {
|
||||
$cFile = '@' . realpath($file);
|
||||
}
|
||||
|
||||
//ADD PARAMETER IN REQUEST LIKE regions
|
||||
$data = array(
|
||||
'upload' => $cFile,
|
||||
'regions' => 'us-ca' // Optional
|
||||
);
|
||||
|
||||
// Prepare new cURL resource
|
||||
$ch = curl_init('https://api.platerecognizer.com/v1/plate-reader/');
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
|
||||
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
|
||||
|
||||
// Set HTTP Header for POST request
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
|
||||
"Authorization: Token d7fff863b815cde9fe3f83d687290399ef4854f4", // TODO: Move to settings or environment variable.
|
||||
)
|
||||
);
|
||||
|
||||
// Submit the POST request and close cURL session handle
|
||||
$result = curl_exec($ch);
|
||||
print_r($result);exit;
|
||||
curl_close($ch);
|
||||
$response->success('Scanner module test executed successfully.');
|
||||
},
|
||||
[
|
||||
@@ -39,14 +71,41 @@ class moduleScannerRoute
|
||||
//self::requirePermission('modules_scanner_lpr');
|
||||
if (empty($base64_image)) {
|
||||
$response->error('Base64 image is required.');}
|
||||
$image_processor = new image_processor();
|
||||
$image_processor->set_image_base64($base64_image);
|
||||
$uploads = new upload_store();
|
||||
$object_name = $uploads->storeTempImageFromBase64(
|
||||
$base64_image
|
||||
);
|
||||
//echo $object_name;
|
||||
//echo "License Plate Recognition result:\n";
|
||||
// Uncomment the line below to use the actual license plate recognizer.
|
||||
$lpr_result = (new licenseplaterecognizer())->licenseplaterecognizer($base64_image);
|
||||
if ($lpr_result['success']) {
|
||||
// Set the LICENSE_PLATE_NUMBER to uppercase and remove spaces.
|
||||
$lpr_result['license_plate_number'] = strtoupper(str_replace(' ', '', $lpr_result['license_plate_number']));
|
||||
// If the confidence is below 90%, consider it a failure.
|
||||
if (isset($lpr_result['confidence']) && $lpr_result['confidence'] < 0.9) {
|
||||
throw new Exception('License plate recognition confidence too low. Score: ' . $lpr_result['confidence'] . ' Plate: ' . $lpr_result['license_plate_number'] . ' Raw: ' . json_encode($lpr_result['raw_response']));
|
||||
}
|
||||
// Success
|
||||
$response->success(['success' => true, 'license_plate_number' => $lpr_result['license_plate_number']]);
|
||||
} else {
|
||||
throw new Exception('License plate extraction failed.');
|
||||
//$response->error($lpr_result['message'] ?? 'License plate recognition failed.', $lpr_result);
|
||||
}
|
||||
exit;
|
||||
// For debugging purposes, we will simulate recognized license plates.
|
||||
$openai = new openai();
|
||||
//$response->success('CU61297');
|
||||
$registration_numbers_debug = [
|
||||
'EC21233',
|
||||
'EC21234',
|
||||
'EC21235',
|
||||
];
|
||||
$random_index = rand(0, count($registration_numbers_debug) - 1);
|
||||
$object_name = $registration_numbers_debug[$random_index];
|
||||
// Attempt to recognize the license plate number from the image.
|
||||
|
||||
//Debug: TODO: Remove this.
|
||||
$response->success(['success' => true, 'license_plate_number' => $object_name]);
|
||||
$response->success($openai->lpr($object_name));
|
||||
},
|
||||
[
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace routes;
|
||||
|
||||
use classes\authentication;
|
||||
use classes\motorapi;
|
||||
use Exception;
|
||||
use objects\logs_o;
|
||||
use objects\motorapi_lookups_o;
|
||||
use objects\orders_o;
|
||||
use traits\route_t;
|
||||
|
||||
class vehicleProductSuggestionRoute
|
||||
{
|
||||
use route_t;
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$this->get(
|
||||
'/vehicle/product-suggestions',
|
||||
function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
$this->requirePermission('vehicle_product_suggestions');
|
||||
// Get the user object
|
||||
$user = (new authentication())->get_user();
|
||||
// Check if the request was successful
|
||||
if ($user) {
|
||||
// Make sure the vehicle plate(s) is provided
|
||||
$reg_1 = null; $reg_2 = null; $reg_3 = null;
|
||||
foreach (['reg_1', 'reg_2', 'reg_3'] as $key) {
|
||||
if ($this->isParametersSet([$key])) {
|
||||
${$key} = (string)$this->fromRequest($key);
|
||||
self::requireType(${$key}, self::type_string());
|
||||
self::requireMinLength($key, 1);
|
||||
self::requireMaxLength($key, 10);
|
||||
}
|
||||
}
|
||||
if (!$reg_1 && !$reg_2 && !$reg_3) {
|
||||
$response->error('At least one vehicle plate must be provided', 400);
|
||||
}
|
||||
// Check if the vehicle has been previously added to an order.
|
||||
// Check if the vehicle has been previously looked up.
|
||||
|
||||
|
||||
} else {
|
||||
// Log the incident
|
||||
(new logs_o())->add('products', 'global', 1, 0, 'FETCH_VEHICLE_PRODUCT_SUGGESTIONS', 'No user found, or invalid session');
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'vehicle_product_suggestions' => 'Access to vehicle product suggestions based on internal and external data',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @throws Exception If the MotorAPI request fails, if the registration is invalid, or if the response is malformed
|
||||
*/
|
||||
protected function getVehicleMotorAPIValue(string $reg): ?object
|
||||
{
|
||||
// Get the MotorAPI response for the vehicle reg
|
||||
$MotorAPI = new motorapi();
|
||||
return $MotorAPI->getLicensePlateInformation($reg, false);
|
||||
}
|
||||
|
||||
protected function getSimilarVehicles(array $values): array
|
||||
{
|
||||
$tmp_result = (new motorapi_lookups_o())->getCachedResultsBySubstring($values);
|
||||
return array_map(
|
||||
function ($item) {
|
||||
return $item->result->value();
|
||||
},
|
||||
$tmp_result
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user