Skip to content

Commit

Permalink
Creating SDT client with endpoint only and making source input option…
Browse files Browse the repository at this point in the history
…s public (Azure#44862)

* SouceInput options are made public. Tests are updated to access stoarge accounts using managed identity and no loger through SAS urls. Single document translation client can be created using endpoint alone, mainly for SDK to work against containers.

* Updating commit ID of specs repo to the latest

* Fixing build and analyze failures

* Fixing build errors

* Fixing tests failing in MacOS by updating Default credentials with Token credentials while creating BlobServiceClient

* Test recordings validated and updated
  • Loading branch information
hamshavathimunibyraiah authored and tejasm-microsoft committed Jul 22, 2024
1 parent 458e91d commit 155ac61
Show file tree
Hide file tree
Showing 15 changed files with 304 additions and 40 deletions.
8 changes: 3 additions & 5 deletions sdk/translation/Azure.AI.Translation.Document/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
# Release History

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

### Features Added

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

### Bugs Fixed

### Other Changes
- 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.

## 2.0.0-beta.1 (2024-05-07)

Expand Down
2 changes: 2 additions & 0 deletions sdk/translation/Azure.AI.Translation.Document/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ Samples showing how to use the Cognitive Services Document Translation library a
- [Operations History][operations_history_sample]

### Advanced samples
- [Start Translation with SourceInput][start_translation_with_sourceInput_sample]
- [Multiple Inputs][multiple_Inputs_sample]
- [Create Storage Containers and start translation][using_storage_sample]

Expand Down Expand Up @@ -517,6 +518,7 @@ This project has adopted the [Microsoft Open Source Code of Conduct][code_of_con
[operations_history_sample]: https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/translation/Azure.AI.Translation.Document/samples/Sample3_OperationsHistory.md
[multiple_inputs_sample]: https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/translation/Azure.AI.Translation.Document/samples/Sample4_MultipleInputs.md
[using_storage_sample]: https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/translation/Azure.AI.Translation.Document/tests/samples/Sample_StartTranslationWithAzureBlob.cs
[start_translation_with_sourceInput_sample]: https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/translation/Azure.AI.Translation.Document/tests/samples/Sample_StartTranslationWithSourceInput.cs

[azure_cli]: https://docs.microsoft.com/cli/azure
[azure_sub]: https://azure.microsoft.com/free/dotnet/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,8 @@ public MultipartFormFileData(string name, System.IO.Stream content, string conte
public partial class SingleDocumentTranslationClient
{
protected SingleDocumentTranslationClient() { }
public SingleDocumentTranslationClient(System.Uri endpoint) { }
public SingleDocumentTranslationClient(System.Uri endpoint, Azure.AI.Translation.Document.DocumentTranslationClientOptions options) { }
public SingleDocumentTranslationClient(System.Uri endpoint, Azure.AzureKeyCredential credential) { }
public SingleDocumentTranslationClient(System.Uri endpoint, Azure.AzureKeyCredential credential, Azure.AI.Translation.Document.DocumentTranslationClientOptions options) { }
public SingleDocumentTranslationClient(System.Uri endpoint, Azure.Core.TokenCredential credential) { }
Expand Down Expand Up @@ -314,6 +316,7 @@ public TranslationGlossary(System.Uri glossaryUri, string format) { }
public partial class TranslationSource : System.ClientModel.Primitives.IJsonModel<Azure.AI.Translation.Document.TranslationSource>, System.ClientModel.Primitives.IPersistableModel<Azure.AI.Translation.Document.TranslationSource>
{
public TranslationSource(System.Uri sourceUri) { }
public TranslationSource(System.Uri sourceUri, string languageCode = null, string storageSource = null, string prefix = null, string suffix = null) { }
public string LanguageCode { get { throw null; } set { } }
public string Prefix { get { throw null; } set { } }
public System.Uri SourceUri { get { throw null; } }
Expand Down
2 changes: 1 addition & 1 deletion sdk/translation/Azure.AI.Translation.Document/assets.json
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_4ee1e847a5"
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Azure Cognitive Services Document Translation is a cloud service that translates
- [Synchronous Document Translation](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/translation/Azure.AI.Translation.Document/samples/Sample5_SynchronousTranslation.md)

## Advanced samples
- [Start Translation with SourceInput](https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/translation/Azure.AI.Translation.Document/tests/samples/Sample_StartTranslationWithSourceInput.cs)
- [Multiple Inputs](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/translation/Azure.AI.Translation.Document/samples/Sample4_MultipleInputs.md)
- [Create Storage Containers And Submit Operation (code sample)](https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/translation/Azure.AI.Translation.Document/tests/samples/Sample_StartTranslationWithAzureBlob.cs)

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,52 @@ 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");
TranslationTarget translationTarget = new TranslationTarget(targetUri, "fr");
List<TranslationTarget> targets = new List<TranslationTarget> { translationTarget };
var input = new DocumentTranslationInput(translationSource, targets);
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),
TestEnvironment.Credential,
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
Loading

0 comments on commit 155ac61

Please sign in to comment.