Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creating SDT client with endpoint only and making source input options public #44862

Merged
merged 7 commits into from
Jul 6, 2024
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# Release History

## 2.0.0-beta.2 (Unreleased)
## 2.0.0-beta.2 (2024-07-05)

### Features Added
- Single document translation client can be created using endpoint alone, mainly for SDK to work against containers.

### Breaking Changes

### Bugs Fixed
- SourceInput options which is a part of TranslationInput is now public. This allows users to enter source language, source storage, and document filter prefix and suffix.

### Other Changes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "net",
"TagPrefix": "net/translation/Azure.AI.Translation.Document",
"Tag": "net/translation/Azure.AI.Translation.Document_d9bcf85e69"
"Tag": "net/translation/Azure.AI.Translation.Document_7271233df3"
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,30 @@ public DocumentTranslationInput(Uri sourceUri, Uri targetUri, string targetLangu
Targets = new List<TranslationTarget> { target };
}

/// <summary>
/// Initializes a new instance of <see cref="DocumentTranslationInput"/>.
/// </summary>
/// <param name="translationSource">The TranslationSource object containing source document info to be translated.
/// See the service documentation for the supported SAS permissions for accessing
/// source storage containers/blobs: <a href="https://aka.ms/azsdk/documenttranslation/sas-permissions"/>.</param>
/// <param name="targetUri">The SAS URI for the target container to which the translated documents will be written.
/// See the service documentation for the supported SAS permissions for accessing
/// target storage containers/blobs: <a href="https://aka.ms/azsdk/documenttranslation/sas-permissions"/>.</param>
/// <param name="targetLanguageCode">Language code to translate documents to. For supported languages see
/// <a href="https://docs.microsoft.com/azure/cognitive-services/translator/language-support#translate"/>.</param>
/// <param name="glossary">Custom <see cref="TranslationGlossary"/> to be used in the translation operation. For supported file types see
/// <see cref="DocumentTranslationClient.GetSupportedFormatsAsync(FileFormatType?, System.Threading.CancellationToken)"/>.</param>
public DocumentTranslationInput(TranslationSource translationSource, Uri targetUri, string targetLanguageCode, TranslationGlossary glossary = default)
{
Source = translationSource;
var target = new TranslationTarget(targetUri, targetLanguageCode);
if (glossary != null)
{
target.Glossaries.Add(glossary);
}
Targets = new List<TranslationTarget> { target };
}

/// <summary>
/// Add a <see cref="TranslationTarget"/> to the translation input.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

// <auto-generated/>

#nullable disable

using System;
using System.Threading;
using System.Threading.Tasks;
using Azure.Core;
using Azure.Core.Pipeline;

namespace Azure.AI.Translation.Document
{
// Data plane generated client.
/// <summary> The SingleDocumentTranslation service client. </summary>
public partial class SingleDocumentTranslationClient
{
/// <summary> Initializes a new instance of SingleDocumentTranslationClient. </summary>
/// <param name="endpoint">
/// Supported document Translation endpoint, protocol and hostname, for example:
/// https://{TranslatorResourceName}-doctranslation.cognitiveservices.azure.com
/// </param>
/// <exception cref="ArgumentNullException"> <paramref name="endpoint"/> is null. </exception>
public SingleDocumentTranslationClient(Uri endpoint) : this(endpoint, new DocumentTranslationClientOptions())
{
}

/// <summary> Initializes a new instance of SingleDocumentTranslationClient. </summary>
/// <param name="endpoint">
/// Supported document Translation endpoint, protocol and hostname, for example:
/// https://{TranslatorResourceName}-doctranslation.cognitiveservices.azure.com
/// </param>
/// <param name="options"> The options for configuring the client. </param>
/// <exception cref="ArgumentNullException"> <paramref name="endpoint"/> is null. </exception>
public SingleDocumentTranslationClient(Uri endpoint, DocumentTranslationClientOptions options)
{
Argument.AssertNotNull(endpoint, nameof(endpoint));
options ??= new DocumentTranslationClientOptions();

ClientDiagnostics = new ClientDiagnostics(options, true);
_pipeline = HttpPipelineBuilder.Build(options, Array.Empty<HttpPipelinePolicy>(), Array.Empty<HttpPipelinePolicy>(), new ResponseClassifier());
_endpoint = endpoint;
_apiVersion = options.Version;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using Azure.Core;

namespace Azure.AI.Translation.Document
Expand Down Expand Up @@ -63,5 +64,35 @@ public string Suffix
/// </summary>
[CodeGenMember("Filter")]
internal DocumentFilter Filter { get; set; }

/// <summary> Initializes a new instance of <see cref="TranslationSource"/>. </summary>
/// <param name="sourceUri"> Location of the folder / container or single file with your documents. </param>
/// <param name="languageCode">
/// Language code
/// If none is specified, we will perform auto detect on the document
/// </param>
/// <param name="storageSource"> Storage Source. </param>
/// <param name="prefix"> Document prefix filter. </param>
/// <param name="suffix"> Document suffix filter. </param>
public TranslationSource(Uri sourceUri, string languageCode = default, string storageSource = default, string prefix = default, string suffix = default)
{
SourceUri = sourceUri;
if (languageCode != null)
{
LanguageCode = languageCode;
}
if (storageSource != null)
{
StorageSource = storageSource;
}
if (prefix != null)
{
Prefix = prefix;
}
if (suffix != null)
{
Suffix = suffix;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Azure.Core.TestFramework;
using NUnit.Framework;

namespace Azure.AI.Translation.Document.Tests
{
public partial class ContainerDocumentTranslationClientTests : DocumentTranslationLiveTestBase
{
/// <summary>
/// Initializes a new instance of the <see cref="ContainerDocumentTranslationClientTests"/> class.
/// </summary>
/// <param name="isAsync">A flag used by the Azure Core Test Framework to differentiate between tests for asynchronous and synchronous methods.</param>
public ContainerDocumentTranslationClientTests(bool isAsync)
: base(isAsync)
{
}

// Before running this test make sure you have docker application running and then run the Translator container
[Test]
[Ignore("Container Test only")]
public async Task StartSynchronousDocumentTranslation()
{
//Once the container is running, note the endpoint it is listening on and update accordingly
var endpoint = new Uri("http://localhost:5000");

SingleDocumentTranslationClient client = new SingleDocumentTranslationClient(endpoint);

string filePath = Path.Combine("TestData", "test-input.txt");
using Stream fileStream = File.OpenRead(filePath);

var sourceDocument = new MultipartFormFileData(Path.GetFileName(filePath), fileStream, "text/html");
DocumentTranslateContent content = new DocumentTranslateContent(sourceDocument);

//make sure this language model "hi" is downloaded
var response = await client.DocumentTranslateAsync("hi", content, "en").ConfigureAwait(false);
var requestString = File.ReadAllText(filePath);
var responseString = Encoding.UTF8.GetString(response.Value.ToArray());
Assert.IsNotEmpty(responseString);
Assert.IsNotNull(responseString);
Assert.AreNotEqual(requestString, responseString);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Azure.Core.TestFramework;
using NUnit.Framework;
Expand All @@ -21,6 +22,50 @@ public DocumentTranslationClientLiveTests(bool isAsync)
{
}

[RecordedTest]
[TestCase(true)]
[TestCase(false)]
public async Task GetTranslationStatusesTestWithSourceInputOptions(bool usetokenCredential)
{
Uri sourceUri = await CreateSourceContainerAsync(oneTestDocuments);
Uri targetUri = await CreateTargetContainerAsync();

DocumentTranslationClient client = GetClient(useTokenCredential: usetokenCredential);

TranslationSource translationSource = new TranslationSource(sourceUri, "en");
var input = new DocumentTranslationInput(translationSource, targetUri, "fr");
var translationOp = await client.StartTranslationAsync(input);
await translationOp.WaitForCompletionAsync();

// list translations with ID filter
var options = new GetTranslationStatusesOptions
{
Ids = { translationOp.Id }
};
var translations = await client.GetTranslationStatusesAsync(options: options).ToEnumerableAsync();

// assert
Assert.GreaterOrEqual(translations.Count, 1);
TranslationStatusResult oneTranslation = translations[0];
Assert.AreNotEqual(new DateTimeOffset(), oneTranslation.CreatedOn);
Assert.AreNotEqual(new DateTimeOffset(), oneTranslation.LastModified);
Assert.GreaterOrEqual(oneTranslation.DocumentsCanceled, 0);
Assert.GreaterOrEqual(oneTranslation.DocumentsFailed, 0);
Assert.GreaterOrEqual(oneTranslation.DocumentsInProgress, 0);
Assert.GreaterOrEqual(oneTranslation.DocumentsNotStarted, 0);
Assert.GreaterOrEqual(oneTranslation.DocumentsSucceeded, 0);
Assert.GreaterOrEqual(oneTranslation.DocumentsTotal, 0);

if (oneTranslation.Status == DocumentTranslationStatus.Succeeded)
{
Assert.Greater(oneTranslation.TotalCharactersCharged, 0);
}
else
{
Assert.AreEqual(0, oneTranslation.TotalCharactersCharged);
}
}

[RecordedTest]
public void ClientCannotAuthenticateWithFakeApiKey()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Text;
using System.Threading.Tasks;
using Azure.Core.TestFramework;
using Azure.Identity;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Sas;
Expand Down Expand Up @@ -79,68 +80,62 @@ public DocumentTranslationClient GetClient(

public BlobContainerClient GetBlobContainerClient(string containerName)
{
return InstrumentClient(new BlobContainerClient(
TestEnvironment.StorageConnectionString,
containerName,
InstrumentClientOptions(new BlobClientOptions(BlobClientOptions.ServiceVersion.V2020_04_08))));
string accountUrl = String.Format("https://{0}.blob.core.windows.net/", TestEnvironment.StorageAccountName);
BlobServiceClient blobServiceClient = new BlobServiceClient(
new Uri(accountUrl),
new DefaultAzureCredential(),
InstrumentClientOptions(new BlobClientOptions(BlobClientOptions.ServiceVersion.V2020_04_08)));
BlobContainerClient blobContainerClient = blobServiceClient.CreateBlobContainer(containerName, PublicAccessType.None);
return InstrumentClient(blobContainerClient);
}

public Uri CreateSourceContainer(List<TestDocument> documents)
{
var containerClient = CreateContainer("source", documents);
var expiresOn = DateTimeOffset.UtcNow.AddHours(1);
return containerClient.GenerateSasUri(BlobContainerSasPermissions.List | BlobContainerSasPermissions.Read, expiresOn);
return containerClient.Uri;
}

public async Task<Uri> CreateSourceContainerAsync(List<TestDocument> documents)
{
var containerClient = await CreateContainerAsync("source", documents);
var expiresOn = DateTimeOffset.UtcNow.AddHours(1);
return containerClient.GenerateSasUri(BlobContainerSasPermissions.List | BlobContainerSasPermissions.Read, expiresOn);
return containerClient.Uri;
}

public Uri CreateTargetContainer(List<TestDocument> documents = default)
{
var containerClient = CreateContainer("target", documents);
var expiresOn = DateTimeOffset.UtcNow.AddHours(1);
return containerClient.GenerateSasUri(BlobContainerSasPermissions.List | BlobContainerSasPermissions.Write, expiresOn);
return containerClient.Uri;
}

public async Task<Uri> CreateTargetContainerAsync(List<TestDocument> documents = default)
{
var containerClient = await CreateContainerAsync("target", documents);
var expiresOn = DateTimeOffset.UtcNow.AddHours(1);
return containerClient.GenerateSasUri(BlobContainerSasPermissions.List | BlobContainerSasPermissions.Write, expiresOn);
return containerClient.Uri;
}
public async Task<Uri> CreateGlossaryAsync(TestDocument document = default)
{
var containerClient = await CreateContainerAsync("glossary", new List<TestDocument> { document });
var expiresOn = DateTimeOffset.UtcNow.AddHours(1);
var glossaryContainerSasUri = containerClient.GenerateSasUri(BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List, expiresOn);
return new Uri(String.Format("{0}{1}{2}{3}/{4}{5}", glossaryContainerSasUri.Scheme, Uri.SchemeDelimiter, glossaryContainerSasUri.Authority, glossaryContainerSasUri.AbsolutePath, document.Name, glossaryContainerSasUri.Query));
var containerUri = containerClient.Uri;
return new Uri(String.Format("{0}/{1}", containerUri, document.Name));
}

public Uri CreateGlossary(TestDocument document = default)
{
var containerClient = CreateContainer("glossary", new List<TestDocument> { document });
var expiresOn = DateTimeOffset.UtcNow.AddHours(1);
var glossaryContainerSasUri = containerClient.GenerateSasUri(BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List, expiresOn);
return new Uri(String.Format("{0}{1}{2}{3}/{4}{5}", glossaryContainerSasUri.Scheme, Uri.SchemeDelimiter, glossaryContainerSasUri.Authority, glossaryContainerSasUri.AbsolutePath, document.Name, glossaryContainerSasUri.Query));
var containerUri = containerClient.Uri;
return new Uri(String.Format("{0}/{1}", containerUri, document.Name));
}

public async Task<Tuple<Uri, BlobContainerClient>> CreateTargetContainerWithClientAsync(List<TestDocument> documents = default)
{
var containerClient = await CreateContainerAsync("target", documents);
var expiresOn = DateTimeOffset.UtcNow.AddHours(1);
var containerSasUri = containerClient.GenerateSasUri(BlobContainerSasPermissions.List | BlobContainerSasPermissions.Write, expiresOn);
return Tuple.Create(containerSasUri, containerClient);
return Tuple.Create(containerClient.Uri, containerClient);
}

private BlobContainerClient CreateContainer(string name, List<TestDocument> documents)
{
var containerName = name + Recording.GenerateId();
var containerClient = GetBlobContainerClient(containerName);
containerClient.Create();
BlobContainerClient containerClient = GetBlobContainerClient(containerName);

if (documents != default)
{
Expand All @@ -153,8 +148,7 @@ private BlobContainerClient CreateContainer(string name, List<TestDocument> docu
private async Task<BlobContainerClient> CreateContainerAsync(string name, List<TestDocument> documents)
{
string containerName = name + Recording.GenerateId();
var containerClient = GetBlobContainerClient(containerName);
await containerClient.CreateAsync().ConfigureAwait(false);
BlobContainerClient containerClient = GetBlobContainerClient(containerName);

if (documents != default)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,10 @@

/// <summary>The name of the environment variable from which the Document Translator Storage Account Name will be extracted for the live tests.</summary>
private const string StorageAccountNameEnvironmentVariableName = "DOCUMENT_TRANSLATION_STORAGE_NAME";

Check failure on line 25 in sdk/translation/Azure.AI.Translation.Document/tests/Infrastructure/DocumentTranslationTestEnvironment.cs

View check run for this annotation

Azure Pipelines / net - translation - ci (Build Test Ubuntu2004_NET60_PackageRef_Debug)

sdk/translation/Azure.AI.Translation.Document/tests/Infrastructure/DocumentTranslationTestEnvironment.cs#L25

sdk/translation/Azure.AI.Translation.Document/tests/Infrastructure/DocumentTranslationTestEnvironment.cs(25,1): Error SA1507: Code should not contain multiple blank lines in a row (https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1507.md)

Check failure on line 25 in sdk/translation/Azure.AI.Translation.Document/tests/Infrastructure/DocumentTranslationTestEnvironment.cs

View check run for this annotation

Azure Pipelines / net - translation - ci (Build Test Ubuntu2004_NET70_ProjectRef_Release)

sdk/translation/Azure.AI.Translation.Document/tests/Infrastructure/DocumentTranslationTestEnvironment.cs#L25

sdk/translation/Azure.AI.Translation.Document/tests/Infrastructure/DocumentTranslationTestEnvironment.cs(25,1): Error SA1507: Code should not contain multiple blank lines in a row (https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1507.md)

Check failure on line 25 in sdk/translation/Azure.AI.Translation.Document/tests/Infrastructure/DocumentTranslationTestEnvironment.cs

View check run for this annotation

Azure Pipelines / net - translation - ci (Build Test MacOS_NET70_ProjectRef_Release)

sdk/translation/Azure.AI.Translation.Document/tests/Infrastructure/DocumentTranslationTestEnvironment.cs#L25

sdk/translation/Azure.AI.Translation.Document/tests/Infrastructure/DocumentTranslationTestEnvironment.cs(25,1): Error SA1507: Code should not contain multiple blank lines in a row (https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1507.md)

Check failure on line 25 in sdk/translation/Azure.AI.Translation.Document/tests/Infrastructure/DocumentTranslationTestEnvironment.cs

View check run for this annotation

Azure Pipelines / net - translation - ci (Build Test MacOS_NET60_PackageRef_Debug)

sdk/translation/Azure.AI.Translation.Document/tests/Infrastructure/DocumentTranslationTestEnvironment.cs#L25

sdk/translation/Azure.AI.Translation.Document/tests/Infrastructure/DocumentTranslationTestEnvironment.cs(25,1): Error SA1507: Code should not contain multiple blank lines in a row (https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1507.md)

Check failure on line 25 in sdk/translation/Azure.AI.Translation.Document/tests/Infrastructure/DocumentTranslationTestEnvironment.cs

View check run for this annotation

Azure Pipelines / net - translation - ci

sdk/translation/Azure.AI.Translation.Document/tests/Infrastructure/DocumentTranslationTestEnvironment.cs#L25

sdk/translation/Azure.AI.Translation.Document/tests/Infrastructure/DocumentTranslationTestEnvironment.cs(25,1): Error SA1507: Code should not contain multiple blank lines in a row (https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1507.md)
/// <summary>The name of the environment variable from which the Document Translator Storage Primary key will be extracted for the live tests.</summary>
private const string StorageConnectionStringEnvironmentVariableName = "DOCUMENT_TRANSLATION_CONNECTION_STRING";

public string ApiKey => GetRecordedVariable(ApiKeyEnvironmentVariableName, options => options.IsSecret());
public string Endpoint => GetRecordedVariable(EndpointEnvironmentVariableName);
public string StorageConnectionString => GetRecordedVariable(StorageConnectionStringEnvironmentVariableName, options => options.HasSecretConnectionStringParameter("AccountKey", SanitizedValue.Base64));
public string StorageAccountName => GetRecordedVariable(StorageAccountNameEnvironmentVariableName);

protected override async ValueTask<bool> IsEnvironmentReadyAsync()
Expand Down
Loading
Loading