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
Merged
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
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