diff --git a/upload/ai/images/test_image.jpg b/upload/ai/images/test_image.jpg
new file mode 100644
index 000000000..138802617
Binary files /dev/null and b/upload/ai/images/test_image.jpg differ
diff --git a/upload/ai/models/readme b/upload/ai/models/readme
new file mode 100644
index 000000000..a954786ae
--- /dev/null
+++ b/upload/ai/models/readme
@@ -0,0 +1 @@
+ telecharger le fichier model.onnx depuis le site : https://huggingface.co/suko/nsfw et le placer dans ce dossier
\ No newline at end of file
diff --git a/upload/cb_install/modes/precheck.php b/upload/cb_install/modes/precheck.php
index 8a450b66b..64f892199 100644
--- a/upload/cb_install/modes/precheck.php
+++ b/upload/cb_install/modes/precheck.php
@@ -61,11 +61,16 @@
}
$line++;
- if( empty($php_extensions[$key]) ) {
- $everything_good = false;
- $msg = ['err' => $extension['display'] . ' extension is not enabled'];
+ if( !in_array($key, $php_extensions, true) ) {
+ $txt = ' extension is not enabled';
+ if( $key == 'ffi' ){
+ $msg = ['war' => $extension['display'] . $txt];
+ } else {
+ $everything_good = false;
+ $msg = ['err' => $extension['display'] . $txt];
+ }
} else {
- $msg = ['msg' => $extension['display'] . ' extension '. $php_extensions[$key]];
+ $msg = ['msg' => $extension['display'] . ' extension enabled'];
}
echo '
';
diff --git a/upload/composer.json b/upload/composer.json
index 7f53de5a3..3f6bdd104 100644
--- a/upload/composer.json
+++ b/upload/composer.json
@@ -8,7 +8,9 @@
"oxygenzsas/composer_lib_discord": "dev-php7",
"psr/http-server-middleware": "1.0.2",
"ext-json": "*",
- "ext-mysqli": "*"
+ "ext-mysqli": "*",
+ "ext-ffi": "*",
+ "veka-server/onnx-php": "dev-php7"
},
"config": {
"platform": {
diff --git a/upload/includes/classes/AIVision.class.php b/upload/includes/classes/AIVision.class.php
new file mode 100644
index 000000000..f0a26408e
--- /dev/null
+++ b/upload/includes/classes/AIVision.class.php
@@ -0,0 +1,207 @@
+ "Naked", 1 => "Safe"];
+ protected $rescale_factor = 0.00392156862745098 ;
+ protected $format = 'rgb';
+ protected $height = 224;
+ protected $width = 224;
+ protected $shape = 'bhwc'; /* batch channel height width */
+ protected $modelNameOrPath ;
+
+ protected $provider = 'CPUExecutionProvider';
+ protected $model;
+
+ public function __construct(array $config = [], $lib = null) {
+
+ if(!empty($config)) {
+ $this->tags = $config['tags'] ?? [] ;
+ $this->rescale_factor = $config['rescale_factor'] ?? 1 ;
+ $this->modelNameOrPath = $config['modelNameOrPath'] ?? null ;
+ $this->format = $config['format'] ?? 'rgb' ;
+ $this->height = $config['height'] ?? 2 ;
+ $this->width = $config['width'] ?? 256 ;
+ $this->shape = $config['shape'] ?? 'bchw' ;
+ }
+
+ if(!empty($lib)) {
+
+ if(!is_file($lib)) {
+ throw new \Exception( 'Unable to find the lib file : ' . dirname($lib) );
+ }
+
+ \Onnx\FFI::$lib = $lib;
+
+ if (\FFI\WorkDirectory\WorkDirectory::set(dirname($lib)) === false) {
+ throw new \Exception( 'FAILED to CWD has been updated to: ' . dirname($lib) );
+ }
+
+ }
+ }
+
+ public function loadModel($model = null) {
+ if(!empty($model)) {
+ $this->modelNameOrPath = $model;
+ }
+
+ if(empty($this->modelNameOrPath)) {
+ throw new \Exception('model missing');
+ }
+
+ /** chargement du model */
+ $this->model = new \Onnx\Model($this->modelNameOrPath);
+ }
+
+ /**
+ * @throws \Exception
+ */
+ public static function createImageGDFromPath($path) {
+
+ $pathParts = pathinfo( $path);
+ switch ( strtolower($pathParts["extension"])) {
+ case 'png':
+ $image = imagecreatefrompng($path);
+ break;
+ case 'jpg':
+ case 'jpeg':
+ $image = imagecreatefromjpeg($path);
+ break;
+ case 'gif':
+ $image = imagecreatefromgif($path);
+ break;
+ default:
+ throw new \Exception('Format de fichier non reconnu');
+ }
+
+ return $image;
+ }
+
+ public static function getGDImageFromImg($image, $width, $height)
+ {
+ $img = self::createImageGDFromPath($image);
+
+ if(imagesx($img) > imagesy($img)) {
+ $reduction = imagesx($img) / $width;
+ } else {
+ $reduction = imagesy($img) / $height;
+ }
+
+ /** converti l'image en $this->dimenssion_imagex$this->dimenssion_image */
+ $image2 = imagecreatetruecolor($width, $height); /* dimmension fixe */
+ imagefill($image2,0,0,0x7fff0000); /* remplir avec de la transparence */
+ imagecopyresampled($image2, $img, 0, 0, 0, 0, floor(imagesx($img)/$reduction), floor(imagesy($img)/$reduction), imagesx($img), imagesy($img)); /* copier l'image */
+
+ return $image2;
+ }
+
+ public static function getPixels($img, $format = 'rgb', $rescale_factor = 1)
+ {
+ $pixels = [];
+ $width = imagesx($img);
+ $height = imagesy($img);
+
+ // Mapping for different formats
+ $formats = [
+ 'bgr' => ['blue', 'green', 'red'],
+ 'rgb' => ['red', 'green', 'blue'],
+ ];
+
+ // Ensure the format exists, otherwise default to 'rgb'
+ $format = isset($formats[strtolower($format)]) ? $formats[strtolower($format)] : $formats['rgb'];
+
+ for ($y = 0; $y < $height; $y++) {
+ $row = [];
+ for ($x = 0; $x < $width; $x++) {
+ $rgb = imagecolorat($img, $x, $y);
+ $color = imagecolorsforindex($img, $rgb);
+ $row[] = [
+ $color[$format[0]] * $rescale_factor,
+ $color[$format[1]] * $rescale_factor,
+ $color[$format[2]] * $rescale_factor
+ ];
+ }
+ $pixels[] = $row;
+ }
+ return $pixels;
+ }
+
+ public function getTags($image){
+
+ /** resize de l'image pour qu'elle soit dans le bon format */
+ $img = self::getGDImageFromImg( $image, $this->width, $this->height );
+
+ /** Extraction des pixels */
+ $pixels = self::getPixels($img, $this->format, $this->rescale_factor);
+
+ /** converti le shape */
+ $pixels = $this->transposeImage([$pixels], $this->shape);
+
+ /** Récuperation du nom de l'input depuis le model */
+ $input_name = $this->model->inputs()[0]['name'];
+
+ $tensor = Tensor::fromArray($pixels,DType::FLOAT32);
+
+ /** prediction IA */
+ $result = $this->model->predict([$input_name => $tensor]);
+
+ $clean_result = $this->postprocess($result);
+
+ return $clean_result;
+ }
+
+ function transposeImage($pixels, $format = 'bhwc') {
+
+ if(strtolower($format) == 'bhwc') {
+ return $pixels;
+ }
+
+ $transposedImage = [];
+
+ if($format == 'bchw') {
+ foreach ($pixels as $b => $batch) {
+ foreach ($batch as $h => $row) {
+ foreach ($row as $w => $pixel) {
+ foreach ($pixel as $c => $value) {
+ $transposedImage[$b][$c][$h][$w] = $value;
+ }
+ }
+ }
+ }
+ }
+
+ return $transposedImage;
+ }
+
+ protected function postprocess($result) {
+
+ $t = [];
+ $output_name = $this->model->outputs()[0]['name'];
+
+ foreach ($result[$output_name][0] as $idx => $v) {
+
+ if(empty($this->tags[$idx])) {
+ continue;
+ }
+
+ $t[$this->tags[$idx]] = $v;
+
+ }
+
+ return $t;
+ }
+
+ public function setProvider(string $provider = null)
+ {
+ if(empty($provider)) {
+ $this->provider = 'CPUExecutionProvider';
+ return ;
+ }
+
+ $this->provider = $provider;
+ }
+
+}
\ No newline at end of file
diff --git a/upload/includes/classes/system.class.php b/upload/includes/classes/system.class.php
index 8a5173b7d..9051983fa 100644
--- a/upload/includes/classes/system.class.php
+++ b/upload/includes/classes/system.class.php
@@ -9,48 +9,7 @@ private static function init_php_extensions($type, $custom_filepath = null)
{
switch($type){
case 'php_web':
- ob_start();
- phpinfo(INFO_MODULES);
- $s = ob_get_contents();
- ob_end_clean();
-
- $s = strip_tags($s, '
| ');
- $s = preg_replace('/ | ]*>([^<]+)<\/th>/', "\\1", $s);
- $s = preg_replace('/ | ]*>([^<]+)<\/td>/', "\\1", $s);
- $vTmp = preg_split('/([^<]+<\/h2>)/', $s, -1, PREG_SPLIT_DELIM_CAPTURE);
- $vModules = [];
- for ($i = 1; $i < count($vTmp); $i++) {
- if (preg_match('/([^<]+)<\/h2>/', $vTmp[$i], $vMat)) {
- $vName = trim($vMat[1]);
- $vTmp2 = explode("\n", $vTmp[$i + 1]);
- foreach ($vTmp2 as $vOne) {
- $vPat = '([^<]+)<\/info>';
- $vPat3 = "/$vPat\s*$vPat\s*$vPat/";
- $vPat2 = "/$vPat\s*$vPat/";
- if (preg_match($vPat3, $vOne, $vMat)) { // 3cols
- $vModules[$vName][trim($vMat[1])] = [
- trim($vMat[2]),
- trim($vMat[3])
- ];
- } elseif (preg_match($vPat2, $vOne, $vMat)) { // 2cols
- $vModules[$vName][trim($vMat[1])] = trim($vMat[2]);
- }
- }
- }
- }
-
- $regex_version = '(\d+\.\d+\.\d+)';
- $php_extensions = self::get_php_extensions_list();
- foreach($php_extensions as $key => $extension){
- foreach($extension['version_tags'] as $tag){
- if (!empty($vModules[$key][$tag]) && empty(self::$extensionsWeb[$key])) {
- $matches = [];
- preg_match($regex_version, $vModules[$key][$tag], $matches);
- self::$extensionsWeb[$key] = $matches[0]??$vModules[$key][$tag];
- }
- }
- }
-
+ self::$extensionsWeb = array_map('strtolower', get_loaded_extensions());
break;
case 'php_cli':
@@ -83,17 +42,7 @@ private static function init_php_extensions($type, $custom_filepath = null)
}
foreach($php_extensions as $key => $extension){
- foreach($extension['version_tags'] as $tag){
- if (strpos($line, $tag) !== false) {
- $line = explode('=>', $line);
- $tmp_version = trim(end($line));
-
- preg_match($regex_version, $tmp_version, $match_version);
- self::$extensionsCli[$key] = $match_version[0] ?? $tmp_version;
-
- continue 3;
- }
- }
+ self::$extensionsCli[] = $key;
}
}
@@ -136,6 +85,10 @@ public static function get_php_extensions_list(): array
'fileinfo' => [
'display' => 'Fileinfo'
,'version_tags' => ['fileinfo support']
+ ],
+ 'ffi' => [
+ 'display' => 'FFI'
+ ,'version_tags' => ['FFI support']
]
];
}
diff --git a/upload/vendor/composer/autoload_psr4.php b/upload/vendor/composer/autoload_psr4.php
index e8fbff4fd..6501a146b 100644
--- a/upload/vendor/composer/autoload_psr4.php
+++ b/upload/vendor/composer/autoload_psr4.php
@@ -13,4 +13,7 @@
'Predis\\' => array($vendorDir . '/predis/predis/src'),
'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'),
'OxygenzSAS\\Discord\\' => array($vendorDir . '/oxygenzsas/composer_lib_discord/src'),
+ 'Onnx\\' => array($vendorDir . '/veka-server/onnx-php/src'),
+ 'FFI\\WorkDirectory\\' => array($vendorDir . '/veka-server/onnx-php/work-directory/src'),
+ 'FFI\\Env\\' => array($vendorDir . '/veka-server/onnx-php/env/src'),
);
diff --git a/upload/vendor/composer/autoload_real.php b/upload/vendor/composer/autoload_real.php
index 5ea3a6501..434d936de 100644
--- a/upload/vendor/composer/autoload_real.php
+++ b/upload/vendor/composer/autoload_real.php
@@ -22,6 +22,8 @@ public static function getLoader()
return self::$loader;
}
+ require __DIR__ . '/platform_check.php';
+
spl_autoload_register(array('ComposerAutoloaderInitc5bfc8e5670876b11014ce9f23d445ff', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInitc5bfc8e5670876b11014ce9f23d445ff', 'loadClassLoader'));
diff --git a/upload/vendor/composer/autoload_static.php b/upload/vendor/composer/autoload_static.php
index 5da16cd40..02406126f 100644
--- a/upload/vendor/composer/autoload_static.php
+++ b/upload/vendor/composer/autoload_static.php
@@ -22,6 +22,12 @@ class ComposerStaticInitc5bfc8e5670876b11014ce9f23d445ff
'O' =>
array (
'OxygenzSAS\\Discord\\' => 19,
+ 'Onnx\\' => 5,
+ ),
+ 'F' =>
+ array (
+ 'FFI\\WorkDirectory\\' => 18,
+ 'FFI\\Env\\' => 8,
),
);
@@ -55,6 +61,18 @@ class ComposerStaticInitc5bfc8e5670876b11014ce9f23d445ff
array (
0 => __DIR__ . '/..' . '/oxygenzsas/composer_lib_discord/src',
),
+ 'Onnx\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/veka-server/onnx-php/src',
+ ),
+ 'FFI\\WorkDirectory\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/veka-server/onnx-php/work-directory/src',
+ ),
+ 'FFI\\Env\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/veka-server/onnx-php/env/src',
+ ),
);
public static $classMap = array (
diff --git a/upload/vendor/composer/installed.json b/upload/vendor/composer/installed.json
index 03826a3e0..4e7e066f5 100644
--- a/upload/vendor/composer/installed.json
+++ b/upload/vendor/composer/installed.json
@@ -282,27 +282,27 @@
},
{
"name": "psr/http-message",
- "version": "1.1",
- "version_normalized": "1.1.0.0",
+ "version": "1.0.1",
+ "version_normalized": "1.0.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
- "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
- "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"shasum": ""
},
"require": {
- "php": "^7.2 || ^8.0"
+ "php": ">=5.3.0"
},
- "time": "2023-04-04T09:50:52+00:00",
+ "time": "2016-08-06T14:39:51+00:00",
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.1.x-dev"
+ "dev-master": "1.0.x-dev"
}
},
"installation-source": "dist",
@@ -332,7 +332,7 @@
"response"
],
"support": {
- "source": "https://github.com/php-fig/http-message/tree/1.1"
+ "source": "https://github.com/php-fig/http-message/tree/master"
},
"install-path": "../psr/http-message"
},
@@ -573,6 +573,61 @@
"source": "https://github.com/smarty-php/smarty/tree/v3.1.48"
},
"install-path": "../smarty/smarty"
+ },
+ {
+ "name": "veka-server/onnx-php",
+ "version": "dev-php7",
+ "version_normalized": "dev-php7",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/veka-server/onnx-php.git",
+ "reference": "69f54a5cdde794cddd5a6871fc62a6603cdeba99"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/veka-server/onnx-php/zipball/69f54a5cdde794cddd5a6871fc62a6603cdeba99",
+ "reference": "69f54a5cdde794cddd5a6871fc62a6603cdeba99",
+ "shasum": ""
+ },
+ "require": {
+ "ext-ffi": "*",
+ "ext-mbstring": "*",
+ "php": ">= 7"
+ },
+ "time": "2024-08-09T15:46:41+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Onnx\\": "src/",
+ "FFI\\Env\\": "env/src",
+ "FFI\\WorkDirectory\\": "work-directory/src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "veka-server",
+ "email": "veka610@gmail.com"
+ }
+ ],
+ "description": "lib for use onnxruntime with php",
+ "keywords": [
+ "ai",
+ "llm",
+ "models",
+ "onnx",
+ "onnxruntime",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/veka-server/onnx-php/issues",
+ "source": "https://github.com/veka-server/onnx-php/tree/php7"
+ },
+ "install-path": "../veka-server/onnx-php"
}
],
"dev": true,
diff --git a/upload/vendor/composer/installed.php b/upload/vendor/composer/installed.php
index 19a3f0291..a1a8e869a 100644
--- a/upload/vendor/composer/installed.php
+++ b/upload/vendor/composer/installed.php
@@ -3,7 +3,7 @@
'name' => '__root__',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
- 'reference' => '4281d3da6a34fb4bd18850d7cfe3d1cc501767c7',
+ 'reference' => 'f60e5b26a59e9906ecb51115e8b5aa5fc11a80a9',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -13,7 +13,7 @@
'__root__' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
- 'reference' => '4281d3da6a34fb4bd18850d7cfe3d1cc501767c7',
+ 'reference' => 'f60e5b26a59e9906ecb51115e8b5aa5fc11a80a9',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -56,9 +56,9 @@
'dev_requirement' => false,
),
'psr/http-message' => array(
- 'pretty_version' => '1.1',
- 'version' => '1.1.0.0',
- 'reference' => 'cb6ce4845ce34a8ad9e68117c10ee90a29919eba',
+ 'pretty_version' => '1.0.1',
+ 'version' => '1.0.1.0',
+ 'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-message',
'aliases' => array(),
@@ -100,5 +100,14 @@
'aliases' => array(),
'dev_requirement' => false,
),
+ 'veka-server/onnx-php' => array(
+ 'pretty_version' => 'dev-php7',
+ 'version' => 'dev-php7',
+ 'reference' => '69f54a5cdde794cddd5a6871fc62a6603cdeba99',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../veka-server/onnx-php',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
),
);
diff --git a/upload/vendor/composer/platform_check.php b/upload/vendor/composer/platform_check.php
new file mode 100644
index 000000000..f79e574be
--- /dev/null
+++ b/upload/vendor/composer/platform_check.php
@@ -0,0 +1,26 @@
+= 70000)) {
+ $issues[] = 'Your Composer dependencies require a PHP version ">= 7.0.0". You are running ' . PHP_VERSION . '.';
+}
+
+if ($issues) {
+ if (!headers_sent()) {
+ header('HTTP/1.1 500 Internal Server Error');
+ }
+ if (!ini_get('display_errors')) {
+ if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
+ fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
+ } elseif (!headers_sent()) {
+ echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
+ }
+ }
+ trigger_error(
+ 'Composer detected issues in your platform: ' . implode(' ', $issues),
+ E_USER_ERROR
+ );
+}
diff --git a/upload/vendor/psr/http-message/README.md b/upload/vendor/psr/http-message/README.md
index 2668be6c3..28185338f 100644
--- a/upload/vendor/psr/http-message/README.md
+++ b/upload/vendor/psr/http-message/README.md
@@ -10,7 +10,4 @@ interface that describes a HTTP message. See the specification for more details.
Usage
-----
-Before reading the usage guide we recommend reading the PSR-7 interfaces method list:
-
-* [`PSR-7 Interfaces Method List`](docs/PSR7-Interfaces.md)
-* [`PSR-7 Usage Guide`](docs/PSR7-Usage.md)
\ No newline at end of file
+We'll certainly need some stuff in here.
\ No newline at end of file
diff --git a/upload/vendor/psr/http-message/composer.json b/upload/vendor/psr/http-message/composer.json
index 56e8c0a6d..b0d2937a0 100644
--- a/upload/vendor/psr/http-message/composer.json
+++ b/upload/vendor/psr/http-message/composer.json
@@ -11,7 +11,7 @@
}
],
"require": {
- "php": "^7.2 || ^8.0"
+ "php": ">=5.3.0"
},
"autoload": {
"psr-4": {
@@ -20,7 +20,7 @@
},
"extra": {
"branch-alias": {
- "dev-master": "1.1.x-dev"
+ "dev-master": "1.0.x-dev"
}
}
}
diff --git a/upload/vendor/psr/http-message/docs/PSR7-Interfaces.md b/upload/vendor/psr/http-message/docs/PSR7-Interfaces.md
deleted file mode 100644
index 3a7e7dda6..000000000
--- a/upload/vendor/psr/http-message/docs/PSR7-Interfaces.md
+++ /dev/null
@@ -1,130 +0,0 @@
-# Interfaces
-
-The purpose of this list is to help in finding the methods when working with PSR-7. This can be considered as a cheatsheet for PSR-7 interfaces.
-
-The interfaces defined in PSR-7 are the following:
-
-| Class Name | Description |
-|---|---|
-| [Psr\Http\Message\MessageInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessagemessageinterface) | Representation of a HTTP message |
-| [Psr\Http\Message\RequestInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessagerequestinterface) | Representation of an outgoing, client-side request. |
-| [Psr\Http\Message\ServerRequestInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageserverrequestinterface) | Representation of an incoming, server-side HTTP request. |
-| [Psr\Http\Message\ResponseInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageresponseinterface) | Representation of an outgoing, server-side response. |
-| [Psr\Http\Message\StreamInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessagestreaminterface) | Describes a data stream |
-| [Psr\Http\Message\UriInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageuriinterface) | Value object representing a URI. |
-| [Psr\Http\Message\UploadedFileInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageuploadedfileinterface) | Value object representing a file uploaded through an HTTP request. |
-
-## `Psr\Http\Message\MessageInterface` Methods
-
-| Method Name | Description | Notes |
-|------------------------------------| ----------- | ----- |
-| `getProtocolVersion()` | Retrieve HTTP protocol version | 1.0 or 1.1 |
-| `withProtocolVersion($version)` | Returns new message instance with given HTTP protocol version | |
-| `getHeaders()` | Retrieve all HTTP Headers | [Request Header List](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields), [Response Header List](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Response_fields) |
-| `hasHeader($name)` | Checks if HTTP Header with given name exists | |
-| `getHeader($name)` | Retrieves a array with the values for a single header | |
-| `getHeaderLine($name)` | Retrieves a comma-separated string of the values for a single header | |
-| `withHeader($name, $value)` | Returns new message instance with given HTTP Header | if the header existed in the original instance, replaces the header value from the original message with the value provided when creating the new instance. |
-| `withAddedHeader($name, $value)` | Returns new message instance with appended value to given header | If header already exists value will be appended, if not a new header will be created |
-| `withoutHeader($name)` | Removes HTTP Header with given name| |
-| `getBody()` | Retrieves the HTTP Message Body | Returns object implementing `StreamInterface`|
-| `withBody(StreamInterface $body)` | Returns new message instance with given HTTP Message Body | |
-
-
-## `Psr\Http\Message\RequestInterface` Methods
-
-Same methods as `Psr\Http\Message\MessageInterface` + the following methods:
-
-| Method Name | Description | Notes |
-|------------------------------------| ----------- | ----- |
-| `getRequestTarget()` | Retrieves the message's request target | origin-form, absolute-form, authority-form, asterisk-form ([RFC7230](https://www.rfc-editor.org/rfc/rfc7230.txt)) |
-| `withRequestTarget($requestTarget)` | Return a new message instance with the specific request-target | |
-| `getMethod()` | Retrieves the HTTP method of the request. | GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE (defined in [RFC7231](https://tools.ietf.org/html/rfc7231)), PATCH (defined in [RFC5789](https://tools.ietf.org/html/rfc5789)) |
-| `withMethod($method)` | Returns a new message instance with the provided HTTP method | |
-| `getUri()` | Retrieves the URI instance | |
-| `withUri(UriInterface $uri, $preserveHost = false)` | Returns a new message instance with the provided URI | |
-
-
-## `Psr\Http\Message\ServerRequestInterface` Methods
-
-Same methods as `Psr\Http\Message\RequestInterface` + the following methods:
-
-| Method Name | Description | Notes |
-|------------------------------------| ----------- | ----- |
-| `getServerParams() ` | Retrieve server parameters | Typically derived from `$_SERVER` |
-| `getCookieParams()` | Retrieves cookies sent by the client to the server. | Typically derived from `$_COOKIES` |
-| `withCookieParams(array $cookies)` | Returns a new request instance with the specified cookies | |
-| `withQueryParams(array $query)` | Returns a new request instance with the specified query string arguments | |
-| `getUploadedFiles()` | Retrieve normalized file upload data | |
-| `withUploadedFiles(array $uploadedFiles)` | Returns a new request instance with the specified uploaded files | |
-| `getParsedBody()` | Retrieve any parameters provided in the request body | |
-| `withParsedBody($data)` | Returns a new request instance with the specified body parameters | |
-| `getAttributes()` | Retrieve attributes derived from the request | |
-| `getAttribute($name, $default = null)` | Retrieve a single derived request attribute | |
-| `withAttribute($name, $value)` | Returns a new request instance with the specified derived request attribute | |
-| `withoutAttribute($name)` | Returns a new request instance that without the specified derived request attribute | |
-
-## `Psr\Http\Message\ResponseInterface` Methods:
-
-Same methods as `Psr\Http\Message\MessageInterface` + the following methods:
-
-| Method Name | Description | Notes |
-|------------------------------------| ----------- | ----- |
-| `getStatusCode()` | Gets the response status code. | |
-| `withStatus($code, $reasonPhrase = '')` | Returns a new response instance with the specified status code and, optionally, reason phrase. | |
-| `getReasonPhrase()` | Gets the response reason phrase associated with the status code. | |
-
-## `Psr\Http\Message\StreamInterface` Methods
-
-| Method Name | Description | Notes |
-|------------------------------------| ----------- | ----- |
-| `__toString()` | Reads all data from the stream into a string, from the beginning to end. | |
-| `close()` | Closes the stream and any underlying resources. | |
-| `detach()` | Separates any underlying resources from the stream. | |
-| `getSize()` | Get the size of the stream if known. | |
-| `eof()` | Returns true if the stream is at the end of the stream.| |
-| `isSeekable()` | Returns whether or not the stream is seekable. | |
-| `seek($offset, $whence = SEEK_SET)` | Seek to a position in the stream. | |
-| `rewind()` | Seek to the beginning of the stream. | |
-| `isWritable()` | Returns whether or not the stream is writable. | |
-| `write($string)` | Write data to the stream. | |
-| `isReadable()` | Returns whether or not the stream is readable. | |
-| `read($length)` | Read data from the stream. | |
-| `getContents()` | Returns the remaining contents in a string | |
-| `getMetadata($key = null)()` | Get stream metadata as an associative array or retrieve a specific key. | |
-
-## `Psr\Http\Message\UriInterface` Methods
-
-| Method Name | Description | Notes |
-|------------------------------------| ----------- | ----- |
-| `getScheme()` | Retrieve the scheme component of the URI. | |
-| `getAuthority()` | Retrieve the authority component of the URI. | |
-| `getUserInfo()` | Retrieve the user information component of the URI. | |
-| `getHost()` | Retrieve the host component of the URI. | |
-| `getPort()` | Retrieve the port component of the URI. | |
-| `getPath()` | Retrieve the path component of the URI. | |
-| `getQuery()` | Retrieve the query string of the URI. | |
-| `getFragment()` | Retrieve the fragment component of the URI. | |
-| `withScheme($scheme)` | Return an instance with the specified scheme. | |
-| `withUserInfo($user, $password = null)` | Return an instance with the specified user information. | |
-| `withHost($host)` | Return an instance with the specified host. | |
-| `withPort($port)` | Return an instance with the specified port. | |
-| `withPath($path)` | Return an instance with the specified path. | |
-| `withQuery($query)` | Return an instance with the specified query string. | |
-| `withFragment($fragment)` | Return an instance with the specified URI fragment. | |
-| `__toString()` | Return the string representation as a URI reference. | |
-
-## `Psr\Http\Message\UploadedFileInterface` Methods
-
-| Method Name | Description | Notes |
-|------------------------------------| ----------- | ----- |
-| `getStream()` | Retrieve a stream representing the uploaded file. | |
-| `moveTo($targetPath)` | Move the uploaded file to a new location. | |
-| `getSize()` | Retrieve the file size. | |
-| `getError()` | Retrieve the error associated with the uploaded file. | |
-| `getClientFilename()` | Retrieve the filename sent by the client. | |
-| `getClientMediaType()` | Retrieve the media type sent by the client. | |
-
-> `RequestInterface`, `ServerRequestInterface`, `ResponseInterface` extend `MessageInterface` because the `Request` and the `Response` are `HTTP Messages`.
-> When using `ServerRequestInterface`, both `RequestInterface` and `Psr\Http\Message\MessageInterface` methods are considered.
-
diff --git a/upload/vendor/psr/http-message/docs/PSR7-Usage.md b/upload/vendor/psr/http-message/docs/PSR7-Usage.md
deleted file mode 100644
index b6d048a34..000000000
--- a/upload/vendor/psr/http-message/docs/PSR7-Usage.md
+++ /dev/null
@@ -1,159 +0,0 @@
-### PSR-7 Usage
-
-All PSR-7 applications comply with these interfaces
-They were created to establish a standard between middleware implementations.
-
-> `RequestInterface`, `ServerRequestInterface`, `ResponseInterface` extend `MessageInterface` because the `Request` and the `Response` are `HTTP Messages`.
-> When using `ServerRequestInterface`, both `RequestInterface` and `Psr\Http\Message\MessageInterface` methods are considered.
-
-
-The following examples will illustrate how basic operations are done in PSR-7.
-
-##### Examples
-
-
-For this examples to work (at least) a PSR-7 implementation package is required. (eg: zendframework/zend-diactoros, guzzlehttp/psr7, slim/slim, etc)
-All PSR-7 implementations should have the same behaviour.
-
-The following will be assumed:
-`$request` is an object of `Psr\Http\Message\RequestInterface` and
-
-`$response` is an object implementing `Psr\Http\Message\RequestInterface`
-
-
-### Working with HTTP Headers
-
-#### Adding headers to response:
-
-```php
-$response->withHeader('My-Custom-Header', 'My Custom Message');
-```
-
-#### Appending values to headers
-
-```php
-$response->withAddedHeader('My-Custom-Header', 'The second message');
-```
-
-#### Checking if header exists:
-
-```php
-$request->hasHeader('My-Custom-Header'); // will return false
-$response->hasHeader('My-Custom-Header'); // will return true
-```
-
-> Note: My-Custom-Header was only added in the Response
-
-#### Getting comma-separated values from a header (also applies to request)
-
-```php
-// getting value from request headers
-$request->getHeaderLine('Content-Type'); // will return: "text/html; charset=UTF-8"
-// getting value from response headers
-$response->getHeaderLine('My-Custom-Header'); // will return: "My Custom Message; The second message"
-```
-
-#### Getting array of value from a header (also applies to request)
-```php
-// getting value from request headers
-$request->getHeader('Content-Type'); // will return: ["text/html", "charset=UTF-8"]
-// getting value from response headers
-$response->getHeader('My-Custom-Header'); // will return: ["My Custom Message", "The second message"]
-```
-
-#### Removing headers from HTTP Messages
-```php
-// removing a header from Request, removing deprecated "Content-MD5" header
-$request->withoutHeader('Content-MD5');
-
-// removing a header from Response
-// effect: the browser won't know the size of the stream
-// the browser will download the stream till it ends
-$response->withoutHeader('Content-Length');
-```
-
-### Working with HTTP Message Body
-
-When working with the PSR-7 there are two methods of implementation:
-#### 1. Getting the body separately
-
-> This method makes the body handling easier to understand and is useful when repeatedly calling body methods. (You only call `getBody()` once). Using this method mistakes like `$response->write()` are also prevented.
-
-```php
-$body = $response->getBody();
-// operations on body, eg. read, write, seek
-// ...
-// replacing the old body
-$response->withBody($body);
-// this last statement is optional as we working with objects
-// in this case the "new" body is same with the "old" one
-// the $body variable has the same value as the one in $request, only the reference is passed
-```
-
-#### 2. Working directly on response
-
-> This method is useful when only performing few operations as the `$request->getBody()` statement fragment is required
-
-```php
-$response->getBody()->write('hello');
-```
-
-### Getting the body contents
-
-The following snippet gets the contents of a stream contents.
-> Note: Streams must be rewinded, if content was written into streams, it will be ignored when calling `getContents()` because the stream pointer is set to the last character, which is `\0` - meaning end of stream.
-```php
-$body = $response->getBody();
-$body->rewind(); // or $body->seek(0);
-$bodyText = $body->getContents();
-```
-> Note: If `$body->seek(1)` is called before `$body->getContents()`, the first character will be ommited as the starting pointer is set to `1`, not `0`. This is why using `$body->rewind()` is recommended.
-
-### Append to body
-
-```php
-$response->getBody()->write('Hello'); // writing directly
-$body = $request->getBody(); // which is a `StreamInterface`
-$body->write('xxxxx');
-```
-
-### Prepend to body
-Prepending is different when it comes to streams. The content must be copied before writing the content to be prepended.
-The following example will explain the behaviour of streams.
-
-```php
-// assuming our response is initially empty
-$body = $repsonse->getBody();
-// writing the string "abcd"
-$body->write('abcd');
-
-// seeking to start of stream
-$body->seek(0);
-// writing 'ef'
-$body->write('ef'); // at this point the stream contains "efcd"
-```
-
-#### Prepending by rewriting separately
-
-```php
-// assuming our response body stream only contains: "abcd"
-$body = $response->getBody();
-$body->rewind();
-$contents = $body->getContents(); // abcd
-// seeking the stream to beginning
-$body->rewind();
-$body->write('ef'); // stream contains "efcd"
-$body->write($contents); // stream contains "efabcd"
-```
-
-> Note: `getContents()` seeks the stream while reading it, therefore if the second `rewind()` method call was not present the stream would have resulted in `abcdefabcd` because the `write()` method appends to stream if not preceeded by `rewind()` or `seek(0)`.
-
-#### Prepending by using contents as a string
-```php
-$body = $response->getBody();
-$body->rewind();
-$contents = $body->getContents(); // efabcd
-$contents = 'ef'.$contents;
-$body->rewind();
-$body->write($contents);
-```
diff --git a/upload/vendor/psr/http-message/src/MessageInterface.php b/upload/vendor/psr/http-message/src/MessageInterface.php
index 8cdb4ed63..dd46e5ec8 100644
--- a/upload/vendor/psr/http-message/src/MessageInterface.php
+++ b/upload/vendor/psr/http-message/src/MessageInterface.php
@@ -1,7 +1,5 @@
= 7",
+ "ext-mbstring": "*",
+ "ext-ffi": "*"
+ }
+}
diff --git a/upload/vendor/veka-server/onnx-php/env/src/Exception/EnvironmentException.php b/upload/vendor/veka-server/onnx-php/env/src/Exception/EnvironmentException.php
new file mode 100644
index 000000000..a5f8c324b
--- /dev/null
+++ b/upload/vendor/veka-server/onnx-php/env/src/Exception/EnvironmentException.php
@@ -0,0 +1,76 @@
+OrtGetApiBase()[0]->GetVersionString)();
+ }
+
+ private static $libc;
+
+ // for Windows
+ public static function libc()
+ {
+ if (!isset(self::$libc)) {
+ self::$libc = \FFI::cdef(
+ 'size_t mbstowcs(void *wcstr, const char *mbstr, size_t count);',
+ 'msvcrt.dll'
+ );
+ }
+
+ return self::$libc;
+ }
+}
diff --git a/upload/vendor/veka-server/onnx-php/src/GraphOptimizationLevel.php b/upload/vendor/veka-server/onnx-php/src/GraphOptimizationLevel.php
new file mode 100644
index 000000000..16db9165b
--- /dev/null
+++ b/upload/vendor/veka-server/onnx-php/src/GraphOptimizationLevel.php
@@ -0,0 +1,12 @@
+ffi = FFI::instance();
+ $this->api = self::api();
+
+ // session options
+ $sessionOptions = $this->ffi->new('OrtSessionOptions*');
+ $this->checkStatus(($this->api->CreateSessionOptions)(\FFI::addr($sessionOptions)));
+ if ($enableCpuMemArena) {
+ $this->checkStatus(($this->api->EnableCpuMemArena)($sessionOptions));
+ } else {
+ $this->checkStatus(($this->api->DisableCpuMemArena)($sessionOptions));
+ }
+ if ($enableMemPattern) {
+ $this->checkStatus(($this->api->EnableMemPattern)($sessionOptions));
+ } else {
+ $this->checkStatus(($this->api->DisableMemPattern)($sessionOptions));
+ }
+ if ($enableProfiling) {
+ $this->checkStatus(($this->api->EnableProfiling)($sessionOptions, $this->ortString($profileFilePrefix ?? 'onnxruntime_profile_')));
+ } else {
+ $this->checkStatus(($this->api->DisableProfiling)($sessionOptions));
+ }
+ if (!is_null($executionMode)) {
+ $this->checkStatus(($this->api->SetSessionExecutionMode)($sessionOptions, $executionMode->value));
+ }
+ if (!is_null($freeDimensionOverridesByDenotation)) {
+ foreach ($freeDimensionOverridesByDenotation as $k => $v) {
+ $this->checkStatus(($this->api->AddFreeDimensionOverride)($sessionOptions, $k, $v));
+ }
+ }
+ if (!is_null($freeDimensionOverridesByName)) {
+ foreach ($freeDimensionOverridesByName as $k => $v) {
+ $this->checkStatus(($this->api->AddFreeDimensionOverrideByName)($sessionOptions, $k, $v));
+ }
+ }
+ if (!is_null($graphOptimizationLevel)) {
+ $this->checkStatus(($this->api->SetSessionGraphOptimizationLevel)($sessionOptions, $graphOptimizationLevel->value));
+ }
+ if (!is_null($interOpNumThreads)) {
+ $this->checkStatus(($this->api->SetInterOpNumThreads)($sessionOptions, $interOpNumThreads));
+ }
+ if (!is_null($intraOpNumThreads)) {
+ $this->checkStatus(($this->api->SetIntraOpNumThreads)($sessionOptions, $intraOpNumThreads));
+ }
+ if (!is_null($logSeverityLevel)) {
+ $this->checkStatus(($this->api->SetSessionLogSeverityLevel)($sessionOptions, $logSeverityLevel));
+ }
+ if (!is_null($logVerbosityLevel)) {
+ $this->checkStatus(($this->api->SetSessionLogVerbosityLevel)($sessionOptions, $logVerbosityLevel));
+ }
+ if (!is_null($logid)) {
+ $this->checkStatus(($this->api->SetSessionLogId)($sessionOptions, $logid));
+ }
+ if (!is_null($optimizedModelFilepath)) {
+ $this->checkStatus(($this->api->SetOptimizedModelFilePath)($sessionOptions, $this->ortString($optimizedModelFilepath)));
+ }
+ if (!is_null($sessionConfigEntries)) {
+ foreach ($sessionConfigEntries as $k => $v) {
+ $this->checkStatus(($this->api->AddSessionConfigEntry)($sessionOptions, $k, $v));
+ }
+ }
+ foreach ($providers as $provider) {
+ if (!in_array($provider, $this->providers())) {
+ trigger_error('Provider not available: ' . $provider, E_USER_WARNING);
+ continue;
+ }
+
+ if ($provider == 'CUDAExecutionProvider') {
+ $cudaOptions = $this->ffi->new('OrtCUDAProviderOptionsV2*');
+ $this->checkStatus(($this->api->CreateCUDAProviderOptions)(\FFI::addr($cudaOptions)));
+ $this->checkStatus(($this->api->SessionOptionsAppendExecutionProvider_CUDA_V2)($sessionOptions, $cudaOptions));
+ ($this->api->ReleaseCUDAProviderOptions)($cudaOptions);
+ } elseif ($provider == 'CPUExecutionProvider') {
+ break;
+ } else {
+ throw new \InvalidArgumentException('Provider not supported: ' . $provider);
+ }
+ }
+
+ $this->session = $this->loadSession($path, $sessionOptions);
+ $this->allocator = $this->loadAllocator();
+ $this->inputs = $this->loadInputs();
+ $this->outputs = $this->loadOutputs();
+
+ ($this->api->ReleaseSessionOptions)($sessionOptions);
+ }
+
+ public function __destruct()
+ {
+ ($this->api->ReleaseSession)($this->session);
+ }
+
+ public function run($outputNames, $inputFeed, $logSeverityLevel = null, $logVerbosityLevel = null, $logid = null, $terminate = null)
+ {
+ // pointer references
+ $refs = [];
+
+ $inputTensor = $this->createInputTensor($inputFeed, $refs);
+
+ if (!isset($outputNames)) {
+ $outputNames = array_map(function($v) {
+ return $v['name'];
+ }, $this->outputs);
+ }
+
+ $outputsSize = count($outputNames);
+ $outputTensor = $this->ffi->new("OrtValue*[$outputsSize]");
+ $inputNodeNames = $this->createNodeNames(array_keys($inputFeed), $refs);
+ $outputNodeNames = $this->createNodeNames($outputNames, $refs);
+
+ // run options
+ $runOptions = $this->ffi->new('OrtRunOptions*');
+ $this->checkStatus(($this->api->CreateRunOptions)(\FFI::addr($runOptions)));
+ if (!is_null($logVerbosityLevel)) {
+ $this->checkStatus(($this->api->RunOptionsSetRunLogSeverityLevel)($runOptions, $logSeverityLevel));
+ }
+ if (!is_null($logVerbosityLevel)) {
+ $this->checkStatus(($this->api->RunOptionsSetRunLogVerbosityLevel)($runOptions, $logVerbosityLevel));
+ }
+ if (!is_null($logid)) {
+ $this->checkStatus(($this->api->RunOptionsSetRunTag)($runOptions, $logid));
+ }
+ if (!is_null($terminate)) {
+ if ($terminate) {
+ $this->checkStatus(($this->api->RunOptionsSetTerminate)($runOptions));
+ } else {
+ $this->checkStatus(($this->api->RunOptionsUnsetTerminate)($runOptions));
+ }
+ }
+
+ $rrr = ($this->api->Run)($this->session, $runOptions, $inputNodeNames, $inputTensor, count($inputFeed), $outputNodeNames, count($outputNames), $outputTensor);
+
+ $this->checkStatus($rrr);
+
+ $output = [];
+ foreach ($outputTensor as $t) {
+ $output[] = $this->createFromOnnxValue($t);
+ }
+
+ // TODO use finally
+ ($this->api->ReleaseRunOptions)($runOptions);
+ if ($inputTensor) {
+ for ($i = 0; $i < count($inputFeed); $i++) {
+ ($this->api->ReleaseValue)($inputTensor[$i]);
+ }
+ }
+ // output values released in createFromOnnxValue
+
+ return $output;
+ }
+
+ public function inputs()
+ {
+ return $this->inputs;
+ }
+
+ public function outputs()
+ {
+ return $this->outputs;
+ }
+
+ public function modelmeta()
+ {
+ $keys = $this->ffi->new('char**');
+ $numKeys = $this->ffi->new('int64_t');
+ $description = $this->ffi->new('char*');
+ $domain = $this->ffi->new('char*');
+ $graphName = $this->ffi->new('char*');
+ $graphDescription = $this->ffi->new('char*');
+ $producerName = $this->ffi->new('char*');
+ $version = $this->ffi->new('int64_t');
+
+ $metadata = $this->ffi->new('OrtModelMetadata*');
+ $this->checkStatus(($this->api->SessionGetModelMetadata)($this->session, \FFI::addr($metadata)));
+
+ $customMetadataMap = [];
+ $this->checkStatus(($this->api->ModelMetadataGetCustomMetadataMapKeys)($metadata, $this->allocator, \FFI::addr($keys), \FFI::addr($numKeys)));
+ for ($i = 0; $i < $numKeys->cdata; $i++) {
+ $keyPtr = $keys[$i];
+ $key = \FFI::string($keyPtr);
+ $value = $this->ffi->new('char*');
+ $this->checkStatus(($this->api->ModelMetadataLookupCustomMetadataMap)($metadata, $this->allocator, $key, \FFI::addr($value)));
+ $customMetadataMap[$key] = \FFI::string($value);
+
+ $this->allocatorFree($keyPtr);
+ $this->allocatorFree($value);
+ }
+ $this->allocatorFree($keys);
+
+ $this->checkStatus(($this->api->ModelMetadataGetDescription)($metadata, $this->allocator, \FFI::addr($description)));
+ $this->checkStatus(($this->api->ModelMetadataGetDomain)($metadata, $this->allocator, \FFI::addr($domain)));
+ $this->checkStatus(($this->api->ModelMetadataGetGraphName)($metadata, $this->allocator, \FFI::addr($graphName)));
+ $this->checkStatus(($this->api->ModelMetadataGetGraphDescription)($metadata, $this->allocator, \FFI::addr($graphDescription)));
+ $this->checkStatus(($this->api->ModelMetadataGetProducerName)($metadata, $this->allocator, \FFI::addr($producerName)));
+ $this->checkStatus(($this->api->ModelMetadataGetVersion)($metadata, \FFI::addr($version)));
+
+ $ret = [
+ 'custom_metadata_map' => $customMetadataMap,
+ 'description' => \FFI::string($description),
+ 'domain' => \FFI::string($domain),
+ 'graph_name' => \FFI::string($graphName),
+ 'graph_description' => \FFI::string($graphDescription),
+ 'producer_name' => \FFI::string($producerName),
+ 'version' => $version->cdata
+ ];
+
+ // TODO use finally
+ ($this->api->ReleaseModelMetadata)($metadata);
+ $this->allocatorFree($description);
+ $this->allocatorFree($domain);
+ $this->allocatorFree($graphName);
+ $this->allocatorFree($graphDescription);
+ $this->allocatorFree($producerName);
+
+ return $ret;
+ }
+
+ // return value has double underscore like Python
+ public function endProfiling()
+ {
+ $out = $this->ffi->new('char*');
+ $this->checkStatus(($this->api->SessionEndProfiling)($this->session, $this->allocator, \FFI::addr($out)));
+ return \FFI::string($out);
+ }
+
+ // no way to set providers with C API yet
+ // so we can return all available providers
+ public function providers()
+ {
+ $outPtr = $this->ffi->new('char**');
+ $lengthPtr = $this->ffi->new('int');
+ $this->checkStatus(($this->api->GetAvailableProviders)(\FFI::addr($outPtr), \FFI::addr($lengthPtr)));
+ $length = $lengthPtr->cdata;
+ $providers = [];
+ for ($i = 0; $i < $length; $i++) {
+ $providers[] = \FFI::string($outPtr[$i]);
+ }
+ ($this->api->ReleaseAvailableProviders)($outPtr, $length);
+ return $providers;
+ }
+
+ private function loadSession($path, $sessionOptions)
+ {
+ $session = $this->ffi->new('OrtSession*');
+ if (is_resource($path) && get_resource_type($path) == 'stream') {
+ $contents = stream_get_contents($path);
+ $this->checkStatus(($this->api->CreateSessionFromArray)(self::env(), $contents, strlen($contents), $sessionOptions, \FFI::addr($session)));
+ } else {
+ $this->checkStatus(($this->api->CreateSession)(self::env(), $this->ortString($path), $sessionOptions, \FFI::addr($session)));
+ }
+ return $session;
+ }
+
+ private function loadAllocator()
+ {
+ $allocator = $this->ffi->new('OrtAllocator*');
+ $this->checkStatus(($this->api->GetAllocatorWithDefaultOptions)(\FFI::addr($allocator)));
+ return $allocator;
+ }
+
+ private function loadInputs()
+ {
+ $inputs = [];
+ $numInputNodes = $this->ffi->new('size_t');
+ $this->checkStatus(($this->api->SessionGetInputCount)($this->session, \FFI::addr($numInputNodes)));
+ for ($i = 0; $i < $numInputNodes->cdata; $i++) {
+ $namePtr = $this->ffi->new('char*');
+ $this->checkStatus(($this->api->SessionGetInputName)($this->session, $i, $this->allocator, \FFI::addr($namePtr)));
+ // freed in nodeInfo
+ $typeinfo = $this->ffi->new('OrtTypeInfo*');
+ $this->checkStatus(($this->api->SessionGetInputTypeInfo)($this->session, $i, \FFI::addr($typeinfo)));
+ $inputs[] = array_merge(['name' => \FFI::string($namePtr)], $this->nodeInfo($typeinfo));
+ $this->allocatorFree($namePtr);
+ }
+ return $inputs;
+ }
+
+ private function loadOutputs()
+ {
+ $outputs = [];
+ $numOutputNodes = $this->ffi->new('size_t');
+ $this->checkStatus(($this->api->SessionGetOutputCount)($this->session, \FFI::addr($numOutputNodes)));
+ for ($i = 0; $i < $numOutputNodes->cdata; $i++) {
+ $namePtr = $this->ffi->new('char*');
+ $this->checkStatus(($this->api->SessionGetOutputName)($this->session, $i, $this->allocator, \FFI::addr($namePtr)));
+ // freed in nodeInfo
+ $typeinfo = $this->ffi->new('OrtTypeInfo*');
+ $this->checkStatus(($this->api->SessionGetOutputTypeInfo)($this->session, $i, \FFI::addr($typeinfo)));
+ $outputs[] = array_merge(['name' => \FFI::string($namePtr)], $this->nodeInfo($typeinfo));
+ $this->allocatorFree($namePtr);
+ }
+ return $outputs;
+ }
+
+ private function createInputTensor($inputFeed, &$refs)
+ {
+ $allocatorInfo = $this->ffi->new('OrtMemoryInfo*');
+ $this->checkStatus(($this->api->CreateCpuMemoryInfo)(1, 0, \FFI::addr($allocatorInfo)));
+ $inputFeedSize = count($inputFeed);
+ if ($inputFeedSize == 0) {
+ throw new \Exception('No input');
+ }
+ $inputTensor = $this->ffi->new("OrtValue*[$inputFeedSize]");
+
+ $idx = 0;
+ /** @var TensorInterface $input */
+ foreach ($inputFeed as $inputName => $input) {
+ // TODO support more types
+ $inp = null;
+ foreach ($this->inputs as $i) {
+ if ($i['name'] == $inputName) {
+ $inp = $i;
+ break;
+ }
+ }
+ if (is_null($inp)) {
+ throw new \Exception("Unknown input: $inputName");
+ }
+
+ $shape = $input->shape();
+ $ndim = $input->ndim();
+ $size = $input->size();
+
+ $inputNodeShape = $this->ffi->new("int64_t[$ndim]");
+ for ($i = 0; $i < $ndim; $i++) {
+ $inputNodeShape[$i] = $shape[$i];
+ }
+
+ if ($inp['type'] == 'tensor(string)') {
+ $inputTensorValues = $this->ffi->new("char*[$size]");
+ $i = 0;
+ $this->fillStringTensorValues($input, $inputTensorValues, $refs);
+
+ $typeEnum = $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING;
+ $this->checkStatus(($this->api->CreateTensorAsOrtValue)($this->allocator, $inputNodeShape, $ndim, $typeEnum, \FFI::addr($inputTensor[$idx])));
+ $this->checkStatus(($this->api->FillStringTensor)($inputTensor[$idx], $inputTensorValues, count($inputTensorValues)));
+ } else {
+
+ $inputTypes = array_flip(array_map(function($v) {
+ return "tensor($v)";
+ }, $this->elementDataTypes()));
+
+ if (isset($inputTypes[$inp['type']])) {
+ $typeEnum = $inputTypes[$inp['type']];
+ $castType = $this->castTypes()[$typeEnum];
+ } else {
+ $this->unsupportedType('input', $inp['type']);
+ }
+
+ if ($size === 0) {
+ $inputTensorValues = $this->ffi->new("void *");
+ } else {
+ $inputTensorValues = $this->ffi->new("{$castType}[$size]");
+ }
+
+ $inputString = $input->toString();
+
+ $refs[] = $inputTensorValues;
+ \FFI::memcpy($inputTensorValues, $inputString, strlen($inputString));
+
+ $this->checkStatus(
+ ($this->api->CreateTensorWithDataAsOrtValue)(
+ $allocatorInfo,
+ $inputTensorValues,
+ \FFI::sizeof($inputTensorValues),
+ $inputNodeShape,
+ $ndim,
+ $typeEnum,
+ \FFI::addr($inputTensor[$idx])
+ )
+ );
+
+ $refs[] = $inputNodeShape;
+ }
+ $idx++;
+ }
+
+ // TODO use finally
+ ($this->api->ReleaseMemoryInfo)($allocatorInfo);
+
+ return $inputTensor;
+ }
+
+ private function fillStringTensorValues(TensorInterface $input, $ptr, &$refs)
+ {
+ foreach ($input->buffer() as $i => $v) {
+ $strPtr = $this->cstring($v);
+ $ptr[$i] = $strPtr;
+ $refs[] = $strPtr;
+ }
+ }
+
+ private function createNodeNames($names, &$refs)
+ {
+ $namesSize = count($names);
+ $ptr = $this->ffi->new("char*[$namesSize]");
+ foreach ($names as $i => $name) {
+ $strPtr = $this->cstring($name);
+ $ptr[$i] = $strPtr;
+ $refs[] = $strPtr;
+ }
+ return $ptr;
+ }
+
+ private function cstring($str)
+ {
+ $bytes = strlen($str) + 1;
+ // TODO fix?
+ $ptr = $this->ffi->new("char[$bytes]", false);
+ \FFI::memcpy($ptr, $str, $bytes - 1);
+ $ptr[$bytes - 1] = "\0";
+ return $ptr;
+ }
+
+ private function createFromOnnxValue($outPtr)
+ {
+ try {
+ $outType = $this->ffi->new('ONNXType');
+ $this->checkStatus(($this->api->GetValueType)($outPtr, \FFI::addr($outType)));
+
+ if ($outType->cdata == $this->ffi->ONNX_TYPE_TENSOR) {
+ $typeinfo = $this->ffi->new('OrtTensorTypeAndShapeInfo*');
+ $this->checkStatus(($this->api->GetTensorTypeAndShape)($outPtr, \FFI::addr($typeinfo)));
+
+ list($type, $shape) = $this->tensorTypeAndShape($typeinfo);
+
+ // TODO skip if string
+ $tensorData = $this->ffi->new('void*');
+ $this->checkStatus(($this->api->GetTensorMutableData)($outPtr, \FFI::addr($tensorData)));
+
+ $outSize = $this->ffi->new('size_t');
+ $this->checkStatus(($this->api->GetTensorShapeElementCount)($typeinfo, \FFI::addr($outSize)));
+ $outputTensorSize = $outSize->cdata;
+
+ ($this->api->ReleaseTensorTypeAndShapeInfo)($typeinfo);
+
+ $castTypes = $this->castTypes();
+ if (isset($castTypes[$type])) {
+ $arr = $this->ffi->cast($castTypes[$type] . "[$outputTensorSize]", $tensorData);
+
+ $dtype = $this->tensorTypes()[$type];
+ $stringPtr = \FFI::string($arr, \FFI::sizeof($arr));
+ return Tensor::fromString($stringPtr, $dtype, $shape);
+ } elseif ($type == $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING) {
+ $arr = $this->createStringsFromOnnxValue($outPtr, $outputTensorSize);
+
+ return Tensor::fromArray($arr, DType::STRING, $shape);
+ } else {
+ $this->unsupportedType('element', $type);
+ }
+ } elseif ($outType->cdata == $this->ffi->ONNX_TYPE_SEQUENCE) {
+ $out = $this->ffi->new('size_t');
+ $this->checkStatus(($this->api->GetValueCount)($outPtr, \FFI::addr($out)));
+
+ $ret = [];
+ for ($i = 0; $i < $out->cdata; $i++) {
+ $seq = $this->ffi->new('OrtValue*');
+ $this->checkStatus(($this->api->GetValue)($outPtr, $i, $this->allocator, \FFI::addr($seq)));
+ $ret[] = $this->createFromOnnxValue($seq);
+ }
+ return $ret;
+ } elseif ($outType->cdata == $this->ffi->ONNX_TYPE_MAP) {
+ $typeShape = $this->ffi->new('OrtTensorTypeAndShapeInfo*');
+ $mapKeys = $this->ffi->new('OrtValue*');
+ $mapValues = $this->ffi->new('OrtValue*');
+ $elemType = $this->ffi->new('ONNXTensorElementDataType');
+
+ $this->checkStatus(($this->api->GetValue)($outPtr, 0, $this->allocator, \FFI::addr($mapKeys)));
+ $this->checkStatus(($this->api->GetValue)($outPtr, 1, $this->allocator, \FFI::addr($mapValues)));
+ $this->checkStatus(($this->api->GetTensorTypeAndShape)($mapKeys, \FFI::addr($typeShape)));
+ $this->checkStatus(($this->api->GetTensorElementType)($typeShape, \FFI::addr($elemType)));
+
+ ($this->api->ReleaseTensorTypeAndShapeInfo)($typeShape);
+
+ // TODO support more types
+ if ($elemType->cdata == $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64) {
+ $ret = [];
+ $keys = $this->createFromOnnxValue($mapKeys);
+ $values = $this->createFromOnnxValue($mapValues);
+ foreach ($keys as $i => $k) {
+ $ret[$k] = $values[$i];
+ }
+ return $ret;
+ } else {
+ $this->unsupportedType('element', $elemType);
+ }
+ } else {
+ $this->unsupportedType('ONNX', $outType->cdata);
+ }
+ } finally {
+ if (!\FFI::isNull($outPtr)) {
+ ($this->api->ReleaseValue)($outPtr);
+ }
+ }
+ }
+
+ private function tensorTypes()
+ {
+ return [
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED => 'undefined',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT => DType::FLOAT32,
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8 => DType::UINT8,
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8 => DType::INT8,
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16 => DType::UINT16,
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16 => DType::INT16,
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32 => DType::INT32,
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64 => DType::INT64,
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING => DType::STRING,
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL => DType::BOOL,
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16 => DType::FLOAT16,
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE => DType::FLOAT64,
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32 => DType::UINT32,
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64 => DType::UINT64,
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX64 => DType::COMPLEX64,
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128 => DType::COMPLEX128,
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16 => DType::BFLOAT16
+ ];
+ }
+
+ private function createStringsFromOnnxValue($outPtr, $outputTensorSize)
+ {
+ $len = $this->ffi->new('size_t');
+ $this->checkStatus(($this->api->GetStringTensorDataLength)($outPtr, \FFI::addr($len)));
+
+ $sLen = $len->cdata;
+ $s = $this->ffi->new("char[$sLen]");
+ $offsets = $this->ffi->new("size_t[$outputTensorSize]");
+ $this->checkStatus(($this->api->GetStringTensorContent)($outPtr, $s, $sLen, $offsets, $outputTensorSize));
+
+ $result = [];
+ foreach ($offsets as $i => $v) {
+ $start = $v;
+ $end = $i < $outputTensorSize - 1 ? $offsets[$i + 1] : $sLen;
+ $size = $end - $start;
+ $result[] = \FFI::string($s + $start, $size);
+ }
+ return $result;
+ }
+
+ private static function checkStatus($status)
+ {
+ if (!is_null($status)) {
+ $message = (self::api()->GetErrorMessage)($status);
+ (self::api()->ReleaseStatus)($status);
+ throw new \Exception($message);
+ }
+ }
+
+ private function nodeInfo($typeinfo)
+ {
+ $onnxType = $this->ffi->new('ONNXType');
+ $this->checkStatus(($this->api->GetOnnxTypeFromTypeInfo)($typeinfo, \FFI::addr($onnxType)));
+
+ if ($onnxType->cdata == $this->ffi->ONNX_TYPE_TENSOR) {
+ $tensorInfo = $this->ffi->new('OrtTensorTypeAndShapeInfo*');
+ // don't free tensor_info
+ $this->checkStatus(($this->api->CastTypeInfoToTensorInfo)($typeinfo, \FFI::addr($tensorInfo)));
+
+ list($type, $shape) = $this->tensorTypeAndShape($tensorInfo);
+ $elementDataType = $this->elementDataTypes()[$type];
+ return ['type' => "tensor($elementDataType)", 'shape' => $shape];
+ } elseif ($onnxType->cdata == $this->ffi->ONNX_TYPE_SEQUENCE) {
+ $sequenceTypeInfo = $this->ffi->new('OrtSequenceTypeInfo*');
+ $this->checkStatus(($this->api->CastTypeInfoToSequenceTypeInfo)($typeinfo, \FFI::addr($sequenceTypeInfo)));
+ $nestedTypeInfo = $this->ffi->new('OrtTypeInfo*');
+ $this->checkStatus(($this->api->GetSequenceElementType)($sequenceTypeInfo, \FFI::addr($nestedTypeInfo)));
+ $v = $this->nodeInfo($nestedTypeInfo)['type'];
+
+ return ['type' => "seq($v)", 'shape' => []];
+ } elseif ($onnxType->cdata == $this->ffi->ONNX_TYPE_MAP) {
+ $mapTypeInfo = $this->ffi->new('OrtMapTypeInfo*');
+ $this->checkStatus(($this->api->CastTypeInfoToMapTypeInfo)($typeinfo, \FFI::addr($mapTypeInfo)));
+
+ // key
+ $keyType = $this->ffi->new('ONNXTensorElementDataType');
+ $this->checkStatus(($this->api->GetMapKeyType)($mapTypeInfo, \FFI::addr($keyType)));
+ $k = $this->elementDataTypes()[$keyType->cdata];
+
+ // value
+ $valueTypeInfo = $this->ffi->new('OrtTypeInfo*');
+ $this->checkStatus(($this->api->GetMapValueType)($mapTypeInfo, \FFI::addr($valueTypeInfo)));
+ $v = $this->nodeInfo($valueTypeInfo)['type'];
+
+ return ['type' => "map($k,$v)", 'shape' => []];
+ } else {
+ $this->unsupportedType('ONNX', $onnxType->cdata);
+ }
+ }
+
+ private function castTypes()
+ {
+ return [
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT => 'float',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8 => 'uint8_t',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8 => 'int8_t',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16 => 'uint16_t',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16 => 'int16_t',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32 => 'int32_t',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64 => 'int64_t',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL => 'bool',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE => 'double',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32 => 'uint32_t',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64 => 'uint64_t'
+ ];
+ }
+
+ private function elementDataTypes()
+ {
+ return [
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED => 'undefined',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT => 'float',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8 => 'uint8',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8 => 'int8',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16 => 'uint16',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16 => 'int16',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32 => 'uint32',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64 => 'int64',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING => 'string',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL => 'bool',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16 => 'float16',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE => 'double',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32 => 'uint32',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64 => 'uint64',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX64 => 'complex64',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128 => 'complex128',
+ $this->ffi->ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16 => 'bfloat16'
+ ];
+ }
+
+ private function tensorTypeAndShape($tensorInfo)
+ {
+ $type = $this->ffi->new('ONNXTensorElementDataType');
+ $this->checkStatus(($this->api->GetTensorElementType)($tensorInfo, \FFI::addr($type)));
+
+ $numDimsPtr = $this->ffi->new('size_t');
+ $this->checkStatus(($this->api->GetDimensionsCount)($tensorInfo, \FFI::addr($numDimsPtr)));
+ $numDims = $numDimsPtr->cdata;
+
+ if ($numDims > 0) {
+ $nodeDims = $this->ffi->new("int64_t[$numDims]");
+ $this->checkStatus(($this->api->GetDimensions)($tensorInfo, $nodeDims, $numDims));
+ $dims = $this->readArray($nodeDims);
+
+ $symbolicDims = $this->ffi->new("char*[$numDims]");
+ $this->checkStatus(($this->api->GetSymbolicDimensions)($tensorInfo, $symbolicDims, $numDims));
+ for ($i = 0; $i < $numDims; $i++) {
+ $namedDim = \FFI::string($symbolicDims[$i]);
+ if ($namedDim != '') {
+ $dims[$i] = $namedDim;
+ }
+ }
+ } else {
+ $dims = [];
+ }
+
+ return [$type->cdata, $dims];
+ }
+
+ private function unsupportedType($name, $type)
+ {
+ throw new \Exception("Unsupported $name type: $type");
+ }
+
+ private function readArray($cdata)
+ {
+ $arr = [];
+ $n = count($cdata);
+ for ($i = 0; $i < $n; $i++) {
+ $arr[] = $cdata[$i];
+ }
+ return $arr;
+ }
+
+ private function allocatorFree($ptr)
+ {
+ ($this->api->AllocatorFree)($this->allocator, $ptr);
+ }
+
+ private static function api()
+ {
+ return (FFI::instance()->OrtGetApiBase()[0]->GetApi)(11)[0];
+ }
+
+ // wide string on Windows
+ // char string on Linux
+ // see ORTCHAR_T in onnxruntime_c_api.h
+ private function ortString($str)
+ {
+ if (PHP_OS == 'WINNT' || PHP_OS == 'WIN32' || PHP_OS == 'Windows') {
+ $libc = FFI::libc();
+ $max = strlen($str) + 1; // for null byte
+ // wchar_t not supported
+ // use char instead of casting later
+ // since FFI::cast only references data
+ $dest = $libc->new('char[' . ($max * 2) . ']');
+ $ret = $libc->mbstowcs($dest, $str, $max);
+ if ($ret != strlen($str)) {
+ throw new \Exception('Expected mbstowcs to return ' . strlen($str) . ", got $ret");
+ }
+ return $dest;
+ } else {
+ return $str;
+ }
+ }
+
+ private static function env()
+ {
+ // TODO use mutex for thread-safety
+ // TODO memoize
+
+ $env = FFI::instance()->new('OrtEnv*');
+ (self::api()->CreateEnv)(3, 'Default', \FFI::addr($env));
+ // disable telemetry
+ // https://github.com/microsoft/onnxruntime/blob/master/docs/Privacy.md
+ self::checkStatus((self::api()->DisableTelemetryEvents)($env));
+ return $env;
+ }
+}
diff --git a/upload/vendor/veka-server/onnx-php/src/Library.php b/upload/vendor/veka-server/onnx-php/src/Library.php
new file mode 100644
index 000000000..7d831edd3
--- /dev/null
+++ b/upload/vendor/veka-server/onnx-php/src/Library.php
@@ -0,0 +1,141 @@
+ [
+ 'file' => 'onnxruntime-linux-x64-{{version}}',
+ 'checksum' => 'fa4d11b3fa1b2bf1c3b2efa8f958634bc34edc95e351ac2a0408c6ad5c5504f0',
+ 'lib' => 'libonnxruntime.so.{{version}}',
+ 'ext' => 'tgz'
+ ],
+ 'aarch64-linux' => [
+ 'file' => 'onnxruntime-linux-aarch64-{{version}}',
+ 'checksum' => 'c278ca7ce725d2b26cf1ec62c93affaec4145a9a3d7721fb5d1af5497136ca76',
+ 'lib' => 'libonnxruntime.so.{{version}}',
+ 'ext' => 'tgz'
+ ],
+ 'x86_64-darwin' => [
+ 'file' => 'onnxruntime-osx-x86_64-{{version}}',
+ 'checksum' => '3af96893675b295e5e0eb886f470de585089f92f9950158d042fbc02b44ed101',
+ 'lib' => 'libonnxruntime.{{version}}.dylib',
+ 'ext' => 'tgz'
+ ],
+ 'arm64-darwin' => [
+ 'file' => 'onnxruntime-osx-arm64-{{version}}',
+ 'checksum' => 'c5ff520d2913e3360670979ca4fe43717fc3aa0c0c367a75fbb6f2f15c0cb48d',
+ 'lib' => 'libonnxruntime.{{version}}.dylib',
+ 'ext' => 'tgz'
+ ],
+ 'x64-windows' => [
+ 'file' => 'onnxruntime-win-x64-{{version}}',
+ 'checksum' => 'a91af21ca8f9bdfa5a1aac3fdd0591384b4e2866d41612925f1758d5522829e7',
+ 'lib' => 'onnxruntime.dll',
+ 'ext' => 'zip'
+ ]
+ ];
+
+ public static function install($event = null)
+ {
+ $dest = self::defaultLib();
+ if (file_exists($dest)) {
+ return;
+ }
+
+ $dir = self::libDir();
+ if (!file_exists($dir)) {
+ mkdir($dir);
+ }
+
+ $file = self::platform('file');
+ $ext = self::platform('ext');
+ $url = self::withVersion("https://github.com/microsoft/onnxruntime/releases/download/v{{version}}/$file.$ext");
+ $contents = file_get_contents($url);
+
+ $checksum = hash('sha256', $contents);
+ if ($checksum != self::platform('checksum')) {
+ throw new \Exception("Bad checksum: $checksum");
+ }
+
+ $tempDest = tempnam(sys_get_temp_dir(), 'onnxruntime') . '.' . $ext;
+ file_put_contents($tempDest, $contents);
+
+ $archive = new \PharData($tempDest);
+ if ($ext != 'zip') {
+ $archive = $archive->decompress();
+ }
+ $archive->extractTo(self::libDir());
+ }
+
+ /**
+ * @throws OnnxException
+ */
+ public static function ThrowExceptionIfLibNotFound()
+ {
+ $dest = self::defaultLib();
+ if (!file_exists($dest)) {
+ throw new OnnxException('OnnxRuntime not found');
+ }
+ }
+
+ public static function defaultLib()
+ {
+ return self::libDir() . DIRECTORY_SEPARATOR . self::libFile();
+ }
+
+ private static function libDir()
+ {
+ return ( self::$folder ?? dirname(__DIR__)).DIRECTORY_SEPARATOR.'lib'.DIRECTORY_SEPARATOR ;
+ }
+
+ public static function setFolder(String $path){
+
+ if(!is_dir($path)){
+ mkdir($path);
+ }
+
+ $path = realpath($path);
+
+ self::$folder = $path;
+ FFI::$lib = self::defaultLib();
+ }
+
+ private static function libFile()
+ {
+ return self::withVersion(self::platform('file') . DIRECTORY_SEPARATOR.'lib'.DIRECTORY_SEPARATOR . self::platform('lib'));
+ }
+
+ private static function platform($key)
+ {
+ return self::PLATFORMS[self::platformKey()][$key];
+ }
+
+ private static function platformKey()
+ {
+ if (PHP_OS == 'WINNT' || PHP_OS == 'WIN32' || PHP_OS == 'Windows') {
+ return 'x64-windows';
+ } elseif (PHP_OS == 'Darwin') {
+ if (php_uname('m') == 'x86_64') {
+ return 'x86_64-darwin';
+ } else {
+ return 'arm64-darwin';
+ }
+ } else {
+ if (php_uname('m') == 'x86_64') {
+ return 'x86_64-linux';
+ } else {
+ return 'aarch64-linux';
+ }
+ }
+ }
+
+ private static function withVersion($str)
+ {
+ return str_replace('{{version}}', self::VERSION, $str);
+ }
+}
diff --git a/upload/vendor/veka-server/onnx-php/src/Model.php b/upload/vendor/veka-server/onnx-php/src/Model.php
new file mode 100644
index 000000000..6242af2fd
--- /dev/null
+++ b/upload/vendor/veka-server/onnx-php/src/Model.php
@@ -0,0 +1,41 @@
+session = new InferenceSession($path, ...$sessionOptions);
+ }
+
+ public function predict($inputFeed, $outputNames = null, ...$runOptions)
+ {
+ // Check if $outputNames is not set or null
+ if (!isset($outputNames)) {
+ $outputNames = array_map(function($o) {
+ return $o['name'];
+ }, $this->outputs());
+ }
+ $predictions = $this->session->run($outputNames, $inputFeed, ...$runOptions);
+ return array_combine($outputNames, $predictions);
+ }
+
+ public function inputs()
+ {
+ return $this->session->inputs();
+ }
+
+ public function outputs()
+ {
+ return $this->session->outputs();
+ }
+
+ public function metadata()
+ {
+ return $this->session->modelmeta();
+ }
+}
diff --git a/upload/vendor/veka-server/onnx-php/src/OnnxException.php b/upload/vendor/veka-server/onnx-php/src/OnnxException.php
new file mode 100644
index 000000000..80dce54c1
--- /dev/null
+++ b/upload/vendor/veka-server/onnx-php/src/OnnxException.php
@@ -0,0 +1,8 @@
+dtype = $dtype;
+ $this->shape = $shape;
+ $this->buffer = $buffer;
+ }
+
+ /**
+ * Create a Tensor instance from a PHP array.
+ *
+ * @param array $array The input array.
+ * @param mixed $dtype The data type of the tensor (optional).
+ * @param array|null $shape The shape of the tensor (optional).
+ * @return static The created Tensor instance.
+ * @throws InvalidArgumentException If the shape isn't provided when the array is empty.
+ */
+ public static function fromArray(array $array, $dtype = null, $shape = null)
+ {
+ if (empty($array) && $shape === null) {
+ throw new InvalidArgumentException('Shape must be provided when the array is empty');
+ }
+
+ if (!isset($shape)) {
+ $shape = self::generateShape($array);
+ }
+ $buffer = [];
+ $index = 0;
+
+ self::flattenArray($array, $buffer, $index, $dtype);
+
+ return new static($buffer, $shape, $dtype);
+ }
+
+ /**
+ * Create a Tensor instance from a packed binary string.
+ *
+ * @param string $string The packed binary string containing the tensor data (flat)
+ * @param DType $dtype The data type of the tensor.
+ * @param array $shape The shape of the tensor.
+ * @return static The created Tensor instance.
+ * @throws RuntimeException If an error occurs during string unpacking.
+ * @throws InvalidArgumentException If the number of elements in the string does not match the shape.
+ * @throws \Exception
+ */
+ public static function fromString(string $string, $dtype, array $shape)
+ {
+ $data = unpack(DType::packFormat($dtype), $string);
+
+ if ($data === false) {
+ throw new RuntimeException('Error unpacking string data');
+ }
+
+ if (count($data) != array_product($shape)) {
+ throw new InvalidArgumentException('The number of elements in the string does not match the shape');
+ }
+
+ $buffer = [];
+ foreach ($data as $i => $value) {
+ $buffer[$i - 1] = DType::castValue($dtype, $value);
+ }
+
+ return new static($buffer, $shape, $dtype);
+ }
+
+ public function shape() :array
+ {
+ return $this->shape;
+ }
+
+ public function ndim() :int
+ {
+ return count($this->shape);
+ }
+
+ public function dtype()
+ {
+ return $this->dtype;
+ }
+
+ public function buffer() :array
+ {
+ return $this->buffer;
+ }
+
+ public function size() :int
+ {
+ return array_product($this->shape);
+ }
+
+ public function reshape(array $shape)
+ {
+ if (array_product($shape) != array_product($this->shape)) {
+ throw new InvalidArgumentException('New shape must have the same number of elements');
+ }
+
+ return new static($this->buffer, $shape, $this->dtype);
+ }
+
+ public function toArray() :array
+ {
+ $i = 0;
+ return self::unflattenArray($this->buffer, $this->shape, $i);
+ }
+
+ public function toString() :string
+ {
+ // Récupération du format de pack avant la boucle pour éviter de l'appeler à chaque itération
+ $packFormat = DType::packFormat($this->dtype);
+
+ $packedValues = '';
+
+ foreach ($this->buffer as $value) {
+ // Stockage des valeurs packées dans le tableau
+ $packedValues .= pack($packFormat, $value);
+ }
+
+ return $packedValues;
+ }
+
+ public function count() :int
+ {
+ return $this->shape[0];
+ }
+
+ public static function generateShape(array $array) :array
+ {
+ $shape = [];
+
+ while (is_array($array)) {
+ $shape[] = count($array);
+ $array = reset($array);
+ }
+
+ return $shape;
+ }
+
+ public static function flattenArray(array $nestedArray, array &$buffer, int &$index, $dtype)
+ {
+ foreach ($nestedArray as $value) {
+ if (is_array($value)) {
+ self::flattenArray($value, $buffer, $index, $dtype);
+ } else {
+ $buffer[$index++] = $value;
+ }
+ }
+ }
+
+ public static function unflattenArray(array &$buffer, array $shape, int &$index) :array
+ {
+ if (array_product($shape) === 0) {
+ return [];
+ }
+
+ $nestedArray = [];
+ $size = array_shift($shape);
+
+ for ($i = 0; $i < $size; $i++) {
+ $nestedArray[] = empty($shape) ? $buffer[$index++] : self::unflattenArray($buffer, $shape, $index);
+ }
+
+ return $nestedArray;
+ }
+
+ public function getIterator() :Traversable
+ {
+ if (empty($this->shape)) {
+ return new EmptyIterator();
+ }
+
+ for ($i = 0; $i < $this->count(); $i++) {
+ yield $i => $this->offsetGet($i);
+ }
+ }
+
+ public function offsetExists($offset) :bool
+ {
+ return $offset >= 0 && $offset < $this->shape[0];
+ }
+
+ public function offsetGet($offset)
+ {
+ if (!$this->offsetExists($offset)) {
+ throw new OutOfBoundsException('Index out of bounds');
+ }
+
+ if (count($this->shape) === 1) {
+ return $this->buffer[$offset];
+ }
+
+ $newShape = array_slice($this->shape, 1);
+ $newSize = array_product($newShape);
+ $buffer = [];
+
+ for ($i = 0; $i < $newSize; $i++) {
+ $buffer[$i] = $this->buffer[$offset * $newSize + $i];
+ }
+
+ return new self($buffer, $newShape, $this->dtype);
+ }
+
+ public function offsetSet($offset, $value)
+ {
+ if (!$this->offsetExists($offset)) {
+ throw new OutOfBoundsException('Index out of bounds');
+ }
+
+ if (count($this->shape) === 0) {
+ if (!is_scalar($value)) {
+ throw new InvalidArgumentException('Value must be scalar');
+ }
+ $this->buffer[$offset] = $value;
+ return;
+ }
+
+ if (!($value instanceof self) || $value->shape() !== array_slice($this->shape, 1)) {
+ throw new InvalidArgumentException('Value must be a tensor with the same sub-shape');
+ }
+
+ $buffer = $value->buffer();
+ $newSize = array_product(array_slice($this->shape, 1));
+
+ for ($i = 0; $i < $newSize; $i++) {
+ $this->buffer[$offset * $newSize + $i] = $buffer[$i];
+ }
+ }
+
+ public function offsetUnset( $offset)
+ {
+ throw new RuntimeException('Cannot unset tensor elements');
+ }
+
+
+ /**
+ * Transpose tensor data from BHWC to BCHW.
+ *
+ * @return static The transposed Tensor instance.
+ * @throws InvalidArgumentException If the tensor does not have exactly 4 dimensions.
+ */
+ public function transposeBhwcToBchw()
+ {
+ if (count($this->shape) !== 4) {
+ throw new InvalidArgumentException('Tensor must have exactly 4 dimensions to transpose from BHWC to BCHW');
+ }
+
+ list($batch, $height, $width, $channels) = $this->shape;
+ $newShape = [$batch, $channels, $height, $width];
+ $newBuffer = array_fill(0, array_product($newShape), 0);
+
+ for ($b = 0; $b < $batch; $b++) {
+ for ($h = 0; $h < $height; $h++) {
+ for ($w = 0; $w < $width; $w++) {
+ for ($c = 0; $c < $channels; $c++) {
+ $oldIndex = (($b * $height + $h) * $width + $w) * $channels + $c;
+ $newIndex = (($b * $channels + $c) * $height + $h) * $width + $w;
+ $newBuffer[$newIndex] = $this->buffer[$oldIndex];
+ }
+ }
+ }
+ }
+
+ return new static($newBuffer, $newShape, $this->dtype);
+ }
+
+}
diff --git a/upload/vendor/veka-server/onnx-php/src/TensorInterface.php b/upload/vendor/veka-server/onnx-php/src/TensorInterface.php
new file mode 100644
index 000000000..da2203874
--- /dev/null
+++ b/upload/vendor/veka-server/onnx-php/src/TensorInterface.php
@@ -0,0 +1,30 @@
+fallback = $this->getInitialCurrentWorkingDirectory();
+ }
+
+ /**
+ * @return non-empty-string|null
+ */
+ private function getInitialCurrentWorkingDirectory()
+ {
+ if ($directory = \getcwd()) {
+ return $directory;
+ }
+
+ if (isset($_SERVER['SCRIPT_NAME']) && $directory = \dirname($_SERVER['SCRIPT_NAME'])) {
+ return $directory;
+ }
+
+ if (isset($_SERVER['SCRIPT_FILENAME']) && $directory = \dirname($_SERVER['SCRIPT_FILENAME'])) {
+ return $directory;
+ }
+
+ if (isset($_SERVER['PHP_SELF']) && $directory = \dirname($_SERVER['PHP_SELF'])) {
+ return $directory;
+ }
+
+ return null;
+ }
+
+ /**
+ * @return array{fallback:non-empty-string|null}
+ */
+ public function __serialize(): array
+ {
+ return ['fallback' => $this->fallback];
+ }
+
+ /**
+ * @param array{fallback:non-empty-string|null} $data
+ */
+ public function __unserialize(array $data)
+ {
+ $this->fallback = $data['fallback'] ?? $this->getInitialCurrentWorkingDirectory();
+ }
+}
diff --git a/upload/vendor/veka-server/onnx-php/work-directory/src/Driver/UnixAwareThreadSafeDriver.php b/upload/vendor/veka-server/onnx-php/work-directory/src/Driver/UnixAwareThreadSafeDriver.php
new file mode 100644
index 000000000..d335407da
--- /dev/null
+++ b/upload/vendor/veka-server/onnx-php/work-directory/src/Driver/UnixAwareThreadSafeDriver.php
@@ -0,0 +1,73 @@
+boot();
+ }
+
+ private function boot()
+ {
+ $this->ffi = \FFI::cdef(self::STDLIB);
+ }
+
+ /**
+ * @return string
+ */
+ abstract protected static function getEnvVariableName();
+
+ public function get()
+ {
+ /**
+ * Note: The getenv function returns a pointer to a string associated
+ * with the matched list member. The string pointed to shall not be
+ * modified by the program, but may be overwritten by a subsequent
+ * call to the getenv function.
+ *
+ * @var CData $directory
+ */
+ $directory = $this->ffi->getenv(static::getEnvVariableName());
+
+ if ($directory === null) {
+ return $this->fallback;
+ }
+
+ return \FFI::string($directory) ?: $this->fallback;
+ }
+
+ public function set($directory):bool
+ {
+ return $this->ffi->setenv(static::getEnvVariableName(), $directory, 1) === 0;
+ }
+
+ public function __unserialize(array $data)
+ {
+ parent::__unserialize($data);
+ $this->boot();
+ }
+}
diff --git a/upload/vendor/veka-server/onnx-php/work-directory/src/Driver/WindowsThreadSafeDriver.php b/upload/vendor/veka-server/onnx-php/work-directory/src/Driver/WindowsThreadSafeDriver.php
new file mode 100644
index 000000000..b4446b394
--- /dev/null
+++ b/upload/vendor/veka-server/onnx-php/work-directory/src/Driver/WindowsThreadSafeDriver.php
@@ -0,0 +1,143 @@
+internal = $this->getDefaultInternalEncoding();
+ $this->external = $this->getDefaultExternalEncoding();
+
+ $this->boot();
+ }
+
+ private function getDefaultInternalEncoding()
+ {
+ return \mb_internal_encoding() ?: self::DEFAULT_INTERNAL_ENCODING;
+ }
+
+ private function getDefaultExternalEncoding()
+ {
+ return 'UTF-16' . (\unpack('S', "\x01\x00")[1] === 1 ? 'LE' : 'BE');
+ }
+
+ private function boot()
+ {
+ $this->ffi = \FFI::cdef(self::KERNEL32, 'kernel32.dll');
+ }
+
+ public function get()
+ {
+ $bufferSizeDiv2 = self::DEFAULT_EXPECTED_BUFFER_SIZE;
+ $uint16Array = $this->ffi->new("uint16_t[$bufferSizeDiv2]", false);
+ $uint16ArrayPointer = \FFI::addr($uint16Array[0]);
+
+ $length = $this->ffi->GetDllDirectoryW(self::DEFAULT_EXPECTED_BUFFER_SIZE, $uint16Array);
+ $result = null;
+
+ if ($length !== 0) {
+ $char8Array = $this->ffi->cast("char*", $uint16ArrayPointer);
+ $char8ArrayPointer = \FFI::addr($char8Array[0]);
+
+ $result = \FFI::string($char8ArrayPointer, $length * 2);
+ $result = \mb_convert_encoding($result, $this->internal, $this->external);
+ }
+
+ try {
+ return $result ?: $this->fallback;
+ } finally {
+ \FFI::free($uint16Array);
+ }
+ }
+
+ public function set($directory) :bool
+ {
+ if (\mb_detect_encoding($directory, 'ASCII', true)) {
+ return $this->ffi->SetDllDirectoryA($directory) !== 0;
+ }
+
+ $directory = \mb_convert_encoding($directory, $this->external, $this->internal) . "\0\0";
+
+ $bytes = \strlen($directory);
+ $charArray = $this->ffi->new("char[$bytes]", false);
+ $charArrayPointer = \FFI::addr($charArray[0]);
+
+ \FFI::memcpy($charArrayPointer, $directory, $bytes);
+
+ $bytesDiv2 = (int)\ceil($bytes / 2);
+ $uint16Array = \FFI::cast("uint16_t[$bytesDiv2]", $charArray);
+ $uint16ArrayPointer = \FFI::addr($uint16Array[0]);
+
+ try {
+ return $this->ffi->SetDllDirectoryW(\FFI::addr($uint16Array[0])) !== 0;
+ } finally {
+ \FFI::free($uint16ArrayPointer);
+ }
+ }
+
+ public function __serialize() :array
+ {
+ return \array_merge(parent::__serialize(), [
+ 'internal' => $this->internal,
+ 'external' => $this->external,
+ ]);
+ }
+
+ public function __unserialize(array $data)
+ {
+ parent::__unserialize($data);
+
+ $this->internal = isset($data['internal']) ? $data['internal'] : $this->getDefaultInternalEncoding();
+ $this->external = isset($data['external']) ? $data['external'] : $this->getDefaultExternalEncoding();
+
+ $this->boot();
+ }
+}
diff --git a/upload/vendor/veka-server/onnx-php/work-directory/src/WorkDirectory.php b/upload/vendor/veka-server/onnx-php/work-directory/src/WorkDirectory.php
new file mode 100644
index 000000000..e80d49e5d
--- /dev/null
+++ b/upload/vendor/veka-server/onnx-php/work-directory/src/WorkDirectory.php
@@ -0,0 +1,74 @@
+get();
+ }
+
+ /**
+ * Change directory.
+ *
+ * @psalm-taint-sink file $directory
+ * @param non-empty-string $directory The new current directory.
+ *
+ * @return bool Returns {@see true} on success or {@see false} on failure.
+ */
+ public static function set(string $directory): bool
+ {
+ $driver = self::driver();
+
+ return $driver->set($directory);
+ }
+}
|