Skip to content

Commit

Permalink
Init
Browse files Browse the repository at this point in the history
  • Loading branch information
drejmanMacopedia committed Mar 29, 2023
1 parent 2a484f2 commit 1d7c9eb
Show file tree
Hide file tree
Showing 24 changed files with 286 additions and 135 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
vendor
var
bin
.idea
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ The highest quality of translation is ensured by artificial intelligence.
Extension uses [Open AI API](https://openai.com/product) - ChatGPT v3.5
### Requirements:

* Akeneo PIM >= 6.x
* Akeneo PIM >= 6.x

## Contact
`Akeneo OpenAI translator` is brought to you by [Macopedia](https://macopedia.com/).

[Contact us](https://macopedia.com/contact)
16 changes: 9 additions & 7 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
}
},
"require": {
"orhanerday/open-ai": "^4.7"
"orhanerday/open-ai": "^4.7",
"akeneo/pim-community-dev": "^6.0.0||^7.0.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.15",
Expand All @@ -30,19 +31,20 @@
},
"scripts": {
"phpstan": [
"vendor/bin/phpstan --configuration=phpstan.neon"
"vendor/bin/phpstan analyse --configuration=\"config/phpstan.neon\""
],
"phpunit": [
"vendor/bin/phpunit --colors=always"
"vendor/bin/phpunit --colors=always --configuration=\"config/phpunit.xml.dist\""
],
"cs:fix": [
"vendor/bin/php-cs-fixer fix --config=\"config/.php-cs-fixer.php\" --using-cache no --allow-risky=yes"
],
"test": [
"vendor/bin/php-cs-fixer fix --dry-run",
"@cs:fix",
"@phpstan",
"@phpunit"
],
"cs:fix": [
"vendor/bin/php-cs-fixer fix"
]

},
"minimum-stability": "stable",
"config": {
Expand Down
45 changes: 45 additions & 0 deletions config/.php-cs-fixer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

$finder = PhpCsFixer\Finder::create()
->in(__DIR__ . '/../')
->exclude(
[
'var',
'node_modules',
'upgrades',
]
)->notPath(
[
'public/index.php',
'public/api.php',
'config/bootstrap.php',
'src/Kernel.php',
]
);

return (new PhpCsFixer\Config())
->setCacheFile(__DIR__ . '/../var/.php_cs.cache')
->setRules(
[
'@PSR12' => true,
'blank_line_after_opening_tag' => true,
'braces' => ['allow_single_line_closure' => true],
'compact_nullable_typehint' => true,
'single_quote' => true,
'concat_space' => ['spacing' => 'one'],
'declare_equal_normalize' => ['space' => 'none'],
'function_typehint_space' => true,
'new_with_braces' => true,
'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
'no_empty_statement' => true,
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_whitespace_in_blank_line' => true,
'return_type_declaration' => ['space_before' => 'none'],
'single_trait_insert_per_statement' => true,
'array_syntax' => ['syntax' => 'short'],
'global_namespace_import' => ['import_classes' => true, 'import_constants' => true, 'import_functions' => true],
'declare_strict_types' => true
]
)
->setFinder($finder);
6 changes: 6 additions & 0 deletions config/phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
parameters:
level: 6
paths:
- ../src
#- ../tests
tmpDir: ../var/phpstan
19 changes: 19 additions & 0 deletions config/phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" colors="true" bootstrap="../tests/bootstrap.php" cacheResultFile="../var/.phpunit.result.cache" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">src</directory>
</include>
</coverage>
<php>
<ini name="error_reporting" value="-1"/>
<server name="APP_ENV" value="test" force="true"/>
<server name="SHELL_VERBOSITY" value="-1"/>
</php>
<testsuites>
<testsuite name="Project Test Suite">
<directory>../tests</directory>
</testsuite>
</testsuites>
</phpunit>
9 changes: 7 additions & 2 deletions src/Macopedia/Translator/Client/OpenAiClient.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<?php

declare(strict_types=1);

namespace Macopedia\Translator\Client;

use JetBrains\PhpStorm\ArrayShape;
use Macopedia\Translator\Client\OpenAiClient\Response;
use Macopedia\Translator\Exception\InvalidOpenAiResponseException;
use Orhanerday\OpenAi\OpenAi;
Expand Down Expand Up @@ -38,7 +41,7 @@ public function ask(string $role, string $content): ?Response
$response = $this->client->chat($message);

if ($response === false) {
throw new InvalidOpenAiResponseException();
throw new InvalidOpenAiResponseException($message);
}

$response = Response::fromArray(json_decode($response, true));
Expand All @@ -50,6 +53,8 @@ public function ask(string $role, string $content): ?Response
return $response;
}


#[ArrayShape(['model' => "string", 'messages' => "\string[][]"])]
private function generateMessage(string $role, string $content): array
{
return [
Expand All @@ -61,4 +66,4 @@ private function generateMessage(string $role, string $content): array
]
];
}
}
}
7 changes: 5 additions & 2 deletions src/Macopedia/Translator/Client/OpenAiClient/Choice.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Macopedia\Translator\Client\OpenAiClient;

class Choice
Expand All @@ -8,10 +10,11 @@ public function __construct(
private Message $message,
private string $finishReason,
private int $index
) {}
) {
}

public function getMessage(): Message
{
return $this->message;
}
}
}
4 changes: 3 additions & 1 deletion src/Macopedia/Translator/Client/OpenAiClient/Choices.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Macopedia\Translator\Client\OpenAiClient;

use Webmozart\Assert\Assert;
Expand Down Expand Up @@ -30,4 +32,4 @@ public function getAnswers(): array
{
return $this->answers;
}
}
}
7 changes: 5 additions & 2 deletions src/Macopedia/Translator/Client/OpenAiClient/Message.php
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
<?php

declare(strict_types=1);

namespace Macopedia\Translator\Client\OpenAiClient;

class Message
{
public function __construct(
private string $role,
private string $content
) {}
) {
}

public function getContent(): string
{
return $this->content;
}
}
}
10 changes: 6 additions & 4 deletions src/Macopedia/Translator/Client/OpenAiClient/Response.php
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
<?php

declare(strict_types=1);

namespace Macopedia\Translator\Client\OpenAiClient;

use Macopedia\Translator\Client\OpenAiClient\Choices;
use Webmozart\Assert\Assert;
use DateTime;

class Response
{
public function __construct(
private string $id,
private string $object,
private \DateTime $created,
private DateTime $created,
private string $model,
private Choices $choices,
array $usage
) {

}

public static function fromArray(array $data)
Expand All @@ -30,7 +32,7 @@ public static function fromArray(array $data)
return new self(
$data['id'],
$data['object'],
(new \DateTime())->setTimestamp($data['created']),
(new DateTime())->setTimestamp($data['created']),
$data['model'],
new Choices($data['choices']),
$data['usage']
Expand All @@ -54,4 +56,4 @@ public function getFirstChoiceMessage(): ?string
}
return $firstMessage->getMessage()->getContent();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,21 @@
<?php

declare(strict_types=1);

namespace Macopedia\Translator\Connector\Processor\MassEdit;

use Akeneo\Pim\Enrichment\Component\Product\Connector\Processor\MassEdit\AbstractProcessor;
use Akeneo\Pim\Enrichment\Component\Product\EntityWithFamilyVariant\CheckAttributeEditable;
use Akeneo\Pim\Enrichment\Component\Product\Model\ProductInterface;
use Akeneo\Pim\Enrichment\Component\Product\Model\ProductModelInterface;
use Akeneo\Pim\Enrichment\Component\Product\Model\ValueInterface;
use Akeneo\Pim\Structure\Component\Model\AttributeInterface;
use Akeneo\Pim\Structure\Component\Repository\AttributeRepositoryInterface;
use Akeneo\Tool\Component\StorageUtils\Updater\PropertySetterInterface;
use Exception;
use InvalidArgumentException;
use Macopedia\Translator\Translator\Language;
use Macopedia\Translator\Translator\TranslatorInterface;
use Macopedia\Translator\Service\TranslateAttributesService;

final class TranslateAttributesProcessor extends AbstractProcessor
{
public function __construct(
private TranslatorInterface $translator,
private AttributeRepositoryInterface $attributeRepository,
private CheckAttributeEditable $checkAttributeEditable,
private PropertySetterInterface $propertySetter
private TranslateAttributesService $translateAttributesService
) {

}

public function process(mixed $item): ProductInterface|ProductModelInterface
Expand All @@ -45,7 +36,7 @@ public function process(mixed $item): ProductInterface|ProductModelInterface
* 'targetChannel' => 'ecommerce',
* 'sourceLocale' => 'pl_PL',
* 'targetLocale' => 'en_US',
* 'translatedAttributes' => [
* 'attributesToTranslate' => [
* 'name',
* 'description',
* ]
Expand All @@ -54,44 +45,6 @@ public function process(mixed $item): ProductInterface|ProductModelInterface
*/
private function translateAttributes(mixed $product, array $action): ProductInterface|ProductModelInterface
{
$sourceScope = $action['sourceChannel'];
$targetScope = $action['targetChannel'];
$sourceLocaleAkeneo = $action['sourceLocale'];
$targetLocaleAkeneo = $action['targetLocale'];
//$sourceLocale = Language::fromCode(explode('_', $sourceLocaleAkeneo)[0]);
$targetLocale = Language::fromCode(explode('_', $targetLocaleAkeneo)[0]);
$attributeCodes = $action['translatedAttributes'];

foreach ($attributeCodes as $attributeCode) {
/** @var AttributeInterface|null $attribute */
$attribute = $this->attributeRepository->findOneByIdentifier($attributeCode);
if (!$this->checkAttributeEditable->isEditable($product, $attribute)) {
continue;
}

if (!$attribute->isScopable()) {
$sourceScope = null;
$targetScope = null;
}
/** @var ValueInterface|null $attributeValue */
$attributeValue = $product->getValue($attributeCode, $sourceLocaleAkeneo, $sourceScope);
if ($attributeValue === null) {
continue;
}

$sourceText = $attributeValue->getData();

$translatedText = $this->translator->translate(
$sourceText,
$targetLocale
);

$this->propertySetter->setData($product, $attributeCode, $translatedText, [
'locale' => $targetLocaleAkeneo,
'scope' => $targetScope,
]);
}

return $product;
return $this->translateAttributesService->translateAttributes($product, $action);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Macopedia\Translator\DependencyInjection;

use Exception;
Expand All @@ -20,6 +22,7 @@ final class MacopediaTranslatorExtension extends Extension
public function load(array $configs, ContainerBuilder $container): void
{
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('connector.yml');
$loader->load('services.yml');
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
<?php

declare(strict_types=1);

namespace Macopedia\Translator\Exception;

class InvalidOpenAiResponseException extends \Exception
use Exception;

class InvalidOpenAiResponseException extends Exception
{
public function __construct()
public function __construct(array $request)
{
parent::__construct('Response from OpenAi is empty');
parent::__construct(sprintf('Response from OpenAi is empty. Request: %s', json_encode($request)));
}
}
2 changes: 2 additions & 0 deletions src/Macopedia/Translator/MacopediaTranslatorBundle.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Macopedia\Translator;

use Symfony\Component\HttpKernel\Bundle\Bundle;
Expand Down
Loading

0 comments on commit 1d7c9eb

Please sign in to comment.