NuGet – HoNoSoFt https://blog.honosoft.com Blog & Roll Tue, 30 Oct 2018 13:06:54 +0000 en-CA hourly 1 https://wordpress.org/?v=6.8.12 https://blog.honosoft.com/wp-content/uploads/2018/06/logo.png NuGet – HoNoSoFt https://blog.honosoft.com 32 32 Dotnet Core et ses templates CLI, pourquoi s’arrêter à C# ou peut-être pas? https://blog.honosoft.com/2018/10/30/dotnet-core-et-ses-templates-cli-pourquoi-sarreter-a-c-ou-peut-etre-pas/?utm_source=rss&utm_medium=rss&utm_campaign=dotnet-core-et-ses-templates-cli-pourquoi-sarreter-a-c-ou-peut-etre-pas https://blog.honosoft.com/2018/10/30/dotnet-core-et-ses-templates-cli-pourquoi-sarreter-a-c-ou-peut-etre-pas/#respond Tue, 30 Oct 2018 13:06:54 +0000 https://blog.honosoft.com/?p=300 Continue Reading]]> Comme le titre l’indique, pourquoi s’arrêter à un template et pourquoi devrait-on, ou pas, faire que des templates C#?

Afin de répondre à cette question, il faut tout d’abord créer un template ou s’inspirer d’un existant. Notez qu’il est possible de créer des packets contenant plusieurs templates à la fois.

Comment créer un template .Net (core ou pas, c’est pas grave)

Pour débuter, on va faire ça simple. Créons un petit template C# dotnet avec rien de bien intéressant à l’intérieur a part peut être un pre-setting pour un album photo (Connection BD + Script de migration entity framework). Dans cet article, nous n’allons pas bâtir l’application, mais seulement expliquer les principes et le packaging.

Par exemple, vous pouriez faire dotnet new mvcet terminer le reste de votre projet de base (template). Ensuite, il afin de transformer ce projet en template, vous aurez à créer un répertoire spécial nommé .template.config qui se situe dans votre répertoire de projet. Ce fichier respecte doit respecter les standards Microsoft (disponible sur le site MSDN si vous cherchez un peu).

Ici par exemple vous pouriez avoir ce qui suit (Vous pouvez adapter à bon vous semble ;)):

{
  "$schema": "http://json.schemastore.org/template",
  "author": "Nordes Menard-Lamarre",
  "classifications": [ "MVC", "PhotoGallery" ],
  "groupIdentity": "HoNoSoFt.DotNet.Web.Templates.Gallery",
  "identity": "HoNoSoFt.Gallery",
  "name": "Ce qui s'affiche dans la description",
  "preferNameDirectory": true,
  "primaryOutputs": [
    {
      "path": "HoNoSoFt.Gallery.csproj"
    }
  ],
  "shortName": "honosoft-gallery",
  "sourceName": "HoNoSoFt.Gallery",
  "sources": [
    {
      "source": "./",
      "target": "./",
      "exclude": [
        ".template.config/**"
      ],
      "modifiers": [
        {
          "condition": "(TargetFrameworkOverride == '')",
          "exclude": [
            "app.config"
          ]
        },
        {
          "condition": "(ExcludeLaunchSettings)",
          "exclude": [
            "Properties/launchSettings.json"
          ]
        }
      ]
    }
  ],
  "symbols": {
    "ExcludeLaunchSettings": {
      "type": "parameter",
      "datatype": "bool",
      "defaultValue": "false",
      "description": "Whether to exclude launchSettings.json from the generated template."
    },
    "HttpPort": {
      "type": "parameter",
      "datatype": "integer",
      "description": "Port number to use for the HTTP endpoint in launchSettings.json."
    },
    "HttpPortGenerated": {
      "type": "generated",
      "generator": "port"
    },
    "HttpPortReplacer": {
      "type": "generated",
      "generator": "coalesce",
      "parameters": {
        "sourceVariableName": "HttpPort",
        "fallbackVariableName": "HttpPortGenerated"
      },
      "replaces": "8080"
    },
    "HttpsPort": {
      "type": "parameter",
      "datatype": "integer",
      "description": "Port number to use for the HTTPS endpoint in launchSettings.json. This option is only applicable when the parameter no-https is not used (no-https will be ignored if either IndividualAuth or OrganizationalAuth is used)."
    },
    "HttpsPortGenerated": {
      "type": "generated",
      "generator": "port",
      "parameters": {
        "low": 44300,
        "high": 44399
      }
    },
    "HttpsPortReplacer": {
      "type": "generated",
      "generator": "coalesce",
      "parameters": {
        "sourceVariableName": "HttpsPort",
        "fallbackVariableName": "HttpsPortGenerated"
      },
      "replaces": "44300"
    },
    "TargetFrameworkOverride": {
      "type": "parameter",
      "description": "Overrides the target framework",
      "replaces": "TargetFrameworkOverride",
      "datatype": "string",
      "defaultValue": ""
    },
    "Framework": {
      "type": "parameter",
      "description": "The target framework for the project.",
      "datatype": "choice",
      "choices": [
        {
          "choice": "netcoreapp2.1",
          "description": "Target netcoreapp2.1"
        }
      ],
      "replaces": "netcoreapp2.1",
      "defaultValue": "netcoreapp2.1"
    },
    "HostIdentifier": {
      "type": "bind",
      "binding": "HostIdentifier"
    },
    "skipRestore": {
      "type": "parameter",
      "datatype": "bool",
      "description": "If specified, skips the automatic restore of the project on create.",
      "defaultValue": "false"
    },
    "NoHttps": {
      "type": "parameter",
      "datatype": "bool",
      "defaultValue": "false",
      "description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth."
    }
  },
  "tags": {
    "language": "C#",
    "type": "project"
  },


  "precedence": 100,
  "guids": [
      "6B3E8EE8-92E3-41CE-A356-A5F880EEA367"
  ],
  "postActions": [
      {
        "condition": "(!skipRestore)",
        "description": "Restore NuGet packages required by this project.",
        "manualInstructions": [
          {
            "text": "Run 'dotnet restore'"
          }
        ],
        "actionId": "210D431B-A78B-4D2F-B762-4ED3E3EA9025",
        "continueOnError": true
      }
    ]
}

Une fois ce fichier sauvegardé, ce n’est pas terminé. Vous devrez créer votre fichier “nuspec”. C’est possible de le créer à partir de Visual Studio, ou si vous avez la flemme, de le créer aussi manuellement. Dans tous les cas, vous devrez télécharger une version de nuget en ligne de commande.

Exemple de fichier nuspec (Aussi très bien documenté sur le site de MSDN):

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
  <metadata>
    <id>HoNoSoFt.DotNet.Web.Spa.ProjectTemplates</id>
    <authors>Nordes Menard-Lamarre</authors>
    <description>
      La description qui apparaitra sur le site de Nuget.org
    </description>
    <packageTypes>
      <packageType name="Template" />
    </packageTypes>
    <version>{{version}}</version>
    <iconUrl>https://www.honosoft.com/img/logo.png</iconUrl>
    <projectUrl>https://github.com/votre_nom/Votre.ProjectTemplates</projectUrl>
    <licenseUrl>https://github.com/votre_nom/Votre.ProjectTemplates/blob/master/LICENSE</licenseUrl>
  </metadata>
  <files>
    <file
      src="HoNoSoFt.Gallery.CSharp/**/*"
      exclude="**/node_modules/**;**/package-lock.json;**/bin/**;**/obj/**;**/.vs/**;**/.vscode/**;**/wwwroot/**"
      target="Content" />
  </files>
</package>

Ici concernant les fichiers, vous n’être absolument pas obligé d’avoir une configuration fichier par template. Si vous voulez vous simplifier la vie, vous pouvez simplement vous créer un répertoire “Contenu” et y mettre vos projets templates en C#. Ceci-dit, une fois complété, pour créer votre package “nupkg“, vous devrez lancer la ligne de commande avec nuget.

La commande est (à partir de votre répertoire nuspec) : nuget pack. Avant de lancer la commande, n’oubliez pas de mettre à jour votre numéro de {{version}}. Cette version doit être sous le standard Majeur.Mineur.Build.

Afin de tester votre template vous pourrez ensuite l’installer en effectuant: dotnet new -i votre.fichier.nupkg. Et pour voir si c’est bien installé, n’oubliez pas que vous pouvez aussi lister votre projet à l’aide de la commande dotnet new -l. Une fois que vous êtes certain que votre template est présent, vous pouvez créer un répertoire “temporaire” et tester l’initialization de votre template. La commande cette fois sera dotnet new votre-nom-de-templateet les options par défauts seront utilisées (Voir le template.json créer plus tôt).

Et si on veut ajouter d’autres templates en même temps?

Oui, c’est possible. Vous pouvez soit ajouter d’autre répertoire dans la liste des fichiers (balise files qui est dans le nuspec) ou bien si vous avez opté pour un répertoire plus global, comme “Contenu”, vous n’avez qu’à créer d’autres projets avec le répertoire .template.config. Cependant, il y a un point important. Et ce point est que vous devez impérativement avoir un nom différent dans le GroupIdentity du fichier template.json. Sinon, si vous voulez utiliser le même nom, vous devrez combiner avec des options (voir les détails du schéma)

Est-ce possible de créer des template non C# ou Microsoft

Je crois que c’est tout à fait possible et ce sera sans doute ce que je ferai dans l’avenir. J’aime bien travailler avec node pour des PoC et je crois que d’utiliser dotnet new avec les templates va faciliter le fait d’utiliser ou non un backend.

Exemple réel

Récemment, j’ai travailler sur un projet personnel qui crée un Template Dotnet Core 2.1 + VueJS + Picnic CSS + beaucoup d’autres trucs. Ce template est disponible sur https://github.com/nordes/HoNoSoFt.DotNet.Web.Spa.ProjectTemplates et vous pouvez aussi voir comment j’ai intégrer le tout avec AppVeyor pour les build automatisé et le déploiement automatique de l’artifact NuGet sur nuget.org.

Tous les détails afin d’utiliser les templates sont disponible sur le site Github ou bien sur la section Wiki de Github.

Bon coding!

Nordès

]]>
https://blog.honosoft.com/2018/10/30/dotnet-core-et-ses-templates-cli-pourquoi-sarreter-a-c-ou-peut-etre-pas/feed/ 0
Créer un générateur de fichier dans VS2017 en utilisant les VSIX https://blog.honosoft.com/2018/10/18/creer-un-generateur-de-fichier-dans-vs2017-en-utilisant-les-vsix/?utm_source=rss&utm_medium=rss&utm_campaign=creer-un-generateur-de-fichier-dans-vs2017-en-utilisant-les-vsix https://blog.honosoft.com/2018/10/18/creer-un-generateur-de-fichier-dans-vs2017-en-utilisant-les-vsix/#comments Thu, 18 Oct 2018 17:07:29 +0000 https://blog.honosoft.com/?p=274 Continue Reading]]> Cet article a pour but de vous aider à créer votre propre génerateur de fichier.

Qu’est-ce que c’est au juste un générateur de fichier?

Parfois dans nos projets, nous avons des fichiers sur lesquels nous devons pré-processer pour avoir un fichier intermédiaire. On peut utiliser un external tool ou utiliser un “Post Build Process” mais ce n’est pas aussi bien intégré. Un bon exemple sont les fichiers “.resx”; ce sont des fichiers de ressources en XML qui une fois générée nous donne comme output un fichier “.Designer.cs”. Et à chaque fois que vous faites une modification, le fichier est généré de nouveau.

Si vous utilisez le clique droit et que vous faites “properties” sur le fichier “resx” en question, vous verrez dans la section “Advanced” le “Custom Tool suivant: “ResXFileCodeGenerator”. C’est cette commande qui est lancé à chaque fois que Visual Studio détecte un changement à votre fichier “.resx”.

Donc la question qui m’a poussé à écrire cet article est: “Comment fait-on pour s’en faire un personnalisé?”

Création d’un générateur pour minifier du Javascript

Cet article suivra les étapes pour créer un “custom tool” pour minifier du javascript. Cet example utilisera aussi une librairie externe en utilisant NuGet. Comme c’est un cas qui arrive souvent, je pense que c’est important de l’inclure dans cet article. Qui plus est, ce n’est pas trivial.

Création d’un projet VSIX

Tout d’abord, je ne connaissais pas ce genre de type de projet avant de commencer à m’intéresser à faire une extension. Auparavant, j’utilisais soit Wix ou l’installeur qui venait avec Visual Studio pour les faire. C’était fastidieux. Donc après avoir lu sur les VSIX, je suis suis dit: pourquoi pas l’essayer.

Dans la documentation de Microsoft, quand on lit, ça semble très simple: vous avez juste à implémenter l’interface IVsSingleFileGenerator. Après avoir cherché un peu sur comment procéder sur l’internet, j’ai découvert qu’on peut utiliser les VSIX. Donc, voici sans plus attendre comment créer votre premier projet.

Requis: Visual Studio SDK

Avant de commencer, soyez sûr que vous avez d’installé le Visual Studio SDK. C’est ce qui va vous permettre de débugger et d’avoir accès au type de projet d’extension VSIX. Pour l’ajouter, vous devrez partir l’installateur de Visual Studio (Visual Studio Installer) et aller ajouter la section SDK

Étapes:

  1. Ouvez Visual Studio 2017
  2. Faites Un nouveau projet de type “VSIX Project”. Ça se retrouve dans la section “Extensibility”. Pour l’exemple, appelons le “MinifyJs“.
  3. Une fois le projet créé, ajoutez un package d’extensibilité au projet: Add -> New Item -> Extensibility -> Visual Studio Async Package. Appelons-le aussi “MinifyJs“.

Une fois ces étapes terminées, vous verrez qu’il y a quelques fichiers qui ont été ajouté. Le fichier qui nous intéresse pour l’instant est “MinifyJs.cs“. Concentrons-nous sur ça et nous reviendrons sur le ménage un peu plus tard.

Implémentation de l’interface IVsSingleFileGenerator

Dans le fichier “MinifyJs.cs“, vous verrez que la classe dérive de la class “AsyncPackage“. Donc voici les étapes à faire pour corriger la situation:

  1. Effacez-tout ce qu’il y a dans la classe à l’exception peut-être de la constante “PackageGuidString“.
  2. Remplacez l’implémentation de l’interface “AsyncPackage” par celle qui nous intéresse: “IVsSingleFileGenerator“.
  3. Ajustez les attributs de la classe (voir dans l’exemple de code ci-bas)
    • Si vous vous demandez d’où vient le GUID dans l’attribut CodeGeneratorRegistration, ça vient de la doc ici.
    • N’oubliez pas d’ajouter les attributs “ComVisible” et le “ProvideObject”.
  4. Ajoutez les 2 méthodes à implémenter.
    • “DefaultExtension” -> Mettez l’extension désiré lors de la conversion du fichier: mettons “.min.js“
    • “Generate” -> C’est ici que vous allez faire votre processing. Pour maintenant, on va retourner “Hello World!”
using System;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;

namespace MinifyJs
{
    [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]
    [InstalledProductRegistration(nameof(MinifyJs), "Minify a javascript file", "1.0")]
    [Guid(PackageGuidString)]
    [ComVisible(true)]
    [ProvideObject(typeof(MinifyJs))]
    [CodeGeneratorRegistration(typeof(MinifyJs), nameof(MinifyJs), "{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}", GeneratesDesignTimeSource = true)]
    public sealed class MinifyJs : IVsSingleFileGenerator
    {
        public const string PackageGuidString = "42c44934-b969-4adf-a5d6-f294b05cf00f";

        public int DefaultExtension(out string pbstrDefaultExtension)
        {
            pbstrDefaultExtension = ".min.js";
            return VSConstants.S_OK;
        }

        public int Generate(string wszInputFilePath, string bstrInputFileContents, string wszDefaultNamespace,
            IntPtr[] rgbOutputFileContents, out uint pcbOutput, IVsGeneratorProgress pGenerateProgress)
        {
            try
            {
                var bytes = Encoding.UTF8.GetBytes("Hello World!");
                var length = bytes.Length;
                rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(length);
                Marshal.Copy(bytes, 0, rgbOutputFileContents[0], length);
                pcbOutput = (uint)length;
            }
            catch (Exception ex)
            {
                ThreadHelper.ThrowIfNotOnUIThread();
                pGenerateProgress.GeneratorError(0, 0, ex.Message, 0, 0);
                pcbOutput = 0;
            }

            return VSConstants.S_OK;
        }
    }
}

à Partir de ça, vous devriez avoir votre premier VSIX de complété et vous pouvez l’essayer!

Tester et Débugger un VSIX

Ce qui est cool avec ce type de projet est la facilité à tester et débugger. Mais avant d’aller plus loin, nous devons faire une modification au fichier de config pour être sûr de bien supporter toutes les versions de Visual Studio:

  1. Ouvrez “source.extension.vsixmanifest“
  2. Cliquez sur “Install Targets“. Vous verrez qu’il y a probablement une seule target “Microsof.VisualStudio.Community“.
  3. Ajoutons les autres distributions de visual studio en faisant “New” (voir image plus bas)
  4. Faites F5 (Run and Debug) et ça va lancer votre Visual Studio Expérimental
  5. Vous allez devoir vous créer un nouveau projet (type console fera l’affaire).
  6. Dans ce projet, créez un fichier “Test.js” et ajouter quelques lignes de code javascript.
  7. Dans le “Solution Explorer“, allez chercher les propriétés du Fichier “Test.cs“
  8. Mettez dans la propriété “custom tool” le nom que vous avez enregistré dans l’attribut “CodeGeneratorRegistration“; dans notre cas “MinifyJs” (voir image plus bas)
  9. Après avoir terminé l’édition, vous devriez voir le fichier généré avec le texte “Hello World!” dedans.
  10. Vous pouvez maintenant fermer le VS Expérimental.

 
Normalement, ce tutorial pourrait s’arrêté ici, mais allors un peu plus loin.

Intégration d’un package NuGet dans un VSIX

L’ajout d’un package NuGet se fait comme d’habitude. Le problème est plutôt quand on arrive au déploiement.

Donc, pour notre exemple, nous allons intégrer la librairie de Yahoo pour compresser notre code Javascript.

  1. Premièrement, ouvrez le dialogue de NuGet: “Tools -> Nuget Package Manager -> Manage NuGet packages for Solution…“
  2. Cliquez sur l’onglet “Browse“
  3. Tapez “YUICompressor.NET” et installez le dans votre projet

Et voilà, vous avez maintenant les dépendances dans votre projet. Maintenant, allons coder la fonction “Generate” avec le vrai code:

var compressor = new JavaScriptCompressor
{
    DisableOptimizations = false,
    ObfuscateJavascript = true
};

var compressedFile = compressor.Compress(bstrInputFileContents);
var bytes = Encoding.UTF8.GetBytes(compressedFile);

Si vous essayez de partir le projet, ça ne fonctionnera pas. Les dépendances ne seront pas “bundler” avec. Il y a 2 méthodes que je connais pour y arriver.

Assets

La première est la plus simple, mais n’est pas recommandé dans ce cas. On clique sur le fichier “source.extension.vsixmanifest“, on va dans “Assets” et on ajoute les dll manuellement.

Le problème majeur est que Visual Studio va copier les fichiers en local dans le projet… et que si vous faites des updates des NuGet packages, vous allez devoir recopier à la main ces dll à chaque fois. Sinon l’application déployée ne fonctionnera pas, dû aux link et aux binaires qui ne correspondront pas.

Ajout d’Attribut dans le projet

Selon moi c’est la meilleure méthode que j’ai trouvé. Donc, voici les étapes:

  1. Cliquez droit sur le projet dans le “Solution Explorer” et cliquez sur”Unload Project“.
  2. Cliquez droit encore sur le projet et faite “Edit“
  3. Chechez les 2 références “EcmaScript.NET” et “Yahoo.Yui.Compressor“, qui ont été ajouté par NuGet.
  4. Ajoutez “<ForceIncludeInVSIX>True</ForceIncludeInVSIX>” comme propriété.
  5. Cliquez droit encore sur le projet et faire Reload après avoir sauvegardé.
<Reference Include="EcmaScript.NET, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\packages\EcmaScript.NET.2.0.0\lib\net45\EcmaScript.NET.dll</HintPath>
      <ForceIncludeInVSIX>True</ForceIncludeInVSIX>
</Reference>
<Reference Include="Yahoo.Yui.Compressor, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\packages\YUICompressor.NET.3.0.0\lib\net452\Yahoo.Yui.Compressor.dll</HintPath>
      <ForceIncludeInVSIX>True</ForceIncludeInVSIX>
</Reference>

Référence: http://comealive.io/Forcing-DLLs-To-Vsix/

Dans le meilleur des mondes, vous auriez juste à faire F5 et tout fonctionnerait parfaitement. Mais non! Cette erreur m’a prise plusieurs heures pour bien comprendre et la régler:

Je n’irai pas dans les détails, mais le problème vient du fait qu’on signe notre “package” et que les dll du NuGet ne le sont pas. Donc, 2 options s’ouvrent à nous: signer manuellement les dll externes ou bien simplement désactiver notre signature.

Ce n’est pas très réaliste de vouloir signer les dll externes, alors nous allons simplement désactiver la signature dans les propriétés de notre projet. Voici un screenshot pour vous aider.

Donc, si vous lancez votre application, vous allez pouvoir faire fonctionner votre minimifieur Javascript.

Installation

Une fois que vous êtes satisfait de votre extension, faite une version release (ou debug) et partagez votre VSIX. Les développeurs auront juste à double cliquer dessus.

Dans les settings du package j’ai vu qu’on pouvait générer un installeur windows, donc j’imagine qu’on peut le distribuer de cette méthode aussi mais je n’ai pas essayé.

Ménage

Avec tout ça, il y a quelques fichiers que nous n’avons plus vraiment de besoin.

  • Index.html – C’est juste de la documentation générique. Je préfère les README.md
  • stylesheet.css – C’est le fichier de style avec l’index.
  • Key.snk – on a désactivé la signature, donc on n’en a plus vraiment de besoin

Trucs et Astuces

  • Une fois que le “Custom Tool” est assigné, vous pouvez manuellement à tout moment lancer la génération via le “custom tool” en cliquant droit sur le fichier et choisissant “Run custom tool“.
  • Dans la fonction “Generate“, il y a un paramètre “IVsGeneratorProgress pGenerateProgress“. Vous pouvez vous en servir pour écrire des messages d’erreurs mais aussi de spécifier le progrès si jamais votre processus est très long.
  • Pour voir si votre extension est installée (dans l’expérimental ou non), juste aller dans: “Tool -> Extensions and Updates“. Vous pouvez la désinstaller de là aussi.
  • Dans la version Expérimentale, les fichiers sont copié à cet endroit: “%USERPROFILE%\AppData\Local\Microsoft\VisualStudio\15.0_<xxx>Exp\Extensions\<USERNAME>\MinifyJs“. Ça peut être pratique pour voir exactement ce qui est copié si jamais vous avez des problèmes de dépendances.

 

]]>
https://blog.honosoft.com/2018/10/18/creer-un-generateur-de-fichier-dans-vs2017-en-utilisant-les-vsix/feed/ 1
Microsoft Cognitive Services Translator V3 – Exploration des APIs – Translate (Part I) https://blog.honosoft.com/2018/06/29/microsoft-cognitive-services-translator-v3-exploration-des-apis-translate-part-i/?utm_source=rss&utm_medium=rss&utm_campaign=microsoft-cognitive-services-translator-v3-exploration-des-apis-translate-part-i https://blog.honosoft.com/2018/06/29/microsoft-cognitive-services-translator-v3-exploration-des-apis-translate-part-i/#respond Fri, 29 Jun 2018 12:47:24 +0000 https://blog.honosoft.com/?p=97 Continue Reading]]> Introduction

Dans cette série, nous allons approcher les APIs proposé par Microsoft Cognitive Services – Translator.

Ces APIs sont plutôt pratique si vous avez a jouer avec des langues différentes à analyser en même temps, car elles permettent de pouvoir faire des actions que les autres APIs concurrente ne permettent pas (Ex.: Google, ou autres). Pour clarifier, je ne travaille pas exclusivement avec les produits Microsoft et je n’ai pas aucun parti pris. C’est seulement qu’après une étude au niveau des coûts et des services offert. J’ai trouvé que celle de Microsoft était plus ouverte sur le format de configuration. On peut envoyer environ n’importe quoi et recevoir la traduction adéquate avec certains extras.

Le coût: 2,000,000 de caractères pour la modique somme de 0$. Pour plus d’informations, si vous voulez traiter plus de caractères, veuillez visiter le site officiel avec les prix du jour. À priori, au moment de l’écriture de cet article, le prix est d’environs 12$ par million de caractères supplémentaire.

Pré-requis

Les pré-requis, sont comme vous pouvez vous l’imaginer, les suivants:

  • Souscription à Azure (Obligatoire, mais c’est gratuit!)
  • .Net Core 2.1 (Pour cet article), mais a priori n’importe quoi fonctionnera
  • Visual Studio normal/code peuvent être utilisé

Notez que les APIs sont accessible pour tous les languages et non seulement C#/.Net. Par vous donner une idée, tous les exemples sont faites à l’aide CURL.  Si l’on regarde le menu à gauche sur le site, vous trouverez toutes les références pour faire les appels API avec NodeJS, Ruby, etc..

API Translator/Translate (V3)

Commençons par les APIs de Translator Translate V3. La V2 fournissait d’autres API, mais ici nous allons nous attarder sur la V3.

Translator, pour ceux qui ne le savent pas encore, est le service de traduction de Microsoft (Bing translate? où si vous voulez tester, l’application Windows Store “Translator”). Cette API comporte plusieurs parties, dont:

  • Languages: Vous offre la liste à jour des langages possible de traduire. C’est-à-dire, si je veux traduire l’anglais, quels sont les langues possible dans lesquels je peux traduire. Cet API permet de donner les possibilités de traduction pour toutes les autres API qui suivent. Donc, si vous faite un appel à cette API, vous pouvez garder en cache un bon moment, car ça ne changera pas souvent. Tout récemment Microsoft à ajouter de nouvelles langues.
  • Translate: L’API le plus intéressant, à mon avis. Traduit le texte d’une langue donnée dans une autre langue. Le type de langue d’input n’est pas nécessaire, mais aide probablement à la rapidité et à l’exactitude du texte donnée. C’est sur ce point que nous allons nous attarder dans cet article.
  • Transliterate: Très utile pour les langues tel que le Japonais. Cette API vous permet d’avoir une translittération du texte ainsi que son script (Latin, Japonais, …). Par exemple こんいちわ devient konnichiwa. Ça permet de faire des analyses plus simple dans un sens. Car dans certaines langues les espaces ne sont pas nécessaire et ça crée certains soucis lorsque l’ont veut filtrer ou autre.
  • Detect: Identifie la langue utilisé dans le texte. Cet API, par exemple, peut être très utile si vous effectuer un chatbot et que la première intérraction vous ne trouvez pas de réponse à la question. Dans ce cas, vous vous assurez que la langue utilisé pour l’analyse était bien la bonne et si ce n’est pas le cas, renvoyer la question dans la bonne langue a votre analyseur et ensuite mettre à jour la session utilisateur afin de l’accomoder. Ceci n’est qu’une idée de ce que l’on pourrait faire avec cet API.
  • BreakSentence: Comme son nom l’indique, cette API brisera vos phrases en morceaux. En fait, vous n’aurez pas les phrases renvoyé par l’API, mais seulement les longueurs de phrases et si demandé lors de la requête la langue ainsi que le score entre 0 et 1 (voir le site MSDN). Ce sera à vous de vous accomoder par la suite. À priori, je n’y vois aucuns problème, tout spécialement avec les nouveaux span en C#.
  • Dictionary Lookup: Cet API vous donnera des alternative à ce qui a été traduit. Ceci peut être utile, si vous voulez que votre utilisateur corrige sa phrase avec des suggestions. Cet API vous donnera aussi le tagging des mots (Verbe, Adverbe, etc.). Sur ce point, je vous conseille fortement d’aller voir l’article MSDN où un exemple complet s’y trouve.
  • Dictionary Example: Dans le même ordre d’idée que le point précédent. Vraiment spécialisé pour des cas très précis. À priori, je ne crois pas que vous utiliserez à l’exception de cas très spéciaux.

La section translate

Nous trouvons tous les paramètres possible pour les appels sur les APIs et leurs limites Commençons par discuter des limites:

  • On peut transmettre 25 sections de document à traduire à la fois;
  • Chaque section peut contenir au maximum 5,000 caractères;
  • Accepte le HTML et le texte. Concernant la limite de caractères, je ne sais pas si le HTML en lui même est compté.
  • Certaines langues ne se traduisent pas directement dans d’autres (et là ça dépend, mais pour anglais-français, aucuns problème);

Ces limites semble petite ou grande, dépendant de ce que vous voulez traduire. Personellement, je vous conseille d’optimiser vos appels pour faire le moins d’appels possible au service. D’après des commentaires vu par le passé, il y aurait aussi une limite sur le nombre d’appel répétés dans un cours délais. Du coup, si vous prévoyer traduire une page de texte, je vous recommenderais d’éviter de traduire:

  • Des phrases en doublons;
  • De petites phrases seules; Le mieux est de joindre plusieurs parties de phrases ensemble;

À priori, je vous dirais de:

  • Créer une cache (Mémoire, Redis, autre) pour éviter de retraduire ce qui est déjà traduit.
  • Utiliser le positionnement des mots si vous désirez éventuellement faire du machine learning et de traduire à un certain moment avec vos propre algorithmes.
  • Joindre les phrases dans une même section;
  • Tenter d’arriver le plus près de toutes les limites afin de faire le plus petit nombre de requête sur les serveurs de Microsoft Cognitive Service.

Let’s go! Coding time! ☆ou presque

Avant de commencer à coder, si vous n’avez pas encore créer dans votre portail Azure un service Cognitive, veuillez procéder.

  1. Créer une nouvelle resource et sélectionner “Cognitive Services”
  2. Remplir tous les points et ça devrait être ok.
  3. Et voilà, vous avez obtenus vos clées (Primaire et secondaire).

Ces clées peuvent fonctionner par rotation et vous pouvez mettre à jour la clée précédente pour obtenir une nouvelle clée. Ce système vous permettra d’être sécure et d’éviter que les gens qui auraient eu connaissance d’une de vos clés utilise votre compte “Cognitive”.

Créons notre projet

Visual Studio 2017 (Dernière update si possible avec Core 2.1):

  1. Fichier
  2. Nouveau projet
  3. Asp .Net Core Web Application
    • Donnez un nom et choisissez votre emplacement favoris (ex.: c:\temp\MyProject
  4. MVC/Web Application (Pour cette demo)
  5. Mettre les packages NuGet à jour (Click droit sur la solution et ensuite gérer les packets pour la solution)
  6. Ajouter un nouveau package CognitiveServices.Translator.Client

Ce package vous évite de faire tous les appels à la mitaine. Grosso modo c’est un Proxy.

  1. Compiler
  2. Executez l’application histoire de valider que ça démarre avant de faire les changements.

Configuration de Cognitive Services (Avec NuGet)

Dans votre fichier AppSettings.json ou AppSettings.Development.json, ajouter la section suivante:

{
  // Some logging stuff
  // New things
  "CognitiveServices": {
    "Name": "Doc_Transl_demo (This is for personal reference only)",
    "SubscriptionKey": "[Insert Key here]"
  }
}

Cette configuration sera automatiquement utilisée par la librairie importée au point précédent.

Injection des dépendences (Dependency Injection ou encore DI)

Comme vous vous l’imaginiez, il faudra aussi injecter les dépendances du packet importé. Dans votre fichier Startup.cs, ajoutez ce qui suit:

// startup.cs
public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
    // some code here...
    // ...

    // Add the cognitive service (in case you want to use DI using the appsettings.json)
    services.AddCognitiveServicesTranslator(Configuration);
}

Ceci vous permettra de recevoir une injection avec l’interface ITranslateClient. Cette interface est injecté pour le “Scope” courant. Donc pour la durée de la requête, ce sera le même objet qui sera utilisé. Si jamais ça pose problème, merci d’ouvrir un bug dans Github.

Exemple d’injection dans un contrôleur (TranslateController.cs):

[Route("api/[controller]")]
public class TranslateController : Controller
{
    private readonly ITranslateClient _translateClient;

    public TranslateController(ITranslateClient translateClient)
    {
        _translateClient = translateClient;
    }

    [HttpPut("withDI")]
    public async Task&lt;IList&lt;ResponseBody&gt;&gt; WithDependencyInjection([FromBody] TranslateRequest translate)
    {
        return await _translateClient.TranslateAsync(translate.RequestContents, translate.Options);
    }

    [HttpPut()]
    public async Task&lt;IList&lt;ResponseBody&gt;&gt; Index([FromBody] TranslateRequest translate)
    {
        // Créer un appel avec une configuration custom à chaque appel.
        var translateClient = new TranslateClient(translate.CognitiveServicesConfig);

        return await translateClient.TranslateAsync(translate.RequestContents, translate.Options);
    }
}

Utilisation de l’API

Maintenant qu’on est capable de faire le minimum. C’est le temps de faire un appel complet à l’API en utilisant certaines options. En fait pour ça je vous dirais de jouer avec l’exemple fourni avec la librairie. Vous y trouverez toutes les options. L’exemple live est disponible à partir d’un site Azure en mode demo (Todo, je dois republier avec le nouveau code).

Important: Je vous assure qu’aucunes capture des clés d’APIs est fait sur le site demo.

Result 1-1

Result 1-2

Point intéressant de l’API

  • Possibilité de connaître la position de ce qui est traduit par rapport à l’original. C’est-à-dire que vous pouvez comprendre comment la traduction s’est effectuée.
  • Performances
  • Qualité
  • Langues disponibles (dont le Japonais)
  • Possibilité de retirer les “méchant” mots du vocabulaire et de les remplacer par des ***
  • Peut traduire le texte qui contient du HTML

Utilisation de l’API sans NuGet

Dans ce cas, vous aurez à appeler les API manuellement. Le packet Nuget vous permet tout simplement d’éviter à avoir a ré-écrire les classes de bases et marche comme un véritable proxy. Dans la documentation Microsoft, les exemples sont fournis avec CURL, mais le transfert vers C# est simple.

]]>
https://blog.honosoft.com/2018/06/29/microsoft-cognitive-services-translator-v3-exploration-des-apis-translate-part-i/feed/ 0