diff --git a/composer.json b/composer.json index d99c188a6b..bc79955492 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "stevenmaguire/oauth2-microsoft": "^2.2", "league/oauth2-github": "^3.1", "league/oauth2-facebook": "^2.2", - "translated/lara-sdk":"^0", + "translated/lara-sdk":"^1.0.1", "psr/log": "~1.0", "ext-curl": "*", "ext-pcntl": "*", diff --git a/composer.lock b/composer.lock index 0c0c9bd931..4425b71b4e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5e5f72c1eab0dc4a605f1c5a870cf052", + "content-hash": "c107c1842a725b53940e15bd728aa088", "packages": [ { "name": "aws/aws-crt-php", @@ -3981,16 +3981,16 @@ }, { "name": "translated/lara-sdk", - "version": "0.0.1", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/translated/lara-php.git", - "reference": "6fdf6548093f98b0b755ec7b5ad90b69cddc19cc" + "reference": "acd4a794550f25b65dc5dd33e75444d347a4c3b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/translated/lara-php/zipball/6fdf6548093f98b0b755ec7b5ad90b69cddc19cc", - "reference": "6fdf6548093f98b0b755ec7b5ad90b69cddc19cc", + "url": "https://api.github.com/repos/translated/lara-php/zipball/acd4a794550f25b65dc5dd33e75444d347a4c3b4", + "reference": "acd4a794550f25b65dc5dd33e75444d347a4c3b4", "shasum": "" }, "require": { @@ -4019,9 +4019,9 @@ "homepage": "https://github.com/translated/lara-php", "support": { "issues": "https://github.com/translated/lara-php/issues", - "source": "https://github.com/translated/lara-php/tree/v0.0.1" + "source": "https://github.com/translated/lara-php/tree/v1.0.1" }, - "time": "2024-11-28T16:26:59+00:00" + "time": "2024-12-03T21:47:29+00:00" } ], "packages-dev": [ diff --git a/lib/Controller/catController.php b/lib/Controller/catController.php index 9beda244eb..49ed2e975d 100644 --- a/lib/Controller/catController.php +++ b/lib/Controller/catController.php @@ -195,7 +195,7 @@ public function doAction() { ]; } - $this->template->active_engine = Utils::escapeJsonEncode( $active_mt_engine_array ); + $this->template->active_engine = $active_mt_engine_array; /* * array_unique cast EnginesModel_EngineStruct to string @@ -380,7 +380,6 @@ public function setTemplateVars() { $this->template->mt_engines = $this->translation_engines; $this->template->translation_engines_intento_providers = Intento::getProviderList(); - $this->template->translation_engines_intento_prov_json = Utils::escapeJsonEncode( Intento::getProviderList() ); $this->template->not_empty_default_tm_key = !empty( INIT::$DEFAULT_TM_KEY ); diff --git a/lib/Controller/engineController.php b/lib/Controller/engineController.php index dea4c703a6..b1ed43668d 100755 --- a/lib/Controller/engineController.php +++ b/lib/Controller/engineController.php @@ -1,6 +1,9 @@ [ 'getTermList' ] // letsmt no longer requires this function. it's left as an example + // 'letsmt' => [ 'getTermList' ] // letsmt no longer requires this function. it's left as an example ]; public function __construct() { @@ -126,7 +129,7 @@ private function add() { $newEngineStruct->extra_parameters[ 'DeepL-Auth-Key' ] = $this->engineData[ 'client_id' ]; try { - DeepLValidator::validate($newEngineStruct); + DeepLValidator::validate( $newEngineStruct ); } catch ( Exception $e ) { $this->result[ 'errors' ][] = [ 'code' => $e->getCode(), 'message' => $e->getMessage() ]; @@ -143,11 +146,11 @@ private function add() { */ $newEngineStruct = EnginesModel_MicrosoftHubStruct::getStruct(); - $newEngineStruct->name = $this->name; - $newEngineStruct->uid = $this->user->uid; - $newEngineStruct->type = Constants_Engines::MT; - $newEngineStruct->extra_parameters[ 'client_id' ] = $this->engineData[ 'client_id' ]; - $newEngineStruct->extra_parameters[ 'category' ] = $this->engineData[ 'category' ]; + $newEngineStruct->name = $this->name; + $newEngineStruct->uid = $this->user->uid; + $newEngineStruct->type = Constants_Engines::MT; + $newEngineStruct->extra_parameters[ 'client_id' ] = $this->engineData[ 'client_id' ]; + $newEngineStruct->extra_parameters[ 'category' ] = $this->engineData[ 'category' ]; break; case strtolower( Constants_Engines::APERTIUM ): @@ -221,28 +224,43 @@ private function add() { break; - case strtolower(Constants_Engines::INTENTO): + case strtolower( Constants_Engines::INTENTO ): /** * Create a record of type Intento */ - $newEngineStruct = EnginesModel_IntentoStruct::getStruct(); - $newEngineStruct->name = $this->name; - $newEngineStruct->uid = $this->user->uid; - $newEngineStruct->type = Constants_Engines::MT; - $newEngineStruct->extra_parameters['apikey'] = $this->engineData['secret']; - $newEngineStruct->extra_parameters['provider'] = $this->engineData['provider']; - $newEngineStruct->extra_parameters['providerkey'] = $this->engineData['providerkey']; - $newEngineStruct->extra_parameters['providercategory'] = $this->engineData['providercategory']; + $newEngineStruct = EnginesModel_IntentoStruct::getStruct(); + $newEngineStruct->name = $this->name; + $newEngineStruct->uid = $this->user->uid; + $newEngineStruct->type = Constants_Engines::MT; + $newEngineStruct->extra_parameters[ 'apikey' ] = $this->engineData[ 'secret' ]; + $newEngineStruct->extra_parameters[ 'provider' ] = $this->engineData[ 'provider' ]; + $newEngineStruct->extra_parameters[ 'providerkey' ] = $this->engineData[ 'providerkey' ]; + $newEngineStruct->extra_parameters[ 'providercategory' ] = $this->engineData[ 'providercategory' ]; + break; + + case strtolower( Constants_Engines::LARA ): + /** + * Create a record of type Lara + */ + $newEngineStruct = LaraStruct::getStruct(); + + $newEngineStruct->name = $this->name; + $newEngineStruct->uid = $this->user->uid; + $newEngineStruct->type = Constants_Engines::MT; + $newEngineStruct->extra_parameters[ 'Lara-AccessKeyId' ] = $this->engineData[ 'lara-access-key-id' ]; + $newEngineStruct->extra_parameters[ 'Lara-AccessKeySecret' ] = $this->engineData[ 'secret' ]; + $newEngineStruct->extra_parameters[ 'MMT-License' ] = $this->engineData[ 'mmt-license' ]; + break; default: // MMT $validEngine = $newEngineStruct = $this->featureSet->filter( 'buildNewEngineStruct', false, (object)[ - 'featureSet' => $this->featureSet, - 'providerName' => $this->provider, - 'logged_user' => $this->user, - 'engineData' => $this->engineData + 'featureSet' => $this->featureSet, + 'providerName' => $this->provider, + 'logged_user' => $this->user, + 'engineData' => $this->engineData ] ); break; @@ -261,7 +279,7 @@ private function add() { if ( array_search( $newEngineStruct->class_load, $engineList ) ) { $newEngineStruct->active = true; - $newCreatedDbRowStruct = $engineDAO->create( $newEngineStruct ); + $newCreatedDbRowStruct = $engineDAO->create( $newEngineStruct ); $this->destroyUserEnginesCache(); } @@ -311,6 +329,23 @@ private function add() { return; } + } elseif ( $newEngineStruct instanceof LaraStruct ) { + + /** + * @var $newTestCreatedMT Lara + */ + $newTestCreatedMT = Engine::createTempInstance( $newCreatedDbRowStruct ); + + try { + $newTestCreatedMT->getAvailableLanguages(); + } catch ( LaraException $e ) { + $this->result[ 'errors' ][] = $e->getMessage(); + $engineDAO->delete( $newCreatedDbRowStruct ); + $this->destroyUserEnginesCache(); + + return; + } + } else { try { diff --git a/lib/Model/EnginesModel/EngineStruct.php b/lib/Model/EnginesModel/EngineStruct.php index 378a3723ad..3e486fc313 100644 --- a/lib/Model/EnginesModel/EngineStruct.php +++ b/lib/Model/EnginesModel/EngineStruct.php @@ -69,7 +69,7 @@ class EnginesModel_EngineStruct /** - * @var array + * @var array|string */ public $extra_parameters; @@ -186,7 +186,7 @@ public function getExtraParamsAsArray() { return $this->extra_parameters; } - if ( empty( $this->extra_parameters ) or $this->extra_parameters === null ) { + if ( empty( $this->extra_parameters ) ) { return []; } diff --git a/lib/Model/EnginesModel/LaraStruct.php b/lib/Model/EnginesModel/LaraStruct.php index daa6976fab..41e6d2f963 100644 --- a/lib/Model/EnginesModel/LaraStruct.php +++ b/lib/Model/EnginesModel/LaraStruct.php @@ -7,13 +7,18 @@ * Time: 14.54 */ +namespace EnginesModel; + +use EnginesModel_EngineStruct; +use Utils\Engines\Lara; + /** - * Class EnginesModel_LaraStruct + * Class LaraStruct * * This class contains the default parameters for a Lara Engine CREATION * */ -class EnginesModel_LaraStruct extends EnginesModel_EngineStruct { +class LaraStruct extends EnginesModel_EngineStruct { /** * @var string @@ -23,7 +28,7 @@ class EnginesModel_LaraStruct extends EnginesModel_EngineStruct { /** * @var string */ - public $description = "Lara for subscribers, includes adaptive suggestions for entire documents, integrated glossary support and TM usage optimization."; + public $description = "Lara for subscribers, includes adaptive suggestions for entire documents, with TM usage optimization."; /** * @var string @@ -50,24 +55,22 @@ class EnginesModel_LaraStruct extends EnginesModel_EngineStruct { */ public $others = [ "tmx_import_relative_url" => "memories/content", - "api_key_check_auth_url" => "users/me", "user_update_activate" => "memories/connect", - "context_get" => "context-vector", ]; /** * @var string */ - public $class_load = Constants_Engines::MMT; + public $class_load = Lara::class; /** * @var array */ public $extra_parameters = [ - 'MMT-License' => "", - 'MMT-pretranslate' => "", - 'MMT-preimport' => "", + 'Lara-AccessKeyId' => "", + 'Lara-AccessKeySecret' => "", + 'MMT-License' => "" ]; /** @@ -82,9 +85,9 @@ class EnginesModel_LaraStruct extends EnginesModel_EngineStruct { /** * An empty struct - * @return EnginesModel_EngineStruct + * @return LaraStruct */ - public static function getStruct() { - return new EnginesModel_MMTStruct(); + public static function getStruct(): LaraStruct { + return new LaraStruct(); } } \ No newline at end of file diff --git a/lib/Plugins/Features/Mmt.php b/lib/Plugins/Features/Mmt.php index db7f59d6d6..4d54910c33 100644 --- a/lib/Plugins/Features/Mmt.php +++ b/lib/Plugins/Features/Mmt.php @@ -250,7 +250,7 @@ public static function analysisBeforeMTGetContribution( $config, Engines_Abstrac $config[ 'secret_key' ] = self::getG2FallbackSecretKey(); $config[ 'priority' ] = 'background'; - $config[ 'keys' ] = @$config[ 'id_user' ]; + $config[ 'keys' ] = $config[ 'id_user' ] ?? []; } diff --git a/lib/Utils/AsyncTasks/Workers/GetContributionWorker.php b/lib/Utils/AsyncTasks/Workers/GetContributionWorker.php index 420a2a16ab..4a53d7eac0 100644 --- a/lib/Utils/AsyncTasks/Workers/GetContributionWorker.php +++ b/lib/Utils/AsyncTasks/Workers/GetContributionWorker.php @@ -510,14 +510,15 @@ protected function _getMatches( ContributionRequestStruct $contributionStruct, $ //if a callback is not set only the first argument is returned, get the config params from the callback $config = $featureSet->filter( 'beforeGetContribution', $config, $mt_engine, $jobStruct ); - $config[ 'segment' ] = $contributionStruct->getContexts()->segment; - $config[ 'source' ] = $jobStruct->source; - $config[ 'target' ] = $jobStruct->target; - $config[ 'email' ] = INIT::$MYMEMORY_API_KEY; - $config[ 'segid' ] = $contributionStruct->segmentId; - $config[ 'job_id' ] = $jobStruct->id; - $config[ 'job_password' ] = $jobStruct->password; - $config[ 'session' ] = $contributionStruct->getSessionId(); + $config[ 'segment' ] = $contributionStruct->getContexts()->segment; + $config[ 'source' ] = $jobStruct->source; + $config[ 'target' ] = $jobStruct->target; + $config[ 'email' ] = INIT::$MYMEMORY_API_KEY; + $config[ 'segid' ] = $contributionStruct->segmentId; + $config[ 'job_id' ] = $jobStruct->id; + $config[ 'job_password' ] = $jobStruct->password; + $config[ 'session' ] = $contributionStruct->getSessionId(); + $config[ 'all_job_tm_keys' ] = $jobStruct->tm_keys; if ( $mt_engine instanceof Engines_MMT ) { $metadataDao = new Projects_MetadataDao(); diff --git a/lib/Utils/Constants/Engines.php b/lib/Utils/Constants/Engines.php index 3a1850bd48..7a4fe9979b 100644 --- a/lib/Utils/Constants/Engines.php +++ b/lib/Utils/Constants/Engines.php @@ -1,5 +1,7 @@ self::INTENTO, self::MMT => self::MMT, self::DEEPL => self::DEEPL, + Lara::class => Lara::class, // new namespaced engine classes must be loaded by fully qualified class name ]; /** diff --git a/lib/Utils/Engine.php b/lib/Utils/Engine.php index 679f520c7a..e1c05de140 100644 --- a/lib/Utils/Engine.php +++ b/lib/Utils/Engine.php @@ -37,8 +37,11 @@ public static function getInstance( $id ) { } $className = 'Engines_' . $engineRecord->class_load; - if ( !class_exists( $className, true ) ) { - throw new Exception( "Engine Class $className not Found" ); + if ( !class_exists( $className ) ) { + $className = $engineRecord->class_load; + if( !class_exists( $className ) ){ + throw new Exception( "Engine Class $className not Found" ); + } } return new $className( $engineRecord ); @@ -48,7 +51,7 @@ public static function getInstance( $id ) { /** * @param EnginesModel_EngineStruct $engineRecord * - * @return mixed + * @return Engines_AbstractEngine */ public static function createTempInstance( EnginesModel_EngineStruct $engineRecord ) { $className = 'Engines_' . $engineRecord->class_load; diff --git a/lib/Utils/Engines/Lara.php b/lib/Utils/Engines/Lara.php new file mode 100644 index 0000000000..7c6a200c06 --- /dev/null +++ b/lib/Utils/Engines/Lara.php @@ -0,0 +1,216 @@ +engineRecord->type != "MT" ) { + throw new Exception( "Engine {$this->engineRecord->id} is not a MT engine, found {$this->engineRecord->type} -> {$this->engineRecord->class_load}" ); + } + + $this->_skipAnalysis = true; + + } + + /** + * Get MMTServiceApi client + * + * @return Translator + */ + protected function _getClient(): Translator { + + if( !empty( $this->clientLoaded ) ){ + return $this->clientLoaded; + } + + $extraParams = $this->engineRecord->getExtraParamsAsArray(); + $credentials = new LaraCredentials( $extraParams[ 'Lara-AccessKeyId' ], $extraParams[ 'Lara-AccessKeySecret' ] ); + + $mmtStruct = EnginesModel_MMTStruct::getStruct(); + $mmtStruct->type = Constants_Engines::MT; + $mmtStruct->extra_parameters = [ + 'MMT-License' => $extraParams[ 'MMT-License' ], + 'MMT-pretranslate' => true, + 'MMT-preimport' => false, + ]; + + $this->mmtUserFallback = Engine::createTempInstance( $mmtStruct ); + + $this->clientLoaded = new Translator( $credentials ); + + return $this->clientLoaded; + } + + /** + * Get the available languages in MMT + * + * @return array + * @throws LaraException + * @throws ReflectionException + */ + public function getAvailableLanguages(): array { + + $cache = ( new RedisHandler() )->getConnection(); + + $value = []; + + try { + $value = unserialize( $cache->get( "lara_languages" ) ); + } catch ( Throwable $e ) { + } + + if ( !empty( $value ) ) { + return $value; + } + + $client = $this->_getClient(); + $value = $client->getLanguages(); + $cache->setex( "lara_languages", 86400, serialize( $value ) ); + + return $value; + + } + + protected function _decode( $rawValue, array $parameters = [], $function = null ) { + // TODO: Implement _decode() method. + } + + /** + * @inheritDoc + * @throws LaraException + * @throws ReflectionException + * @throws Exception + */ + public function get( $_config ) { + + $tm_keys = TmKeyManagement_TmKeyManagement::getOwnerKeys( [ $_config[ 'all_job_tm_keys' ] ] ); + $_config[ 'keys' ] = array_map( function ( $tm_key ) { + /** + * @var $tm_key TmKeyManagement_MemoryKeyStruct + */ + return $tm_key->key; + }, $tm_keys ); + + // configuration for mmt fallback + $_config[ 'secret_key' ] = Mmt::getG2FallbackSecretKey(); + if ( $this->_isAnalysis && $this->_skipAnalysis ) { + // for MMT + $_config[ 'include_score' ] = true; + $_config[ 'priority' ] = 'background'; + // analysis on Lara is disabled, fallback on MMT + + return $this->mmtUserFallback->get( $_config ); + } else { + $_config[ 'priority' ] = 'normal'; + } + + $client = $this->_getClient(); + $_lara_keys = $this->_reMapKeyList( $_config[ 'keys' ] ); + + $languagesList = $this->getAvailableLanguages(); + + if ( in_array( $_config[ 'source' ], $languagesList ) && in_array( $_config[ 'target' ], $languagesList ) ) { + // call lara + $translateOptions = new TranslateOptions(); +// $translateOptions->setAdaptTo( $_lara_keys ); + $translateOptions->setPriority( $_config[ 'priority' ] ); + $translation = $client->translate( $_config[ 'segment' ], $_config[ 'source' ], $_config[ 'target' ], $translateOptions ); + } else { + // mmt fallback + return $this->mmtUserFallback->get( $_config ); + } + + return ( new Engines_Results_MyMemory_Matches( + $_config[ 'segment' ], + $translation->getTranslation(), + 100 - $this->getPenalty() . "%", + "MT-" . $this->getName(), + date( "Y-m-d" ) + ) )->getMatches( 1, [], $_config[ 'source' ], $_config[ 'target' ] ); + + } + + /** + * @inheritDoc + */ + public function set( $_config ) { + // TODO: Implement set() method. + } + + /** + * @inheritDoc + */ + public function update( $_config ) { + // TODO: Implement update() method. + } + + /** + * @inheritDoc + */ + public function delete( $_config ) { + // TODO: Implement delete() method. + } + + /** + * @param array $_keys + * + * @return array + */ + protected function _reMapKeyList( array $_keys = [] ): array { + + if ( !empty( $_keys ) ) { + + if ( !is_array( $_keys ) ) { + $_keys = [ $_keys ]; + } + + $_keys = array_map( function ( $key ) { + return 'ext_my_' . $key; + }, $_keys ); + + } + + return $_keys; + + } + +} \ No newline at end of file diff --git a/lib/Utils/Engines/MMT.php b/lib/Utils/Engines/MMT.php index 6d8d54d832..252a6c7767 100644 --- a/lib/Utils/Engines/MMT.php +++ b/lib/Utils/Engines/MMT.php @@ -45,7 +45,7 @@ public function __construct( $engineRecord ) { throw new Exception( "Engine {$this->engineRecord->id} is not a MT engine, found {$this->engineRecord->type} -> {$this->engineRecord->class_load}" ); } - if ( isset( $this->engineRecord->extra_parameters[ 'MMT-pretranslate' ] ) && $this->engineRecord->extra_parameters[ 'MMT-pretranslate' ] == true ) { + if ( isset( $this->engineRecord->extra_parameters[ 'MMT-pretranslate' ] ) && $this->engineRecord->extra_parameters[ 'MMT-pretranslate' ] ) { $this->_skipAnalysis = false; } diff --git a/lib/Utils/Utils.php b/lib/Utils/Utils.php index 1e8b7e8ef0..0bce8d24d4 100644 --- a/lib/Utils/Utils.php +++ b/lib/Utils/Utils.php @@ -814,18 +814,6 @@ public static function truncatePhrase( string $phrase, int $max_words ): string return $phrase; } - /** - * This escape is need by - * javascript JSON.parse() function - * - * @param array $data - * - * @return string - */ - public static function escapeJsonEncode( array $data ): string { - return str_replace( "\\\"", "\\\\\\\"", json_encode( $data ) ); - } - /** * This function strips html tag, but preserves hrefs. * diff --git a/lib/View/templates/_index.html b/lib/View/templates/_index.html index a8def86491..bc61e7bb42 100755 --- a/lib/View/templates/_index.html +++ b/lib/View/templates/_index.html @@ -49,7 +49,7 @@ analysis_enabled: '${analysis_enabled}', not_empty_default_tm_key: ${not_empty_default_tm_key|string:false}, footer_show_revise_link: ${footer_show_revise_link || string: false}, - intento_providers: JSON.parse('${translation_engines_intento_prov_json}'), + intento_providers: JSON.parse(String.raw`${php: json_encode(translation_engines_intento_providers)}`), get job_id() { console.info('job_id is deprecated, use id_job instead', getStackTrace().split("\n")[2]); return this.id_job ; @@ -85,7 +85,7 @@ mark_as_complete_button_enabled : ${mark_as_complete_button_enabled | 'false'}, status_labels : JSON.parse( '${status_labels}' ), searchable_statuses : JSON.parse( '${ php: json_encode(searchable_statuses)}'), - active_engine: JSON.parse('${active_engine}'), + active_engine: JSON.parse(String.raw`${php: json_encode(active_engine)}`), isGDriveProject : ${isGDriveProject|string:false}, remoteFilesInJob : JSON.parse( '${ php: json_encode(remoteFilesInJob)}'), translation_matches_enabled : ${translation_matches_enabled} ,